OLD | NEW |
(Empty) | |
| 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, 2009, 2010 The S
Cons 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 __revision__ = "src/engine/SCons/Variables/__init__.py 5134 2010/08/16 23:02:40
bdeegan" |
| 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 # okay |
| 40 from EnumVariable import EnumVariable # okay |
| 41 from ListVariable import ListVariable # naja |
| 42 from PackageVariable import PackageVariable # naja |
| 43 from PathVariable import PathVariable # okay |
| 44 |
| 45 |
| 46 class Variables(object): |
| 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=[], args={}, 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 self.options = [] |
| 60 self.args = args |
| 61 if not SCons.Util.is_List(files): |
| 62 if files: |
| 63 files = [ files ] |
| 64 else: |
| 65 files = [] |
| 66 self.files = files |
| 67 self.unknown = {} |
| 68 |
| 69 # create the singleton instance |
| 70 if is_global: |
| 71 self=Variables.instance |
| 72 |
| 73 if not Variables.instance: |
| 74 Variables.instance=self |
| 75 |
| 76 def _do_add(self, key, help="", default=None, validator=None, converter=None
): |
| 77 class Variable(object): |
| 78 pass |
| 79 |
| 80 option = Variable() |
| 81 |
| 82 # if we get a list or a tuple, we take the first element as the |
| 83 # option key and store the remaining in aliases. |
| 84 if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key): |
| 85 option.key = key[0] |
| 86 option.aliases = key[1:] |
| 87 else: |
| 88 option.key = key |
| 89 option.aliases = [ key ] |
| 90 option.help = help |
| 91 option.default = default |
| 92 option.validator = validator |
| 93 option.converter = converter |
| 94 |
| 95 self.options.append(option) |
| 96 |
| 97 # options might be added after the 'unknown' dict has been set up, |
| 98 # so we remove the key and all its aliases from that dict |
| 99 for alias in list(option.aliases) + [ option.key ]: |
| 100 if alias in self.unknown: |
| 101 del self.unknown[alias] |
| 102 |
| 103 def keys(self): |
| 104 """ |
| 105 Returns the keywords for the options |
| 106 """ |
| 107 return [o.key for o in self.options] |
| 108 |
| 109 def Add(self, key, help="", default=None, validator=None, converter=None, **
kw): |
| 110 """ |
| 111 Add an option. |
| 112 |
| 113 key - the name of the variable, or a list or tuple of arguments |
| 114 help - optional help text for the options |
| 115 default - optional default value |
| 116 validator - optional function that is called to validate the option's va
lue |
| 117 Called with (key, value, environment) |
| 118 converter - optional function that is called to convert the option's val
ue before |
| 119 putting it in the environment. |
| 120 """ |
| 121 |
| 122 if SCons.Util.is_List(key) or isinstance(key, tuple): |
| 123 self._do_add(*key) |
| 124 return |
| 125 |
| 126 if not SCons.Util.is_String(key) or \ |
| 127 not SCons.Environment.is_valid_construction_var(key): |
| 128 raise SCons.Errors.UserError("Illegal Variables.Add() key `%s'"
% str(key)) |
| 129 |
| 130 self._do_add(key, help, default, validator, converter) |
| 131 |
| 132 def AddVariables(self, *optlist): |
| 133 """ |
| 134 Add a list of options. |
| 135 |
| 136 Each list element is a tuple/list of arguments to be passed on |
| 137 to the underlying method for adding options. |
| 138 |
| 139 Example: |
| 140 opt.AddVariables( |
| 141 ('debug', '', 0), |
| 142 ('CC', 'The C compiler'), |
| 143 ('VALIDATE', 'An option for testing validation', 'notset', |
| 144 validator, None), |
| 145 ) |
| 146 """ |
| 147 for o in optlist: |
| 148 self._do_add(*o) |
| 149 |
| 150 |
| 151 def Update(self, env, args=None): |
| 152 """ |
| 153 Update an environment with the option variables. |
| 154 |
| 155 env - the environment to update. |
| 156 """ |
| 157 |
| 158 values = {} |
| 159 |
| 160 # first set the defaults: |
| 161 for option in self.options: |
| 162 if not option.default is None: |
| 163 values[option.key] = option.default |
| 164 |
| 165 # next set the value specified in the options file |
| 166 for filename in self.files: |
| 167 if os.path.exists(filename): |
| 168 dir = os.path.split(os.path.abspath(filename))[0] |
| 169 if dir: |
| 170 sys.path.insert(0, dir) |
| 171 try: |
| 172 values['__name__'] = filename |
| 173 exec open(filename, 'rU').read() in {}, values |
| 174 finally: |
| 175 if dir: |
| 176 del sys.path[0] |
| 177 del values['__name__'] |
| 178 |
| 179 # set the values specified on the command line |
| 180 if args is None: |
| 181 args = self.args |
| 182 |
| 183 for arg, value in args.items(): |
| 184 added = False |
| 185 for option in self.options: |
| 186 if arg in list(option.aliases) + [ option.key ]: |
| 187 values[option.key] = value |
| 188 added = True |
| 189 if not added: |
| 190 self.unknown[arg] = value |
| 191 |
| 192 # put the variables in the environment: |
| 193 # (don't copy over variables that are not declared as options) |
| 194 for option in self.options: |
| 195 try: |
| 196 env[option.key] = values[option.key] |
| 197 except KeyError: |
| 198 pass |
| 199 |
| 200 # Call the convert functions: |
| 201 for option in self.options: |
| 202 if option.converter and option.key in values: |
| 203 value = env.subst('${%s}'%option.key) |
| 204 try: |
| 205 try: |
| 206 env[option.key] = option.converter(value) |
| 207 except TypeError: |
| 208 env[option.key] = option.converter(value, env) |
| 209 except ValueError, x: |
| 210 raise SCons.Errors.UserError('Error converting option: %s\n%
s'%(option.key, x)) |
| 211 |
| 212 |
| 213 # Finally validate the values: |
| 214 for option in self.options: |
| 215 if option.validator and option.key in values: |
| 216 option.validator(option.key, env.subst('${%s}'%option.key), env) |
| 217 |
| 218 def UnknownVariables(self): |
| 219 """ |
| 220 Returns any options in the specified arguments lists that |
| 221 were not known, declared options in this object. |
| 222 """ |
| 223 return self.unknown |
| 224 |
| 225 def Save(self, filename, env): |
| 226 """ |
| 227 Saves all the options in the given file. This file can |
| 228 then be used to load the options next run. This can be used |
| 229 to create an option cache file. |
| 230 |
| 231 filename - Name of the file to save into |
| 232 env - the environment get the option values from |
| 233 """ |
| 234 |
| 235 # Create the file and write out the header |
| 236 try: |
| 237 fh = open(filename, 'w') |
| 238 |
| 239 try: |
| 240 # Make an assignment in the file for each option |
| 241 # within the environment that was assigned a value |
| 242 # other than the default. |
| 243 for option in self.options: |
| 244 try: |
| 245 value = env[option.key] |
| 246 try: |
| 247 prepare = value.prepare_to_store |
| 248 except AttributeError: |
| 249 try: |
| 250 eval(repr(value)) |
| 251 except KeyboardInterrupt: |
| 252 raise |
| 253 except: |
| 254 # Convert stuff that has a repr() that |
| 255 # cannot be evaluated into a string |
| 256 value = SCons.Util.to_String(value) |
| 257 else: |
| 258 value = prepare() |
| 259 |
| 260 defaultVal = env.subst(SCons.Util.to_String(option.defau
lt)) |
| 261 if option.converter: |
| 262 defaultVal = option.converter(defaultVal) |
| 263 |
| 264 if str(env.subst('${%s}' % option.key)) != str(defaultVa
l): |
| 265 fh.write('%s = %s\n' % (option.key, repr(value))) |
| 266 except KeyError: |
| 267 pass |
| 268 finally: |
| 269 fh.close() |
| 270 |
| 271 except IOError, x: |
| 272 raise SCons.Errors.UserError('Error writing options to file: %s\n%s'
% (filename, x)) |
| 273 |
| 274 def GenerateHelpText(self, env, sort=None): |
| 275 """ |
| 276 Generate the help text for the options. |
| 277 |
| 278 env - an environment that is used to get the current values |
| 279 of the options. |
| 280 """ |
| 281 |
| 282 if sort: |
| 283 options = sorted(self.options, key=lambda x: x.key) |
| 284 else: |
| 285 options = self.options |
| 286 |
| 287 def format(opt, self=self, env=env): |
| 288 if opt.key in env: |
| 289 actual = env.subst('${%s}' % opt.key) |
| 290 else: |
| 291 actual = None |
| 292 return self.FormatVariableHelpText(env, opt.key, opt.help, opt.defau
lt, actual, opt.aliases) |
| 293 lines = [_f for _f in map(format, options) if _f] |
| 294 |
| 295 return ''.join(lines) |
| 296 |
| 297 format = '\n%s: %s\n default: %s\n actual: %s\n' |
| 298 format_ = '\n%s: %s\n default: %s\n actual: %s\n aliases: %s\n' |
| 299 |
| 300 def FormatVariableHelpText(self, env, key, help, default, actual, aliases=[]
): |
| 301 # Don't display the key name itself as an alias. |
| 302 aliases = [a for a in aliases if a != key] |
| 303 if len(aliases)==0: |
| 304 return self.format % (key, help, default, actual) |
| 305 else: |
| 306 return self.format_ % (key, help, default, actual, aliases) |
| 307 |
| 308 # Local Variables: |
| 309 # tab-width:4 |
| 310 # indent-tabs-mode:nil |
| 311 # End: |
| 312 # vim: set expandtab tabstop=4 shiftwidth=4: |
OLD | NEW |