1"""SCons.Action
2
3This encapsulates information about executing any sort of action that
4can build one or more target Nodes (typically files) from one or more
5source Nodes (also typically files) given a specific Environment.
6
7The base class here is ActionBase.  The base class supplies just a few
8OO utility methods and some generic methods for displaying information
9about an Action in response to the various commands that control printing.
10
11A second-level base class is _ActionAction.  This extends ActionBase
12by providing the methods that can be used to show and perform an
13action.  True Action objects will subclass _ActionAction; Action
14factory class objects will subclass ActionBase.
15
16The heavy lifting is handled by subclasses for the different types of
17actions we might execute:
18
19    CommandAction
20    CommandGeneratorAction
21    FunctionAction
22    ListAction
23
24The subclasses supply the following public interface methods used by
25other 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
46Subclasses also supply the following methods for internal use within
47this 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
69There is a related independent ActionCaller class that looks like a
70regular Action, and which serves as a wrapper for arbitrary functions
71that we want to let the user specify the arguments to now, but actually
72execute later (when an out-of-date check determines that it's needed to
73be executed, for example).  Objects of this class are returned by an
74ActionFactory class that provides a __call__() method as a convenient
75way for wrapping up the functions.
76
77"""
78
79# Copyright (c) 2001 - 2014 The SCons Foundation
80#
81# Permission is hereby granted, free of charge, to any person obtaining
82# a copy of this software and associated documentation files (the
83# "Software"), to deal in the Software without restriction, including
84# without limitation the rights to use, copy, modify, merge, publish,
85# distribute, sublicense, and/or sell copies of the Software, and to
86# permit persons to whom the Software is furnished to do so, subject to
87# the following conditions:
88#
89# The above copyright notice and this permission notice shall be included
90# in all copies or substantial portions of the Software.
91#
92# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
93# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
94# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
95# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
96# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
97# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
98# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
99
100__revision__ = "src/engine/SCons/Action.py  2014/07/05 09:42:21 garyo"
101
102import SCons.compat
103
104import dis
105import os
106# compat layer imports "cPickle" for us if it's available.
107import pickle
108import re
109import sys
110import subprocess
111
112import SCons.Debug
113from SCons.Debug import logInstanceCreation
114import SCons.Errors
115import SCons.Executor
116import SCons.Util
117import SCons.Subst
118
119# we use these a lot, so try to optimize them
120is_String = SCons.Util.is_String
121is_List = SCons.Util.is_List
122
123class _null(object):
124    pass
125
126print_actions = 1
127execute_actions = 1
128print_actions_presub = 0
129
130def rfile(n):
131    try:
132        return n.rfile()
133    except AttributeError:
134        return n
135
136def default_exitstatfunc(s):
137    return s
138
139try:
140    SET_LINENO = dis.SET_LINENO
141    HAVE_ARGUMENT = dis.HAVE_ARGUMENT
142except AttributeError:
143    remove_set_lineno_codes = lambda x: x
144else:
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
161strip_quotes = re.compile('^[\'"](.*)[\'"]$')
162
163
164def _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
186def _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
224def _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
270def _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
298def _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:
305        return a2
306    if a2 is None:
307        return a1
308    if isinstance(a1, ListAction):
309        if isinstance(a2, ListAction):
310            return ListAction(a1.list + a2.list)
311        else:
312            return ListAction(a1.list + [ a2 ])
313    else:
314        if isinstance(a2, ListAction):
315            return ListAction([ a1 ] + a2.list)
316        else:
317            return ListAction([ a1, a2 ])
318
319def _do_create_keywords(args, kw):
320    """This converts any arguments after the action argument into
321    their equivalent keywords and adds them to the kw argument.
322    """
323    v = kw.get('varlist', ())
324    # prevent varlist="FOO" from being interpreted as ['F', 'O', 'O']
325    if is_String(v): v = (v,)
326    kw['varlist'] = tuple(v)
327    if args:
328        # turn positional args into equivalent keywords
329        cmdstrfunc = args[0]
330        if cmdstrfunc is None or is_String(cmdstrfunc):
331            kw['cmdstr'] = cmdstrfunc
332        elif callable(cmdstrfunc):
333            kw['strfunction'] = cmdstrfunc
334        else:
335            raise SCons.Errors.UserError(
336                'Invalid command display variable type. '
337                'You must either pass a string or a callback which '
338                'accepts (target, source, env) as parameters.')
339        if len(args) > 1:
340            kw['varlist'] = tuple(SCons.Util.flatten(args[1:])) + kw['varlist']
341    if kw.get('strfunction', _null) is not _null \
342                      and kw.get('cmdstr', _null) is not _null:
343        raise SCons.Errors.UserError(
344            'Cannot have both strfunction and cmdstr args to Action()')
345
346def _do_create_action(act, kw):
347    """This is the actual "implementation" for the
348    Action factory method, below.  This handles the
349    fact that passing lists to Action() itself has
350    different semantics than passing lists as elements
351    of lists.
352
353    The former will create a ListAction, the latter
354    will create a CommandAction by converting the inner
355    list elements to strings."""
356
357    if isinstance(act, ActionBase):
358        return act
359
360    if is_List(act):
361        return CommandAction(act, **kw)
362
363    if callable(act):
364        try:
365            gen = kw['generator']
366            del kw['generator']
367        except KeyError:
368            gen = 0
369        if gen:
370            action_type = CommandGeneratorAction
371        else:
372            action_type = FunctionAction
373        return action_type(act, kw)
374
375    if is_String(act):
376        var=SCons.Util.get_environment_var(act)
377        if var:
378            # This looks like a string that is purely an Environment
379            # variable reference, like "$FOO" or "${FOO}".  We do
380            # something special here...we lazily evaluate the contents
381            # of that Environment variable, so a user could put something
382            # like a function or a CommandGenerator in that variable
383            # instead of a string.
384            return LazyAction(var, kw)
385        commands = str(act).split('\n')
386        if len(commands) == 1:
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    # Catch a common error case with a nice message:
392    if isinstance(act, int) or isinstance(act, float):
393        raise TypeError("Don't know how to create an Action from a number (%s)"%act)
394    # Else fail silently (???)
395    return None
396
397def _do_create_list_action(act, kw):
398    """A factory for list actions.  Convert the input list into Actions
399    and then wrap them in a ListAction."""
400    acts = []
401    for a in act:
402        aa = _do_create_action(a, kw)
403        if aa is not None: acts.append(aa)
404    if not acts:
405        return ListAction([])
406    elif len(acts) == 1:
407        return acts[0]
408    else:
409        return ListAction(acts)
410
411def Action(act, *args, **kw):
412    """A factory for action objects."""
413    # Really simple: the _do_create_* routines do the heavy lifting.
414    _do_create_keywords(args, kw)
415    if is_List(act):
416        return _do_create_list_action(act, kw)
417    return _do_create_action(act, kw)
418
419class ActionBase(object):
420    """Base class for all types of action objects that can be held by
421    other objects (Builders, Executors, etc.)  This provides the
422    common methods for manipulating and combining those actions."""
423
424    def __cmp__(self, other):
425        return cmp(self.__dict__, other)
426
427    def no_batch_key(self, env, target, source):
428        return None
429
430    batch_key = no_batch_key
431
432    def genstring(self, target, source, env):
433        return str(self)
434
435    def get_contents(self, target, source, env):
436        result = [ self.get_presig(target, source, env) ]
437        # This should never happen, as the Action() factory should wrap
438        # the varlist, but just in case an action is created directly,
439        # we duplicate this check here.
440        vl = self.get_varlist(target, source, env)
441        if is_String(vl): vl = (vl,)
442        for v in vl:
443            # do the subst this way to ignore $(...$) parts:
444            result.append(env.subst_target_source('${'+v+'}', SCons.Subst.SUBST_SIG, target, source))
445        return ''.join(result)
446
447    def __add__(self, other):
448        return _actionAppend(self, other)
449
450    def __radd__(self, other):
451        return _actionAppend(other, self)
452
453    def presub_lines(self, env):
454        # CommandGeneratorAction needs a real environment
455        # in order to return the proper string here, since
456        # it may call LazyAction, which looks up a key
457        # in that env.  So we temporarily remember the env here,
458        # and CommandGeneratorAction will use this env
459        # when it calls its _generate method.
460        self.presub_env = env
461        lines = str(self).split('\n')
462        self.presub_env = None      # don't need this any more
463        return lines
464
465    def get_varlist(self, target, source, env, executor=None):
466        return self.varlist
467
468    def get_targets(self, env, executor):
469        """
470        Returns the type of targets ($TARGETS, $CHANGED_TARGETS) used
471        by this action.
472        """
473        return self.targets
474
475class _ActionAction(ActionBase):
476    """Base class for actions that create output objects."""
477    def __init__(self, cmdstr=_null, strfunction=_null, varlist=(),
478                       presub=_null, chdir=None, exitstatfunc=None,
479                       batch_key=None, targets='$TARGETS',
480                 **kw):
481        self.cmdstr = cmdstr
482        if strfunction is not _null:
483            if strfunction is None:
484                self.cmdstr = None
485            else:
486                self.strfunction = strfunction
487        self.varlist = varlist
488        self.presub = presub
489        self.chdir = chdir
490        if not exitstatfunc:
491            exitstatfunc = default_exitstatfunc
492        self.exitstatfunc = exitstatfunc
493
494        self.targets = targets
495
496        if batch_key:
497            if not callable(batch_key):
498                # They have set batch_key, but not to their own
499                # callable.  The default behavior here will batch
500                # *all* targets+sources using this action, separated
501                # for each construction environment.
502                def default_batch_key(self, env, target, source):
503                    return (id(self), id(env))
504                batch_key = default_batch_key
505            SCons.Util.AddMethod(self, batch_key, 'batch_key')
506
507    def print_cmd_line(self, s, target, source, env):
508        # In python 3, and in some of our tests, sys.stdout is
509        # a String io object, and it takes unicode strings only
510        # In other cases it's a regular Python 2.x file object
511        # which takes strings (bytes), and if you pass those a
512        # unicode object they try to decode with 'ascii' codec
513        # which fails if the cmd line has any hi-bit-set chars.
514        # This code assumes s is a regular string, but should
515        # work if it's unicode too.
516        try:
517            sys.stdout.write(unicode(s + "\n"))
518        except UnicodeDecodeError:
519            sys.stdout.write(s + "\n")
520
521    def __call__(self, target, source, env,
522                               exitstatfunc=_null,
523                               presub=_null,
524                               show=_null,
525                               execute=_null,
526                               chdir=_null,
527                               executor=None):
528        if not is_List(target):
529            target = [target]
530        if not is_List(source):
531            source = [source]
532
533        if presub is _null:
534            presub = self.presub
535            if presub is _null:
536                presub = print_actions_presub
537        if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
538        if show is _null:  show = print_actions
539        if execute is _null:  execute = execute_actions
540        if chdir is _null: chdir = self.chdir
541        save_cwd = None
542        if chdir:
543            save_cwd = os.getcwd()
544            try:
545                chdir = str(chdir.abspath)
546            except AttributeError:
547                if not is_String(chdir):
548                    if executor:
549                        chdir = str(executor.batches[0].targets[0].dir)
550                    else:
551                        chdir = str(target[0].dir)
552        if presub:
553            if executor:
554                target = executor.get_all_targets()
555                source = executor.get_all_sources()
556            t = ' and '.join(map(str, target))
557            l = '\n  '.join(self.presub_lines(env))
558            out = u"Building %s with action:\n  %s\n" % (t, l)
559            sys.stdout.write(out)
560        cmd = None
561        if show and self.strfunction:
562            if executor:
563                target = executor.get_all_targets()
564                source = executor.get_all_sources()
565            try:
566                cmd = self.strfunction(target, source, env, executor)
567            except TypeError:
568                cmd = self.strfunction(target, source, env)
569            if cmd:
570                if chdir:
571                    cmd = ('os.chdir(%s)\n' % repr(chdir)) + cmd
572                try:
573                    get = env.get
574                except AttributeError:
575                    print_func = self.print_cmd_line
576                else:
577                    print_func = get('PRINT_CMD_LINE_FUNC')
578                    if not print_func:
579                        print_func = self.print_cmd_line
580                print_func(cmd, target, source, env)
581        stat = 0
582        if execute:
583            if chdir:
584                os.chdir(chdir)
585            try:
586                stat = self.execute(target, source, env, executor=executor)
587                if isinstance(stat, SCons.Errors.BuildError):
588                    s = exitstatfunc(stat.status)
589                    if s:
590                        stat.status = s
591                    else:
592                        stat = s
593                else:
594                    stat = exitstatfunc(stat)
595            finally:
596                if save_cwd:
597                    os.chdir(save_cwd)
598        if cmd and save_cwd:
599            print_func('os.chdir(%s)' % repr(save_cwd), target, source, env)
600
601        return stat
602
603
604def _string_from_cmd_list(cmd_list):
605    """Takes a list of command line arguments and returns a pretty
606    representation for printing."""
607    cl = []
608    for arg in map(str, cmd_list):
609        if ' ' in arg or '\t' in arg:
610            arg = '"' + arg + '"'
611        cl.append(arg)
612    return ' '.join(cl)
613
614# A fiddlin' little function that has an 'import SCons.Environment' which
615# can't be moved to the top level without creating an import loop.  Since
616# this import creates a local variable named 'SCons', it blocks access to
617# the global variable, so we move it here to prevent complaints about local
618# variables being used uninitialized.
619default_ENV = None
620def get_default_ENV(env):
621    global default_ENV
622    try:
623        return env['ENV']
624    except KeyError:
625        if not default_ENV:
626            import SCons.Environment
627            # This is a hideously expensive way to get a default shell
628            # environment.  What it really should do is run the platform
629            # setup to get the default ENV.  Fortunately, it's incredibly
630            # rare for an Environment not to have a shell environment, so
631            # we're not going to worry about it overmuch.
632            default_ENV = SCons.Environment.Environment()['ENV']
633        return default_ENV
634
635# This function is still in draft mode.  We're going to need something like
636# it in the long run as more and more places use subprocess, but I'm sure
637# it'll have to be tweaked to get the full desired functionality.
638# one special arg (so far?), 'error', to tell what to do with exceptions.
639def _subproc(scons_env, cmd, error = 'ignore', **kw):
640    """Do common setup for a subprocess.Popen() call"""
641    # allow std{in,out,err} to be "'devnull'"
642    io = kw.get('stdin')
643    if is_String(io) and io == 'devnull':
644        kw['stdin'] = open(os.devnull)
645    io = kw.get('stdout')
646    if is_String(io) and io == 'devnull':
647        kw['stdout'] = open(os.devnull, 'w')
648    io = kw.get('stderr')
649    if is_String(io) and io == 'devnull':
650        kw['stderr'] = open(os.devnull, 'w')
651
652    # Figure out what shell environment to use
653    ENV = kw.get('env', None)
654    if ENV is None: ENV = get_default_ENV(scons_env)
655
656    # Ensure that the ENV values are all strings:
657    new_env = {}
658    for key, value in ENV.items():
659        if is_List(value):
660            # If the value is a list, then we assume it is a path list,
661            # because that's a pretty common list-like value to stick
662            # in an environment variable:
663            value = SCons.Util.flatten_sequence(value)
664            new_env[key] = os.pathsep.join(map(str, value))
665        else:
666            # It's either a string or something else.  If it's a string,
667            # we still want to call str() because it might be a *Unicode*
668            # string, which makes subprocess.Popen() gag.  If it isn't a
669            # string or a list, then we just coerce it to a string, which
670            # is the proper way to handle Dir and File instances and will
671            # produce something reasonable for just about everything else:
672            new_env[key] = str(value)
673    kw['env'] = new_env
674
675    try:
676        return subprocess.Popen(cmd, **kw)
677    except EnvironmentError, e:
678        if error == 'raise': raise
679        # return a dummy Popen instance that only returns error
680        class dummyPopen(object):
681            def __init__(self, e): self.exception = e
682            def communicate(self,input=None): return ('','')
683            def wait(self): return -self.exception.errno
684            stdin = None
685            class f(object):
686                def read(self): return ''
687                def readline(self): return ''
688                def __iter__(self): return iter(())
689            stdout = stderr = f()
690        return dummyPopen(e)
691
692class CommandAction(_ActionAction):
693    """Class for command-execution actions."""
694    def __init__(self, cmd, **kw):
695        # Cmd can actually be a list or a single item; if it's a
696        # single item it should be the command string to execute; if a
697        # list then it should be the words of the command string to
698        # execute.  Only a single command should be executed by this
699        # object; lists of commands should be handled by embedding
700        # these objects in a ListAction object (which the Action()
701        # factory above does).  cmd will be passed to
702        # Environment.subst_list() for substituting environment
703        # variables.
704        if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.CommandAction')
705
706        _ActionAction.__init__(self, **kw)
707        if is_List(cmd):
708            if list(filter(is_List, cmd)):
709                raise TypeError("CommandAction should be given only " \
710                      "a single command")
711        self.cmd_list = cmd
712
713    def __str__(self):
714        if is_List(self.cmd_list):
715            return ' '.join(map(str, self.cmd_list))
716        return str(self.cmd_list)
717
718    def process(self, target, source, env, executor=None):
719        if executor:
720            result = env.subst_list(self.cmd_list, 0, executor=executor)
721        else:
722            result = env.subst_list(self.cmd_list, 0, target, source)
723        silent = None
724        ignore = None
725        while True:
726            try: c = result[0][0][0]
727            except IndexError: c = None
728            if c == '@': silent = 1
729            elif c == '-': ignore = 1
730            else: break
731            result[0][0] = result[0][0][1:]
732        try:
733            if not result[0][0]:
734                result[0] = result[0][1:]
735        except IndexError:
736            pass
737        return result, ignore, silent
738
739    def strfunction(self, target, source, env, executor=None):
740        if self.cmdstr is None:
741            return None
742        if self.cmdstr is not _null:
743            from SCons.Subst import SUBST_RAW
744            if executor:
745                c = env.subst(self.cmdstr, SUBST_RAW, executor=executor)
746            else:
747                c = env.subst(self.cmdstr, SUBST_RAW, target, source)
748            if c:
749                return c
750        cmd_list, ignore, silent = self.process(target, source, env, executor)
751        if silent:
752            return ''
753        return _string_from_cmd_list(cmd_list[0])
754
755    def execute(self, target, source, env, executor=None):
756        """Execute a command action.
757
758        This will handle lists of commands as well as individual commands,
759        because construction variable substitution may turn a single
760        "command" into a list.  This means that this class can actually
761        handle lists of commands, even though that's not how we use it
762        externally.
763        """
764        escape_list = SCons.Subst.escape_list
765        flatten_sequence = SCons.Util.flatten_sequence
766
767        try:
768            shell = env['SHELL']
769        except KeyError:
770            raise SCons.Errors.UserError('Missing SHELL construction variable.')
771
772        try:
773            spawn = env['SPAWN']
774        except KeyError:
775            raise SCons.Errors.UserError('Missing SPAWN construction variable.')
776        else:
777            if is_String(spawn):
778                spawn = env.subst(spawn, raw=1, conv=lambda x: x)
779
780        escape = env.get('ESCAPE', lambda x: x)
781
782        ENV = get_default_ENV(env)
783
784        # Ensure that the ENV values are all strings:
785        for key, value in ENV.items():
786            if not is_String(value):
787                if is_List(value):
788                    # If the value is a list, then we assume it is a
789                    # path list, because that's a pretty common list-like
790                    # value to stick in an environment variable:
791                    value = flatten_sequence(value)
792                    ENV[key] = os.pathsep.join(map(str, value))
793                else:
794                    # If it isn't a string or a list, then we just coerce
795                    # it to a string, which is the proper way to handle
796                    # Dir and File instances and will produce something
797                    # reasonable for just about everything else:
798                    ENV[key] = str(value)
799
800        if executor:
801            target = executor.get_all_targets()
802            source = executor.get_all_sources()
803        cmd_list, ignore, silent = self.process(target, list(map(rfile, source)), env, executor)
804
805        # Use len() to filter out any "command" that's zero-length.
806        for cmd_line in filter(len, cmd_list):
807            # Escape the command line for the interpreter we are using.
808            cmd_line = escape_list(cmd_line, escape)
809            result = spawn(shell, escape, cmd_line[0], cmd_line, ENV)
810            if not ignore and result:
811                msg = "Error %s" % result
812                return SCons.Errors.BuildError(errstr=msg,
813                                               status=result,
814                                               action=self,
815                                               command=cmd_line)
816        return 0
817
818    def get_presig(self, target, source, env, executor=None):
819        """Return the signature contents of this action's command line.
820
821        This strips $(-$) and everything in between the string,
822        since those parts don't affect signatures.
823        """
824        from SCons.Subst import SUBST_SIG
825        cmd = self.cmd_list
826        if is_List(cmd):
827            cmd = ' '.join(map(str, cmd))
828        else:
829            cmd = str(cmd)
830        if executor:
831            return env.subst_target_source(cmd, SUBST_SIG, executor=executor)
832        else:
833            return env.subst_target_source(cmd, SUBST_SIG, target, source)
834
835    def get_implicit_deps(self, target, source, env, executor=None):
836        icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True)
837        if is_String(icd) and icd[:1] == '$':
838            icd = env.subst(icd)
839        if not icd or icd in ('0', 'None'):
840            return []
841        from SCons.Subst import SUBST_SIG
842        if executor:
843            cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, executor=executor)
844        else:
845            cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source)
846        res = []
847        for cmd_line in cmd_list:
848            if cmd_line:
849                d = str(cmd_line[0])
850                m = strip_quotes.match(d)
851                if m:
852                    d = m.group(1)
853                d = env.WhereIs(d)
854                if d:
855                    res.append(env.fs.File(d))
856        return res
857
858class CommandGeneratorAction(ActionBase):
859    """Class for command-generator actions."""
860    def __init__(self, generator, kw):
861        if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.CommandGeneratorAction')
862        self.generator = generator
863        self.gen_kw = kw
864        self.varlist = kw.get('varlist', ())
865        self.targets = kw.get('targets', '$TARGETS')
866
867    def _generate(self, target, source, env, for_signature, executor=None):
868        # ensure that target is a list, to make it easier to write
869        # generator functions:
870        if not is_List(target):
871            target = [target]
872
873        if executor:
874            target = executor.get_all_targets()
875            source = executor.get_all_sources()
876        ret = self.generator(target=target,
877                             source=source,
878                             env=env,
879                             for_signature=for_signature)
880        gen_cmd = Action(ret, **self.gen_kw)
881        if not gen_cmd:
882            raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret))
883        return gen_cmd
884
885    def __str__(self):
886        try:
887            env = self.presub_env
888        except AttributeError:
889            env = None
890        if env is None:
891            env = SCons.Defaults.DefaultEnvironment()
892        act = self._generate([], [], env, 1)
893        return str(act)
894
895    def batch_key(self, env, target, source):
896        return self._generate(target, source, env, 1).batch_key(env, target, source)
897
898    def genstring(self, target, source, env, executor=None):
899        return self._generate(target, source, env, 1, executor).genstring(target, source, env)
900
901    def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
902                 show=_null, execute=_null, chdir=_null, executor=None):
903        act = self._generate(target, source, env, 0, executor)
904        if act is None:
905            raise SCons.Errors.UserError("While building `%s': "
906                            "Cannot deduce file extension from source files: %s"
907                % (repr(list(map(str, target))), repr(list(map(str, source)))))
908        return act(target, source, env, exitstatfunc, presub,
909                   show, execute, chdir, executor)
910
911    def get_presig(self, target, source, env, executor=None):
912        """Return the signature contents of this action's command line.
913
914        This strips $(-$) and everything in between the string,
915        since those parts don't affect signatures.
916        """
917        return self._generate(target, source, env, 1, executor).get_presig(target, source, env)
918
919    def get_implicit_deps(self, target, source, env, executor=None):
920        return self._generate(target, source, env, 1, executor).get_implicit_deps(target, source, env)
921
922    def get_varlist(self, target, source, env, executor=None):
923        return self._generate(target, source, env, 1, executor).get_varlist(target, source, env, executor)
924
925    def get_targets(self, env, executor):
926        return self._generate(None, None, env, 1, executor).get_targets(env, executor)
927
928
929
930# A LazyAction is a kind of hybrid generator and command action for
931# strings of the form "$VAR".  These strings normally expand to other
932# strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also
933# want to be able to replace them with functions in the construction
934# environment.  Consequently, we want lazy evaluation and creation of
935# an Action in the case of the function, but that's overkill in the more
936# normal case of expansion to other strings.
937#
938# So we do this with a subclass that's both a generator *and*
939# a command action.  The overridden methods all do a quick check
940# of the construction variable, and if it's a string we just call
941# the corresponding CommandAction method to do the heavy lifting.
942# If not, then we call the same-named CommandGeneratorAction method.
943# The CommandGeneratorAction methods work by using the overridden
944# _generate() method, that is, our own way of handling "generation" of
945# an action based on what's in the construction variable.
946
947class LazyAction(CommandGeneratorAction, CommandAction):
948
949    def __init__(self, var, kw):
950        if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.LazyAction')
951        #FUTURE CommandAction.__init__(self, '${'+var+'}', **kw)
952        CommandAction.__init__(self, '${'+var+'}', **kw)
953        self.var = SCons.Util.to_String(var)
954        self.gen_kw = kw
955
956    def get_parent_class(self, env):
957        c = env.get(self.var)
958        if is_String(c) and not '\n' in c:
959            return CommandAction
960        return CommandGeneratorAction
961
962    def _generate_cache(self, env):
963        if env:
964            c = env.get(self.var, '')
965        else:
966            c = ''
967        gen_cmd = Action(c, **self.gen_kw)
968        if not gen_cmd:
969            raise SCons.Errors.UserError("$%s value %s cannot be used to create an Action." % (self.var, repr(c)))
970        return gen_cmd
971
972    def _generate(self, target, source, env, for_signature, executor=None):
973        return self._generate_cache(env)
974
975    def __call__(self, target, source, env, *args, **kw):
976        c = self.get_parent_class(env)
977        return c.__call__(self, target, source, env, *args, **kw)
978
979    def get_presig(self, target, source, env):
980        c = self.get_parent_class(env)
981        return c.get_presig(self, target, source, env)
982
983    def get_varlist(self, target, source, env, executor=None):
984        c = self.get_parent_class(env)
985        return c.get_varlist(self, target, source, env, executor)
986
987
988class FunctionAction(_ActionAction):
989    """Class for Python function actions."""
990
991    def __init__(self, execfunction, kw):
992        if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.FunctionAction')
993
994        self.execfunction = execfunction
995        try:
996            self.funccontents = _callable_contents(execfunction)
997        except AttributeError:
998            try:
999                # See if execfunction will do the heavy lifting for us.
1000                self.gc = execfunction.get_contents
1001            except AttributeError:
1002                # This is weird, just do the best we can.
1003                self.funccontents = _object_contents(execfunction)
1004
1005        _ActionAction.__init__(self, **kw)
1006
1007    def function_name(self):
1008        try:
1009            return self.execfunction.__name__
1010        except AttributeError:
1011            try:
1012                return self.execfunction.__class__.__name__
1013            except AttributeError:
1014                return "unknown_python_function"
1015
1016    def strfunction(self, target, source, env, executor=None):
1017        if self.cmdstr is None:
1018            return None
1019        if self.cmdstr is not _null:
1020            from SCons.Subst import SUBST_RAW
1021            if executor:
1022                c = env.subst(self.cmdstr, SUBST_RAW, executor=executor)
1023            else:
1024                c = env.subst(self.cmdstr, SUBST_RAW, target, source)
1025            if c:
1026                return c
1027        def array(a):
1028            def quote(s):
1029                try:
1030                    str_for_display = s.str_for_display
1031                except AttributeError:
1032                    s = repr(s)
1033                else:
1034                    s = str_for_display()
1035                return s
1036            return '[' + ", ".join(map(quote, a)) + ']'
1037        try:
1038            strfunc = self.execfunction.strfunction
1039        except AttributeError:
1040            pass
1041        else:
1042            if strfunc is None:
1043                return None
1044            if callable(strfunc):
1045                return strfunc(target, source, env)
1046        name = self.function_name()
1047        tstr = array(target)
1048        sstr = array(source)
1049        return "%s(%s, %s)" % (name, tstr, sstr)
1050
1051    def __str__(self):
1052        name = self.function_name()
1053        if name == 'ActionCaller':
1054            return str(self.execfunction)
1055        return "%s(target, source, env)" % name
1056
1057    def execute(self, target, source, env, executor=None):
1058        exc_info = (None,None,None)
1059        try:
1060            if executor:
1061                target = executor.get_all_targets()
1062                source = executor.get_all_sources()
1063            rsources = list(map(rfile, source))
1064            try:
1065                result = self.execfunction(target=target, source=rsources, env=env)
1066            except KeyboardInterrupt, e:
1067                raise
1068            except SystemExit, e:
1069                raise
1070            except Exception, e:
1071                result = e
1072                exc_info = sys.exc_info()
1073
1074            if result:
1075                result = SCons.Errors.convert_to_BuildError(result, exc_info)
1076                result.node=target
1077                result.action=self
1078                try:
1079                    result.command=self.strfunction(target, source, env, executor)
1080                except TypeError:
1081                    result.command=self.strfunction(target, source, env)
1082
1083                # FIXME: This maintains backward compatibility with respect to
1084                # which type of exceptions were returned by raising an
1085                # exception and which ones were returned by value. It would
1086                # probably be best to always return them by value here, but
1087                # some codes do not check the return value of Actions and I do
1088                # not have the time to modify them at this point.
1089                if (exc_info[1] and
1090                    not isinstance(exc_info[1],EnvironmentError)):
1091                    raise result
1092
1093            return result
1094        finally:
1095            # Break the cycle between the traceback object and this
1096            # function stack frame. See the sys.exc_info() doc info for
1097            # more information about this issue.
1098            del exc_info
1099
1100
1101    def get_presig(self, target, source, env):
1102        """Return the signature contents of this callable action."""
1103        try:
1104            return self.gc(target, source, env)
1105        except AttributeError:
1106            return self.funccontents
1107
1108    def get_implicit_deps(self, target, source, env):
1109        return []
1110
1111class ListAction(ActionBase):
1112    """Class for lists of other actions."""
1113    def __init__(self, actionlist):
1114        if SCons.Debug.track_instances: logInstanceCreation(self, 'Action.ListAction')
1115        def list_of_actions(x):
1116            if isinstance(x, ActionBase):
1117                return x
1118            return Action(x)
1119        self.list = list(map(list_of_actions, actionlist))
1120        # our children will have had any varlist
1121        # applied; we don't need to do it again
1122        self.varlist = ()
1123        self.targets = '$TARGETS'
1124
1125    def genstring(self, target, source, env):
1126        return '\n'.join([a.genstring(target, source, env) for a in self.list])
1127
1128    def __str__(self):
1129        return '\n'.join(map(str, self.list))
1130
1131    def presub_lines(self, env):
1132        return SCons.Util.flatten_sequence(
1133            [a.presub_lines(env) for a in self.list])
1134
1135    def get_presig(self, target, source, env):
1136        """Return the signature contents of this action list.
1137
1138        Simple concatenation of the signatures of the elements.
1139        """
1140        return "".join([x.get_contents(target, source, env) for x in self.list])
1141
1142    def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
1143                 show=_null, execute=_null, chdir=_null, executor=None):
1144        if executor:
1145            target = executor.get_all_targets()
1146            source = executor.get_all_sources()
1147        for act in self.list:
1148            stat = act(target, source, env, exitstatfunc, presub,
1149                       show, execute, chdir, executor)
1150            if stat:
1151                return stat
1152        return 0
1153
1154    def get_implicit_deps(self, target, source, env):
1155        result = []
1156        for act in self.list:
1157            result.extend(act.get_implicit_deps(target, source, env))
1158        return result
1159
1160    def get_varlist(self, target, source, env, executor=None):
1161        result = SCons.Util.OrderedDict()
1162        for act in self.list:
1163            for var in act.get_varlist(target, source, env, executor):
1164                result[var] = True
1165        return list(result.keys())
1166
1167class ActionCaller(object):
1168    """A class for delaying calling an Action function with specific
1169    (positional and keyword) arguments until the Action is actually
1170    executed.
1171
1172    This class looks to the rest of the world like a normal Action object,
1173    but what it's really doing is hanging on to the arguments until we
1174    have a target, source and env to use for the expansion.
1175    """
1176    def __init__(self, parent, args, kw):
1177        self.parent = parent
1178        self.args = args
1179        self.kw = kw
1180
1181    def get_contents(self, target, source, env):
1182        actfunc = self.parent.actfunc
1183        try:
1184            # "self.actfunc" is a function.
1185            contents = str(actfunc.func_code.co_code)
1186        except AttributeError:
1187            # "self.actfunc" is a callable object.
1188            try:
1189                contents = str(actfunc.__call__.im_func.func_code.co_code)
1190            except AttributeError:
1191                # No __call__() method, so it might be a builtin
1192                # or something like that.  Do the best we can.
1193                contents = str(actfunc)
1194        contents = remove_set_lineno_codes(contents)
1195        return contents
1196
1197    def subst(self, s, target, source, env):
1198        # If s is a list, recursively apply subst()
1199        # to every element in the list
1200        if is_List(s):
1201            result = []
1202            for elem in s:
1203                result.append(self.subst(elem, target, source, env))
1204            return self.parent.convert(result)
1205
1206        # Special-case hack:  Let a custom function wrapped in an
1207        # ActionCaller get at the environment through which the action
1208        # was called by using this hard-coded value as a special return.
1209        if s == '$__env__':
1210            return env
1211        elif is_String(s):
1212            return env.subst(s, 1, target, source)
1213        return self.parent.convert(s)
1214
1215    def subst_args(self, target, source, env):
1216        return [self.subst(x, target, source, env) for x in self.args]
1217
1218    def subst_kw(self, target, source, env):
1219        kw = {}
1220        for key in self.kw.keys():
1221            kw[key] = self.subst(self.kw[key], target, source, env)
1222        return kw
1223
1224    def __call__(self, target, source, env, executor=None):
1225        args = self.subst_args(target, source, env)
1226        kw = self.subst_kw(target, source, env)
1227        return self.parent.actfunc(*args, **kw)
1228
1229    def strfunction(self, target, source, env):
1230        args = self.subst_args(target, source, env)
1231        kw = self.subst_kw(target, source, env)
1232        return self.parent.strfunc(*args, **kw)
1233
1234    def __str__(self):
1235        return self.parent.strfunc(*self.args, **self.kw)
1236
1237class ActionFactory(object):
1238    """A factory class that will wrap up an arbitrary function
1239    as an SCons-executable Action object.
1240
1241    The real heavy lifting here is done by the ActionCaller class.
1242    We just collect the (positional and keyword) arguments that we're
1243    called with and give them to the ActionCaller object we create,
1244    so it can hang onto them until it needs them.
1245    """
1246    def __init__(self, actfunc, strfunc, convert=lambda x: x):
1247        self.actfunc = actfunc
1248        self.strfunc = strfunc
1249        self.convert = convert
1250
1251    def __call__(self, *args, **kw):
1252        ac = ActionCaller(self, args, kw)
1253        action = Action(ac, strfunction=ac.strfunction)
1254        return action
1255
1256# Local Variables:
1257# tab-width:4
1258# indent-tabs-mode:nil
1259# End:
1260# vim: set expandtab tabstop=4 shiftwidth=4:
1261