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 |