1 """engine.SCons.Variables
2
3 This file defines the Variables class that is used to add user-friendly
4 customizable variables to an SCons build.
5 """
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 __revision__ = "src/engine/SCons/Variables/__init__.py 3a41ed6b288cee8d085373ad7fa02894e1903864 2019-01-23 17:30:35 bdeegan"
30
31 import os.path
32 import sys
33 from functools import cmp_to_key
34
35 import SCons.Environment
36 import SCons.Errors
37 import SCons.Util
38 import SCons.Warnings
39
40 from .BoolVariable import BoolVariable
41 from .EnumVariable import EnumVariable
42 from .ListVariable import ListVariable
43 from .PackageVariable import PackageVariable
44 from .PathVariable import PathVariable
45
46
48 instance=None
49
50 """
51 Holds all the options, updates the environment with the variables,
52 and renders the help text.
53 """
54 - def __init__(self, files=None, args=None, is_global=1):
55 """
56 files - [optional] List of option configuration files to load
57 (backward compatibility) If a single string is passed it is
58 automatically placed in a file list
59 """
60
61 if files is None:
62 files = []
63 if args is None:
64 args = {}
65 self.options = []
66 self.args = args
67 if not SCons.Util.is_List(files):
68 if files:
69 files = [ files ]
70 else:
71 files = []
72 self.files = files
73 self.unknown = {}
74
75
76 if is_global:
77 self=Variables.instance
78
79 if not Variables.instance:
80 Variables.instance=self
81
82 - def _do_add(self, key, help="", default=None, validator=None, converter=None):
83 class Variable(object):
84 pass
85
86 option = Variable()
87
88
89
90 if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key):
91 option.key = key[0]
92 option.aliases = key[1:]
93 else:
94 option.key = key
95 option.aliases = [ key ]
96 option.help = help
97 option.default = default
98 option.validator = validator
99 option.converter = converter
100
101 self.options.append(option)
102
103
104
105 for alias in list(option.aliases) + [ option.key ]:
106 if alias in self.unknown:
107 del self.unknown[alias]
108
110 """
111 Returns the keywords for the options
112 """
113 return [o.key for o in self.options]
114
115 - def Add(self, key, help="", default=None, validator=None, converter=None, **kw):
116 """
117 Add an option.
118
119
120 @param key: the name of the variable, or a list or tuple of arguments
121 @param help: optional help text for the options
122 @param default: optional default value
123 @param validator: optional function that is called to validate the option's value
124 @type validator: Called with (key, value, environment)
125 @param converter: optional function that is called to convert the option's value before putting it in the environment.
126 """
127
128 if SCons.Util.is_List(key) or isinstance(key, tuple):
129 self._do_add(*key)
130 return
131
132 if not SCons.Util.is_String(key) or \
133 not SCons.Environment.is_valid_construction_var(key):
134 raise SCons.Errors.UserError("Illegal Variables.Add() key `%s'" % str(key))
135
136 self._do_add(key, help, default, validator, converter)
137
139 """
140 Add a list of options.
141
142 Each list element is a tuple/list of arguments to be passed on
143 to the underlying method for adding options.
144
145 Example::
146
147 opt.AddVariables(
148 ('debug', '', 0),
149 ('CC', 'The C compiler'),
150 ('VALIDATE', 'An option for testing validation', 'notset',
151 validator, None),
152 )
153
154 """
155
156 for o in optlist:
157 self._do_add(*o)
158
159
160 - def Update(self, env, args=None):
161 """
162 Update an environment with the option variables.
163
164 env - the environment to update.
165 """
166
167 values = {}
168
169
170 for option in self.options:
171 if not option.default is None:
172 values[option.key] = option.default
173
174
175 for filename in self.files:
176 if os.path.exists(filename):
177 dir = os.path.split(os.path.abspath(filename))[0]
178 if dir:
179 sys.path.insert(0, dir)
180 try:
181 values['__name__'] = filename
182 with open(filename, 'r') as f:
183 contents = f.read()
184 exec(contents, {}, values)
185 finally:
186 if dir:
187 del sys.path[0]
188 del values['__name__']
189
190
191 if args is None:
192 args = self.args
193
194 for arg, value in args.items():
195 added = False
196 for option in self.options:
197 if arg in list(option.aliases) + [ option.key ]:
198 values[option.key] = value
199 added = True
200 if not added:
201 self.unknown[arg] = value
202
203
204
205 for option in self.options:
206 try:
207 env[option.key] = values[option.key]
208 except KeyError:
209 pass
210
211
212 for option in self.options:
213 if option.converter and option.key in values:
214 value = env.subst('${%s}'%option.key)
215 try:
216 try:
217 env[option.key] = option.converter(value)
218 except TypeError:
219 env[option.key] = option.converter(value, env)
220 except ValueError as x:
221 raise SCons.Errors.UserError('Error converting option: %s\n%s'%(option.key, x))
222
223
224
225 for option in self.options:
226 if option.validator and option.key in values:
227 option.validator(option.key, env.subst('${%s}'%option.key), env)
228
230 """
231 Returns any options in the specified arguments lists that
232 were not known, declared options in this object.
233 """
234 return self.unknown
235
236 - def Save(self, filename, env):
237 """
238 Saves all the options in the given file. This file can
239 then be used to load the options next run. This can be used
240 to create an option cache file.
241
242 filename - Name of the file to save into
243 env - the environment get the option values from
244 """
245
246
247 try:
248 fh = open(filename, 'w')
249
250 try:
251
252
253
254 for option in self.options:
255 try:
256 value = env[option.key]
257 try:
258 prepare = value.prepare_to_store
259 except AttributeError:
260 try:
261 eval(repr(value))
262 except KeyboardInterrupt:
263 raise
264 except:
265
266
267 value = SCons.Util.to_String(value)
268 else:
269 value = prepare()
270
271 defaultVal = env.subst(SCons.Util.to_String(option.default))
272 if option.converter:
273 defaultVal = option.converter(defaultVal)
274
275 if str(env.subst('${%s}' % option.key)) != str(defaultVal):
276 fh.write('%s = %s\n' % (option.key, repr(value)))
277 except KeyError:
278 pass
279 finally:
280 fh.close()
281
282 except IOError as x:
283 raise SCons.Errors.UserError('Error writing options to file: %s\n%s' % (filename, x))
284
285 - def GenerateHelpText(self, env, sort=None):
286 """
287 Generate the help text for the options.
288
289 env - an environment that is used to get the current values
290 of the options.
291 cmp - Either a function as follows: The specific sort function should take two arguments and return -1, 0 or 1
292 or a boolean to indicate if it should be sorted.
293 """
294
295 if callable(sort):
296 options = sorted(self.options, key=cmp_to_key(lambda x,y: sort(x.key,y.key)))
297 elif sort is True:
298 options = sorted(self.options, key=lambda x: x.key)
299 else:
300 options = self.options
301
302 def format(opt, self=self, env=env):
303 if opt.key in env:
304 actual = env.subst('${%s}' % opt.key)
305 else:
306 actual = None
307 return self.FormatVariableHelpText(env, opt.key, opt.help, opt.default, actual, opt.aliases)
308 lines = [_f for _f in map(format, options) if _f]
309
310 return ''.join(lines)
311
312 format = '\n%s: %s\n default: %s\n actual: %s\n'
313 format_ = '\n%s: %s\n default: %s\n actual: %s\n aliases: %s\n'
314
316
317 aliases = [a for a in aliases if a != key]
318 if len(aliases)==0:
319 return self.format % (key, help, default, actual)
320 else:
321 return self.format_ % (key, help, default, actual, aliases)
322
323
324
325
326
327
328