| OLD | NEW |
| 1 """SCons.Action | 1 """SCons.Action |
| 2 | 2 |
| 3 This encapsulates information about executing any sort of action that | 3 This encapsulates information about executing any sort of action that |
| 4 can build one or more target Nodes (typically files) from one or more | 4 can build one or more target Nodes (typically files) from one or more |
| 5 source Nodes (also typically files) given a specific Environment. | 5 source Nodes (also typically files) given a specific Environment. |
| 6 | 6 |
| 7 The base class here is ActionBase. The base class supplies just a few | 7 The base class here is ActionBase. The base class supplies just a few |
| 8 OO utility methods and some generic methods for displaying information | 8 OO utility methods and some generic methods for displaying information |
| 9 about an Action in response to the various commands that control printing. | 9 about an Action in response to the various commands that control printing. |
| 10 | 10 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 | 23 |
| 24 The subclasses supply the following public interface methods used by | 24 The subclasses supply the following public interface methods used by |
| 25 other modules: | 25 other modules: |
| 26 | 26 |
| 27 __call__() | 27 __call__() |
| 28 THE public interface, "calling" an Action object executes the | 28 THE public interface, "calling" an Action object executes the |
| 29 command or Python function. This also takes care of printing | 29 command or Python function. This also takes care of printing |
| 30 a pre-substitution command for debugging purposes. | 30 a pre-substitution command for debugging purposes. |
| 31 | 31 |
| 32 get_contents() | 32 get_contents() |
| 33 Fetches the "contents" of an Action for signature calculation. | 33 Fetches the "contents" of an Action for signature calculation |
| 34 This is what gets MD5 checksumm'ed to decide if a target needs | 34 plus the varlist. This is what gets MD5 checksummed to decide |
| 35 to be rebuilt because its action changed. | 35 if a target needs to be rebuilt because its action changed. |
| 36 | 36 |
| 37 genstring() | 37 genstring() |
| 38 Returns a string representation of the Action *without* | 38 Returns a string representation of the Action *without* |
| 39 command substitution, but allows a CommandGeneratorAction to | 39 command substitution, but allows a CommandGeneratorAction to |
| 40 generate the right action based on the specified target, | 40 generate the right action based on the specified target, |
| 41 source and env. This is used by the Signature subsystem | 41 source and env. This is used by the Signature subsystem |
| 42 (through the Executor) to obtain an (imprecise) representation | 42 (through the Executor) to obtain an (imprecise) representation |
| 43 of the Action operation for informative purposes. | 43 of the Action operation for informative purposes. |
| 44 | 44 |
| 45 | 45 |
| 46 Subclasses also supply the following methods for internal use within | 46 Subclasses also supply the following methods for internal use within |
| 47 this module: | 47 this module: |
| 48 | 48 |
| 49 __str__() | 49 __str__() |
| 50 Returns a string approximation of the Action; no variable | 50 Returns a string approximation of the Action; no variable |
| 51 substitution is performed. | 51 substitution is performed. |
| 52 | 52 |
| 53 execute() | 53 execute() |
| 54 The internal method that really, truly, actually handles the | 54 The internal method that really, truly, actually handles the |
| 55 execution of a command or Python function. This is used so | 55 execution of a command or Python function. This is used so |
| 56 that the __call__() methods can take care of displaying any | 56 that the __call__() methods can take care of displaying any |
| 57 pre-substitution representations, and *then* execute an action | 57 pre-substitution representations, and *then* execute an action |
| 58 without worrying about the specific Actions involved. | 58 without worrying about the specific Actions involved. |
| 59 | 59 |
| 60 get_presig() |
| 61 Fetches the "contents" of a subclass for signature calculation. |
| 62 The varlist is added to this to produce the Action's contents. |
| 63 |
| 60 strfunction() | 64 strfunction() |
| 61 Returns a substituted string representation of the Action. | 65 Returns a substituted string representation of the Action. |
| 62 This is used by the _ActionAction.show() command to display the | 66 This is used by the _ActionAction.show() command to display the |
| 63 command/function that will be executed to generate the target(s). | 67 command/function that will be executed to generate the target(s). |
| 64 | 68 |
| 65 There is a related independent ActionCaller class that looks like a | 69 There is a related independent ActionCaller class that looks like a |
| 66 regular Action, and which serves as a wrapper for arbitrary functions | 70 regular Action, and which serves as a wrapper for arbitrary functions |
| 67 that we want to let the user specify the arguments to now, but actually | 71 that we want to let the user specify the arguments to now, but actually |
| 68 execute later (when an out-of-date check determines that it's needed to | 72 execute later (when an out-of-date check determines that it's needed to |
| 69 be executed, for example). Objects of this class are returned by an | 73 be executed, for example). Objects of this class are returned by an |
| 70 ActionFactory class that provides a __call__() method as a convenient | 74 ActionFactory class that provides a __call__() method as a convenient |
| 71 way for wrapping up the functions. | 75 way for wrapping up the functions. |
| 72 | 76 |
| 73 """ | 77 """ |
| 74 | 78 |
| 75 # | |
| 76 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundat
ion | 79 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundat
ion |
| 77 # | 80 # |
| 78 # Permission is hereby granted, free of charge, to any person obtaining | 81 # Permission is hereby granted, free of charge, to any person obtaining |
| 79 # a copy of this software and associated documentation files (the | 82 # a copy of this software and associated documentation files (the |
| 80 # "Software"), to deal in the Software without restriction, including | 83 # "Software"), to deal in the Software without restriction, including |
| 81 # without limitation the rights to use, copy, modify, merge, publish, | 84 # without limitation the rights to use, copy, modify, merge, publish, |
| 82 # distribute, sublicense, and/or sell copies of the Software, and to | 85 # distribute, sublicense, and/or sell copies of the Software, and to |
| 83 # permit persons to whom the Software is furnished to do so, subject to | 86 # permit persons to whom the Software is furnished to do so, subject to |
| 84 # the following conditions: | 87 # the following conditions: |
| 85 # | 88 # |
| 86 # The above copyright notice and this permission notice shall be included | 89 # The above copyright notice and this permission notice shall be included |
| 87 # in all copies or substantial portions of the Software. | 90 # in all copies or substantial portions of the Software. |
| 88 # | 91 # |
| 89 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY | 92 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
| 90 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | 93 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
| 91 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | 94 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 92 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | 95 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| 93 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | 96 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| 94 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | 97 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 95 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 98 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 96 # | |
| 97 | 99 |
| 98 __revision__ = "src/engine/SCons/Action.py 3603 2008/10/10 05:46:45 scons" | 100 __revision__ = "src/engine/SCons/Action.py 3842 2008/12/20 22:59:52 scons" |
| 99 | 101 |
| 100 import cPickle | 102 import cPickle |
| 101 import dis | 103 import dis |
| 102 import os | 104 import os |
| 103 import os.path | |
| 104 import string | 105 import string |
| 105 import sys | 106 import sys |
| 106 import subprocess | 107 import subprocess |
| 107 | 108 |
| 108 from SCons.Debug import logInstanceCreation | 109 from SCons.Debug import logInstanceCreation |
| 109 import SCons.Errors | 110 import SCons.Errors |
| 110 import SCons.Executor | 111 import SCons.Executor |
| 111 import SCons.Util | 112 import SCons.Util |
| 113 import SCons.Subst |
| 112 | 114 |
| 113 class _Null: | 115 # we use these a lot, so try to optimize them |
| 116 is_String = SCons.Util.is_String |
| 117 is_List = SCons.Util.is_List |
| 118 |
| 119 class _null: |
| 114 pass | 120 pass |
| 115 | 121 |
| 116 _null = _Null | |
| 117 | |
| 118 print_actions = 1 | 122 print_actions = 1 |
| 119 execute_actions = 1 | 123 execute_actions = 1 |
| 120 print_actions_presub = 0 | 124 print_actions_presub = 0 |
| 121 | 125 |
| 122 def rfile(n): | 126 def rfile(n): |
| 123 try: | 127 try: |
| 124 return n.rfile() | 128 return n.rfile() |
| 125 except AttributeError: | 129 except AttributeError: |
| 126 return n | 130 return n |
| 127 | 131 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 # Test if obj is a code object. | 172 # Test if obj is a code object. |
| 169 return _code_contents(obj) | 173 return _code_contents(obj) |
| 170 | 174 |
| 171 except AttributeError: | 175 except AttributeError: |
| 172 # Test if obj is a function object. | 176 # Test if obj is a function object. |
| 173 return _function_contents(obj) | 177 return _function_contents(obj) |
| 174 | 178 |
| 175 | 179 |
| 176 def _object_contents(obj): | 180 def _object_contents(obj): |
| 177 """Return the signature contents of any Python object. | 181 """Return the signature contents of any Python object. |
| 178 | 182 |
| 179 We have to handle the case where object contains a code object | 183 We have to handle the case where object contains a code object |
| 180 since it can be pickled directly. | 184 since it can be pickled directly. |
| 181 """ | 185 """ |
| 182 try: | 186 try: |
| 183 # Test if obj is a method. | 187 # Test if obj is a method. |
| 184 return _function_contents(obj.im_func) | 188 return _function_contents(obj.im_func) |
| 185 | 189 |
| 186 except AttributeError: | 190 except AttributeError: |
| 187 try: | 191 try: |
| 188 # Test if obj is a callable object. | 192 # Test if obj is a callable object. |
| 189 return _function_contents(obj.__call__.im_func) | 193 return _function_contents(obj.__call__.im_func) |
| 190 | 194 |
| 191 except AttributeError: | 195 except AttributeError: |
| 192 try: | 196 try: |
| 193 # Test if obj is a code object. | 197 # Test if obj is a code object. |
| 194 return _code_contents(obj) | 198 return _code_contents(obj) |
| 195 | 199 |
| 196 except AttributeError: | 200 except AttributeError: |
| 197 try: | 201 try: |
| 198 # Test if obj is a function object. | 202 # Test if obj is a function object. |
| 199 return _function_contents(obj) | 203 return _function_contents(obj) |
| 200 | 204 |
| 201 except AttributeError: | 205 except AttributeError: |
| 202 # Should be a pickable Python object. | 206 # Should be a pickable Python object. |
| 203 try: | 207 try: |
| 204 return cPickle.dumps(obj) | 208 return cPickle.dumps(obj) |
| 205 except (cPickle.PicklingError, TypeError): | 209 except (cPickle.PicklingError, TypeError): |
| 206 # This is weird, but it seems that nested classes | 210 # This is weird, but it seems that nested classes |
| 207 # are unpickable. The Python docs say it should | 211 # are unpickable. The Python docs say it should |
| 208 # always be a PicklingError, but some Python | 212 # always be a PicklingError, but some Python |
| 209 # versions seem to return TypeError. Just do | 213 # versions seem to return TypeError. Just do |
| 210 # the best we can. | 214 # the best we can. |
| 211 return str(obj) | 215 return str(obj) |
| 212 | 216 |
| 213 | 217 |
| 214 def _code_contents(code): | 218 def _code_contents(code): |
| 215 """Return the signature contents of a code object. | 219 """Return the signature contents of a code object. |
| 216 | 220 |
| 217 By providing direct access to the code object of the | 221 By providing direct access to the code object of the |
| 218 function, Python makes this extremely easy. Hooray! | 222 function, Python makes this extremely easy. Hooray! |
| 219 | 223 |
| 220 Unfortunately, older versions of Python include line | 224 Unfortunately, older versions of Python include line |
| 221 number indications in the compiled byte code. Boo! | 225 number indications in the compiled byte code. Boo! |
| 222 So we remove the line number byte codes to prevent | 226 So we remove the line number byte codes to prevent |
| 223 recompilations from moving a Python function. | 227 recompilations from moving a Python function. |
| 224 """ | 228 """ |
| 225 | 229 |
| 226 contents = [] | 230 contents = [] |
| 227 | 231 |
| 228 # The code contents depends on the number of local variables | 232 # The code contents depends on the number of local variables |
| 229 # but not their actual names. | 233 # but not their actual names. |
| 230 contents.append("%s,%s" % (code.co_argcount, len(code.co_varnames))) | 234 contents.append("%s,%s" % (code.co_argcount, len(code.co_varnames))) |
| 231 try: | 235 try: |
| 232 contents.append(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars)
)) | 236 contents.append(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars)
)) |
| 233 except AttributeError: | 237 except AttributeError: |
| 234 # Older versions of Python do not support closures. | 238 # Older versions of Python do not support closures. |
| 235 contents.append(",0,0") | 239 contents.append(",0,0") |
| 236 | 240 |
| 237 # The code contents depends on any constants accessed by the | 241 # The code contents depends on any constants accessed by the |
| 238 # function. Note that we have to call _object_contents on each | 242 # function. Note that we have to call _object_contents on each |
| 239 # constants because the code object of nested functions can | 243 # constants because the code object of nested functions can |
| 240 # show-up among the constants. | 244 # show-up among the constants. |
| 241 # | 245 # |
| 242 # Note that we also always ignore the first entry of co_consts | 246 # Note that we also always ignore the first entry of co_consts |
| 243 # which contains the function doc string. We assume that the | 247 # which contains the function doc string. We assume that the |
| 244 # function does not access its doc string. | 248 # function does not access its doc string. |
| 245 contents.append(',(' + string.join(map(_object_contents,code.co_consts[1:]),
',') + ')') | 249 contents.append(',(' + string.join(map(_object_contents,code.co_consts[1:]),
',') + ')') |
| 246 | 250 |
| 247 # The code contents depends on the variable names used to | 251 # The code contents depends on the variable names used to |
| 248 # accessed global variable, as changing the variable name changes | 252 # accessed global variable, as changing the variable name changes |
| 249 # the variable actually accessed and therefore changes the | 253 # the variable actually accessed and therefore changes the |
| 250 # function result. | 254 # function result. |
| 251 contents.append(',(' + string.join(map(_object_contents,code.co_names),',')
+ ')') | 255 contents.append(',(' + string.join(map(_object_contents,code.co_names),',')
+ ')') |
| 252 | 256 |
| 253 | 257 |
| 254 # The code contents depends on its actual code!!! | 258 # The code contents depends on its actual code!!! |
| 255 contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')') | 259 contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')') |
| 256 | 260 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 276 closure = [] | 280 closure = [] |
| 277 | 281 |
| 278 #xxx = [_object_contents(x.cell_contents) for x in closure] | 282 #xxx = [_object_contents(x.cell_contents) for x in closure] |
| 279 try: | 283 try: |
| 280 xxx = map(lambda x: _object_contents(x.cell_contents), closure) | 284 xxx = map(lambda x: _object_contents(x.cell_contents), closure) |
| 281 except AttributeError: | 285 except AttributeError: |
| 282 xxx = [] | 286 xxx = [] |
| 283 contents.append(',(' + string.join(xxx, ',') + ')') | 287 contents.append(',(' + string.join(xxx, ',') + ')') |
| 284 | 288 |
| 285 return string.join(contents, '') | 289 return string.join(contents, '') |
| 286 | 290 |
| 287 | 291 |
| 288 def _actionAppend(act1, act2): | 292 def _actionAppend(act1, act2): |
| 289 # This function knows how to slap two actions together. | 293 # This function knows how to slap two actions together. |
| 290 # Mainly, it handles ListActions by concatenating into | 294 # Mainly, it handles ListActions by concatenating into |
| 291 # a single ListAction. | 295 # a single ListAction. |
| 292 a1 = Action(act1) | 296 a1 = Action(act1) |
| 293 a2 = Action(act2) | 297 a2 = Action(act2) |
| 294 if a1 is None or a2 is None: | 298 if a1 is None or a2 is None: |
| 295 raise TypeError, "Cannot append %s to %s" % (type(act1), type(act2)) | 299 raise TypeError, "Cannot append %s to %s" % (type(act1), type(act2)) |
| 296 if isinstance(a1, ListAction): | 300 if isinstance(a1, ListAction): |
| 297 if isinstance(a2, ListAction): | 301 if isinstance(a2, ListAction): |
| 298 return ListAction(a1.list + a2.list) | 302 return ListAction(a1.list + a2.list) |
| 299 else: | 303 else: |
| 300 return ListAction(a1.list + [ a2 ]) | 304 return ListAction(a1.list + [ a2 ]) |
| 301 else: | 305 else: |
| 302 if isinstance(a2, ListAction): | 306 if isinstance(a2, ListAction): |
| 303 return ListAction([ a1 ] + a2.list) | 307 return ListAction([ a1 ] + a2.list) |
| 304 else: | 308 else: |
| 305 return ListAction([ a1, a2 ]) | 309 return ListAction([ a1, a2 ]) |
| 306 | 310 |
| 307 def _do_create_action(act, *args, **kw): | 311 def _do_create_keywords(args, kw): |
| 312 """This converts any arguments after the action argument into |
| 313 their equivalent keywords and adds them to the kw argument. |
| 314 """ |
| 315 v = kw.get('varlist', ()) |
| 316 # prevent varlist="FOO" from being interpreted as ['F', 'O', 'O'] |
| 317 if is_String(v): v = (v,) |
| 318 kw['varlist'] = tuple(v) |
| 319 if args: |
| 320 # turn positional args into equivalent keywords |
| 321 cmdstrfunc = args[0] |
| 322 if cmdstrfunc is None or is_String(cmdstrfunc): |
| 323 kw['cmdstr'] = cmdstrfunc |
| 324 elif callable(cmdstrfunc): |
| 325 kw['strfunction'] = cmdstrfunc |
| 326 else: |
| 327 raise SCons.Errors.UserError( |
| 328 'Invalid command display variable type. ' |
| 329 'You must either pass a string or a callback which ' |
| 330 'accepts (target, source, env) as parameters.') |
| 331 if len(args) > 1: |
| 332 kw['varlist'] = args[1:] + kw['varlist'] |
| 333 if kw.get('strfunction', _null) is not _null \ |
| 334 and kw.get('cmdstr', _null) is not _null: |
| 335 raise SCons.Errors.UserError( |
| 336 'Cannot have both strfunction and cmdstr args to Action()') |
| 337 |
| 338 def _do_create_action(act, kw): |
| 308 """This is the actual "implementation" for the | 339 """This is the actual "implementation" for the |
| 309 Action factory method, below. This handles the | 340 Action factory method, below. This handles the |
| 310 fact that passing lists to Action() itself has | 341 fact that passing lists to Action() itself has |
| 311 different semantics than passing lists as elements | 342 different semantics than passing lists as elements |
| 312 of lists. | 343 of lists. |
| 313 | 344 |
| 314 The former will create a ListAction, the latter | 345 The former will create a ListAction, the latter |
| 315 will create a CommandAction by converting the inner | 346 will create a CommandAction by converting the inner |
| 316 list elements to strings.""" | 347 list elements to strings.""" |
| 317 | 348 |
| 318 if isinstance(act, ActionBase): | 349 if isinstance(act, ActionBase): |
| 319 return act | 350 return act |
| 320 if SCons.Util.is_List(act): | 351 |
| 321 return apply(CommandAction, (act,)+args, kw) | 352 if is_List(act): |
| 353 #TODO(1.5) return CommandAction(act, **kw) |
| 354 return apply(CommandAction, (act,), kw) |
| 355 |
| 322 if callable(act): | 356 if callable(act): |
| 323 try: | 357 try: |
| 324 gen = kw['generator'] | 358 gen = kw['generator'] |
| 325 del kw['generator'] | 359 del kw['generator'] |
| 326 except KeyError: | 360 except KeyError: |
| 327 gen = 0 | 361 gen = 0 |
| 328 if gen: | 362 if gen: |
| 329 action_type = CommandGeneratorAction | 363 action_type = CommandGeneratorAction |
| 330 else: | 364 else: |
| 331 action_type = FunctionAction | 365 action_type = FunctionAction |
| 332 return apply(action_type, (act,)+args, kw) | 366 return action_type(act, kw) |
| 333 if SCons.Util.is_String(act): | 367 |
| 368 if is_String(act): |
| 334 var=SCons.Util.get_environment_var(act) | 369 var=SCons.Util.get_environment_var(act) |
| 335 if var: | 370 if var: |
| 336 # This looks like a string that is purely an Environment | 371 # This looks like a string that is purely an Environment |
| 337 # variable reference, like "$FOO" or "${FOO}". We do | 372 # variable reference, like "$FOO" or "${FOO}". We do |
| 338 # something special here...we lazily evaluate the contents | 373 # something special here...we lazily evaluate the contents |
| 339 # of that Environment variable, so a user could put something | 374 # of that Environment variable, so a user could put something |
| 340 # like a function or a CommandGenerator in that variable | 375 # like a function or a CommandGenerator in that variable |
| 341 # instead of a string. | 376 # instead of a string. |
| 342 return apply(LazyAction, (var,)+args, kw) | 377 return LazyAction(var, kw) |
| 343 commands = string.split(str(act), '\n') | 378 commands = string.split(str(act), '\n') |
| 344 if len(commands) == 1: | 379 if len(commands) == 1: |
| 345 return apply(CommandAction, (commands[0],)+args, kw) | 380 #TODO(1.5) return CommandAction(commands[0], **kw) |
| 346 else: | 381 return apply(CommandAction, (commands[0],), kw) |
| 347 listCmdActions = map(lambda x, args=args, kw=kw: | 382 # The list of string commands may include a LazyAction, so we |
| 348 apply(CommandAction, (x,)+args, kw), | 383 # reprocess them via _do_create_list_action. |
| 349 commands) | 384 return _do_create_list_action(commands, kw) |
| 350 return ListAction(listCmdActions) | |
| 351 return None | 385 return None |
| 352 | 386 |
| 387 def _do_create_list_action(act, kw): |
| 388 """A factory for list actions. Convert the input list into Actions |
| 389 and then wrap them in a ListAction.""" |
| 390 acts = [] |
| 391 for a in act: |
| 392 aa = _do_create_action(a, kw) |
| 393 if aa is not None: acts.append(aa) |
| 394 if not acts: |
| 395 return None |
| 396 elif len(acts) == 1: |
| 397 return acts[0] |
| 398 else: |
| 399 return ListAction(acts) |
| 400 |
| 353 def Action(act, *args, **kw): | 401 def Action(act, *args, **kw): |
| 354 """A factory for action objects.""" | 402 """A factory for action objects.""" |
| 355 if SCons.Util.is_List(act): | 403 # Really simple: the _do_create_* routines do the heavy lifting. |
| 356 acts = map(lambda a, args=args, kw=kw: | 404 _do_create_keywords(args, kw) |
| 357 apply(_do_create_action, (a,)+args, kw), | 405 if is_List(act): |
| 358 act) | 406 return _do_create_list_action(act, kw) |
| 359 acts = filter(None, acts) | 407 return _do_create_action(act, kw) |
| 360 if len(acts) == 1: | |
| 361 return acts[0] | |
| 362 else: | |
| 363 return ListAction(acts) | |
| 364 else: | |
| 365 return apply(_do_create_action, (act,)+args, kw) | |
| 366 | 408 |
| 367 class ActionBase: | 409 class ActionBase: |
| 368 """Base class for all types of action objects that can be held by | 410 """Base class for all types of action objects that can be held by |
| 369 other objects (Builders, Executors, etc.) This provides the | 411 other objects (Builders, Executors, etc.) This provides the |
| 370 common methods for manipulating and combining those actions.""" | 412 common methods for manipulating and combining those actions.""" |
| 371 | 413 |
| 372 def __cmp__(self, other): | 414 def __cmp__(self, other): |
| 373 return cmp(self.__dict__, other) | 415 return cmp(self.__dict__, other) |
| 374 | 416 |
| 375 def genstring(self, target, source, env): | 417 def genstring(self, target, source, env): |
| 376 return str(self) | 418 return str(self) |
| 377 | 419 |
| 420 def get_contents(self, target, source, env): |
| 421 result = [ self.get_presig(target, source, env) ] |
| 422 # This should never happen, as the Action() factory should wrap |
| 423 # the varlist, but just in case an action is created directly, |
| 424 # we duplicate this check here. |
| 425 vl = self.varlist |
| 426 if is_String(vl): vl = (vl,) |
| 427 for v in vl: |
| 428 result.append(env.subst('${'+v+'}')) |
| 429 return string.join(result, '') |
| 430 |
| 378 def __add__(self, other): | 431 def __add__(self, other): |
| 379 return _actionAppend(self, other) | 432 return _actionAppend(self, other) |
| 380 | 433 |
| 381 def __radd__(self, other): | 434 def __radd__(self, other): |
| 382 return _actionAppend(other, self) | 435 return _actionAppend(other, self) |
| 383 | 436 |
| 384 def presub_lines(self, env): | 437 def presub_lines(self, env): |
| 385 # CommandGeneratorAction needs a real environment | 438 # CommandGeneratorAction needs a real environment |
| 386 # in order to return the proper string here, since | 439 # in order to return the proper string here, since |
| 387 # it may call LazyAction, which looks up a key | 440 # it may call LazyAction, which looks up a key |
| 388 # in that env. So we temporarily remember the env here, | 441 # in that env. So we temporarily remember the env here, |
| 389 # and CommandGeneratorAction will use this env | 442 # and CommandGeneratorAction will use this env |
| 390 # when it calls its _generate method. | 443 # when it calls its _generate method. |
| 391 self.presub_env = env | 444 self.presub_env = env |
| 392 lines = string.split(str(self), '\n') | 445 lines = string.split(str(self), '\n') |
| 393 self.presub_env = None # don't need this any more | 446 self.presub_env = None # don't need this any more |
| 394 return lines | 447 return lines |
| 395 | 448 |
| 396 def get_executor(self, env, overrides, tlist, slist, executor_kw): | 449 def get_executor(self, env, overrides, tlist, slist, executor_kw): |
| 397 """Return the Executor for this Action.""" | 450 """Return the Executor for this Action.""" |
| 398 return SCons.Executor.Executor(self, env, overrides, | 451 return SCons.Executor.Executor(self, env, overrides, |
| 399 tlist, slist, executor_kw) | 452 tlist, slist, executor_kw) |
| 400 | 453 |
| 401 class _ActionAction(ActionBase): | 454 class _ActionAction(ActionBase): |
| 402 """Base class for actions that create output objects.""" | 455 """Base class for actions that create output objects.""" |
| 403 def __init__(self, strfunction=_null, presub=_null, chdir=None, exitstatfunc
=None, **kw): | 456 def __init__(self, cmdstr=_null, strfunction=_null, varlist=(), |
| 404 if not strfunction is _null: | 457 presub=_null, chdir=None, exitstatfunc=None, |
| 405 self.strfunction = strfunction | 458 **kw): |
| 459 self.cmdstr = cmdstr |
| 460 if strfunction is not _null: |
| 461 if strfunction is None: |
| 462 self.cmdstr = None |
| 463 else: |
| 464 self.strfunction = strfunction |
| 465 self.varlist = varlist |
| 406 self.presub = presub | 466 self.presub = presub |
| 407 self.chdir = chdir | 467 self.chdir = chdir |
| 408 if not exitstatfunc: | 468 if not exitstatfunc: |
| 409 exitstatfunc = default_exitstatfunc | 469 exitstatfunc = default_exitstatfunc |
| 410 self.exitstatfunc = exitstatfunc | 470 self.exitstatfunc = exitstatfunc |
| 411 | 471 |
| 412 def print_cmd_line(self, s, target, source, env): | 472 def print_cmd_line(self, s, target, source, env): |
| 413 sys.stdout.write(s + "\n") | 473 sys.stdout.write(s + "\n") |
| 414 | 474 |
| 415 def __call__(self, target, source, env, | 475 def __call__(self, target, source, env, |
| 416 exitstatfunc=_null, | 476 exitstatfunc=_null, |
| 417 presub=_null, | 477 presub=_null, |
| 418 show=_null, | 478 show=_null, |
| 419 execute=_null, | 479 execute=_null, |
| 420 chdir=_null): | 480 chdir=_null): |
| 421 if not SCons.Util.is_List(target): | 481 if not is_List(target): |
| 422 target = [target] | 482 target = [target] |
| 423 if not SCons.Util.is_List(source): | 483 if not is_List(source): |
| 424 source = [source] | 484 source = [source] |
| 425 | 485 |
| 426 if exitstatfunc is _null: exitstatfunc = self.exitstatfunc | |
| 427 if presub is _null: | 486 if presub is _null: |
| 428 presub = self.presub | 487 presub = self.presub |
| 429 if presub is _null: | 488 if presub is _null: |
| 430 presub = print_actions_presub | 489 presub = print_actions_presub |
| 490 if exitstatfunc is _null: exitstatfunc = self.exitstatfunc |
| 431 if show is _null: show = print_actions | 491 if show is _null: show = print_actions |
| 432 if execute is _null: execute = execute_actions | 492 if execute is _null: execute = execute_actions |
| 433 if chdir is _null: chdir = self.chdir | 493 if chdir is _null: chdir = self.chdir |
| 434 save_cwd = None | 494 save_cwd = None |
| 435 if chdir: | 495 if chdir: |
| 436 save_cwd = os.getcwd() | 496 save_cwd = os.getcwd() |
| 437 try: | 497 try: |
| 438 chdir = str(chdir.abspath) | 498 chdir = str(chdir.abspath) |
| 439 except AttributeError: | 499 except AttributeError: |
| 440 if not SCons.Util.is_String(chdir): | 500 if not is_String(chdir): |
| 441 chdir = str(target[0].dir) | 501 chdir = str(target[0].dir) |
| 442 if presub: | 502 if presub: |
| 443 t = string.join(map(str, target), ' and ') | 503 t = string.join(map(str, target), ' and ') |
| 444 l = string.join(self.presub_lines(env), '\n ') | 504 l = string.join(self.presub_lines(env), '\n ') |
| 445 out = "Building %s with action:\n %s\n" % (t, l) | 505 out = "Building %s with action:\n %s\n" % (t, l) |
| 446 sys.stdout.write(out) | 506 sys.stdout.write(out) |
| 447 s = None | 507 cmd = None |
| 448 if show and self.strfunction: | 508 if show and self.strfunction: |
| 449 s = self.strfunction(target, source, env) | 509 cmd = self.strfunction(target, source, env) |
| 450 if s: | 510 if cmd: |
| 451 if chdir: | 511 if chdir: |
| 452 s = ('os.chdir(%s)\n' % repr(chdir)) + s | 512 cmd = ('os.chdir(%s)\n' % repr(chdir)) + cmd |
| 453 try: | 513 try: |
| 454 get = env.get | 514 get = env.get |
| 455 except AttributeError: | 515 except AttributeError: |
| 456 print_func = self.print_cmd_line | 516 print_func = self.print_cmd_line |
| 457 else: | 517 else: |
| 458 print_func = get('PRINT_CMD_LINE_FUNC') | 518 print_func = get('PRINT_CMD_LINE_FUNC') |
| 459 if not print_func: | 519 if not print_func: |
| 460 print_func = self.print_cmd_line | 520 print_func = self.print_cmd_line |
| 461 print_func(s, target, source, env) | 521 print_func(cmd, target, source, env) |
| 462 stat = 0 | 522 stat = 0 |
| 463 if execute: | 523 if execute: |
| 464 if chdir: | 524 if chdir: |
| 465 os.chdir(chdir) | 525 os.chdir(chdir) |
| 466 try: | 526 try: |
| 467 stat = self.execute(target, source, env) | 527 stat = self.execute(target, source, env) |
| 468 if isinstance(stat, SCons.Errors.BuildError): | 528 if isinstance(stat, SCons.Errors.BuildError): |
| 469 s = exitstatfunc(stat.status) | 529 s = exitstatfunc(stat.status) |
| 470 if s: | 530 if s: |
| 471 stat.status = s | 531 stat.status = s |
| 472 else: | 532 else: |
| 473 stat = s | 533 stat = s |
| 474 else: | 534 else: |
| 475 stat = exitstatfunc(stat) | 535 stat = exitstatfunc(stat) |
| 476 finally: | 536 finally: |
| 477 if save_cwd: | 537 if save_cwd: |
| 478 os.chdir(save_cwd) | 538 os.chdir(save_cwd) |
| 479 if s and save_cwd: | 539 if cmd and save_cwd: |
| 480 print_func('os.chdir(%s)' % repr(save_cwd), target, source, env) | 540 print_func('os.chdir(%s)' % repr(save_cwd), target, source, env) |
| 481 | 541 |
| 482 return stat | 542 return stat |
| 483 | 543 |
| 484 | 544 |
| 485 def _string_from_cmd_list(cmd_list): | 545 def _string_from_cmd_list(cmd_list): |
| 486 """Takes a list of command line arguments and returns a pretty | 546 """Takes a list of command line arguments and returns a pretty |
| 487 representation for printing.""" | 547 representation for printing.""" |
| 488 cl = [] | 548 cl = [] |
| 489 for arg in map(str, cmd_list): | 549 for arg in map(str, cmd_list): |
| 490 if ' ' in arg or '\t' in arg: | 550 if ' ' in arg or '\t' in arg: |
| 491 arg = '"' + arg + '"' | 551 arg = '"' + arg + '"' |
| 492 cl.append(arg) | 552 cl.append(arg) |
| 493 return string.join(cl) | 553 return string.join(cl) |
| 494 | 554 |
| 495 # this function is still in draft mode. We're going to need something like | 555 # A fiddlin' little function that has an 'import SCons.Environment' which |
| 496 # it in the long run as more and more places use it, but I'm sure it'll have | 556 # can't be moved to the top level without creating an import loop. Since |
| 497 # to be tweaked to get the full desired functionality. | 557 # this import creates a local variable named 'SCons', it blocks access to |
| 558 # the global variable, so we move it here to prevent complaints about local |
| 559 # variables being used uninitialized. |
| 498 default_ENV = None | 560 default_ENV = None |
| 499 # one special arg, 'error', to tell what to do with exceptions. | 561 def get_default_ENV(env): |
| 562 global default_ENV |
| 563 try: |
| 564 return env['ENV'] |
| 565 except KeyError: |
| 566 if not default_ENV: |
| 567 import SCons.Environment |
| 568 # This is a hideously expensive way to get a default shell |
| 569 # environment. What it really should do is run the platform |
| 570 # setup to get the default ENV. Fortunately, it's incredibly |
| 571 # rare for an Environment not to have a shell environment, so |
| 572 # we're not going to worry about it overmuch. |
| 573 default_ENV = SCons.Environment.Environment()['ENV'] |
| 574 return default_ENV |
| 575 |
| 576 # This function is still in draft mode. We're going to need something like |
| 577 # it in the long run as more and more places use subprocess, but I'm sure |
| 578 # it'll have to be tweaked to get the full desired functionality. |
| 579 # one special arg (so far?), 'error', to tell what to do with exceptions. |
| 500 def _subproc(env, cmd, error = 'ignore', **kw): | 580 def _subproc(env, cmd, error = 'ignore', **kw): |
| 501 """Do setup for a subprocess.Popen() call""" | 581 """Do common setup for a subprocess.Popen() call""" |
| 582 # allow std{in,out,err} to be "'devnull'" |
| 583 io = kw.get('stdin') |
| 584 if is_String(io) and io == 'devnull': |
| 585 kw['stdin'] = open(os.devnull) |
| 586 io = kw.get('stdout') |
| 587 if is_String(io) and io == 'devnull': |
| 588 kw['stdout'] = open(os.devnull, 'w') |
| 589 io = kw.get('stderr') |
| 590 if is_String(io) and io == 'devnull': |
| 591 kw['stderr'] = open(os.devnull, 'w') |
| 502 | 592 |
| 503 # If the env has no ENV, get a default | 593 # Figure out what shell environment to use |
| 504 try: | 594 ENV = kw.get('env', None) |
| 505 ENV = env['ENV'] | 595 if ENV is None: ENV = get_default_ENV(env) |
| 506 except KeyError: | 596 |
| 507 global default_ENV | |
| 508 if default_ENV is None: | |
| 509 # Unbelievably expensive. What it really should do | |
| 510 # is run the platform setup to get the default ENV. | |
| 511 # Fortunately, it should almost never happen. | |
| 512 default_ENV = SCons.Environment.Environment(tools=[])['ENV'] | |
| 513 ENV = default_ENV | |
| 514 | |
| 515 # Ensure that the ENV values are all strings: | 597 # Ensure that the ENV values are all strings: |
| 516 new_env = {} | 598 new_env = {} |
| 517 # It's a string 99.44% of the time, so optimize this | |
| 518 is_String = SCons.Util.is_String | |
| 519 for key, value in ENV.items(): | 599 for key, value in ENV.items(): |
| 520 if is_String(value): | 600 if is_List(value): |
| 521 # Call str() even though it's a "string" because it might be | 601 # If the value is a list, then we assume it is a path list, |
| 522 # a *Unicode* string, which makes subprocess.Popen() gag. | 602 # because that's a pretty common list-like value to stick |
| 603 # in an environment variable: |
| 604 value = SCons.Util.flatten_sequence(value) |
| 605 new_env[key] = string.join(map(str, value), os.pathsep) |
| 606 else: |
| 607 # It's either a string or something else. If it's a string, |
| 608 # we still want to call str() because it might be a *Unicode* |
| 609 # string, which makes subprocess.Popen() gag. If it isn't a |
| 610 # string or a list, then we just coerce it to a string, which |
| 611 # is the proper way to handle Dir and File instances and will |
| 612 # produce something reasonable for just about everything else: |
| 523 new_env[key] = str(value) | 613 new_env[key] = str(value) |
| 524 elif SCons.Util.is_List(value): | |
| 525 # If the value is a list, then we assume it is a | |
| 526 # path list, because that's a pretty common list-like | |
| 527 # value to stick in an environment variable: | |
| 528 value = SCons.Util.flatten_sequence(value) | |
| 529 ENV[key] = string.join(map(str, value), os.pathsep) | |
| 530 else: | |
| 531 # If it isn't a string or a list, then we just coerce | |
| 532 # it to a string, which is the proper way to handle | |
| 533 # Dir and File instances and will produce something | |
| 534 # reasonable for just about everything else: | |
| 535 ENV[key] = str(value) | |
| 536 kw['env'] = new_env | 614 kw['env'] = new_env |
| 537 | 615 |
| 538 try: | 616 try: |
| 539 #FUTURE return subprocess.Popen(cmd, **kw) | 617 #FUTURE return subprocess.Popen(cmd, **kw) |
| 540 return apply(subprocess.Popen, (cmd,), kw) | 618 return apply(subprocess.Popen, (cmd,), kw) |
| 541 except EnvironmentError, e: | 619 except EnvironmentError, e: |
| 542 if error == 'raise': raise | 620 if error == 'raise': raise |
| 543 # return a dummy Popen instance that only returns error | 621 # return a dummy Popen instance that only returns error |
| 544 class popen: | 622 class dummyPopen: |
| 545 def __init__(self, e): self.exception = e | 623 def __init__(self, e): self.exception = e |
| 546 def communicate(self): return ('','') | 624 def communicate(self): return ('','') |
| 547 def wait(self): return -self.exception.errno | 625 def wait(self): return -self.exception.errno |
| 548 stdin = None | 626 stdin = None |
| 549 class f: | 627 class f: |
| 550 def read(self): return '' | 628 def read(self): return '' |
| 551 def readline(self): return '' | 629 def readline(self): return '' |
| 552 stdout = stderr = f() | 630 stdout = stderr = f() |
| 553 return popen(e) | 631 return dummyPopen(e) |
| 554 | 632 |
| 555 class CommandAction(_ActionAction): | 633 class CommandAction(_ActionAction): |
| 556 """Class for command-execution actions.""" | 634 """Class for command-execution actions.""" |
| 557 def __init__(self, cmd, cmdstr=None, *args, **kw): | 635 def __init__(self, cmd, **kw): |
| 558 # Cmd can actually be a list or a single item; if it's a | 636 # Cmd can actually be a list or a single item; if it's a |
| 559 # single item it should be the command string to execute; if a | 637 # single item it should be the command string to execute; if a |
| 560 # list then it should be the words of the command string to | 638 # list then it should be the words of the command string to |
| 561 # execute. Only a single command should be executed by this | 639 # execute. Only a single command should be executed by this |
| 562 # object; lists of commands should be handled by embedding | 640 # object; lists of commands should be handled by embedding |
| 563 # these objects in a ListAction object (which the Action() | 641 # these objects in a ListAction object (which the Action() |
| 564 # factory above does). cmd will be passed to | 642 # factory above does). cmd will be passed to |
| 565 # Environment.subst_list() for substituting environment | 643 # Environment.subst_list() for substituting environment |
| 566 # variables. | 644 # variables. |
| 567 if __debug__: logInstanceCreation(self, 'Action.CommandAction') | 645 if __debug__: logInstanceCreation(self, 'Action.CommandAction') |
| 568 | 646 |
| 569 if not cmdstr is None: | 647 #TODO(1.5) _ActionAction.__init__(self, **kw) |
| 570 if callable(cmdstr): | 648 apply(_ActionAction.__init__, (self,), kw) |
| 571 args = (cmdstr,)+args | 649 if is_List(cmd): |
| 572 elif not SCons.Util.is_String(cmdstr): | 650 if filter(is_List, cmd): |
| 573 raise SCons.Errors.UserError(\ | |
| 574 'Invalid command display variable type. ' \ | |
| 575 'You must either pass a string or a callback which ' \ | |
| 576 'accepts (target, source, env) as parameters.') | |
| 577 | |
| 578 apply(_ActionAction.__init__, (self,)+args, kw) | |
| 579 if SCons.Util.is_List(cmd): | |
| 580 if filter(SCons.Util.is_List, cmd): | |
| 581 raise TypeError, "CommandAction should be given only " \ | 651 raise TypeError, "CommandAction should be given only " \ |
| 582 "a single command" | 652 "a single command" |
| 583 self.cmd_list = cmd | 653 self.cmd_list = cmd |
| 584 self.cmdstr = cmdstr | |
| 585 | 654 |
| 586 def __str__(self): | 655 def __str__(self): |
| 587 if SCons.Util.is_List(self.cmd_list): | 656 if is_List(self.cmd_list): |
| 588 return string.join(map(str, self.cmd_list), ' ') | 657 return string.join(map(str, self.cmd_list), ' ') |
| 589 return str(self.cmd_list) | 658 return str(self.cmd_list) |
| 590 | 659 |
| 591 def process(self, target, source, env): | 660 def process(self, target, source, env): |
| 592 result = env.subst_list(self.cmd_list, 0, target, source) | 661 result = env.subst_list(self.cmd_list, 0, target, source) |
| 593 silent = None | 662 silent = None |
| 594 ignore = None | 663 ignore = None |
| 595 while 1: | 664 while 1: |
| 596 try: c = result[0][0][0] | 665 try: c = result[0][0][0] |
| 597 except IndexError: c = None | 666 except IndexError: c = None |
| 598 if c == '@': silent = 1 | 667 if c == '@': silent = 1 |
| 599 elif c == '-': ignore = 1 | 668 elif c == '-': ignore = 1 |
| 600 else: break | 669 else: break |
| 601 result[0][0] = result[0][0][1:] | 670 result[0][0] = result[0][0][1:] |
| 602 try: | 671 try: |
| 603 if not result[0][0]: | 672 if not result[0][0]: |
| 604 result[0] = result[0][1:] | 673 result[0] = result[0][1:] |
| 605 except IndexError: | 674 except IndexError: |
| 606 pass | 675 pass |
| 607 return result, ignore, silent | 676 return result, ignore, silent |
| 608 | 677 |
| 609 def strfunction(self, target, source, env): | 678 def strfunction(self, target, source, env): |
| 610 if not self.cmdstr is None: | 679 if self.cmdstr is None: |
| 680 return None |
| 681 if self.cmdstr is not _null: |
| 611 from SCons.Subst import SUBST_RAW | 682 from SCons.Subst import SUBST_RAW |
| 612 c = env.subst(self.cmdstr, SUBST_RAW, target, source) | 683 c = env.subst(self.cmdstr, SUBST_RAW, target, source) |
| 613 if c: | 684 if c: |
| 614 return c | 685 return c |
| 615 cmd_list, ignore, silent = self.process(target, source, env) | 686 cmd_list, ignore, silent = self.process(target, source, env) |
| 616 if silent: | 687 if silent: |
| 617 return '' | 688 return '' |
| 618 return _string_from_cmd_list(cmd_list[0]) | 689 return _string_from_cmd_list(cmd_list[0]) |
| 619 | 690 |
| 620 def execute(self, target, source, env): | 691 def execute(self, target, source, env): |
| 621 """Execute a command action. | 692 """Execute a command action. |
| 622 | 693 |
| 623 This will handle lists of commands as well as individual commands, | 694 This will handle lists of commands as well as individual commands, |
| 624 because construction variable substitution may turn a single | 695 because construction variable substitution may turn a single |
| 625 "command" into a list. This means that this class can actually | 696 "command" into a list. This means that this class can actually |
| 626 handle lists of commands, even though that's not how we use it | 697 handle lists of commands, even though that's not how we use it |
| 627 externally. | 698 externally. |
| 628 """ | 699 """ |
| 629 from SCons.Subst import escape_list | 700 escape_list = SCons.Subst.escape_list |
| 630 import SCons.Util | |
| 631 flatten_sequence = SCons.Util.flatten_sequence | 701 flatten_sequence = SCons.Util.flatten_sequence |
| 632 is_String = SCons.Util.is_String | |
| 633 is_List = SCons.Util.is_List | |
| 634 | 702 |
| 635 try: | 703 try: |
| 636 shell = env['SHELL'] | 704 shell = env['SHELL'] |
| 637 except KeyError: | 705 except KeyError: |
| 638 raise SCons.Errors.UserError('Missing SHELL construction variable.') | 706 raise SCons.Errors.UserError('Missing SHELL construction variable.') |
| 639 | 707 |
| 640 try: | 708 try: |
| 641 spawn = env['SPAWN'] | 709 spawn = env['SPAWN'] |
| 642 except KeyError: | 710 except KeyError: |
| 643 raise SCons.Errors.UserError('Missing SPAWN construction variable.') | 711 raise SCons.Errors.UserError('Missing SPAWN construction variable.') |
| 644 else: | 712 else: |
| 645 if is_String(spawn): | 713 if is_String(spawn): |
| 646 spawn = env.subst(spawn, raw=1, conv=lambda x: x) | 714 spawn = env.subst(spawn, raw=1, conv=lambda x: x) |
| 647 | 715 |
| 648 escape = env.get('ESCAPE', lambda x: x) | 716 escape = env.get('ESCAPE', lambda x: x) |
| 649 | 717 |
| 650 try: | 718 ENV = get_default_ENV(env) |
| 651 ENV = env['ENV'] | |
| 652 except KeyError: | |
| 653 global default_ENV | |
| 654 if not default_ENV: | |
| 655 import SCons.Environment | |
| 656 default_ENV = SCons.Environment.Environment()['ENV'] | |
| 657 ENV = default_ENV | |
| 658 | 719 |
| 659 # Ensure that the ENV values are all strings: | 720 # Ensure that the ENV values are all strings: |
| 660 for key, value in ENV.items(): | 721 for key, value in ENV.items(): |
| 661 if not is_String(value): | 722 if not is_String(value): |
| 662 if is_List(value): | 723 if is_List(value): |
| 663 # If the value is a list, then we assume it is a | 724 # If the value is a list, then we assume it is a |
| 664 # path list, because that's a pretty common list-like | 725 # path list, because that's a pretty common list-like |
| 665 # value to stick in an environment variable: | 726 # value to stick in an environment variable: |
| 666 value = flatten_sequence(value) | 727 value = flatten_sequence(value) |
| 667 ENV[key] = string.join(map(str, value), os.pathsep) | 728 ENV[key] = string.join(map(str, value), os.pathsep) |
| (...skipping 12 matching lines...) Expand all Loading... |
| 680 cmd_line = escape_list(cmd_line, escape) | 741 cmd_line = escape_list(cmd_line, escape) |
| 681 result = spawn(shell, escape, cmd_line[0], cmd_line, ENV) | 742 result = spawn(shell, escape, cmd_line[0], cmd_line, ENV) |
| 682 if not ignore and result: | 743 if not ignore and result: |
| 683 msg = "Error %s" % result | 744 msg = "Error %s" % result |
| 684 return SCons.Errors.BuildError(errstr=msg, | 745 return SCons.Errors.BuildError(errstr=msg, |
| 685 status=result, | 746 status=result, |
| 686 action=self, | 747 action=self, |
| 687 command=cmd_line) | 748 command=cmd_line) |
| 688 return 0 | 749 return 0 |
| 689 | 750 |
| 690 def get_contents(self, target, source, env): | 751 def get_presig(self, target, source, env): |
| 691 """Return the signature contents of this action's command line. | 752 """Return the signature contents of this action's command line. |
| 692 | 753 |
| 693 This strips $(-$) and everything in between the string, | 754 This strips $(-$) and everything in between the string, |
| 694 since those parts don't affect signatures. | 755 since those parts don't affect signatures. |
| 695 """ | 756 """ |
| 696 from SCons.Subst import SUBST_SIG | 757 from SCons.Subst import SUBST_SIG |
| 697 cmd = self.cmd_list | 758 cmd = self.cmd_list |
| 698 if SCons.Util.is_List(cmd): | 759 if is_List(cmd): |
| 699 cmd = string.join(map(str, cmd)) | 760 cmd = string.join(map(str, cmd)) |
| 700 else: | 761 else: |
| 701 cmd = str(cmd) | 762 cmd = str(cmd) |
| 702 return env.subst_target_source(cmd, SUBST_SIG, target, source) | 763 return env.subst_target_source(cmd, SUBST_SIG, target, source) |
| 703 | 764 |
| 704 def get_implicit_deps(self, target, source, env): | 765 def get_implicit_deps(self, target, source, env): |
| 705 icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True) | 766 icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True) |
| 706 if SCons.Util.is_String(icd) and icd[:1] == '$': | 767 if is_String(icd) and icd[:1] == '$': |
| 707 icd = env.subst(icd) | 768 icd = env.subst(icd) |
| 708 if not icd or icd in ('0', 'None'): | 769 if not icd or icd in ('0', 'None'): |
| 709 return [] | 770 return [] |
| 710 from SCons.Subst import SUBST_SIG | 771 from SCons.Subst import SUBST_SIG |
| 711 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source) | 772 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source) |
| 712 res = [] | 773 res = [] |
| 713 for cmd_line in cmd_list: | 774 for cmd_line in cmd_list: |
| 714 if cmd_line: | 775 if cmd_line: |
| 715 d = env.WhereIs(str(cmd_line[0])) | 776 d = env.WhereIs(str(cmd_line[0])) |
| 716 if d: | 777 if d: |
| 717 res.append(env.fs.File(d)) | 778 res.append(env.fs.File(d)) |
| 718 return res | 779 return res |
| 719 | 780 |
| 720 class CommandGeneratorAction(ActionBase): | 781 class CommandGeneratorAction(ActionBase): |
| 721 """Class for command-generator actions.""" | 782 """Class for command-generator actions.""" |
| 722 def __init__(self, generator, *args, **kw): | 783 def __init__(self, generator, kw): |
| 723 if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction') | 784 if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction') |
| 724 self.generator = generator | 785 self.generator = generator |
| 725 self.gen_args = args | |
| 726 self.gen_kw = kw | 786 self.gen_kw = kw |
| 787 self.varlist = kw.get('varlist', ()) |
| 727 | 788 |
| 728 def _generate(self, target, source, env, for_signature): | 789 def _generate(self, target, source, env, for_signature): |
| 729 # ensure that target is a list, to make it easier to write | 790 # ensure that target is a list, to make it easier to write |
| 730 # generator functions: | 791 # generator functions: |
| 731 if not SCons.Util.is_List(target): | 792 if not is_List(target): |
| 732 target = [target] | 793 target = [target] |
| 733 | 794 |
| 734 ret = self.generator(target=target, source=source, env=env, for_signatur
e=for_signature) | 795 ret = self.generator(target=target, source=source, env=env, for_signatur
e=for_signature) |
| 735 gen_cmd = apply(Action, (ret,)+self.gen_args, self.gen_kw) | 796 #TODO(1.5) gen_cmd = Action(ret, **self.gen_kw) |
| 797 gen_cmd = apply(Action, (ret,), self.gen_kw) |
| 736 if not gen_cmd: | 798 if not gen_cmd: |
| 737 raise SCons.Errors.UserError("Object returned from command generator
: %s cannot be used to create an Action." % repr(ret)) | 799 raise SCons.Errors.UserError("Object returned from command generator
: %s cannot be used to create an Action." % repr(ret)) |
| 738 return gen_cmd | 800 return gen_cmd |
| 739 | 801 |
| 740 def __str__(self): | 802 def __str__(self): |
| 741 try: | 803 try: |
| 742 env = self.presub_env | 804 env = self.presub_env |
| 743 except AttributeError: | 805 except AttributeError: |
| 744 env = None | 806 env = None |
| 745 if env is None: | 807 if env is None: |
| 746 env = SCons.Defaults.DefaultEnvironment() | 808 env = SCons.Defaults.DefaultEnvironment() |
| 747 act = self._generate([], [], env, 1) | 809 act = self._generate([], [], env, 1) |
| 748 return str(act) | 810 return str(act) |
| 749 | 811 |
| 750 def genstring(self, target, source, env): | 812 def genstring(self, target, source, env): |
| 751 return self._generate(target, source, env, 1).genstring(target, source,
env) | 813 return self._generate(target, source, env, 1).genstring(target, source,
env) |
| 752 | 814 |
| 753 def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, | 815 def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, |
| 754 show=_null, execute=_null, chdir=_null): | 816 show=_null, execute=_null, chdir=_null): |
| 755 act = self._generate(target, source, env, 0) | 817 act = self._generate(target, source, env, 0) |
| 756 return act(target, source, env, exitstatfunc, presub, | 818 return act(target, source, env, exitstatfunc, presub, |
| 757 show, execute, chdir) | 819 show, execute, chdir) |
| 758 | 820 |
| 759 def get_contents(self, target, source, env): | 821 def get_presig(self, target, source, env): |
| 760 """Return the signature contents of this action's command line. | 822 """Return the signature contents of this action's command line. |
| 761 | 823 |
| 762 This strips $(-$) and everything in between the string, | 824 This strips $(-$) and everything in between the string, |
| 763 since those parts don't affect signatures. | 825 since those parts don't affect signatures. |
| 764 """ | 826 """ |
| 765 return self._generate(target, source, env, 1).get_contents(target, sourc
e, env) | 827 return self._generate(target, source, env, 1).get_presig(target, source,
env) |
| 766 | 828 |
| 767 def get_implicit_deps(self, target, source, env): | 829 def get_implicit_deps(self, target, source, env): |
| 768 return self._generate(target, source, env, 1).get_implicit_deps(target,
source, env) | 830 return self._generate(target, source, env, 1).get_implicit_deps(target,
source, env) |
| 769 | 831 |
| 770 | 832 |
| 771 | 833 |
| 772 # A LazyAction is a kind of hybrid generator and command action for | 834 # A LazyAction is a kind of hybrid generator and command action for |
| 773 # strings of the form "$VAR". These strings normally expand to other | 835 # strings of the form "$VAR". These strings normally expand to other |
| 774 # strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also | 836 # strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also |
| 775 # want to be able to replace them with functions in the construction | 837 # want to be able to replace them with functions in the construction |
| 776 # environment. Consequently, we want lazy evaluation and creation of | 838 # environment. Consequently, we want lazy evaluation and creation of |
| 777 # an Action in the case of the function, but that's overkill in the more | 839 # an Action in the case of the function, but that's overkill in the more |
| 778 # normal case of expansion to other strings. | 840 # normal case of expansion to other strings. |
| 779 # | 841 # |
| 780 # So we do this with a subclass that's both a generator *and* | 842 # So we do this with a subclass that's both a generator *and* |
| 781 # a command action. The overridden methods all do a quick check | 843 # a command action. The overridden methods all do a quick check |
| 782 # of the construction variable, and if it's a string we just call | 844 # of the construction variable, and if it's a string we just call |
| 783 # the corresponding CommandAction method to do the heavy lifting. | 845 # the corresponding CommandAction method to do the heavy lifting. |
| 784 # If not, then we call the same-named CommandGeneratorAction method. | 846 # If not, then we call the same-named CommandGeneratorAction method. |
| 785 # The CommandGeneratorAction methods work by using the overridden | 847 # The CommandGeneratorAction methods work by using the overridden |
| 786 # _generate() method, that is, our own way of handling "generation" of | 848 # _generate() method, that is, our own way of handling "generation" of |
| 787 # an action based on what's in the construction variable. | 849 # an action based on what's in the construction variable. |
| 788 | 850 |
| 789 class LazyAction(CommandGeneratorAction, CommandAction): | 851 class LazyAction(CommandGeneratorAction, CommandAction): |
| 790 | 852 |
| 791 def __init__(self, var, *args, **kw): | 853 def __init__(self, var, kw): |
| 792 if __debug__: logInstanceCreation(self, 'Action.LazyAction') | 854 if __debug__: logInstanceCreation(self, 'Action.LazyAction') |
| 793 apply(CommandAction.__init__, (self, '$'+var)+args, kw) | 855 #FUTURE CommandAction.__init__(self, '${'+var+'}', **kw) |
| 856 apply(CommandAction.__init__, (self, '${'+var+'}'), kw) |
| 794 self.var = SCons.Util.to_String(var) | 857 self.var = SCons.Util.to_String(var) |
| 795 self.gen_args = args | |
| 796 self.gen_kw = kw | 858 self.gen_kw = kw |
| 797 | 859 |
| 798 def get_parent_class(self, env): | 860 def get_parent_class(self, env): |
| 799 c = env.get(self.var) | 861 c = env.get(self.var) |
| 800 if SCons.Util.is_String(c) and not '\n' in c: | 862 if is_String(c) and not '\n' in c: |
| 801 return CommandAction | 863 return CommandAction |
| 802 return CommandGeneratorAction | 864 return CommandGeneratorAction |
| 803 | 865 |
| 804 def _generate_cache(self, env): | 866 def _generate_cache(self, env): |
| 805 c = env.get(self.var, '') | 867 c = env.get(self.var, '') |
| 806 gen_cmd = apply(Action, (c,)+self.gen_args, self.gen_kw) | 868 #TODO(1.5) gen_cmd = Action(c, **self.gen_kw) |
| 869 gen_cmd = apply(Action, (c,), self.gen_kw) |
| 807 if not gen_cmd: | 870 if not gen_cmd: |
| 808 raise SCons.Errors.UserError("$%s value %s cannot be used to create
an Action." % (self.var, repr(c))) | 871 raise SCons.Errors.UserError("$%s value %s cannot be used to create
an Action." % (self.var, repr(c))) |
| 809 return gen_cmd | 872 return gen_cmd |
| 810 | 873 |
| 811 def _generate(self, target, source, env, for_signature): | 874 def _generate(self, target, source, env, for_signature): |
| 812 return self._generate_cache(env) | 875 return self._generate_cache(env) |
| 813 | 876 |
| 814 def __call__(self, target, source, env, *args, **kw): | 877 def __call__(self, target, source, env, *args, **kw): |
| 815 args = (self, target, source, env) + args | 878 args = (self, target, source, env) + args |
| 816 c = self.get_parent_class(env) | 879 c = self.get_parent_class(env) |
| 880 #TODO(1.5) return c.__call__(*args, **kw) |
| 817 return apply(c.__call__, args, kw) | 881 return apply(c.__call__, args, kw) |
| 818 | 882 |
| 819 def get_contents(self, target, source, env): | 883 def get_presig(self, target, source, env): |
| 820 c = self.get_parent_class(env) | 884 c = self.get_parent_class(env) |
| 821 return c.get_contents(self, target, source, env) | 885 return c.get_presig(self, target, source, env) |
| 822 | 886 |
| 823 | 887 |
| 824 | 888 |
| 825 class FunctionAction(_ActionAction): | 889 class FunctionAction(_ActionAction): |
| 826 """Class for Python function actions.""" | 890 """Class for Python function actions.""" |
| 827 | 891 |
| 828 def __init__(self, execfunction, cmdstr=_null, *args, **kw): | 892 def __init__(self, execfunction, kw): |
| 829 if __debug__: logInstanceCreation(self, 'Action.FunctionAction') | 893 if __debug__: logInstanceCreation(self, 'Action.FunctionAction') |
| 830 | 894 |
| 831 if not cmdstr is _null: | |
| 832 if callable(cmdstr): | |
| 833 args = (cmdstr,)+args | |
| 834 elif not (cmdstr is None or SCons.Util.is_String(cmdstr)): | |
| 835 raise SCons.Errors.UserError(\ | |
| 836 'Invalid function display variable type. ' \ | |
| 837 'You must either pass a string or a callback which ' \ | |
| 838 'accepts (target, source, env) as parameters.') | |
| 839 | |
| 840 self.execfunction = execfunction | 895 self.execfunction = execfunction |
| 841 try: | 896 try: |
| 842 self.funccontents = _callable_contents(execfunction) | 897 self.funccontents = _callable_contents(execfunction) |
| 843 except AttributeError: | 898 except AttributeError: |
| 844 try: | 899 try: |
| 845 # See if execfunction will do the heavy lifting for us. | 900 # See if execfunction will do the heavy lifting for us. |
| 846 self.gc = execfunction.get_contents | 901 self.gc = execfunction.get_contents |
| 847 except AttributeError: | 902 except AttributeError: |
| 848 # This is weird, just do the best we can. | 903 # This is weird, just do the best we can. |
| 849 self.funccontents = _object_contents(execfunction) | 904 self.funccontents = _object_contents(execfunction) |
| 850 | 905 |
| 851 apply(_ActionAction.__init__, (self,)+args, kw) | 906 #TODO(1.5) _ActionAction.__init__(self, **kw) |
| 852 self.varlist = kw.get('varlist', []) | 907 apply(_ActionAction.__init__, (self,), kw) |
| 853 if SCons.Util.is_String(self.varlist): | |
| 854 # prevent varlist="FOO" from being interpreted as ['F', 'O', 'O'] | |
| 855 self.varlist=[self.varlist] | |
| 856 self.cmdstr = cmdstr | |
| 857 | 908 |
| 858 def function_name(self): | 909 def function_name(self): |
| 859 try: | 910 try: |
| 860 return self.execfunction.__name__ | 911 return self.execfunction.__name__ |
| 861 except AttributeError: | 912 except AttributeError: |
| 862 try: | 913 try: |
| 863 return self.execfunction.__class__.__name__ | 914 return self.execfunction.__class__.__name__ |
| 864 except AttributeError: | 915 except AttributeError: |
| 865 return "unknown_python_function" | 916 return "unknown_python_function" |
| 866 | 917 |
| 867 def strfunction(self, target, source, env): | 918 def strfunction(self, target, source, env): |
| 868 if self.cmdstr is None: | 919 if self.cmdstr is None: |
| 869 return None | 920 return None |
| 870 if not self.cmdstr is _null: | 921 if self.cmdstr is not _null: |
| 871 from SCons.Subst import SUBST_RAW | 922 from SCons.Subst import SUBST_RAW |
| 872 c = env.subst(self.cmdstr, SUBST_RAW, target, source) | 923 c = env.subst(self.cmdstr, SUBST_RAW, target, source) |
| 873 if c: | 924 if c: |
| 874 return c | 925 return c |
| 875 def array(a): | 926 def array(a): |
| 876 def quote(s): | 927 def quote(s): |
| 877 try: | 928 try: |
| 878 str_for_display = s.str_for_display | 929 str_for_display = s.str_for_display |
| 879 except AttributeError: | 930 except AttributeError: |
| 880 s = repr(s) | 931 s = repr(s) |
| (...skipping 15 matching lines...) Expand all Loading... |
| 896 sstr = array(source) | 947 sstr = array(source) |
| 897 return "%s(%s, %s)" % (name, tstr, sstr) | 948 return "%s(%s, %s)" % (name, tstr, sstr) |
| 898 | 949 |
| 899 def __str__(self): | 950 def __str__(self): |
| 900 name = self.function_name() | 951 name = self.function_name() |
| 901 if name == 'ActionCaller': | 952 if name == 'ActionCaller': |
| 902 return str(self.execfunction) | 953 return str(self.execfunction) |
| 903 return "%s(target, source, env)" % name | 954 return "%s(target, source, env)" % name |
| 904 | 955 |
| 905 def execute(self, target, source, env): | 956 def execute(self, target, source, env): |
| 906 rsources = map(rfile, source) | 957 exc_info = (None,None,None) |
| 907 try: | 958 try: |
| 908 result = self.execfunction(target=target, source=rsources, env=env) | 959 rsources = map(rfile, source) |
| 909 except EnvironmentError, e: | 960 try: |
| 910 # If an IOError/OSError happens, raise a BuildError. | 961 result = self.execfunction(target=target, source=rsources, env=e
nv) |
| 911 # Report the name of the file or directory that caused the | 962 except KeyboardInterrupt, e: |
| 912 # error, which might be different from the target being built | 963 raise |
| 913 # (for example, failure to create the directory in which the | 964 except SystemExit, e: |
| 914 # target file will appear). | 965 raise |
| 915 try: filename = e.filename | 966 except Exception, e: |
| 916 except AttributeError: filename = None | 967 result = e |
| 917 result = SCons.Errors.BuildError(node=target, | 968 exc_info = sys.exc_info() |
| 918 errstr=e.strerror, | 969 |
| 919 status=1, | |
| 920 filename=filename, | |
| 921 action=self, | |
| 922 command=self.strfunction(target, so
urce, env)) | |
| 923 else: | |
| 924 if result: | 970 if result: |
| 925 msg = "Error %s" % result | 971 result = SCons.Errors.convert_to_BuildError(result, exc_info) |
| 926 result = SCons.Errors.BuildError(errstr=msg, | 972 result.node=target |
| 927 status=result, | 973 result.action=self |
| 928 action=self, | 974 result.command=self.strfunction(target, source, env) |
| 929 command=self.strfunction(target
, source, env)) | |
| 930 return result | |
| 931 | 975 |
| 932 def get_contents(self, target, source, env): | 976 # FIXME: This maintains backward compatibility with respect to |
| 977 # which type of exceptions were returned by raising an |
| 978 # exception and which ones were returned by value. It would |
| 979 # probably be best to always return them by value here, but |
| 980 # some codes do not check the return value of Actions and I do |
| 981 # not have the time to modify them at this point. |
| 982 if (exc_info[1] and |
| 983 not isinstance(exc_info[1],EnvironmentError)): |
| 984 raise result |
| 985 |
| 986 return result |
| 987 finally: |
| 988 # Break the cycle between the traceback object and this |
| 989 # function stack frame. See the sys.exc_info() doc info for |
| 990 # more information about this issue. |
| 991 del exc_info |
| 992 |
| 993 |
| 994 def get_presig(self, target, source, env): |
| 933 """Return the signature contents of this callable action.""" | 995 """Return the signature contents of this callable action.""" |
| 934 try: | 996 try: |
| 935 contents = self.gc(target, source, env) | 997 return self.gc(target, source, env) |
| 936 except AttributeError: | 998 except AttributeError: |
| 937 contents = self.funccontents | 999 return self.funccontents |
| 938 | |
| 939 result = [contents] | |
| 940 for v in self.varlist: | |
| 941 result.append(env.subst('${'+v+'}')) | |
| 942 | |
| 943 return string.join(result, '') | |
| 944 | 1000 |
| 945 def get_implicit_deps(self, target, source, env): | 1001 def get_implicit_deps(self, target, source, env): |
| 946 return [] | 1002 return [] |
| 947 | 1003 |
| 948 class ListAction(ActionBase): | 1004 class ListAction(ActionBase): |
| 949 """Class for lists of other actions.""" | 1005 """Class for lists of other actions.""" |
| 950 def __init__(self, list): | 1006 def __init__(self, list): |
| 951 if __debug__: logInstanceCreation(self, 'Action.ListAction') | 1007 if __debug__: logInstanceCreation(self, 'Action.ListAction') |
| 952 def list_of_actions(x): | 1008 def list_of_actions(x): |
| 953 if isinstance(x, ActionBase): | 1009 if isinstance(x, ActionBase): |
| 954 return x | 1010 return x |
| 955 return Action(x) | 1011 return Action(x) |
| 956 self.list = map(list_of_actions, list) | 1012 self.list = map(list_of_actions, list) |
| 1013 # our children will have had any varlist |
| 1014 # applied; we don't need to do it again |
| 1015 self.varlist = () |
| 957 | 1016 |
| 958 def genstring(self, target, source, env): | 1017 def genstring(self, target, source, env): |
| 959 return string.join(map(lambda a, t=target, s=source, e=env: | 1018 return string.join(map(lambda a, t=target, s=source, e=env: |
| 960 a.genstring(t, s, e), | 1019 a.genstring(t, s, e), |
| 961 self.list), | 1020 self.list), |
| 962 '\n') | 1021 '\n') |
| 963 | 1022 |
| 964 def __str__(self): | 1023 def __str__(self): |
| 965 return string.join(map(str, self.list), '\n') | 1024 return string.join(map(str, self.list), '\n') |
| 966 | 1025 |
| 967 def presub_lines(self, env): | 1026 def presub_lines(self, env): |
| 968 return SCons.Util.flatten_sequence( | 1027 return SCons.Util.flatten_sequence( |
| 969 map(lambda a, env=env: a.presub_lines(env), self.list)) | 1028 map(lambda a, env=env: a.presub_lines(env), self.list)) |
| 970 | 1029 |
| 971 def get_contents(self, target, source, env): | 1030 def get_presig(self, target, source, env): |
| 972 """Return the signature contents of this action list. | 1031 """Return the signature contents of this action list. |
| 973 | 1032 |
| 974 Simple concatenation of the signatures of the elements. | 1033 Simple concatenation of the signatures of the elements. |
| 975 """ | 1034 """ |
| 976 return string.join(map(lambda x, t=target, s=source, e=env: | 1035 return string.join(map(lambda x, t=target, s=source, e=env: |
| 977 x.get_contents(t, s, e), | 1036 x.get_contents(t, s, e), |
| 978 self.list), | 1037 self.list), |
| 979 "") | 1038 "") |
| 980 | 1039 |
| 981 def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, | 1040 def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, |
| (...skipping 17 matching lines...) Expand all Loading... |
| 999 executed. | 1058 executed. |
| 1000 | 1059 |
| 1001 This class looks to the rest of the world like a normal Action object, | 1060 This class looks to the rest of the world like a normal Action object, |
| 1002 but what it's really doing is hanging on to the arguments until we | 1061 but what it's really doing is hanging on to the arguments until we |
| 1003 have a target, source and env to use for the expansion. | 1062 have a target, source and env to use for the expansion. |
| 1004 """ | 1063 """ |
| 1005 def __init__(self, parent, args, kw): | 1064 def __init__(self, parent, args, kw): |
| 1006 self.parent = parent | 1065 self.parent = parent |
| 1007 self.args = args | 1066 self.args = args |
| 1008 self.kw = kw | 1067 self.kw = kw |
| 1068 |
| 1009 def get_contents(self, target, source, env): | 1069 def get_contents(self, target, source, env): |
| 1010 actfunc = self.parent.actfunc | 1070 actfunc = self.parent.actfunc |
| 1011 try: | 1071 try: |
| 1012 # "self.actfunc" is a function. | 1072 # "self.actfunc" is a function. |
| 1013 contents = str(actfunc.func_code.co_code) | 1073 contents = str(actfunc.func_code.co_code) |
| 1014 except AttributeError: | 1074 except AttributeError: |
| 1015 # "self.actfunc" is a callable object. | 1075 # "self.actfunc" is a callable object. |
| 1016 try: | 1076 try: |
| 1017 contents = str(actfunc.__call__.im_func.func_code.co_code) | 1077 contents = str(actfunc.__call__.im_func.func_code.co_code) |
| 1018 except AttributeError: | 1078 except AttributeError: |
| 1019 # No __call__() method, so it might be a builtin | 1079 # No __call__() method, so it might be a builtin |
| 1020 # or something like that. Do the best we can. | 1080 # or something like that. Do the best we can. |
| 1021 contents = str(actfunc) | 1081 contents = str(actfunc) |
| 1022 contents = remove_set_lineno_codes(contents) | 1082 contents = remove_set_lineno_codes(contents) |
| 1023 return contents | 1083 return contents |
| 1084 |
| 1024 def subst(self, s, target, source, env): | 1085 def subst(self, s, target, source, env): |
| 1025 # If s is a list, recursively apply subst() | 1086 # If s is a list, recursively apply subst() |
| 1026 # to every element in the list | 1087 # to every element in the list |
| 1027 if SCons.Util.is_List(s): | 1088 if is_List(s): |
| 1028 result = [] | 1089 result = [] |
| 1029 for elem in s: | 1090 for elem in s: |
| 1030 result.append(self.subst(elem, target, source, env)) | 1091 result.append(self.subst(elem, target, source, env)) |
| 1031 return self.parent.convert(result) | 1092 return self.parent.convert(result) |
| 1032 | 1093 |
| 1033 # Special-case hack: Let a custom function wrapped in an | 1094 # Special-case hack: Let a custom function wrapped in an |
| 1034 # ActionCaller get at the environment through which the action | 1095 # ActionCaller get at the environment through which the action |
| 1035 # was called by using this hard-coded value as a special return. | 1096 # was called by using this hard-coded value as a special return. |
| 1036 if s == '$__env__': | 1097 if s == '$__env__': |
| 1037 return env | 1098 return env |
| 1038 elif SCons.Util.is_String(s): | 1099 elif is_String(s): |
| 1039 return env.subst(s, 1, target, source) | 1100 return env.subst(s, 1, target, source) |
| 1040 return self.parent.convert(s) | 1101 return self.parent.convert(s) |
| 1102 |
| 1041 def subst_args(self, target, source, env): | 1103 def subst_args(self, target, source, env): |
| 1042 return map(lambda x, self=self, t=target, s=source, e=env: | 1104 return map(lambda x, self=self, t=target, s=source, e=env: |
| 1043 self.subst(x, t, s, e), | 1105 self.subst(x, t, s, e), |
| 1044 self.args) | 1106 self.args) |
| 1107 |
| 1045 def subst_kw(self, target, source, env): | 1108 def subst_kw(self, target, source, env): |
| 1046 kw = {} | 1109 kw = {} |
| 1047 for key in self.kw.keys(): | 1110 for key in self.kw.keys(): |
| 1048 kw[key] = self.subst(self.kw[key], target, source, env) | 1111 kw[key] = self.subst(self.kw[key], target, source, env) |
| 1049 return kw | 1112 return kw |
| 1113 |
| 1050 def __call__(self, target, source, env): | 1114 def __call__(self, target, source, env): |
| 1051 args = self.subst_args(target, source, env) | 1115 args = self.subst_args(target, source, env) |
| 1052 kw = self.subst_kw(target, source, env) | 1116 kw = self.subst_kw(target, source, env) |
| 1117 #TODO(1.5) return self.parent.actfunc(*args, **kw) |
| 1053 return apply(self.parent.actfunc, args, kw) | 1118 return apply(self.parent.actfunc, args, kw) |
| 1119 |
| 1054 def strfunction(self, target, source, env): | 1120 def strfunction(self, target, source, env): |
| 1055 args = self.subst_args(target, source, env) | 1121 args = self.subst_args(target, source, env) |
| 1056 kw = self.subst_kw(target, source, env) | 1122 kw = self.subst_kw(target, source, env) |
| 1123 #TODO(1.5) return self.parent.strfunc(*args, **kw) |
| 1057 return apply(self.parent.strfunc, args, kw) | 1124 return apply(self.parent.strfunc, args, kw) |
| 1125 |
| 1058 def __str__(self): | 1126 def __str__(self): |
| 1127 #TODO(1.5) return self.parent.strfunc(*self.args, **self.kw) |
| 1059 return apply(self.parent.strfunc, self.args, self.kw) | 1128 return apply(self.parent.strfunc, self.args, self.kw) |
| 1060 | 1129 |
| 1061 class ActionFactory: | 1130 class ActionFactory: |
| 1062 """A factory class that will wrap up an arbitrary function | 1131 """A factory class that will wrap up an arbitrary function |
| 1063 as an SCons-executable Action object. | 1132 as an SCons-executable Action object. |
| 1064 | 1133 |
| 1065 The real heavy lifting here is done by the ActionCaller class. | 1134 The real heavy lifting here is done by the ActionCaller class. |
| 1066 We just collect the (positional and keyword) arguments that we're | 1135 We just collect the (positional and keyword) arguments that we're |
| 1067 called with and give them to the ActionCaller object we create, | 1136 called with and give them to the ActionCaller object we create, |
| 1068 so it can hang onto them until it needs them. | 1137 so it can hang onto them until it needs them. |
| 1069 """ | 1138 """ |
| 1070 def __init__(self, actfunc, strfunc, convert=lambda x: x): | 1139 def __init__(self, actfunc, strfunc, convert=lambda x: x): |
| 1071 self.actfunc = actfunc | 1140 self.actfunc = actfunc |
| 1072 self.strfunc = strfunc | 1141 self.strfunc = strfunc |
| 1073 self.convert = convert | 1142 self.convert = convert |
| 1143 |
| 1074 def __call__(self, *args, **kw): | 1144 def __call__(self, *args, **kw): |
| 1075 ac = ActionCaller(self, args, kw) | 1145 ac = ActionCaller(self, args, kw) |
| 1076 action = Action(ac, strfunction=ac.strfunction) | 1146 action = Action(ac, strfunction=ac.strfunction) |
| 1077 return action | 1147 return action |
| OLD | NEW |