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