5d73e10dd0be6f967c57a0ce6daa9aa62a0a4935
[senf.git] / scons / scons-1.2.0 / engine / SCons / Variables / __init__.py
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 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
9 #
10 # Permission is hereby granted, free of charge, to any person obtaining
11 # a copy of this software and associated documentation files (the
12 # "Software"), to deal in the Software without restriction, including
13 # without limitation the rights to use, copy, modify, merge, publish,
14 # distribute, sublicense, and/or sell copies of the Software, and to
15 # permit persons to whom the Software is furnished to do so, subject to
16 # the following conditions:
17 #
18 # The above copyright notice and this permission notice shall be included
19 # in all copies or substantial portions of the Software.
20 #
21 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
22 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
23 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #
29
30 __revision__ = "src/engine/SCons/Variables/__init__.py 3842 2008/12/20 22:59:52 scons"
31
32 import os.path
33 import string
34 import sys
35
36 import SCons.Environment
37 import SCons.Errors
38 import SCons.Util
39 import SCons.Warnings
40
41 from BoolVariable import BoolVariable  # okay
42 from EnumVariable import EnumVariable  # okay
43 from ListVariable import ListVariable  # naja
44 from PackageVariable import PackageVariable # naja
45 from PathVariable import PathVariable # okay
46
47
48 class Variables:
49     instance=None
50
51     """
52     Holds all the options, updates the environment with the variables,
53     and renders the help text.
54     """
55     def __init__(self, files=[], args={}, is_global=1):
56         """
57         files - [optional] List of option configuration files to load
58             (backward compatibility) If a single string is passed it is
59                                      automatically placed in a file list
60         """
61         self.options = []
62         self.args = args
63         if not SCons.Util.is_List(files):
64             if files:
65                 files = [ files ]
66             else:
67                 files = []
68         self.files = files
69         self.unknown = {}
70
71         # create the singleton instance
72         if is_global:
73             self=Variables.instance
74
75             if not Variables.instance:
76                 Variables.instance=self
77
78     def _do_add(self, key, help="", default=None, validator=None, converter=None):
79         class Variable:
80             pass
81
82         option = Variable()
83
84         # if we get a list or a tuple, we take the first element as the
85         # option key and store the remaining in aliases.
86         if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key):
87           option.key     = key[0]
88           option.aliases = key[1:]
89         else:
90           option.key     = key
91           option.aliases = [ key ]
92         option.help = help
93         option.default = default
94         option.validator = validator
95         option.converter = converter
96
97         self.options.append(option)
98
99     def keys(self):
100         """
101         Returns the keywords for the options
102         """
103         return map(lambda o: o.key, self.options)
104
105     def Add(self, key, help="", default=None, validator=None, converter=None, **kw):
106         """
107         Add an option.
108
109         key - the name of the variable, or a list or tuple of arguments
110         help - optional help text for the options
111         default - optional default value
112         validator - optional function that is called to validate the option's value
113                     Called with (key, value, environment)
114         converter - optional function that is called to convert the option's value before
115                     putting it in the environment.
116         """
117
118         if SCons.Util.is_List(key) or type(key) == type(()):
119             apply(self._do_add, key)
120             return
121
122         if not SCons.Util.is_String(key) or \
123            not SCons.Environment.is_valid_construction_var(key):
124             raise SCons.Errors.UserError, "Illegal Variables.Add() key `%s'" % str(key)
125
126         self._do_add(key, help, default, validator, converter)
127
128     def AddVariables(self, *optlist):
129         """
130         Add a list of options.
131
132         Each list element is a tuple/list of arguments to be passed on
133         to the underlying method for adding options.
134
135         Example:
136           opt.AddVariables(
137             ('debug', '', 0),
138             ('CC', 'The C compiler'),
139             ('VALIDATE', 'An option for testing validation', 'notset',
140              validator, None),
141             )
142         """
143         for o in optlist:
144             apply(self._do_add, o)
145
146
147     def Update(self, env, args=None):
148         """
149         Update an environment with the option variables.
150
151         env - the environment to update.
152         """
153
154         values = {}
155
156         # first set the defaults:
157         for option in self.options:
158             if not option.default is None:
159                 values[option.key] = option.default
160
161         # next set the value specified in the options file
162         for filename in self.files:
163             if os.path.exists(filename):
164                 dir = os.path.split(os.path.abspath(filename))[0]
165                 if dir:
166                     sys.path.insert(0, dir)
167                 try:
168                     values['__name__'] = filename
169                     execfile(filename, {}, values)
170                 finally:
171                     if dir:
172                         del sys.path[0]
173                     del values['__name__']
174
175         # set the values specified on the command line
176         if args is None:
177             args = self.args
178
179         for arg, value in args.items():
180             added = False
181             for option in self.options:
182                 if arg in option.aliases + [ option.key ]:
183                     values[option.key] = value
184                     added = True
185             if not added:
186                 self.unknown[arg] = value
187
188         # put the variables in the environment:
189         # (don't copy over variables that are not declared as options)
190         for option in self.options:
191             try:
192                 env[option.key] = values[option.key]
193             except KeyError:
194                 pass
195
196         # Call the convert functions:
197         for option in self.options:
198             if option.converter and values.has_key(option.key):
199                 value = env.subst('${%s}'%option.key)
200                 try:
201                     try:
202                         env[option.key] = option.converter(value)
203                     except TypeError:
204                         env[option.key] = option.converter(value, env)
205                 except ValueError, x:
206                     raise SCons.Errors.UserError, 'Error converting option: %s\n%s'%(option.key, x)
207
208
209         # Finally validate the values:
210         for option in self.options:
211             if option.validator and values.has_key(option.key):
212                 option.validator(option.key, env.subst('${%s}'%option.key), env)
213
214     def UnknownVariables(self):
215         """
216         Returns any options in the specified arguments lists that
217         were not known, declared options in this object.
218         """
219         return self.unknown
220
221     def Save(self, filename, env):
222         """
223         Saves all the options in the given file.  This file can
224         then be used to load the options next run.  This can be used
225         to create an option cache file.
226
227         filename - Name of the file to save into
228         env - the environment get the option values from
229         """
230
231         # Create the file and write out the header
232         try:
233             fh = open(filename, 'w')
234
235             try:
236                 # Make an assignment in the file for each option
237                 # within the environment that was assigned a value
238                 # other than the default.
239                 for option in self.options:
240                     try:
241                         value = env[option.key]
242                         try:
243                             prepare = value.prepare_to_store
244                         except AttributeError:
245                             try:
246                                 eval(repr(value))
247                             except KeyboardInterrupt:
248                                 raise
249                             except:
250                                 # Convert stuff that has a repr() that
251                                 # cannot be evaluated into a string
252                                 value = SCons.Util.to_String(value)
253                         else:
254                             value = prepare()
255
256                         defaultVal = env.subst(SCons.Util.to_String(option.default))
257                         if option.converter:
258                             defaultVal = option.converter(defaultVal)
259
260                         if str(env.subst('${%s}' % option.key)) != str(defaultVal):
261                             fh.write('%s = %s\n' % (option.key, repr(value)))
262                     except KeyError:
263                         pass
264             finally:
265                 fh.close()
266
267         except IOError, x:
268             raise SCons.Errors.UserError, 'Error writing options to file: %s\n%s' % (filename, x)
269
270     def GenerateHelpText(self, env, sort=None):
271         """
272         Generate the help text for the options.
273
274         env - an environment that is used to get the current values
275               of the options.
276         """
277
278         if sort:
279             options = self.options[:]
280             options.sort(lambda x,y,func=sort: func(x.key,y.key))
281         else:
282             options = self.options
283
284         def format(opt, self=self, env=env):
285             if env.has_key(opt.key):
286                 actual = env.subst('${%s}' % opt.key)
287             else:
288                 actual = None
289             return self.FormatVariableHelpText(env, opt.key, opt.help, opt.default, actual, opt.aliases)
290         lines = filter(None, map(format, options))
291
292         return string.join(lines, '')
293
294     format  = '\n%s: %s\n    default: %s\n    actual: %s\n'
295     format_ = '\n%s: %s\n    default: %s\n    actual: %s\n    aliases: %s\n'
296
297     def FormatVariableHelpText(self, env, key, help, default, actual, aliases=[]):
298         # Don't display the key name itself as an alias.
299         aliases = filter(lambda a, k=key: a != k, aliases)
300         if len(aliases)==0:
301             return self.format % (key, help, default, actual)
302         else:
303             return self.format_ % (key, help, default, actual, aliases)
304