cfd4a50c57cac72804478aef1aab705a5f27a0ac
[scons.git] / src / engine / SCons / Action.py
1 """SCons.Action
2
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.
6
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.
10
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.
15
16 The heavy lifting is handled by subclasses for the different types of
17 actions we might execute:
18
19     CommandAction
20     CommandGeneratorAction
21     FunctionAction
22     ListAction
23
24 The subclasses supply the following public interface methods used by
25 other modules:
26
27     __call__()
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.
31
32     get_contents()
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.
36
37     genstring()
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.
44
45
46 Subclasses also supply the following methods for internal use within
47 this module:
48
49     __str__()
50         Returns a string approximation of the Action; no variable
51         substitution is performed.
52
53     execute()
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.
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
64     strfunction()
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).
68
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.
76
77 """
78
79 # __COPYRIGHT__
80 #
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:
88 #
89 # The above copyright notice and this permission notice shall be included
90 # in all copies or substantial portions of the Software.
91 #
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.
99
100 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
101
102 import cPickle
103 import dis
104 import os
105 import os.path
106 import string
107 import sys
108 import subprocess
109
110 from SCons.Debug import logInstanceCreation
111 import SCons.Errors
112 import SCons.Executor
113 import SCons.Util
114 import SCons.Subst
115
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
119
120 class _null:
121     pass
122
123 print_actions = 1
124 execute_actions = 1
125 print_actions_presub = 0
126
127 def rfile(n):
128     try:
129         return n.rfile()
130     except AttributeError:
131         return n
132
133 def default_exitstatfunc(s):
134     return s
135
136 try:
137     SET_LINENO = dis.SET_LINENO
138     HAVE_ARGUMENT = dis.HAVE_ARGUMENT
139 except AttributeError:
140     remove_set_lineno_codes = lambda x: x
141 else:
142     def remove_set_lineno_codes(code):
143         result = []
144         n = len(code)
145         i = 0
146         while i < n:
147             c = code[i]
148             op = ord(c)
149             if op >= HAVE_ARGUMENT:
150                 if op != SET_LINENO:
151                     result.append(code[i:i+3])
152                 i = i+3
153             else:
154                 result.append(c)
155                 i = i+1
156         return string.join(result, '')
157
158
159 def _callable_contents(obj):
160     """Return the signature contents of a callable Python object.
161     """
162     try:
163         # Test if obj is a method.
164         return _function_contents(obj.im_func)
165
166     except AttributeError:
167         try:
168             # Test if obj is a callable object.
169             return _function_contents(obj.__call__.im_func)
170
171         except AttributeError:
172             try:
173                 # Test if obj is a code object.
174                 return _code_contents(obj)
175
176             except AttributeError:
177                     # Test if obj is a function object.
178                     return _function_contents(obj)
179
180
181 def _object_contents(obj):
182     """Return the signature contents of any Python object.
183
184     We have to handle the case where object contains a code object
185     since it can be pickled directly.
186     """
187     try:
188         # Test if obj is a method.
189         return _function_contents(obj.im_func)
190
191     except AttributeError:
192         try:
193             # Test if obj is a callable object.
194             return _function_contents(obj.__call__.im_func)
195
196         except AttributeError:
197             try:
198                 # Test if obj is a code object.
199                 return _code_contents(obj)
200
201             except AttributeError:
202                 try:
203                     # Test if obj is a function object.
204                     return _function_contents(obj)
205
206                 except AttributeError:
207                     # Should be a pickable Python object.
208                     try:
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
215                         # the best we can.
216                         return str(obj)
217
218
219 def _code_contents(code):
220     """Return the signature contents of a code object.
221
222     By providing direct access to the code object of the
223     function, Python makes this extremely easy.  Hooray!
224
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.
229     """
230
231     contents = []
232
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)))
236     try:
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")
241
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.
246     #
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:]),',') + ')')
251
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
255     # function result.
256     contents.append(',(' + string.join(map(_object_contents,code.co_names),',') + ')')
257
258
259     # The code contents depends on its actual code!!!
260     contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')')
261
262     return string.join(contents, '')
263
264
265 def _function_contents(func):
266     """Return the signature contents of a function."""
267
268     contents = [_code_contents(func.func_code)]
269
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),',') + ')')
273     else:
274         contents.append(',()')
275
276     # The function contents depends on the closure captured cell values.
277     try:
278         closure = func.func_closure or []
279     except AttributeError:
280         # Older versions of Python do not support closures.
281         closure = []
282
283     #xxx = [_object_contents(x.cell_contents) for x in closure]
284     try:
285         xxx = map(lambda x: _object_contents(x.cell_contents), closure)
286     except AttributeError:
287         xxx = []
288     contents.append(',(' + string.join(xxx, ',') + ')')
289
290     return string.join(contents, '')
291
292
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.
297     a1 = Action(act1)
298     a2 = Action(act2)
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)
304         else:
305             return ListAction(a1.list + [ a2 ])
306     else:
307         if isinstance(a2, ListAction):
308             return ListAction([ a1 ] + a2.list)
309         else:
310             return ListAction([ a1, a2 ])
311
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.
315     """
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)
320     if args:
321         # turn positional args into equivalent keywords
322         cmdstrfunc = args[0]
323         if cmdstrfunc is None or is_String(cmdstrfunc):
324             kw['cmdstr'] = cmdstrfunc
325         elif callable(cmdstrfunc):
326             kw['strfunction'] = cmdstrfunc
327         else:
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.')
332         if len(args) > 1:
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()')
338
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
344     of lists.
345
346     The former will create a ListAction, the latter
347     will create a CommandAction by converting the inner
348     list elements to strings."""
349
350     if isinstance(act, ActionBase):
351         return act
352
353     if is_List(act):
354         #TODO(1.5) return CommandAction(act, **kw)
355         return apply(CommandAction, (act,), kw)
356
357     if callable(act):
358         try:
359             gen = kw['generator']
360             del kw['generator']
361         except KeyError:
362             gen = 0
363         if gen:
364             action_type = CommandGeneratorAction
365         else:
366             action_type = FunctionAction
367         return action_type(act, kw)
368
369     if is_String(act):
370         var=SCons.Util.get_environment_var(act)
371         if var:
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)
386     return None
387
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."""
391     acts = []
392     for a in act:
393         aa = _do_create_action(a, kw)
394         if aa is not None: acts.append(aa)
395     if not acts:
396         return None
397     elif len(acts) == 1:
398         return acts[0]
399     else:
400         return ListAction(acts)
401
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)
406     if is_List(act):
407         return _do_create_list_action(act, kw)
408     return _do_create_action(act, kw)
409
410 class ActionBase:
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."""
414
415     def __cmp__(self, other):
416         return cmp(self.__dict__, other)
417
418     def genstring(self, target, source, env):
419         return str(self)
420
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.
426         vl = self.varlist
427         if is_String(vl): vl = (vl,)
428         for v in vl:
429             result.append(env.subst('${'+v+'}'))
430         return string.join(result, '')
431
432     def __add__(self, other):
433         return _actionAppend(self, other)
434
435     def __radd__(self, other):
436         return _actionAppend(other, self)
437
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
448         return lines
449
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)
454
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,
459                  **kw):
460         self.cmdstr = cmdstr
461         if strfunction is not _null:
462             if strfunction is None:
463                 self.cmdstr = None
464             else:
465                 self.strfunction = strfunction
466         self.varlist = varlist
467         self.presub = presub
468         self.chdir = chdir
469         if not exitstatfunc:
470             exitstatfunc = default_exitstatfunc
471         self.exitstatfunc = exitstatfunc
472
473     def print_cmd_line(self, s, target, source, env):
474         sys.stdout.write(s + "\n")
475
476     def __call__(self, target, source, env,
477                                exitstatfunc=_null,
478                                presub=_null,
479                                show=_null,
480                                execute=_null,
481                                chdir=_null):
482         if not is_List(target):
483             target = [target]
484         if not is_List(source):
485             source = [source]
486
487         if presub is _null:
488             presub = self.presub
489             if presub is _null:
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
495         save_cwd = None
496         if chdir:
497             save_cwd = os.getcwd()
498             try:
499                 chdir = str(chdir.abspath)
500             except AttributeError:
501                 if not is_String(chdir):
502                     chdir = str(target[0].dir)
503         if presub:
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)
508         s = None
509         if show and self.strfunction:
510             s = self.strfunction(target, source, env)
511             if s:
512                 if chdir:
513                     s = ('os.chdir(%s)\n' % repr(chdir)) + s
514                 try:
515                     get = env.get
516                 except AttributeError:
517                     print_func = self.print_cmd_line
518                 else:
519                     print_func = get('PRINT_CMD_LINE_FUNC')
520                     if not print_func:
521                         print_func = self.print_cmd_line
522                 print_func(s, target, source, env)
523         stat = 0
524         if execute:
525             if chdir:
526                 os.chdir(chdir)
527             try:
528                 stat = self.execute(target, source, env)
529                 if isinstance(stat, SCons.Errors.BuildError):
530                     s = exitstatfunc(stat.status)
531                     if s:
532                         stat.status = s
533                     else:
534                         stat = s
535                 else:
536                     stat = exitstatfunc(stat)
537             finally:
538                 if save_cwd:
539                     os.chdir(save_cwd)
540         if s and save_cwd:
541             print_func('os.chdir(%s)' % repr(save_cwd), target, source, env)
542
543         return stat
544
545
546 def _string_from_cmd_list(cmd_list):
547     """Takes a list of command line arguments and returns a pretty
548     representation for printing."""
549     cl = []
550     for arg in map(str, cmd_list):
551         if ' ' in arg or '\t' in arg:
552             arg = '"' + arg + '"'
553         cl.append(arg)
554     return string.join(cl)
555
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.
561 default_ENV = None
562 def get_default_ENV(env):
563     global default_ENV
564     try:
565         return env['ENV']
566     except KeyError:
567         if not default_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']
575         return default_ENV
576
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)
584
585     # Figure out what shell environment to use
586     ENV = kw.get('env', None)
587     if ENV is None: ENV = get_default_ENV(env)
588
589     # Ensure that the ENV values are all strings:
590     new_env = {}
591     for key, value in ENV.items():
592         if is_List(value):
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)
598         else:
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)
606     kw['env'] = new_env
607
608     try:
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
614         class dummyPopen:
615             def __init__(self, e): self.exception = e
616             def communicate(self): return ('','')
617             def wait(self): return -self.exception.errno
618             stdin = None
619             class f:
620                 def read(self): return ''
621                 def readline(self): return ''
622             stdout = stderr = f()
623         return dummyPopen(e)
624
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
636         # variables.
637         if __debug__: logInstanceCreation(self, 'Action.CommandAction')
638
639         #TODO(1.5) _ActionAction.__init__(self, **kw)
640         apply(_ActionAction.__init__, (self,), kw)
641         if is_List(cmd):
642             if filter(is_List, cmd):
643                 raise TypeError, "CommandAction should be given only " \
644                       "a single command"
645         self.cmd_list = cmd
646
647     def __str__(self):
648         if is_List(self.cmd_list):
649             return string.join(map(str, self.cmd_list), ' ')
650         return str(self.cmd_list)
651
652     def process(self, target, source, env):
653         result = env.subst_list(self.cmd_list, 0, target, source)
654         silent = None
655         ignore = None
656         while 1:
657             try: c = result[0][0][0]
658             except IndexError: c = None
659             if c == '@': silent = 1
660             elif c == '-': ignore = 1
661             else: break
662             result[0][0] = result[0][0][1:]
663         try:
664             if not result[0][0]:
665                 result[0] = result[0][1:]
666         except IndexError:
667             pass
668         return result, ignore, silent
669
670     def strfunction(self, target, source, env):
671         if self.cmdstr is None:
672             return 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)
676             if c:
677                 return c
678         cmd_list, ignore, silent = self.process(target, source, env)
679         if silent:
680             return ''
681         return _string_from_cmd_list(cmd_list[0])
682
683     def execute(self, target, source, env):
684         """Execute a command action.
685
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
690         externally.
691         """
692         escape_list = SCons.Subst.escape_list
693         flatten_sequence = SCons.Util.flatten_sequence
694
695         try:
696             shell = env['SHELL']
697         except KeyError:
698             raise SCons.Errors.UserError('Missing SHELL construction variable.')
699
700         try:
701             spawn = env['SPAWN']
702         except KeyError:
703             raise SCons.Errors.UserError('Missing SPAWN construction variable.')
704         else:
705             if is_String(spawn):
706                 spawn = env.subst(spawn, raw=1, conv=lambda x: x)
707
708         escape = env.get('ESCAPE', lambda x: x)
709
710         ENV = get_default_ENV(env)
711
712         # Ensure that the ENV values are all strings:
713         for key, value in ENV.items():
714             if not is_String(value):
715                 if is_List(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)
721                 else:
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)
727
728         cmd_list, ignore, silent = self.process(target, map(rfile, source), env)
729
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,
738                                                status=result,
739                                                action=self,
740                                                command=cmd_line)
741         return 0
742
743     def get_presig(self, target, source, env):
744         """Return the signature contents of this action's command line.
745
746         This strips $(-$) and everything in between the string,
747         since those parts don't affect signatures.
748         """
749         from SCons.Subst import SUBST_SIG
750         cmd = self.cmd_list
751         if is_List(cmd):
752             cmd = string.join(map(str, cmd))
753         else:
754             cmd = str(cmd)
755         return env.subst_target_source(cmd, SUBST_SIG, target, source)
756
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] == '$':
760             icd = env.subst(icd)
761         if not icd or icd in ('0', 'None'):
762             return []
763         from SCons.Subst import SUBST_SIG
764         cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source)
765         res = []
766         for cmd_line in cmd_list:
767             if cmd_line:
768                 d = env.WhereIs(str(cmd_line[0]))
769                 if d:
770                     res.append(env.fs.File(d))
771         return res
772
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
778         self.gen_kw = kw
779         self.varlist = kw.get('varlist', ())
780
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):
785             target = [target]
786
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)
790         if not gen_cmd:
791             raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret))
792         return gen_cmd
793
794     def __str__(self):
795         try:
796             env = self.presub_env
797         except AttributeError:
798             env = None
799         if env is None:
800             env = SCons.Defaults.DefaultEnvironment()
801         act = self._generate([], [], env, 1)
802         return str(act)
803
804     def genstring(self, target, source, env):
805         return self._generate(target, source, env, 1).genstring(target, source, env)
806
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)
812
813     def get_presig(self, target, source, env):
814         """Return the signature contents of this action's command line.
815
816         This strips $(-$) and everything in between the string,
817         since those parts don't affect signatures.
818         """
819         return self._generate(target, source, env, 1).get_presig(target, source, env)
820
821     def get_implicit_deps(self, target, source, env):
822         return self._generate(target, source, env, 1).get_implicit_deps(target, source, env)
823
824
825
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.
833 #
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.
842
843 class LazyAction(CommandGeneratorAction, CommandAction):
844
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)
850         self.gen_kw = kw
851
852     def get_parent_class(self, env):
853         c = env.get(self.var)
854         if is_String(c) and not '\n' in c:
855             return CommandAction
856         return CommandGeneratorAction
857
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)
862         if not gen_cmd:
863             raise SCons.Errors.UserError("$%s value %s cannot be used to create an Action." % (self.var, repr(c)))
864         return gen_cmd
865
866     def _generate(self, target, source, env, for_signature):
867         return self._generate_cache(env)
868
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)
874
875     def get_presig(self, target, source, env):
876         c = self.get_parent_class(env)
877         return c.get_presig(self, target, source, env)
878
879
880
881 class FunctionAction(_ActionAction):
882     """Class for Python function actions."""
883
884     def __init__(self, execfunction, kw):
885         if __debug__: logInstanceCreation(self, 'Action.FunctionAction')
886
887         self.execfunction = execfunction
888         try:
889             self.funccontents = _callable_contents(execfunction)
890         except AttributeError:
891             try:
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)
897
898         #TODO(1.5) _ActionAction.__init__(self, **kw)
899         apply(_ActionAction.__init__, (self,), kw)
900
901     def function_name(self):
902         try:
903             return self.execfunction.__name__
904         except AttributeError:
905             try:
906                 return self.execfunction.__class__.__name__
907             except AttributeError:
908                 return "unknown_python_function"
909
910     def strfunction(self, target, source, env):
911         if self.cmdstr is None:
912             return 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)
916             if c:
917                 return c
918         def array(a):
919             def quote(s):
920                 try:
921                     str_for_display = s.str_for_display
922                 except AttributeError:
923                     s = repr(s)
924                 else:
925                     s = str_for_display()
926                 return s
927             return '[' + string.join(map(quote, a), ", ") + ']'
928         try:
929             strfunc = self.execfunction.strfunction
930         except AttributeError:
931             pass
932         else:
933             if strfunc is None:
934                 return None
935             if callable(strfunc):
936                 return strfunc(target, source, env)
937         name = self.function_name()
938         tstr = array(target)
939         sstr = array(source)
940         return "%s(%s, %s)" % (name, tstr, sstr)
941
942     def __str__(self):
943         name = self.function_name()
944         if name == 'ActionCaller':
945             return str(self.execfunction)
946         return "%s(target, source, env)" % name
947
948     def execute(self, target, source, env):
949         exc_info = (None,None,None)
950         try:
951             rsources = map(rfile, source)
952             try:
953                 result = self.execfunction(target=target, source=rsources, env=env)
954             except Exception, e:
955                 result = e
956                 exc_info = sys.exc_info()
957
958             if result:
959                 result = SCons.Errors.convert_to_BuildError(result, exc_info)
960                 result.node=target
961                 result.action=self
962                 result.command=self.strfunction(target, source, env)
963
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.
970                 if (exc_info[1] and 
971                     not isinstance(exc_info[1],EnvironmentError)):
972                     raise result
973
974             return result
975         finally:
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.
979             del exc_info
980
981
982     def get_presig(self, target, source, env):
983         """Return the signature contents of this callable action."""
984         try:
985             return self.gc(target, source, env)
986         except AttributeError:
987             return self.funccontents
988
989     def get_implicit_deps(self, target, source, env):
990         return []
991
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):
998                 return x
999             return Action(x)
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
1003         self.varlist = ()
1004
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),
1008                                self.list),
1009                            '\n')
1010
1011     def __str__(self):
1012         return string.join(map(str, self.list), '\n')
1013
1014     def presub_lines(self, env):
1015         return SCons.Util.flatten_sequence(
1016             map(lambda a, env=env: a.presub_lines(env), self.list))
1017
1018     def get_presig(self, target, source, env):
1019         """Return the signature contents of this action list.
1020
1021         Simple concatenation of the signatures of the elements.
1022         """
1023         return string.join(map(lambda x, t=target, s=source, e=env:
1024                                       x.get_contents(t, s, e),
1025                                self.list),
1026                            "")
1027
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)
1033             if stat:
1034                 return stat
1035         return 0
1036
1037     def get_implicit_deps(self, target, source, env):
1038         result = []
1039         for act in self.list:
1040             result.extend(act.get_implicit_deps(target, source, env))
1041         return result
1042
1043 class ActionCaller:
1044     """A class for delaying calling an Action function with specific
1045     (positional and keyword) arguments until the Action is actually
1046     executed.
1047
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.
1051     """
1052     def __init__(self, parent, args, kw):
1053         self.parent = parent
1054         self.args = args
1055         self.kw = kw
1056
1057     def get_contents(self, target, source, env):
1058         actfunc = self.parent.actfunc
1059         try:
1060             # "self.actfunc" is a function.
1061             contents = str(actfunc.func_code.co_code)
1062         except AttributeError:
1063             # "self.actfunc" is a callable object.
1064             try:
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)
1071         return contents
1072
1073     def subst(self, s, target, source, env):
1074         # If s is a list, recursively apply subst()
1075         # to every element in the list
1076         if is_List(s):
1077             result = []
1078             for elem in s:
1079                 result.append(self.subst(elem, target, source, env))
1080             return self.parent.convert(result)
1081
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.
1085         if s == '$__env__':
1086             return env
1087         elif is_String(s):
1088             return env.subst(s, 1, target, source)
1089         return self.parent.convert(s)
1090
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),
1094                    self.args)
1095
1096     def subst_kw(self, target, source, env):
1097         kw = {}
1098         for key in self.kw.keys():
1099             kw[key] = self.subst(self.kw[key], target, source, env)
1100         return kw
1101
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)
1107
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)
1113
1114     def __str__(self):
1115         #TODO(1.5) return self.parent.strfunc(*self.args, **self.kw)
1116         return apply(self.parent.strfunc, self.args, self.kw)
1117
1118 class ActionFactory:
1119     """A factory class that will wrap up an arbitrary function
1120     as an SCons-executable Action object.
1121
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.
1126     """
1127     def __init__(self, actfunc, strfunc, convert=lambda x: x):
1128         self.actfunc = actfunc
1129         self.strfunc = strfunc
1130         self.convert = convert
1131
1132     def __call__(self, *args, **kw):
1133         ac = ActionCaller(self, args, kw)
1134         action = Action(ac, strfunction=ac.strfunction)
1135         return action