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
5 source Nodes (also typically files) given a specific Environment.
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
9 about an Action in response to the various commands that control printing.
11 A second-level base class is _ActionAction. This extends ActionBase
12 by providing the methods that can be used to show and perform an
13 action. True Action objects will subclass _ActionAction; Action
14 factory class objects will subclass ActionBase.
16 The heavy lifting is handled by subclasses for the different types of
17 actions we might execute:
20 CommandGeneratorAction
24 The subclasses supply the following public interface methods used by
28 THE public interface, "calling" an Action object executes the
29 command or Python function. This also takes care of printing
30 a pre-substitution command for debugging purposes.
33 Fetches the "contents" of an Action for signature calculation
34 plus the varlist. This is what gets MD5 checksummed to decide
35 if a target needs to be rebuilt because its action changed.
38 Returns a string representation of the Action *without*
39 command substitution, but allows a CommandGeneratorAction to
40 generate the right action based on the specified target,
41 source and env. This is used by the Signature subsystem
42 (through the Executor) to obtain an (imprecise) representation
43 of the Action operation for informative purposes.
46 Subclasses also supply the following methods for internal use within
50 Returns a string approximation of the Action; no variable
51 substitution is performed.
54 The internal method that really, truly, actually handles the
55 execution of a command or Python function. This is used so
56 that the __call__() methods can take care of displaying any
57 pre-substitution representations, and *then* execute an action
58 without worrying about the specific Actions involved.
61 Fetches the "contents" of a subclass for signature calculation.
62 The varlist is added to this to produce the Action's contents.
65 Returns a substituted string representation of the Action.
66 This is used by the _ActionAction.show() command to display the
67 command/function that will be executed to generate the target(s).
69 There is a related independent ActionCaller class that looks like a
70 regular Action, and which serves as a wrapper for arbitrary functions
71 that we want to let the user specify the arguments to now, but actually
72 execute later (when an out-of-date check determines that it's needed to
73 be executed, for example). Objects of this class are returned by an
74 ActionFactory class that provides a __call__() method as a convenient
75 way for wrapping up the functions.
81 # Permission is hereby granted, free of charge, to any person obtaining
82 # a copy of this software and associated documentation files (the
83 # "Software"), to deal in the Software without restriction, including
84 # without limitation the rights to use, copy, modify, merge, publish,
85 # distribute, sublicense, and/or sell copies of the Software, and to
86 # permit persons to whom the Software is furnished to do so, subject to
87 # the following conditions:
89 # The above copyright notice and this permission notice shall be included
90 # in all copies or substantial portions of the Software.
92 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
93 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
94 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
95 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
96 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
97 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
98 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
100 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
110 from SCons.Debug import logInstanceCreation
112 import SCons.Executor
116 # we use these a lot, so try to optimize them
117 is_String = SCons.Util.is_String
118 is_List = SCons.Util.is_List
125 print_actions_presub = 0
130 except AttributeError:
133 def default_exitstatfunc(s):
137 SET_LINENO = dis.SET_LINENO
138 HAVE_ARGUMENT = dis.HAVE_ARGUMENT
139 except AttributeError:
140 remove_set_lineno_codes = lambda x: x
142 def remove_set_lineno_codes(code):
149 if op >= HAVE_ARGUMENT:
151 result.append(code[i:i+3])
156 return string.join(result, '')
159 def _callable_contents(obj):
160 """Return the signature contents of a callable Python object.
163 # Test if obj is a method.
164 return _function_contents(obj.im_func)
166 except AttributeError:
168 # Test if obj is a callable object.
169 return _function_contents(obj.__call__.im_func)
171 except AttributeError:
173 # Test if obj is a code object.
174 return _code_contents(obj)
176 except AttributeError:
177 # Test if obj is a function object.
178 return _function_contents(obj)
181 def _object_contents(obj):
182 """Return the signature contents of any Python object.
184 We have to handle the case where object contains a code object
185 since it can be pickled directly.
188 # Test if obj is a method.
189 return _function_contents(obj.im_func)
191 except AttributeError:
193 # Test if obj is a callable object.
194 return _function_contents(obj.__call__.im_func)
196 except AttributeError:
198 # Test if obj is a code object.
199 return _code_contents(obj)
201 except AttributeError:
203 # Test if obj is a function object.
204 return _function_contents(obj)
206 except AttributeError:
207 # Should be a pickable Python object.
209 return cPickle.dumps(obj)
210 except (cPickle.PicklingError, TypeError):
211 # This is weird, but it seems that nested classes
212 # are unpickable. The Python docs say it should
213 # always be a PicklingError, but some Python
214 # versions seem to return TypeError. Just do
219 def _code_contents(code):
220 """Return the signature contents of a code object.
222 By providing direct access to the code object of the
223 function, Python makes this extremely easy. Hooray!
225 Unfortunately, older versions of Python include line
226 number indications in the compiled byte code. Boo!
227 So we remove the line number byte codes to prevent
228 recompilations from moving a Python function.
233 # The code contents depends on the number of local variables
234 # but not their actual names.
235 contents.append("%s,%s" % (code.co_argcount, len(code.co_varnames)))
237 contents.append(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars)))
238 except AttributeError:
239 # Older versions of Python do not support closures.
240 contents.append(",0,0")
242 # The code contents depends on any constants accessed by the
243 # function. Note that we have to call _object_contents on each
244 # constants because the code object of nested functions can
245 # show-up among the constants.
247 # Note that we also always ignore the first entry of co_consts
248 # which contains the function doc string. We assume that the
249 # function does not access its doc string.
250 contents.append(',(' + string.join(map(_object_contents,code.co_consts[1:]),',') + ')')
252 # The code contents depends on the variable names used to
253 # accessed global variable, as changing the variable name changes
254 # the variable actually accessed and therefore changes the
256 contents.append(',(' + string.join(map(_object_contents,code.co_names),',') + ')')
259 # The code contents depends on its actual code!!!
260 contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')')
262 return string.join(contents, '')
265 def _function_contents(func):
266 """Return the signature contents of a function."""
268 contents = [_code_contents(func.func_code)]
270 # The function contents depends on the value of defaults arguments
271 if func.func_defaults:
272 contents.append(',(' + string.join(map(_object_contents,func.func_defaults),',') + ')')
274 contents.append(',()')
276 # The function contents depends on the closure captured cell values.
278 closure = func.func_closure or []
279 except AttributeError:
280 # Older versions of Python do not support closures.
283 #xxx = [_object_contents(x.cell_contents) for x in closure]
285 xxx = map(lambda x: _object_contents(x.cell_contents), closure)
286 except AttributeError:
288 contents.append(',(' + string.join(xxx, ',') + ')')
290 return string.join(contents, '')
293 def _actionAppend(act1, act2):
294 # This function knows how to slap two actions together.
295 # Mainly, it handles ListActions by concatenating into
296 # a single ListAction.
299 if a1 is None or a2 is None:
300 raise TypeError, "Cannot append %s to %s" % (type(act1), type(act2))
301 if isinstance(a1, ListAction):
302 if isinstance(a2, ListAction):
303 return ListAction(a1.list + a2.list)
305 return ListAction(a1.list + [ a2 ])
307 if isinstance(a2, ListAction):
308 return ListAction([ a1 ] + a2.list)
310 return ListAction([ a1, a2 ])
312 def _do_create_keywords(args, kw):
313 """This converts any arguments after the action argument into
314 their equivalent keywords and adds them to the kw argument.
316 v = kw.get('varlist', ())
317 # prevent varlist="FOO" from being interpreted as ['F', 'O', 'O']
318 if is_String(v): v = (v,)
319 kw['varlist'] = tuple(v)
321 # turn positional args into equivalent keywords
323 if cmdstrfunc is None or is_String(cmdstrfunc):
324 kw['cmdstr'] = cmdstrfunc
325 elif callable(cmdstrfunc):
326 kw['strfunction'] = cmdstrfunc
328 raise SCons.Errors.UserError(
329 'Invalid command display variable type. '
330 'You must either pass a string or a callback which '
331 'accepts (target, source, env) as parameters.')
333 kw['varlist'] = args[1:] + kw['varlist']
334 if kw.get('strfunction', _null) is not _null \
335 and kw.get('cmdstr', _null) is not _null:
336 raise SCons.Errors.UserError(
337 'Cannot have both strfunction and cmdstr args to Action()')
339 def _do_create_action(act, kw):
340 """This is the actual "implementation" for the
341 Action factory method, below. This handles the
342 fact that passing lists to Action() itself has
343 different semantics than passing lists as elements
346 The former will create a ListAction, the latter
347 will create a CommandAction by converting the inner
348 list elements to strings."""
350 if isinstance(act, ActionBase):
354 #TODO(1.5) return CommandAction(act, **kw)
355 return apply(CommandAction, (act,), kw)
359 gen = kw['generator']
364 action_type = CommandGeneratorAction
366 action_type = FunctionAction
367 return action_type(act, kw)
370 var=SCons.Util.get_environment_var(act)
372 # This looks like a string that is purely an Environment
373 # variable reference, like "$FOO" or "${FOO}". We do
374 # something special here...we lazily evaluate the contents
375 # of that Environment variable, so a user could put something
376 # like a function or a CommandGenerator in that variable
377 # instead of a string.
378 return LazyAction(var, kw)
379 commands = string.split(str(act), '\n')
380 if len(commands) == 1:
381 #TODO(1.5) return CommandAction(commands[0], **kw)
382 return apply(CommandAction, (commands[0],), kw)
383 # The list of string commands may include a LazyAction, so we
384 # reprocess them via _do_create_list_action.
385 return _do_create_list_action(commands, kw)
388 def _do_create_list_action(act, kw):
389 """A factory for list actions. Convert the input list into Actions
390 and then wrap them in a ListAction."""
393 aa = _do_create_action(a, kw)
394 if aa is not None: acts.append(aa)
400 return ListAction(acts)
402 def Action(act, *args, **kw):
403 """A factory for action objects."""
404 # Really simple: the _do_create_* routines do the heavy lifting.
405 _do_create_keywords(args, kw)
407 return _do_create_list_action(act, kw)
408 return _do_create_action(act, kw)
411 """Base class for all types of action objects that can be held by
412 other objects (Builders, Executors, etc.) This provides the
413 common methods for manipulating and combining those actions."""
415 def __cmp__(self, other):
416 return cmp(self.__dict__, other)
418 def genstring(self, target, source, env):
421 def get_contents(self, target, source, env):
422 result = [ self.get_presig(target, source, env) ]
423 # This should never happen, as the Action() factory should wrap
424 # the varlist, but just in case an action is created directly,
425 # we duplicate this check here.
427 if is_String(vl): vl = (vl,)
429 result.append(env.subst('${'+v+'}'))
430 return string.join(result, '')
432 def __add__(self, other):
433 return _actionAppend(self, other)
435 def __radd__(self, other):
436 return _actionAppend(other, self)
438 def presub_lines(self, env):
439 # CommandGeneratorAction needs a real environment
440 # in order to return the proper string here, since
441 # it may call LazyAction, which looks up a key
442 # in that env. So we temporarily remember the env here,
443 # and CommandGeneratorAction will use this env
444 # when it calls its _generate method.
445 self.presub_env = env
446 lines = string.split(str(self), '\n')
447 self.presub_env = None # don't need this any more
450 def get_executor(self, env, overrides, tlist, slist, executor_kw):
451 """Return the Executor for this Action."""
452 return SCons.Executor.Executor(self, env, overrides,
453 tlist, slist, executor_kw)
455 class _ActionAction(ActionBase):
456 """Base class for actions that create output objects."""
457 def __init__(self, cmdstr=_null, strfunction=_null, varlist=(),
458 presub=_null, chdir=None, exitstatfunc=None,
461 if strfunction is not _null:
462 if strfunction is None:
465 self.strfunction = strfunction
466 self.varlist = varlist
470 exitstatfunc = default_exitstatfunc
471 self.exitstatfunc = exitstatfunc
473 def print_cmd_line(self, s, target, source, env):
474 sys.stdout.write(s + "\n")
476 def __call__(self, target, source, env,
482 if not is_List(target):
484 if not is_List(source):
490 presub = print_actions_presub
491 if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
492 if show is _null: show = print_actions
493 if execute is _null: execute = execute_actions
494 if chdir is _null: chdir = self.chdir
497 save_cwd = os.getcwd()
499 chdir = str(chdir.abspath)
500 except AttributeError:
501 if not is_String(chdir):
502 chdir = str(target[0].dir)
504 t = string.join(map(str, target), ' and ')
505 l = string.join(self.presub_lines(env), '\n ')
506 out = "Building %s with action:\n %s\n" % (t, l)
507 sys.stdout.write(out)
509 if show and self.strfunction:
510 s = self.strfunction(target, source, env)
513 s = ('os.chdir(%s)\n' % repr(chdir)) + s
516 except AttributeError:
517 print_func = self.print_cmd_line
519 print_func = get('PRINT_CMD_LINE_FUNC')
521 print_func = self.print_cmd_line
522 print_func(s, target, source, env)
528 stat = self.execute(target, source, env)
529 if isinstance(stat, SCons.Errors.BuildError):
530 s = exitstatfunc(stat.status)
536 stat = exitstatfunc(stat)
541 print_func('os.chdir(%s)' % repr(save_cwd), target, source, env)
546 def _string_from_cmd_list(cmd_list):
547 """Takes a list of command line arguments and returns a pretty
548 representation for printing."""
550 for arg in map(str, cmd_list):
551 if ' ' in arg or '\t' in arg:
552 arg = '"' + arg + '"'
554 return string.join(cl)
556 # A fiddlin' little function that has an 'import SCons.Environment' which
557 # can't be moved to the top level without creating an import loop. Since
558 # this import creates a local variable named 'SCons', it blocks access to
559 # the global variable, so we move it here to prevent complaints about local
560 # variables being used uninitialized.
562 def get_default_ENV(env):
568 import SCons.Environment
569 # This is a hideously expensive way to get a default shell
570 # environment. What it really should do is run the platform
571 # setup to get the default ENV. Fortunately, it's incredibly
572 # rare for an Environment not to have a shell environment, so
573 # we're not going to worry about it overmuch.
574 default_ENV = SCons.Environment.Environment()['ENV']
577 # This function is still in draft mode. We're going to need something like
578 # it in the long run as more and more places use subprocess, but I'm sure
579 # it'll have to be tweaked to get the full desired functionality.
580 # one special arg (so far?), 'error', to tell what to do with exceptions.
581 def _subproc(env, cmd, error = 'ignore', **kw):
582 """Do setup for a subprocess.Popen() call"""
583 ### TODO: allow std{in,out,err} to be "'devnull'" (see issue 2228)
585 # Figure out what shell environment to use
586 ENV = kw.get('env', None)
587 if ENV is None: ENV = get_default_ENV(env)
589 # Ensure that the ENV values are all strings:
591 for key, value in ENV.items():
593 # If the value is a list, then we assume it is a path list,
594 # because that's a pretty common list-like value to stick
595 # in an environment variable:
596 value = SCons.Util.flatten_sequence(value)
597 new_env[key] = string.join(map(str, value), os.pathsep)
599 # It's either a string or something else. If it's a string,
600 # we still want to call str() because it might be a *Unicode*
601 # string, which makes subprocess.Popen() gag. If it isn't a
602 # string or a list, then we just coerce it to a string, which
603 # is the proper way to handle Dir and File instances and will
604 # produce something reasonable for just about everything else:
605 new_env[key] = str(value)
609 #FUTURE return subprocess.Popen(cmd, **kw)
610 return apply(subprocess.Popen, (cmd,), kw)
611 except EnvironmentError, e:
612 if error == 'raise': raise
613 # return a dummy Popen instance that only returns error
615 def __init__(self, e): self.exception = e
616 def communicate(self): return ('','')
617 def wait(self): return -self.exception.errno
620 def read(self): return ''
621 def readline(self): return ''
622 stdout = stderr = f()
625 class CommandAction(_ActionAction):
626 """Class for command-execution actions."""
627 def __init__(self, cmd, **kw):
628 # Cmd can actually be a list or a single item; if it's a
629 # single item it should be the command string to execute; if a
630 # list then it should be the words of the command string to
631 # execute. Only a single command should be executed by this
632 # object; lists of commands should be handled by embedding
633 # these objects in a ListAction object (which the Action()
634 # factory above does). cmd will be passed to
635 # Environment.subst_list() for substituting environment
637 if __debug__: logInstanceCreation(self, 'Action.CommandAction')
639 #TODO(1.5) _ActionAction.__init__(self, **kw)
640 apply(_ActionAction.__init__, (self,), kw)
642 if filter(is_List, cmd):
643 raise TypeError, "CommandAction should be given only " \
648 if is_List(self.cmd_list):
649 return string.join(map(str, self.cmd_list), ' ')
650 return str(self.cmd_list)
652 def process(self, target, source, env):
653 result = env.subst_list(self.cmd_list, 0, target, source)
657 try: c = result[0][0][0]
658 except IndexError: c = None
659 if c == '@': silent = 1
660 elif c == '-': ignore = 1
662 result[0][0] = result[0][0][1:]
665 result[0] = result[0][1:]
668 return result, ignore, silent
670 def strfunction(self, target, source, env):
671 if self.cmdstr is None:
673 if self.cmdstr is not _null:
674 from SCons.Subst import SUBST_RAW
675 c = env.subst(self.cmdstr, SUBST_RAW, target, source)
678 cmd_list, ignore, silent = self.process(target, source, env)
681 return _string_from_cmd_list(cmd_list[0])
683 def execute(self, target, source, env):
684 """Execute a command action.
686 This will handle lists of commands as well as individual commands,
687 because construction variable substitution may turn a single
688 "command" into a list. This means that this class can actually
689 handle lists of commands, even though that's not how we use it
692 escape_list = SCons.Subst.escape_list
693 flatten_sequence = SCons.Util.flatten_sequence
698 raise SCons.Errors.UserError('Missing SHELL construction variable.')
703 raise SCons.Errors.UserError('Missing SPAWN construction variable.')
706 spawn = env.subst(spawn, raw=1, conv=lambda x: x)
708 escape = env.get('ESCAPE', lambda x: x)
710 ENV = get_default_ENV(env)
712 # Ensure that the ENV values are all strings:
713 for key, value in ENV.items():
714 if not is_String(value):
716 # If the value is a list, then we assume it is a
717 # path list, because that's a pretty common list-like
718 # value to stick in an environment variable:
719 value = flatten_sequence(value)
720 ENV[key] = string.join(map(str, value), os.pathsep)
722 # If it isn't a string or a list, then we just coerce
723 # it to a string, which is the proper way to handle
724 # Dir and File instances and will produce something
725 # reasonable for just about everything else:
726 ENV[key] = str(value)
728 cmd_list, ignore, silent = self.process(target, map(rfile, source), env)
730 # Use len() to filter out any "command" that's zero-length.
731 for cmd_line in filter(len, cmd_list):
732 # Escape the command line for the interpreter we are using.
733 cmd_line = escape_list(cmd_line, escape)
734 result = spawn(shell, escape, cmd_line[0], cmd_line, ENV)
735 if not ignore and result:
736 msg = "Error %s" % result
737 return SCons.Errors.BuildError(errstr=msg,
743 def get_presig(self, target, source, env):
744 """Return the signature contents of this action's command line.
746 This strips $(-$) and everything in between the string,
747 since those parts don't affect signatures.
749 from SCons.Subst import SUBST_SIG
752 cmd = string.join(map(str, cmd))
755 return env.subst_target_source(cmd, SUBST_SIG, target, source)
757 def get_implicit_deps(self, target, source, env):
758 icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True)
759 if is_String(icd) and icd[:1] == '$':
761 if not icd or icd in ('0', 'None'):
763 from SCons.Subst import SUBST_SIG
764 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source)
766 for cmd_line in cmd_list:
768 d = env.WhereIs(str(cmd_line[0]))
770 res.append(env.fs.File(d))
773 class CommandGeneratorAction(ActionBase):
774 """Class for command-generator actions."""
775 def __init__(self, generator, kw):
776 if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction')
777 self.generator = generator
779 self.varlist = kw.get('varlist', ())
781 def _generate(self, target, source, env, for_signature):
782 # ensure that target is a list, to make it easier to write
783 # generator functions:
784 if not is_List(target):
787 ret = self.generator(target=target, source=source, env=env, for_signature=for_signature)
788 #TODO(1.5) gen_cmd = Action(ret, **self.gen_kw)
789 gen_cmd = apply(Action, (ret,), self.gen_kw)
791 raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret))
796 env = self.presub_env
797 except AttributeError:
800 env = SCons.Defaults.DefaultEnvironment()
801 act = self._generate([], [], env, 1)
804 def genstring(self, target, source, env):
805 return self._generate(target, source, env, 1).genstring(target, source, env)
807 def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
808 show=_null, execute=_null, chdir=_null):
809 act = self._generate(target, source, env, 0)
810 return act(target, source, env, exitstatfunc, presub,
811 show, execute, chdir)
813 def get_presig(self, target, source, env):
814 """Return the signature contents of this action's command line.
816 This strips $(-$) and everything in between the string,
817 since those parts don't affect signatures.
819 return self._generate(target, source, env, 1).get_presig(target, source, env)
821 def get_implicit_deps(self, target, source, env):
822 return self._generate(target, source, env, 1).get_implicit_deps(target, source, env)
826 # A LazyAction is a kind of hybrid generator and command action for
827 # strings of the form "$VAR". These strings normally expand to other
828 # strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also
829 # want to be able to replace them with functions in the construction
830 # environment. Consequently, we want lazy evaluation and creation of
831 # an Action in the case of the function, but that's overkill in the more
832 # normal case of expansion to other strings.
834 # So we do this with a subclass that's both a generator *and*
835 # a command action. The overridden methods all do a quick check
836 # of the construction variable, and if it's a string we just call
837 # the corresponding CommandAction method to do the heavy lifting.
838 # If not, then we call the same-named CommandGeneratorAction method.
839 # The CommandGeneratorAction methods work by using the overridden
840 # _generate() method, that is, our own way of handling "generation" of
841 # an action based on what's in the construction variable.
843 class LazyAction(CommandGeneratorAction, CommandAction):
845 def __init__(self, var, kw):
846 if __debug__: logInstanceCreation(self, 'Action.LazyAction')
847 #FUTURE CommandAction.__init__(self, '${'+var+'}', **kw)
848 apply(CommandAction.__init__, (self, '${'+var+'}'), kw)
849 self.var = SCons.Util.to_String(var)
852 def get_parent_class(self, env):
853 c = env.get(self.var)
854 if is_String(c) and not '\n' in c:
856 return CommandGeneratorAction
858 def _generate_cache(self, env):
859 c = env.get(self.var, '')
860 #TODO(1.5) gen_cmd = Action(c, **self.gen_kw)
861 gen_cmd = apply(Action, (c,), self.gen_kw)
863 raise SCons.Errors.UserError("$%s value %s cannot be used to create an Action." % (self.var, repr(c)))
866 def _generate(self, target, source, env, for_signature):
867 return self._generate_cache(env)
869 def __call__(self, target, source, env, *args, **kw):
870 args = (self, target, source, env) + args
871 c = self.get_parent_class(env)
872 #TODO(1.5) return c.__call__(*args, **kw)
873 return apply(c.__call__, args, kw)
875 def get_presig(self, target, source, env):
876 c = self.get_parent_class(env)
877 return c.get_presig(self, target, source, env)
881 class FunctionAction(_ActionAction):
882 """Class for Python function actions."""
884 def __init__(self, execfunction, kw):
885 if __debug__: logInstanceCreation(self, 'Action.FunctionAction')
887 self.execfunction = execfunction
889 self.funccontents = _callable_contents(execfunction)
890 except AttributeError:
892 # See if execfunction will do the heavy lifting for us.
893 self.gc = execfunction.get_contents
894 except AttributeError:
895 # This is weird, just do the best we can.
896 self.funccontents = _object_contents(execfunction)
898 #TODO(1.5) _ActionAction.__init__(self, **kw)
899 apply(_ActionAction.__init__, (self,), kw)
901 def function_name(self):
903 return self.execfunction.__name__
904 except AttributeError:
906 return self.execfunction.__class__.__name__
907 except AttributeError:
908 return "unknown_python_function"
910 def strfunction(self, target, source, env):
911 if self.cmdstr is None:
913 if self.cmdstr is not _null:
914 from SCons.Subst import SUBST_RAW
915 c = env.subst(self.cmdstr, SUBST_RAW, target, source)
921 str_for_display = s.str_for_display
922 except AttributeError:
925 s = str_for_display()
927 return '[' + string.join(map(quote, a), ", ") + ']'
929 strfunc = self.execfunction.strfunction
930 except AttributeError:
935 if callable(strfunc):
936 return strfunc(target, source, env)
937 name = self.function_name()
940 return "%s(%s, %s)" % (name, tstr, sstr)
943 name = self.function_name()
944 if name == 'ActionCaller':
945 return str(self.execfunction)
946 return "%s(target, source, env)" % name
948 def execute(self, target, source, env):
949 exc_info = (None,None,None)
951 rsources = map(rfile, source)
953 result = self.execfunction(target=target, source=rsources, env=env)
956 exc_info = sys.exc_info()
959 result = SCons.Errors.convert_to_BuildError(result, exc_info)
962 result.command=self.strfunction(target, source, env)
964 # FIXME: This maintains backward compatibility with respect to
965 # which type of exceptions were returned by raising an
966 # exception and which ones were returned by value. It would
967 # probably be best to always return them by value here, but
968 # some codes do not check the return value of Actions and I do
969 # not have the time to modify them at this point.
971 not isinstance(exc_info[1],EnvironmentError)):
976 # Break the cycle between the traceback object and this
977 # function stack frame. See the sys.exc_info() doc info for
978 # more information about this issue.
982 def get_presig(self, target, source, env):
983 """Return the signature contents of this callable action."""
985 return self.gc(target, source, env)
986 except AttributeError:
987 return self.funccontents
989 def get_implicit_deps(self, target, source, env):
992 class ListAction(ActionBase):
993 """Class for lists of other actions."""
994 def __init__(self, list):
995 if __debug__: logInstanceCreation(self, 'Action.ListAction')
996 def list_of_actions(x):
997 if isinstance(x, ActionBase):
1000 self.list = map(list_of_actions, list)
1001 # our children will have had any varlist
1002 # applied; we don't need to do it again
1005 def genstring(self, target, source, env):
1006 return string.join(map(lambda a, t=target, s=source, e=env:
1007 a.genstring(t, s, e),
1012 return string.join(map(str, self.list), '\n')
1014 def presub_lines(self, env):
1015 return SCons.Util.flatten_sequence(
1016 map(lambda a, env=env: a.presub_lines(env), self.list))
1018 def get_presig(self, target, source, env):
1019 """Return the signature contents of this action list.
1021 Simple concatenation of the signatures of the elements.
1023 return string.join(map(lambda x, t=target, s=source, e=env:
1024 x.get_contents(t, s, e),
1028 def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
1029 show=_null, execute=_null, chdir=_null):
1030 for act in self.list:
1031 stat = act(target, source, env, exitstatfunc, presub,
1032 show, execute, chdir)
1037 def get_implicit_deps(self, target, source, env):
1039 for act in self.list:
1040 result.extend(act.get_implicit_deps(target, source, env))
1044 """A class for delaying calling an Action function with specific
1045 (positional and keyword) arguments until the Action is actually
1048 This class looks to the rest of the world like a normal Action object,
1049 but what it's really doing is hanging on to the arguments until we
1050 have a target, source and env to use for the expansion.
1052 def __init__(self, parent, args, kw):
1053 self.parent = parent
1057 def get_contents(self, target, source, env):
1058 actfunc = self.parent.actfunc
1060 # "self.actfunc" is a function.
1061 contents = str(actfunc.func_code.co_code)
1062 except AttributeError:
1063 # "self.actfunc" is a callable object.
1065 contents = str(actfunc.__call__.im_func.func_code.co_code)
1066 except AttributeError:
1067 # No __call__() method, so it might be a builtin
1068 # or something like that. Do the best we can.
1069 contents = str(actfunc)
1070 contents = remove_set_lineno_codes(contents)
1073 def subst(self, s, target, source, env):
1074 # If s is a list, recursively apply subst()
1075 # to every element in the list
1079 result.append(self.subst(elem, target, source, env))
1080 return self.parent.convert(result)
1082 # Special-case hack: Let a custom function wrapped in an
1083 # ActionCaller get at the environment through which the action
1084 # was called by using this hard-coded value as a special return.
1088 return env.subst(s, 1, target, source)
1089 return self.parent.convert(s)
1091 def subst_args(self, target, source, env):
1092 return map(lambda x, self=self, t=target, s=source, e=env:
1093 self.subst(x, t, s, e),
1096 def subst_kw(self, target, source, env):
1098 for key in self.kw.keys():
1099 kw[key] = self.subst(self.kw[key], target, source, env)
1102 def __call__(self, target, source, env):
1103 args = self.subst_args(target, source, env)
1104 kw = self.subst_kw(target, source, env)
1105 #TODO(1.5) return self.parent.actfunc(*args, **kw)
1106 return apply(self.parent.actfunc, args, kw)
1108 def strfunction(self, target, source, env):
1109 args = self.subst_args(target, source, env)
1110 kw = self.subst_kw(target, source, env)
1111 #TODO(1.5) return self.parent.strfunc(*args, **kw)
1112 return apply(self.parent.strfunc, args, kw)
1115 #TODO(1.5) return self.parent.strfunc(*self.args, **self.kw)
1116 return apply(self.parent.strfunc, self.args, self.kw)
1118 class ActionFactory:
1119 """A factory class that will wrap up an arbitrary function
1120 as an SCons-executable Action object.
1122 The real heavy lifting here is done by the ActionCaller class.
1123 We just collect the (positional and keyword) arguments that we're
1124 called with and give them to the ActionCaller object we create,
1125 so it can hang onto them until it needs them.
1127 def __init__(self, actfunc, strfunc, convert=lambda x: x):
1128 self.actfunc = actfunc
1129 self.strfunc = strfunc
1130 self.convert = convert
1132 def __call__(self, *args, **kw):
1133 ac = ActionCaller(self, args, kw)
1134 action = Action(ac, strfunction=ac.strfunction)