Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(177)

Side by Side Diff: third_party/scons/scons-local/SCons/Action.py

Issue 17024: Update to SCons 1.2.0. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/scons/scons.py ('k') | third_party/scons/scons-local/SCons/Builder.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « third_party/scons/scons.py ('k') | third_party/scons/scons-local/SCons/Builder.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698