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