ff67b490ee8aecdaaa89d7363db1a17dbac613a8
[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 from __future__ import generators  ### KEEP FOR COMPATIBILITY FIXERS
100
101 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
102
103 import SCons.compat
104
105 import dis
106 import os
107 # compat layer imports "cPickle" for us if it's available.
108 import pickle
109 import re
110 import sys
111 import subprocess
112
113 from SCons.Debug import logInstanceCreation
114 import SCons.Errors
115 import SCons.Executor
116 import SCons.Util
117 import SCons.Subst
118
119 # we use these a lot, so try to optimize them
120 is_String = SCons.Util.is_String
121 is_List = SCons.Util.is_List
122
123 class _null:
124     pass
125
126 print_actions = 1
127 execute_actions = 1
128 print_actions_presub = 0
129
130 def rfile(n):
131     try:
132         return n.rfile()
133     except AttributeError:
134         return n
135
136 def default_exitstatfunc(s):
137     return s
138
139 try:
140     SET_LINENO = dis.SET_LINENO
141     HAVE_ARGUMENT = dis.HAVE_ARGUMENT
142 except AttributeError:
143     remove_set_lineno_codes = lambda x: x
144 else:
145     def remove_set_lineno_codes(code):
146         result = []
147         n = len(code)
148         i = 0
149         while i < n:
150             c = code[i]
151             op = ord(c)
152             if op >= HAVE_ARGUMENT:
153                 if op != SET_LINENO:
154                     result.append(code[i:i+3])
155                 i = i+3
156             else:
157                 result.append(c)
158                 i = i+1
159         return ''.join(result)
160
161 strip_quotes = re.compile('^[\'"](.*)[\'"]$')
162
163
164 def _callable_contents(obj):
165     """Return the signature contents of a callable Python object.
166     """
167     try:
168         # Test if obj is a method.
169         return _function_contents(obj.im_func)
170
171     except AttributeError:
172         try:
173             # Test if obj is a callable object.
174             return _function_contents(obj.__call__.im_func)
175
176         except AttributeError:
177             try:
178                 # Test if obj is a code object.
179                 return _code_contents(obj)
180
181             except AttributeError:
182                     # Test if obj is a function object.
183                     return _function_contents(obj)
184
185
186 def _object_contents(obj):
187     """Return the signature contents of any Python object.
188
189     We have to handle the case where object contains a code object
190     since it can be pickled directly.
191     """
192     try:
193         # Test if obj is a method.
194         return _function_contents(obj.im_func)
195
196     except AttributeError:
197         try:
198             # Test if obj is a callable object.
199             return _function_contents(obj.__call__.im_func)
200
201         except AttributeError:
202             try:
203                 # Test if obj is a code object.
204                 return _code_contents(obj)
205
206             except AttributeError:
207                 try:
208                     # Test if obj is a function object.
209                     return _function_contents(obj)
210
211                 except AttributeError:
212                     # Should be a pickable Python object.
213                     try:
214                         return pickle.dumps(obj)
215                     except (pickle.PicklingError, TypeError):
216                         # This is weird, but it seems that nested classes
217                         # are unpickable. The Python docs say it should
218                         # always be a PicklingError, but some Python
219                         # versions seem to return TypeError.  Just do
220                         # the best we can.
221                         return str(obj)
222
223
224 def _code_contents(code):
225     """Return the signature contents of a code object.
226
227     By providing direct access to the code object of the
228     function, Python makes this extremely easy.  Hooray!
229
230     Unfortunately, older versions of Python include line
231     number indications in the compiled byte code.  Boo!
232     So we remove the line number byte codes to prevent
233     recompilations from moving a Python function.
234     """
235
236     contents = []
237
238     # The code contents depends on the number of local variables
239     # but not their actual names.
240     contents.append("%s,%s" % (code.co_argcount, len(code.co_varnames)))
241     try:
242         contents.append(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars)))
243     except AttributeError:
244         # Older versions of Python do not support closures.
245         contents.append(",0,0")
246
247     # The code contents depends on any constants accessed by the
248     # function. Note that we have to call _object_contents on each
249     # constants because the code object of nested functions can
250     # show-up among the constants.
251     #
252     # Note that we also always ignore the first entry of co_consts
253     # which contains the function doc string. We assume that the
254     # function does not access its doc string.
255     contents.append(',(' + ','.join(map(_object_contents,code.co_consts[1:])) + ')')
256
257     # The code contents depends on the variable names used to
258     # accessed global variable, as changing the variable name changes
259     # the variable actually accessed and therefore changes the
260     # function result.
261     contents.append(',(' + ','.join(map(_object_contents,code.co_names)) + ')')
262
263
264     # The code contents depends on its actual code!!!
265     contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')')
266
267     return ''.join(contents)
268
269
270 def _function_contents(func):
271     """Return the signature contents of a function."""
272
273     contents = [_code_contents(func.func_code)]
274
275     # The function contents depends on the value of defaults arguments
276     if func.func_defaults:
277         contents.append(',(' + ','.join(map(_object_contents,func.func_defaults)) + ')')
278     else:
279         contents.append(',()')
280
281     # The function contents depends on the closure captured cell values.
282     try:
283         closure = func.func_closure or []
284     except AttributeError:
285         # Older versions of Python do not support closures.
286         closure = []
287
288     #xxx = [_object_contents(x.cell_contents) for x in closure]
289     try:
290         xxx = [_object_contents(x.cell_contents) for x in closure]
291     except AttributeError:
292         xxx = []
293     contents.append(',(' + ','.join(xxx) + ')')
294
295     return ''.join(contents)
296
297
298 def _actionAppend(act1, act2):
299     # This function knows how to slap two actions together.
300     # Mainly, it handles ListActions by concatenating into
301     # a single ListAction.
302     a1 = Action(act1)
303     a2 = Action(act2)
304     if a1 is None or a2 is None:
305         raise TypeError, "Cannot append %s to %s" % (type(act1), type(act2))
306     if isinstance(a1, ListAction):
307         if isinstance(a2, ListAction):
308             return ListAction(a1.list + a2.list)
309         else:
310             return ListAction(a1.list + [ a2 ])
311     else:
312         if isinstance(a2, ListAction):
313             return ListAction([ a1 ] + a2.list)
314         else:
315             return ListAction([ a1, a2 ])
316
317 def _do_create_keywords(args, kw):
318     """This converts any arguments after the action argument into
319     their equivalent keywords and adds them to the kw argument.
320     """
321     v = kw.get('varlist', ())
322     # prevent varlist="FOO" from being interpreted as ['F', 'O', 'O']
323     if is_String(v): v = (v,)
324     kw['varlist'] = tuple(v)
325     if args:
326         # turn positional args into equivalent keywords
327         cmdstrfunc = args[0]
328         if cmdstrfunc is None or is_String(cmdstrfunc):
329             kw['cmdstr'] = cmdstrfunc
330         elif callable(cmdstrfunc):
331             kw['strfunction'] = cmdstrfunc
332         else:
333             raise SCons.Errors.UserError(
334                 'Invalid command display variable type. '
335                 'You must either pass a string or a callback which '
336                 'accepts (target, source, env) as parameters.')
337         if len(args) > 1:
338             kw['varlist'] = args[1:] + kw['varlist']
339     if kw.get('strfunction', _null) is not _null \
340                       and kw.get('cmdstr', _null) is not _null:
341         raise SCons.Errors.UserError(
342             'Cannot have both strfunction and cmdstr args to Action()')
343
344 def _do_create_action(act, kw):
345     """This is the actual "implementation" for the
346     Action factory method, below.  This handles the
347     fact that passing lists to Action() itself has
348     different semantics than passing lists as elements
349     of lists.
350
351     The former will create a ListAction, the latter
352     will create a CommandAction by converting the inner
353     list elements to strings."""
354
355     if isinstance(act, ActionBase):
356         return act
357
358     if is_List(act):
359         #TODO(1.5) return CommandAction(act, **kw)
360         return CommandAction(act, **kw)
361
362     if callable(act):
363         try:
364             gen = kw['generator']
365             del kw['generator']
366         except KeyError:
367             gen = 0
368         if gen:
369             action_type = CommandGeneratorAction
370         else:
371             action_type = FunctionAction
372         return action_type(act, kw)
373
374     if is_String(act):
375         var=SCons.Util.get_environment_var(act)
376         if var:
377             # This looks like a string that is purely an Environment
378             # variable reference, like "$FOO" or "${FOO}".  We do
379             # something special here...we lazily evaluate the contents
380             # of that Environment variable, so a user could put something
381             # like a function or a CommandGenerator in that variable
382             # instead of a string.
383             return LazyAction(var, kw)
384         commands = str(act).split('\n')
385         if len(commands) == 1:
386             #TODO(1.5) return CommandAction(commands[0], **kw)
387             return CommandAction(commands[0], **kw)
388         # The list of string commands may include a LazyAction, so we
389         # reprocess them via _do_create_list_action.
390         return _do_create_list_action(commands, kw)
391     return None
392
393 def _do_create_list_action(act, kw):
394     """A factory for list actions.  Convert the input list into Actions
395     and then wrap them in a ListAction."""
396     acts = []
397     for a in act:
398         aa = _do_create_action(a, kw)
399         if aa is not None: acts.append(aa)
400     if not acts:
401         return ListAction([])
402     elif len(acts) == 1:
403         return acts[0]
404     else:
405         return ListAction(acts)
406
407 def Action(act, *args, **kw):
408     """A factory for action objects."""
409     # Really simple: the _do_create_* routines do the heavy lifting.
410     _do_create_keywords(args, kw)
411     if is_List(act):
412         return _do_create_list_action(act, kw)
413     return _do_create_action(act, kw)
414
415 class ActionBase:
416     """Base class for all types of action objects that can be held by
417     other objects (Builders, Executors, etc.)  This provides the
418     common methods for manipulating and combining those actions."""
419
420     def __cmp__(self, other):
421         return cmp(self.__dict__, other)
422
423     def no_batch_key(self, env, target, source):
424         return None
425
426     batch_key = no_batch_key
427
428     def genstring(self, target, source, env):
429         return str(self)
430
431     def get_contents(self, target, source, env):
432         result = [ self.get_presig(target, source, env) ]
433         # This should never happen, as the Action() factory should wrap
434         # the varlist, but just in case an action is created directly,
435         # we duplicate this check here.
436         vl = self.get_varlist(target, source, env)
437         if is_String(vl): vl = (vl,)
438         for v in vl:
439             result.append(env.subst('${'+v+'}'))
440         return ''.join(result)
441
442     def __add__(self, other):
443         return _actionAppend(self, other)
444
445     def __radd__(self, other):
446         return _actionAppend(other, self)
447
448     def presub_lines(self, env):
449         # CommandGeneratorAction needs a real environment
450         # in order to return the proper string here, since
451         # it may call LazyAction, which looks up a key
452         # in that env.  So we temporarily remember the env here,
453         # and CommandGeneratorAction will use this env
454         # when it calls its _generate method.
455         self.presub_env = env
456         lines = str(self).split('\n')
457         self.presub_env = None      # don't need this any more
458         return lines
459
460     def get_varlist(self, target, source, env, executor=None):
461         return self.varlist
462
463     def get_targets(self, env, executor):
464         """
465         Returns the type of targets ($TARGETS, $CHANGED_TARGETS) used
466         by this action.
467         """
468         return self.targets
469
470 class _ActionAction(ActionBase):
471     """Base class for actions that create output objects."""
472     def __init__(self, cmdstr=_null, strfunction=_null, varlist=(),
473                        presub=_null, chdir=None, exitstatfunc=None,
474                        batch_key=None, targets='$TARGETS',
475                  **kw):
476         self.cmdstr = cmdstr
477         if strfunction is not _null:
478             if strfunction is None:
479                 self.cmdstr = None
480             else:
481                 self.strfunction = strfunction
482         self.varlist = varlist
483         self.presub = presub
484         self.chdir = chdir
485         if not exitstatfunc:
486             exitstatfunc = default_exitstatfunc
487         self.exitstatfunc = exitstatfunc
488
489         self.targets = targets
490
491         if batch_key:
492             if not callable(batch_key):
493                 # They have set batch_key, but not to their own
494                 # callable.  The default behavior here will batch
495                 # *all* targets+sources using this action, separated
496                 # for each construction environment.
497                 def default_batch_key(self, env, target, source):
498                     return (id(self), id(env))
499                 batch_key = default_batch_key
500             SCons.Util.AddMethod(self, batch_key, 'batch_key')
501
502     def print_cmd_line(self, s, target, source, env):
503         sys.stdout.write(s + u"\n")
504
505     def __call__(self, target, source, env,
506                                exitstatfunc=_null,
507                                presub=_null,
508                                show=_null,
509                                execute=_null,
510                                chdir=_null,
511                                executor=None):
512         if not is_List(target):
513             target = [target]
514         if not is_List(source):
515             source = [source]
516
517         if presub is _null:
518             presub = self.presub
519             if presub is _null:
520                 presub = print_actions_presub
521         if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
522         if show is _null:  show = print_actions
523         if execute is _null:  execute = execute_actions
524         if chdir is _null: chdir = self.chdir
525         save_cwd = None
526         if chdir:
527             save_cwd = os.getcwd()
528             try:
529                 chdir = str(chdir.abspath)
530             except AttributeError:
531                 if not is_String(chdir):
532                     if executor:
533                         chdir = str(executor.batches[0].targets[0].dir)
534                     else:
535                         chdir = str(target[0].dir)
536         if presub:
537             if executor:
538                 target = executor.get_all_targets()
539                 source = executor.get_all_sources()
540             t = ' and '.join(map(str, target))
541             l = '\n  '.join(self.presub_lines(env))
542             out = u"Building %s with action:\n  %s\n" % (t, l)
543             sys.stdout.write(out)
544         cmd = None
545         if show and self.strfunction:
546             if executor:
547                 target = executor.get_all_targets()
548                 source = executor.get_all_sources()
549             try:
550                 cmd = self.strfunction(target, source, env, executor)
551             except TypeError:
552                 cmd = self.strfunction(target, source, env)
553             if cmd:
554                 if chdir:
555                     cmd = ('os.chdir(%s)\n' % repr(chdir)) + cmd
556                 try:
557                     get = env.get
558                 except AttributeError:
559                     print_func = self.print_cmd_line
560                 else:
561                     print_func = get('PRINT_CMD_LINE_FUNC')
562                     if not print_func:
563                         print_func = self.print_cmd_line
564                 print_func(cmd, target, source, env)
565         stat = 0
566         if execute:
567             if chdir:
568                 os.chdir(chdir)
569             try:
570                 stat = self.execute(target, source, env, executor=executor)
571                 if isinstance(stat, SCons.Errors.BuildError):
572                     s = exitstatfunc(stat.status)
573                     if s:
574                         stat.status = s
575                     else:
576                         stat = s
577                 else:
578                     stat = exitstatfunc(stat)
579             finally:
580                 if save_cwd:
581                     os.chdir(save_cwd)
582         if cmd and save_cwd:
583             print_func('os.chdir(%s)' % repr(save_cwd), target, source, env)
584
585         return stat
586
587
588 def _string_from_cmd_list(cmd_list):
589     """Takes a list of command line arguments and returns a pretty
590     representation for printing."""
591     cl = []
592     for arg in map(str, cmd_list):
593         if ' ' in arg or '\t' in arg:
594             arg = '"' + arg + '"'
595         cl.append(arg)
596     return ' '.join(cl)
597
598 # A fiddlin' little function that has an 'import SCons.Environment' which
599 # can't be moved to the top level without creating an import loop.  Since
600 # this import creates a local variable named 'SCons', it blocks access to
601 # the global variable, so we move it here to prevent complaints about local
602 # variables being used uninitialized.
603 default_ENV = None
604 def get_default_ENV(env):
605     global default_ENV
606     try:
607         return env['ENV']
608     except KeyError:
609         if not default_ENV:
610             import SCons.Environment
611             # This is a hideously expensive way to get a default shell
612             # environment.  What it really should do is run the platform
613             # setup to get the default ENV.  Fortunately, it's incredibly
614             # rare for an Environment not to have a shell environment, so
615             # we're not going to worry about it overmuch.
616             default_ENV = SCons.Environment.Environment()['ENV']
617         return default_ENV
618
619 # This function is still in draft mode.  We're going to need something like
620 # it in the long run as more and more places use subprocess, but I'm sure
621 # it'll have to be tweaked to get the full desired functionality.
622 # one special arg (so far?), 'error', to tell what to do with exceptions.
623 def _subproc(env, cmd, error = 'ignore', **kw):
624     """Do common setup for a subprocess.Popen() call"""
625     # allow std{in,out,err} to be "'devnull'"
626     io = kw.get('stdin')
627     if is_String(io) and io == 'devnull':
628         kw['stdin'] = open(os.devnull)
629     io = kw.get('stdout')
630     if is_String(io) and io == 'devnull':
631         kw['stdout'] = open(os.devnull, 'w')
632     io = kw.get('stderr')
633     if is_String(io) and io == 'devnull':
634         kw['stderr'] = open(os.devnull, 'w')
635
636     # Figure out what shell environment to use
637     ENV = kw.get('env', None)
638     if ENV is None: ENV = get_default_ENV(env)
639
640     # Ensure that the ENV values are all strings:
641     new_env = {}
642     for key, value in ENV.items():
643         if is_List(value):
644             # If the value is a list, then we assume it is a path list,
645             # because that's a pretty common list-like value to stick
646             # in an environment variable:
647             value = SCons.Util.flatten_sequence(value)
648             new_env[key] = os.pathsep.join(map(str, value))
649         else:
650             # It's either a string or something else.  If it's a string,
651             # we still want to call str() because it might be a *Unicode*
652             # string, which makes subprocess.Popen() gag.  If it isn't a
653             # string or a list, then we just coerce it to a string, which
654             # is the proper way to handle Dir and File instances and will
655             # produce something reasonable for just about everything else:
656             new_env[key] = str(value)
657     kw['env'] = new_env
658
659     try:
660         #FUTURE return subprocess.Popen(cmd, **kw)
661         return subprocess.Popen(cmd, **kw)
662     except EnvironmentError, e:
663         if error == 'raise': raise
664         # return a dummy Popen instance that only returns error
665         class dummyPopen:
666             def __init__(self, e): self.exception = e
667             def communicate(self): return ('','')
668             def wait(self): return -self.exception.errno
669             stdin = None
670             class f:
671                 def read(self): return ''
672                 def readline(self): return ''
673             stdout = stderr = f()
674         return dummyPopen(e)
675
676 class CommandAction(_ActionAction):
677     """Class for command-execution actions."""
678     def __init__(self, cmd, **kw):
679         # Cmd can actually be a list or a single item; if it's a
680         # single item it should be the command string to execute; if a
681         # list then it should be the words of the command string to
682         # execute.  Only a single command should be executed by this
683         # object; lists of commands should be handled by embedding
684         # these objects in a ListAction object (which the Action()
685         # factory above does).  cmd will be passed to
686         # Environment.subst_list() for substituting environment
687         # variables.
688         if __debug__: logInstanceCreation(self, 'Action.CommandAction')
689
690         #TODO(1.5) _ActionAction.__init__(self, **kw)
691         _ActionAction.__init__(self, **kw)
692         if is_List(cmd):
693             if list(filter(is_List, cmd)):
694                 raise TypeError, "CommandAction should be given only " \
695                       "a single command"
696         self.cmd_list = cmd
697
698     def __str__(self):
699         if is_List(self.cmd_list):
700             return ' '.join(map(str, self.cmd_list))
701         return str(self.cmd_list)
702
703     def process(self, target, source, env, executor=None):
704         if executor:
705             result = env.subst_list(self.cmd_list, 0, executor=executor)
706         else:
707             result = env.subst_list(self.cmd_list, 0, target, source)
708         silent = None
709         ignore = None
710         while True:
711             try: c = result[0][0][0]
712             except IndexError: c = None
713             if c == '@': silent = 1
714             elif c == '-': ignore = 1
715             else: break
716             result[0][0] = result[0][0][1:]
717         try:
718             if not result[0][0]:
719                 result[0] = result[0][1:]
720         except IndexError:
721             pass
722         return result, ignore, silent
723
724     def strfunction(self, target, source, env, executor=None):
725         if self.cmdstr is None:
726             return None
727         if self.cmdstr is not _null:
728             from SCons.Subst import SUBST_RAW
729             if executor:
730                 c = env.subst(self.cmdstr, SUBST_RAW, executor=executor)
731             else:
732                 c = env.subst(self.cmdstr, SUBST_RAW, target, source)
733             if c:
734                 return c
735         cmd_list, ignore, silent = self.process(target, source, env, executor)
736         if silent:
737             return ''
738         return _string_from_cmd_list(cmd_list[0])
739
740     def execute(self, target, source, env, executor=None):
741         """Execute a command action.
742
743         This will handle lists of commands as well as individual commands,
744         because construction variable substitution may turn a single
745         "command" into a list.  This means that this class can actually
746         handle lists of commands, even though that's not how we use it
747         externally.
748         """
749         escape_list = SCons.Subst.escape_list
750         flatten_sequence = SCons.Util.flatten_sequence
751
752         try:
753             shell = env['SHELL']
754         except KeyError:
755             raise SCons.Errors.UserError('Missing SHELL construction variable.')
756
757         try:
758             spawn = env['SPAWN']
759         except KeyError:
760             raise SCons.Errors.UserError('Missing SPAWN construction variable.')
761         else:
762             if is_String(spawn):
763                 spawn = env.subst(spawn, raw=1, conv=lambda x: x)
764
765         escape = env.get('ESCAPE', lambda x: x)
766
767         ENV = get_default_ENV(env)
768
769         # Ensure that the ENV values are all strings:
770         for key, value in ENV.items():
771             if not is_String(value):
772                 if is_List(value):
773                     # If the value is a list, then we assume it is a
774                     # path list, because that's a pretty common list-like
775                     # value to stick in an environment variable:
776                     value = flatten_sequence(value)
777                     ENV[key] = os.pathsep.join(map(str, value))
778                 else:
779                     # If it isn't a string or a list, then we just coerce
780                     # it to a string, which is the proper way to handle
781                     # Dir and File instances and will produce something
782                     # reasonable for just about everything else:
783                     ENV[key] = str(value)
784
785         if executor:
786             target = executor.get_all_targets()
787             source = executor.get_all_sources()
788         cmd_list, ignore, silent = self.process(target, list(map(rfile, source)), env, executor)
789
790         # Use len() to filter out any "command" that's zero-length.
791         for cmd_line in filter(len, cmd_list):
792             # Escape the command line for the interpreter we are using.
793             cmd_line = escape_list(cmd_line, escape)
794             result = spawn(shell, escape, cmd_line[0], cmd_line, ENV)
795             if not ignore and result:
796                 msg = "Error %s" % result
797                 return SCons.Errors.BuildError(errstr=msg,
798                                                status=result,
799                                                action=self,
800                                                command=cmd_line)
801         return 0
802
803     def get_presig(self, target, source, env, executor=None):
804         """Return the signature contents of this action's command line.
805
806         This strips $(-$) and everything in between the string,
807         since those parts don't affect signatures.
808         """
809         from SCons.Subst import SUBST_SIG
810         cmd = self.cmd_list
811         if is_List(cmd):
812             cmd = ' '.join(map(str, cmd))
813         else:
814             cmd = str(cmd)
815         if executor:
816             return env.subst_target_source(cmd, SUBST_SIG, executor=executor)
817         else:
818             return env.subst_target_source(cmd, SUBST_SIG, target, source)
819
820     def get_implicit_deps(self, target, source, env, executor=None):
821         icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True)
822         if is_String(icd) and icd[:1] == '$':
823             icd = env.subst(icd)
824         if not icd or icd in ('0', 'None'):
825             return []
826         from SCons.Subst import SUBST_SIG
827         if executor:
828             cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, executor=executor)
829         else:
830             cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source)
831         res = []
832         for cmd_line in cmd_list:
833             if cmd_line:
834                 d = str(cmd_line[0])
835                 m = strip_quotes.match(d)
836                 if m:
837                     d = m.group(1)
838                 d = env.WhereIs(d)
839                 if d:
840                     res.append(env.fs.File(d))
841         return res
842
843 class CommandGeneratorAction(ActionBase):
844     """Class for command-generator actions."""
845     def __init__(self, generator, kw):
846         if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction')
847         self.generator = generator
848         self.gen_kw = kw
849         self.varlist = kw.get('varlist', ())
850         self.targets = kw.get('targets', '$TARGETS')
851
852     def _generate(self, target, source, env, for_signature, executor=None):
853         # ensure that target is a list, to make it easier to write
854         # generator functions:
855         if not is_List(target):
856             target = [target]
857
858         if executor:
859             target = executor.get_all_targets()
860             source = executor.get_all_sources()
861         ret = self.generator(target=target,
862                              source=source,
863                              env=env,
864                              for_signature=for_signature)
865         #TODO(1.5) gen_cmd = Action(ret, **self.gen_kw)
866         gen_cmd = Action(ret, **self.gen_kw)
867         if not gen_cmd:
868             raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret))
869         return gen_cmd
870
871     def __str__(self):
872         try:
873             env = self.presub_env
874         except AttributeError:
875             env = None
876         if env is None:
877             env = SCons.Defaults.DefaultEnvironment()
878         act = self._generate([], [], env, 1)
879         return str(act)
880
881     def batch_key(self, env, target, source):
882         return self._generate(target, source, env, 1).batch_key(env, target, source)
883
884     def genstring(self, target, source, env, executor=None):
885         return self._generate(target, source, env, 1, executor).genstring(target, source, env)
886
887     def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
888                  show=_null, execute=_null, chdir=_null, executor=None):
889         act = self._generate(target, source, env, 0, executor)
890         if act is None:
891             raise UserError("While building `%s': "
892                             "Cannot deduce file extension from source files: %s"
893                 % (repr(list(map(str, target))), repr(list(map(str, source)))))
894         return act(target, source, env, exitstatfunc, presub,
895                    show, execute, chdir, executor)
896
897     def get_presig(self, target, source, env, executor=None):
898         """Return the signature contents of this action's command line.
899
900         This strips $(-$) and everything in between the string,
901         since those parts don't affect signatures.
902         """
903         return self._generate(target, source, env, 1, executor).get_presig(target, source, env)
904
905     def get_implicit_deps(self, target, source, env, executor=None):
906         return self._generate(target, source, env, 1, executor).get_implicit_deps(target, source, env)
907
908     def get_varlist(self, target, source, env, executor=None):
909         return self._generate(target, source, env, 1, executor).get_varlist(target, source, env, executor)
910
911     def get_targets(self, env, executor):
912         return self._generate(None, None, env, 1, executor).get_targets(env, executor)
913
914
915
916 # A LazyAction is a kind of hybrid generator and command action for
917 # strings of the form "$VAR".  These strings normally expand to other
918 # strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also
919 # want to be able to replace them with functions in the construction
920 # environment.  Consequently, we want lazy evaluation and creation of
921 # an Action in the case of the function, but that's overkill in the more
922 # normal case of expansion to other strings.
923 #
924 # So we do this with a subclass that's both a generator *and*
925 # a command action.  The overridden methods all do a quick check
926 # of the construction variable, and if it's a string we just call
927 # the corresponding CommandAction method to do the heavy lifting.
928 # If not, then we call the same-named CommandGeneratorAction method.
929 # The CommandGeneratorAction methods work by using the overridden
930 # _generate() method, that is, our own way of handling "generation" of
931 # an action based on what's in the construction variable.
932
933 class LazyAction(CommandGeneratorAction, CommandAction):
934
935     def __init__(self, var, kw):
936         if __debug__: logInstanceCreation(self, 'Action.LazyAction')
937         #FUTURE CommandAction.__init__(self, '${'+var+'}', **kw)
938         CommandAction.__init__(self, '${'+var+'}', **kw)
939         self.var = SCons.Util.to_String(var)
940         self.gen_kw = kw
941
942     def get_parent_class(self, env):
943         c = env.get(self.var)
944         if is_String(c) and not '\n' in c:
945             return CommandAction
946         return CommandGeneratorAction
947
948     def _generate_cache(self, env):
949         if env:
950             c = env.get(self.var, '')
951         else:
952             c = ''
953         #TODO(1.5) gen_cmd = Action(c, **self.gen_kw)
954         gen_cmd = Action(c, **self.gen_kw)
955         if not gen_cmd:
956             raise SCons.Errors.UserError("$%s value %s cannot be used to create an Action." % (self.var, repr(c)))
957         return gen_cmd
958
959     def _generate(self, target, source, env, for_signature, executor=None):
960         return self._generate_cache(env)
961
962     def __call__(self, target, source, env, *args, **kw):
963         c = self.get_parent_class(env)
964         return c.__call__(self, target, source, env, *args, **kw)
965
966     def get_presig(self, target, source, env):
967         c = self.get_parent_class(env)
968         return c.get_presig(self, target, source, env)
969
970     def get_varlist(self, target, source, env, executor=None):
971         c = self.get_parent_class(env)
972         return c.get_varlist(self, target, source, env, executor)
973
974
975 class FunctionAction(_ActionAction):
976     """Class for Python function actions."""
977
978     def __init__(self, execfunction, kw):
979         if __debug__: logInstanceCreation(self, 'Action.FunctionAction')
980
981         self.execfunction = execfunction
982         try:
983             self.funccontents = _callable_contents(execfunction)
984         except AttributeError:
985             try:
986                 # See if execfunction will do the heavy lifting for us.
987                 self.gc = execfunction.get_contents
988             except AttributeError:
989                 # This is weird, just do the best we can.
990                 self.funccontents = _object_contents(execfunction)
991
992         #TODO(1.5) _ActionAction.__init__(self, **kw)
993         _ActionAction.__init__(self, **kw)
994
995     def function_name(self):
996         try:
997             return self.execfunction.__name__
998         except AttributeError:
999             try:
1000                 return self.execfunction.__class__.__name__
1001             except AttributeError:
1002                 return "unknown_python_function"
1003
1004     def strfunction(self, target, source, env, executor=None):
1005         if self.cmdstr is None:
1006             return None
1007         if self.cmdstr is not _null:
1008             from SCons.Subst import SUBST_RAW
1009             if executor:
1010                 c = env.subst(self.cmdstr, SUBST_RAW, executor=executor)
1011             else:
1012                 c = env.subst(self.cmdstr, SUBST_RAW, target, source)
1013             if c:
1014                 return c
1015         def array(a):
1016             def quote(s):
1017                 try:
1018                     str_for_display = s.str_for_display
1019                 except AttributeError:
1020                     s = repr(s)
1021                 else:
1022                     s = str_for_display()
1023                 return s
1024             return '[' + ", ".join(map(quote, a)) + ']'
1025         try:
1026             strfunc = self.execfunction.strfunction
1027         except AttributeError:
1028             pass
1029         else:
1030             if strfunc is None:
1031                 return None
1032             if callable(strfunc):
1033                 return strfunc(target, source, env)
1034         name = self.function_name()
1035         tstr = array(target)
1036         sstr = array(source)
1037         return "%s(%s, %s)" % (name, tstr, sstr)
1038
1039     def __str__(self):
1040         name = self.function_name()
1041         if name == 'ActionCaller':
1042             return str(self.execfunction)
1043         return "%s(target, source, env)" % name
1044
1045     def execute(self, target, source, env, executor=None):
1046         exc_info = (None,None,None)
1047         try:
1048             if executor:
1049                 target = executor.get_all_targets()
1050                 source = executor.get_all_sources()
1051             rsources = list(map(rfile, source))
1052             try:
1053                 result = self.execfunction(target=target, source=rsources, env=env)
1054             except KeyboardInterrupt, e:
1055                 raise
1056             except SystemExit, e:
1057                 raise
1058             except Exception, e:
1059                 result = e
1060                 exc_info = sys.exc_info()
1061
1062             if result:
1063                 result = SCons.Errors.convert_to_BuildError(result, exc_info)
1064                 result.node=target
1065                 result.action=self
1066                 try:
1067                     result.command=self.strfunction(target, source, env, executor)
1068                 except TypeError:
1069                     result.command=self.strfunction(target, source, env)
1070
1071                 # FIXME: This maintains backward compatibility with respect to
1072                 # which type of exceptions were returned by raising an
1073                 # exception and which ones were returned by value. It would
1074                 # probably be best to always return them by value here, but
1075                 # some codes do not check the return value of Actions and I do
1076                 # not have the time to modify them at this point.
1077                 if (exc_info[1] and
1078                     not isinstance(exc_info[1],EnvironmentError)):
1079                     raise result
1080
1081             return result
1082         finally:
1083             # Break the cycle between the traceback object and this
1084             # function stack frame. See the sys.exc_info() doc info for
1085             # more information about this issue.
1086             del exc_info
1087
1088
1089     def get_presig(self, target, source, env):
1090         """Return the signature contents of this callable action."""
1091         try:
1092             return self.gc(target, source, env)
1093         except AttributeError:
1094             return self.funccontents
1095
1096     def get_implicit_deps(self, target, source, env):
1097         return []
1098
1099 class ListAction(ActionBase):
1100     """Class for lists of other actions."""
1101     def __init__(self, actionlist):
1102         if __debug__: logInstanceCreation(self, 'Action.ListAction')
1103         def list_of_actions(x):
1104             if isinstance(x, ActionBase):
1105                 return x
1106             return Action(x)
1107         self.list = list(map(list_of_actions, actionlist))
1108         # our children will have had any varlist
1109         # applied; we don't need to do it again
1110         self.varlist = ()
1111         self.targets = '$TARGETS'
1112
1113     def genstring(self, target, source, env):
1114         return '\n'.join([a.genstring(target, source, env) for a in self.list])
1115
1116     def __str__(self):
1117         return '\n'.join(map(str, self.list))
1118
1119     def presub_lines(self, env):
1120         return SCons.Util.flatten_sequence(
1121             [a.presub_lines(env) for a in self.list])
1122
1123     def get_presig(self, target, source, env):
1124         """Return the signature contents of this action list.
1125
1126         Simple concatenation of the signatures of the elements.
1127         """
1128         return "".join([x.get_contents(target, source, env) for x in self.list])
1129
1130     def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
1131                  show=_null, execute=_null, chdir=_null, executor=None):
1132         if executor:
1133             target = executor.get_all_targets()
1134             source = executor.get_all_sources()
1135         for act in self.list:
1136             stat = act(target, source, env, exitstatfunc, presub,
1137                        show, execute, chdir, executor)
1138             if stat:
1139                 return stat
1140         return 0
1141
1142     def get_implicit_deps(self, target, source, env):
1143         result = []
1144         for act in self.list:
1145             result.extend(act.get_implicit_deps(target, source, env))
1146         return result
1147
1148     def get_varlist(self, target, source, env, executor=None):
1149         result = SCons.Util.OrderedDict()
1150         for act in self.list:
1151             for var in act.get_varlist(target, source, env, executor):
1152                 result[var] = True
1153         return result.keys()
1154
1155 class ActionCaller:
1156     """A class for delaying calling an Action function with specific
1157     (positional and keyword) arguments until the Action is actually
1158     executed.
1159
1160     This class looks to the rest of the world like a normal Action object,
1161     but what it's really doing is hanging on to the arguments until we
1162     have a target, source and env to use for the expansion.
1163     """
1164     def __init__(self, parent, args, kw):
1165         self.parent = parent
1166         self.args = args
1167         self.kw = kw
1168
1169     def get_contents(self, target, source, env):
1170         actfunc = self.parent.actfunc
1171         try:
1172             # "self.actfunc" is a function.
1173             contents = str(actfunc.func_code.co_code)
1174         except AttributeError:
1175             # "self.actfunc" is a callable object.
1176             try:
1177                 contents = str(actfunc.__call__.im_func.func_code.co_code)
1178             except AttributeError:
1179                 # No __call__() method, so it might be a builtin
1180                 # or something like that.  Do the best we can.
1181                 contents = str(actfunc)
1182         contents = remove_set_lineno_codes(contents)
1183         return contents
1184
1185     def subst(self, s, target, source, env):
1186         # If s is a list, recursively apply subst()
1187         # to every element in the list
1188         if is_List(s):
1189             result = []
1190             for elem in s:
1191                 result.append(self.subst(elem, target, source, env))
1192             return self.parent.convert(result)
1193
1194         # Special-case hack:  Let a custom function wrapped in an
1195         # ActionCaller get at the environment through which the action
1196         # was called by using this hard-coded value as a special return.
1197         if s == '$__env__':
1198             return env
1199         elif is_String(s):
1200             return env.subst(s, 1, target, source)
1201         return self.parent.convert(s)
1202
1203     def subst_args(self, target, source, env):
1204         return [self.subst(x, target, source, env) for x in self.args]
1205
1206     def subst_kw(self, target, source, env):
1207         kw = {}
1208         for key in self.kw.keys():
1209             kw[key] = self.subst(self.kw[key], target, source, env)
1210         return kw
1211
1212     def __call__(self, target, source, env, executor=None):
1213         args = self.subst_args(target, source, env)
1214         kw = self.subst_kw(target, source, env)
1215         #TODO(1.5) return self.parent.actfunc(*args, **kw)
1216         return self.parent.actfunc(*args, **kw)
1217
1218     def strfunction(self, target, source, env):
1219         args = self.subst_args(target, source, env)
1220         kw = self.subst_kw(target, source, env)
1221         #TODO(1.5) return self.parent.strfunc(*args, **kw)
1222         return self.parent.strfunc(*args, **kw)
1223
1224     def __str__(self):
1225         #TODO(1.5) return self.parent.strfunc(*self.args, **self.kw)
1226         return self.parent.strfunc(*self.args, **self.kw)
1227
1228 class ActionFactory:
1229     """A factory class that will wrap up an arbitrary function
1230     as an SCons-executable Action object.
1231
1232     The real heavy lifting here is done by the ActionCaller class.
1233     We just collect the (positional and keyword) arguments that we're
1234     called with and give them to the ActionCaller object we create,
1235     so it can hang onto them until it needs them.
1236     """
1237     def __init__(self, actfunc, strfunc, convert=lambda x: x):
1238         self.actfunc = actfunc
1239         self.strfunc = strfunc
1240         self.convert = convert
1241
1242     def __call__(self, *args, **kw):
1243         ac = ActionCaller(self, args, kw)
1244         action = Action(ac, strfunction=ac.strfunction)
1245         return action
1246
1247 # Local Variables:
1248 # tab-width:4
1249 # indent-tabs-mode:nil
1250 # End:
1251 # vim: set expandtab tabstop=4 shiftwidth=4: