| Index: third_party/scons/scons-local/SCons/Action.py
|
| ===================================================================
|
| --- third_party/scons/scons-local/SCons/Action.py (revision 7505)
|
| +++ third_party/scons/scons-local/SCons/Action.py (working copy)
|
| @@ -30,9 +30,9 @@
|
| a pre-substitution command for debugging purposes.
|
|
|
| get_contents()
|
| - Fetches the "contents" of an Action for signature calculation.
|
| - This is what gets MD5 checksumm'ed to decide if a target needs
|
| - to be rebuilt because its action changed.
|
| + Fetches the "contents" of an Action for signature calculation
|
| + plus the varlist. This is what gets MD5 checksummed to decide
|
| + if a target needs to be rebuilt because its action changed.
|
|
|
| genstring()
|
| Returns a string representation of the Action *without*
|
| @@ -49,7 +49,7 @@
|
| __str__()
|
| Returns a string approximation of the Action; no variable
|
| substitution is performed.
|
| -
|
| +
|
| execute()
|
| The internal method that really, truly, actually handles the
|
| execution of a command or Python function. This is used so
|
| @@ -57,6 +57,10 @@
|
| pre-substitution representations, and *then* execute an action
|
| without worrying about the specific Actions involved.
|
|
|
| + get_presig()
|
| + Fetches the "contents" of a subclass for signature calculation.
|
| + The varlist is added to this to produce the Action's contents.
|
| +
|
| strfunction()
|
| Returns a substituted string representation of the Action.
|
| This is used by the _ActionAction.show() command to display the
|
| @@ -72,7 +76,6 @@
|
|
|
| """
|
|
|
| -#
|
| # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
|
| #
|
| # Permission is hereby granted, free of charge, to any person obtaining
|
| @@ -93,14 +96,12 @@
|
| # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
| # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
| # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
| -#
|
|
|
| -__revision__ = "src/engine/SCons/Action.py 3603 2008/10/10 05:46:45 scons"
|
| +__revision__ = "src/engine/SCons/Action.py 3842 2008/12/20 22:59:52 scons"
|
|
|
| import cPickle
|
| import dis
|
| import os
|
| -import os.path
|
| import string
|
| import sys
|
| import subprocess
|
| @@ -109,12 +110,15 @@
|
| import SCons.Errors
|
| import SCons.Executor
|
| import SCons.Util
|
| +import SCons.Subst
|
|
|
| -class _Null:
|
| +# we use these a lot, so try to optimize them
|
| +is_String = SCons.Util.is_String
|
| +is_List = SCons.Util.is_List
|
| +
|
| +class _null:
|
| pass
|
|
|
| -_null = _Null
|
| -
|
| print_actions = 1
|
| execute_actions = 1
|
| print_actions_presub = 0
|
| @@ -175,7 +179,7 @@
|
|
|
| def _object_contents(obj):
|
| """Return the signature contents of any Python object.
|
| -
|
| +
|
| We have to handle the case where object contains a code object
|
| since it can be pickled directly.
|
| """
|
| @@ -199,7 +203,7 @@
|
| return _function_contents(obj)
|
|
|
| except AttributeError:
|
| - # Should be a pickable Python object.
|
| + # Should be a pickable Python object.
|
| try:
|
| return cPickle.dumps(obj)
|
| except (cPickle.PicklingError, TypeError):
|
| @@ -216,7 +220,7 @@
|
|
|
| By providing direct access to the code object of the
|
| function, Python makes this extremely easy. Hooray!
|
| -
|
| +
|
| Unfortunately, older versions of Python include line
|
| number indications in the compiled byte code. Boo!
|
| So we remove the line number byte codes to prevent
|
| @@ -237,13 +241,13 @@
|
| # The code contents depends on any constants accessed by the
|
| # function. Note that we have to call _object_contents on each
|
| # constants because the code object of nested functions can
|
| - # show-up among the constants.
|
| - #
|
| + # show-up among the constants.
|
| + #
|
| # Note that we also always ignore the first entry of co_consts
|
| # which contains the function doc string. We assume that the
|
| # function does not access its doc string.
|
| contents.append(',(' + string.join(map(_object_contents,code.co_consts[1:]),',') + ')')
|
| -
|
| +
|
| # The code contents depends on the variable names used to
|
| # accessed global variable, as changing the variable name changes
|
| # the variable actually accessed and therefore changes the
|
| @@ -283,8 +287,8 @@
|
| contents.append(',(' + string.join(xxx, ',') + ')')
|
|
|
| return string.join(contents, '')
|
| -
|
|
|
| +
|
| def _actionAppend(act1, act2):
|
| # This function knows how to slap two actions together.
|
| # Mainly, it handles ListActions by concatenating into
|
| @@ -304,7 +308,34 @@
|
| else:
|
| return ListAction([ a1, a2 ])
|
|
|
| -def _do_create_action(act, *args, **kw):
|
| +def _do_create_keywords(args, kw):
|
| + """This converts any arguments after the action argument into
|
| + their equivalent keywords and adds them to the kw argument.
|
| + """
|
| + v = kw.get('varlist', ())
|
| + # prevent varlist="FOO" from being interpreted as ['F', 'O', 'O']
|
| + if is_String(v): v = (v,)
|
| + kw['varlist'] = tuple(v)
|
| + if args:
|
| + # turn positional args into equivalent keywords
|
| + cmdstrfunc = args[0]
|
| + if cmdstrfunc is None or is_String(cmdstrfunc):
|
| + kw['cmdstr'] = cmdstrfunc
|
| + elif callable(cmdstrfunc):
|
| + kw['strfunction'] = cmdstrfunc
|
| + else:
|
| + raise SCons.Errors.UserError(
|
| + 'Invalid command display variable type. '
|
| + 'You must either pass a string or a callback which '
|
| + 'accepts (target, source, env) as parameters.')
|
| + if len(args) > 1:
|
| + kw['varlist'] = args[1:] + kw['varlist']
|
| + if kw.get('strfunction', _null) is not _null \
|
| + and kw.get('cmdstr', _null) is not _null:
|
| + raise SCons.Errors.UserError(
|
| + 'Cannot have both strfunction and cmdstr args to Action()')
|
| +
|
| +def _do_create_action(act, kw):
|
| """This is the actual "implementation" for the
|
| Action factory method, below. This handles the
|
| fact that passing lists to Action() itself has
|
| @@ -317,8 +348,11 @@
|
|
|
| if isinstance(act, ActionBase):
|
| return act
|
| - if SCons.Util.is_List(act):
|
| - return apply(CommandAction, (act,)+args, kw)
|
| +
|
| + if is_List(act):
|
| + #TODO(1.5) return CommandAction(act, **kw)
|
| + return apply(CommandAction, (act,), kw)
|
| +
|
| if callable(act):
|
| try:
|
| gen = kw['generator']
|
| @@ -329,8 +363,9 @@
|
| action_type = CommandGeneratorAction
|
| else:
|
| action_type = FunctionAction
|
| - return apply(action_type, (act,)+args, kw)
|
| - if SCons.Util.is_String(act):
|
| + return action_type(act, kw)
|
| +
|
| + if is_String(act):
|
| var=SCons.Util.get_environment_var(act)
|
| if var:
|
| # This looks like a string that is purely an Environment
|
| @@ -339,30 +374,37 @@
|
| # of that Environment variable, so a user could put something
|
| # like a function or a CommandGenerator in that variable
|
| # instead of a string.
|
| - return apply(LazyAction, (var,)+args, kw)
|
| + return LazyAction(var, kw)
|
| commands = string.split(str(act), '\n')
|
| if len(commands) == 1:
|
| - return apply(CommandAction, (commands[0],)+args, kw)
|
| - else:
|
| - listCmdActions = map(lambda x, args=args, kw=kw:
|
| - apply(CommandAction, (x,)+args, kw),
|
| - commands)
|
| - return ListAction(listCmdActions)
|
| + #TODO(1.5) return CommandAction(commands[0], **kw)
|
| + return apply(CommandAction, (commands[0],), kw)
|
| + # The list of string commands may include a LazyAction, so we
|
| + # reprocess them via _do_create_list_action.
|
| + return _do_create_list_action(commands, kw)
|
| return None
|
|
|
| +def _do_create_list_action(act, kw):
|
| + """A factory for list actions. Convert the input list into Actions
|
| + and then wrap them in a ListAction."""
|
| + acts = []
|
| + for a in act:
|
| + aa = _do_create_action(a, kw)
|
| + if aa is not None: acts.append(aa)
|
| + if not acts:
|
| + return None
|
| + elif len(acts) == 1:
|
| + return acts[0]
|
| + else:
|
| + return ListAction(acts)
|
| +
|
| def Action(act, *args, **kw):
|
| """A factory for action objects."""
|
| - if SCons.Util.is_List(act):
|
| - acts = map(lambda a, args=args, kw=kw:
|
| - apply(_do_create_action, (a,)+args, kw),
|
| - act)
|
| - acts = filter(None, acts)
|
| - if len(acts) == 1:
|
| - return acts[0]
|
| - else:
|
| - return ListAction(acts)
|
| - else:
|
| - return apply(_do_create_action, (act,)+args, kw)
|
| + # Really simple: the _do_create_* routines do the heavy lifting.
|
| + _do_create_keywords(args, kw)
|
| + if is_List(act):
|
| + return _do_create_list_action(act, kw)
|
| + return _do_create_action(act, kw)
|
|
|
| class ActionBase:
|
| """Base class for all types of action objects that can be held by
|
| @@ -375,6 +417,17 @@
|
| def genstring(self, target, source, env):
|
| return str(self)
|
|
|
| + def get_contents(self, target, source, env):
|
| + result = [ self.get_presig(target, source, env) ]
|
| + # This should never happen, as the Action() factory should wrap
|
| + # the varlist, but just in case an action is created directly,
|
| + # we duplicate this check here.
|
| + vl = self.varlist
|
| + if is_String(vl): vl = (vl,)
|
| + for v in vl:
|
| + result.append(env.subst('${'+v+'}'))
|
| + return string.join(result, '')
|
| +
|
| def __add__(self, other):
|
| return _actionAppend(self, other)
|
|
|
| @@ -400,9 +453,16 @@
|
|
|
| class _ActionAction(ActionBase):
|
| """Base class for actions that create output objects."""
|
| - def __init__(self, strfunction=_null, presub=_null, chdir=None, exitstatfunc=None, **kw):
|
| - if not strfunction is _null:
|
| - self.strfunction = strfunction
|
| + def __init__(self, cmdstr=_null, strfunction=_null, varlist=(),
|
| + presub=_null, chdir=None, exitstatfunc=None,
|
| + **kw):
|
| + self.cmdstr = cmdstr
|
| + if strfunction is not _null:
|
| + if strfunction is None:
|
| + self.cmdstr = None
|
| + else:
|
| + self.strfunction = strfunction
|
| + self.varlist = varlist
|
| self.presub = presub
|
| self.chdir = chdir
|
| if not exitstatfunc:
|
| @@ -418,16 +478,16 @@
|
| show=_null,
|
| execute=_null,
|
| chdir=_null):
|
| - if not SCons.Util.is_List(target):
|
| + if not is_List(target):
|
| target = [target]
|
| - if not SCons.Util.is_List(source):
|
| + if not is_List(source):
|
| source = [source]
|
|
|
| - if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
|
| if presub is _null:
|
| presub = self.presub
|
| - if presub is _null:
|
| - presub = print_actions_presub
|
| + if presub is _null:
|
| + presub = print_actions_presub
|
| + if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
|
| if show is _null: show = print_actions
|
| if execute is _null: execute = execute_actions
|
| if chdir is _null: chdir = self.chdir
|
| @@ -437,19 +497,19 @@
|
| try:
|
| chdir = str(chdir.abspath)
|
| except AttributeError:
|
| - if not SCons.Util.is_String(chdir):
|
| + if not is_String(chdir):
|
| chdir = str(target[0].dir)
|
| if presub:
|
| t = string.join(map(str, target), ' and ')
|
| l = string.join(self.presub_lines(env), '\n ')
|
| out = "Building %s with action:\n %s\n" % (t, l)
|
| sys.stdout.write(out)
|
| - s = None
|
| + cmd = None
|
| if show and self.strfunction:
|
| - s = self.strfunction(target, source, env)
|
| - if s:
|
| + cmd = self.strfunction(target, source, env)
|
| + if cmd:
|
| if chdir:
|
| - s = ('os.chdir(%s)\n' % repr(chdir)) + s
|
| + cmd = ('os.chdir(%s)\n' % repr(chdir)) + cmd
|
| try:
|
| get = env.get
|
| except AttributeError:
|
| @@ -458,7 +518,7 @@
|
| print_func = get('PRINT_CMD_LINE_FUNC')
|
| if not print_func:
|
| print_func = self.print_cmd_line
|
| - print_func(s, target, source, env)
|
| + print_func(cmd, target, source, env)
|
| stat = 0
|
| if execute:
|
| if chdir:
|
| @@ -476,7 +536,7 @@
|
| finally:
|
| if save_cwd:
|
| os.chdir(save_cwd)
|
| - if s and save_cwd:
|
| + if cmd and save_cwd:
|
| print_func('os.chdir(%s)' % repr(save_cwd), target, source, env)
|
|
|
| return stat
|
| @@ -492,47 +552,65 @@
|
| cl.append(arg)
|
| return string.join(cl)
|
|
|
| -# this function is still in draft mode. We're going to need something like
|
| -# it in the long run as more and more places use it, but I'm sure it'll have
|
| -# to be tweaked to get the full desired functionality.
|
| +# A fiddlin' little function that has an 'import SCons.Environment' which
|
| +# can't be moved to the top level without creating an import loop. Since
|
| +# this import creates a local variable named 'SCons', it blocks access to
|
| +# the global variable, so we move it here to prevent complaints about local
|
| +# variables being used uninitialized.
|
| default_ENV = None
|
| -# one special arg, 'error', to tell what to do with exceptions.
|
| +def get_default_ENV(env):
|
| + global default_ENV
|
| + try:
|
| + return env['ENV']
|
| + except KeyError:
|
| + if not default_ENV:
|
| + import SCons.Environment
|
| + # This is a hideously expensive way to get a default shell
|
| + # environment. What it really should do is run the platform
|
| + # setup to get the default ENV. Fortunately, it's incredibly
|
| + # rare for an Environment not to have a shell environment, so
|
| + # we're not going to worry about it overmuch.
|
| + default_ENV = SCons.Environment.Environment()['ENV']
|
| + return default_ENV
|
| +
|
| +# This function is still in draft mode. We're going to need something like
|
| +# it in the long run as more and more places use subprocess, but I'm sure
|
| +# it'll have to be tweaked to get the full desired functionality.
|
| +# one special arg (so far?), 'error', to tell what to do with exceptions.
|
| def _subproc(env, cmd, error = 'ignore', **kw):
|
| - """Do setup for a subprocess.Popen() call"""
|
| + """Do common setup for a subprocess.Popen() call"""
|
| + # allow std{in,out,err} to be "'devnull'"
|
| + io = kw.get('stdin')
|
| + if is_String(io) and io == 'devnull':
|
| + kw['stdin'] = open(os.devnull)
|
| + io = kw.get('stdout')
|
| + if is_String(io) and io == 'devnull':
|
| + kw['stdout'] = open(os.devnull, 'w')
|
| + io = kw.get('stderr')
|
| + if is_String(io) and io == 'devnull':
|
| + kw['stderr'] = open(os.devnull, 'w')
|
|
|
| - # If the env has no ENV, get a default
|
| - try:
|
| - ENV = env['ENV']
|
| - except KeyError:
|
| - global default_ENV
|
| - if default_ENV is None:
|
| - # Unbelievably expensive. What it really should do
|
| - # is run the platform setup to get the default ENV.
|
| - # Fortunately, it should almost never happen.
|
| - default_ENV = SCons.Environment.Environment(tools=[])['ENV']
|
| - ENV = default_ENV
|
| -
|
| + # Figure out what shell environment to use
|
| + ENV = kw.get('env', None)
|
| + if ENV is None: ENV = get_default_ENV(env)
|
| +
|
| # Ensure that the ENV values are all strings:
|
| new_env = {}
|
| - # It's a string 99.44% of the time, so optimize this
|
| - is_String = SCons.Util.is_String
|
| for key, value in ENV.items():
|
| - if is_String(value):
|
| - # Call str() even though it's a "string" because it might be
|
| - # a *Unicode* string, which makes subprocess.Popen() gag.
|
| - new_env[key] = str(value)
|
| - elif SCons.Util.is_List(value):
|
| - # If the value is a list, then we assume it is a
|
| - # path list, because that's a pretty common list-like
|
| - # value to stick in an environment variable:
|
| + if is_List(value):
|
| + # If the value is a list, then we assume it is a path list,
|
| + # because that's a pretty common list-like value to stick
|
| + # in an environment variable:
|
| value = SCons.Util.flatten_sequence(value)
|
| - ENV[key] = string.join(map(str, value), os.pathsep)
|
| + new_env[key] = string.join(map(str, value), os.pathsep)
|
| else:
|
| - # If it isn't a string or a list, then we just coerce
|
| - # it to a string, which is the proper way to handle
|
| - # Dir and File instances and will produce something
|
| - # reasonable for just about everything else:
|
| - ENV[key] = str(value)
|
| + # It's either a string or something else. If it's a string,
|
| + # we still want to call str() because it might be a *Unicode*
|
| + # string, which makes subprocess.Popen() gag. If it isn't a
|
| + # string or a list, then we just coerce it to a string, which
|
| + # is the proper way to handle Dir and File instances and will
|
| + # produce something reasonable for just about everything else:
|
| + new_env[key] = str(value)
|
| kw['env'] = new_env
|
|
|
| try:
|
| @@ -541,7 +619,7 @@
|
| except EnvironmentError, e:
|
| if error == 'raise': raise
|
| # return a dummy Popen instance that only returns error
|
| - class popen:
|
| + class dummyPopen:
|
| def __init__(self, e): self.exception = e
|
| def communicate(self): return ('','')
|
| def wait(self): return -self.exception.errno
|
| @@ -550,11 +628,11 @@
|
| def read(self): return ''
|
| def readline(self): return ''
|
| stdout = stderr = f()
|
| - return popen(e)
|
| + return dummyPopen(e)
|
|
|
| class CommandAction(_ActionAction):
|
| """Class for command-execution actions."""
|
| - def __init__(self, cmd, cmdstr=None, *args, **kw):
|
| + def __init__(self, cmd, **kw):
|
| # Cmd can actually be a list or a single item; if it's a
|
| # single item it should be the command string to execute; if a
|
| # list then it should be the words of the command string to
|
| @@ -566,25 +644,16 @@
|
| # variables.
|
| if __debug__: logInstanceCreation(self, 'Action.CommandAction')
|
|
|
| - if not cmdstr is None:
|
| - if callable(cmdstr):
|
| - args = (cmdstr,)+args
|
| - elif not SCons.Util.is_String(cmdstr):
|
| - raise SCons.Errors.UserError(\
|
| - 'Invalid command display variable type. ' \
|
| - 'You must either pass a string or a callback which ' \
|
| - 'accepts (target, source, env) as parameters.')
|
| -
|
| - apply(_ActionAction.__init__, (self,)+args, kw)
|
| - if SCons.Util.is_List(cmd):
|
| - if filter(SCons.Util.is_List, cmd):
|
| + #TODO(1.5) _ActionAction.__init__(self, **kw)
|
| + apply(_ActionAction.__init__, (self,), kw)
|
| + if is_List(cmd):
|
| + if filter(is_List, cmd):
|
| raise TypeError, "CommandAction should be given only " \
|
| "a single command"
|
| self.cmd_list = cmd
|
| - self.cmdstr = cmdstr
|
|
|
| def __str__(self):
|
| - if SCons.Util.is_List(self.cmd_list):
|
| + if is_List(self.cmd_list):
|
| return string.join(map(str, self.cmd_list), ' ')
|
| return str(self.cmd_list)
|
|
|
| @@ -607,7 +676,9 @@
|
| return result, ignore, silent
|
|
|
| def strfunction(self, target, source, env):
|
| - if not self.cmdstr is None:
|
| + if self.cmdstr is None:
|
| + return None
|
| + if self.cmdstr is not _null:
|
| from SCons.Subst import SUBST_RAW
|
| c = env.subst(self.cmdstr, SUBST_RAW, target, source)
|
| if c:
|
| @@ -626,11 +697,8 @@
|
| handle lists of commands, even though that's not how we use it
|
| externally.
|
| """
|
| - from SCons.Subst import escape_list
|
| - import SCons.Util
|
| + escape_list = SCons.Subst.escape_list
|
| flatten_sequence = SCons.Util.flatten_sequence
|
| - is_String = SCons.Util.is_String
|
| - is_List = SCons.Util.is_List
|
|
|
| try:
|
| shell = env['SHELL']
|
| @@ -647,14 +715,7 @@
|
|
|
| escape = env.get('ESCAPE', lambda x: x)
|
|
|
| - try:
|
| - ENV = env['ENV']
|
| - except KeyError:
|
| - global default_ENV
|
| - if not default_ENV:
|
| - import SCons.Environment
|
| - default_ENV = SCons.Environment.Environment()['ENV']
|
| - ENV = default_ENV
|
| + ENV = get_default_ENV(env)
|
|
|
| # Ensure that the ENV values are all strings:
|
| for key, value in ENV.items():
|
| @@ -687,7 +748,7 @@
|
| command=cmd_line)
|
| return 0
|
|
|
| - def get_contents(self, target, source, env):
|
| + def get_presig(self, target, source, env):
|
| """Return the signature contents of this action's command line.
|
|
|
| This strips $(-$) and everything in between the string,
|
| @@ -695,7 +756,7 @@
|
| """
|
| from SCons.Subst import SUBST_SIG
|
| cmd = self.cmd_list
|
| - if SCons.Util.is_List(cmd):
|
| + if is_List(cmd):
|
| cmd = string.join(map(str, cmd))
|
| else:
|
| cmd = str(cmd)
|
| @@ -703,7 +764,7 @@
|
|
|
| def get_implicit_deps(self, target, source, env):
|
| icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True)
|
| - if SCons.Util.is_String(icd) and icd[:1] == '$':
|
| + if is_String(icd) and icd[:1] == '$':
|
| icd = env.subst(icd)
|
| if not icd or icd in ('0', 'None'):
|
| return []
|
| @@ -719,20 +780,21 @@
|
|
|
| class CommandGeneratorAction(ActionBase):
|
| """Class for command-generator actions."""
|
| - def __init__(self, generator, *args, **kw):
|
| + def __init__(self, generator, kw):
|
| if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction')
|
| self.generator = generator
|
| - self.gen_args = args
|
| self.gen_kw = kw
|
| + self.varlist = kw.get('varlist', ())
|
|
|
| def _generate(self, target, source, env, for_signature):
|
| # ensure that target is a list, to make it easier to write
|
| # generator functions:
|
| - if not SCons.Util.is_List(target):
|
| + if not is_List(target):
|
| target = [target]
|
|
|
| ret = self.generator(target=target, source=source, env=env, for_signature=for_signature)
|
| - gen_cmd = apply(Action, (ret,)+self.gen_args, self.gen_kw)
|
| + #TODO(1.5) gen_cmd = Action(ret, **self.gen_kw)
|
| + gen_cmd = apply(Action, (ret,), self.gen_kw)
|
| if not gen_cmd:
|
| raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret))
|
| return gen_cmd
|
| @@ -756,13 +818,13 @@
|
| return act(target, source, env, exitstatfunc, presub,
|
| show, execute, chdir)
|
|
|
| - def get_contents(self, target, source, env):
|
| + def get_presig(self, target, source, env):
|
| """Return the signature contents of this action's command line.
|
|
|
| This strips $(-$) and everything in between the string,
|
| since those parts don't affect signatures.
|
| """
|
| - return self._generate(target, source, env, 1).get_contents(target, source, env)
|
| + return self._generate(target, source, env, 1).get_presig(target, source, env)
|
|
|
| def get_implicit_deps(self, target, source, env):
|
| return self._generate(target, source, env, 1).get_implicit_deps(target, source, env)
|
| @@ -788,22 +850,23 @@
|
|
|
| class LazyAction(CommandGeneratorAction, CommandAction):
|
|
|
| - def __init__(self, var, *args, **kw):
|
| + def __init__(self, var, kw):
|
| if __debug__: logInstanceCreation(self, 'Action.LazyAction')
|
| - apply(CommandAction.__init__, (self, '$'+var)+args, kw)
|
| + #FUTURE CommandAction.__init__(self, '${'+var+'}', **kw)
|
| + apply(CommandAction.__init__, (self, '${'+var+'}'), kw)
|
| self.var = SCons.Util.to_String(var)
|
| - self.gen_args = args
|
| self.gen_kw = kw
|
|
|
| def get_parent_class(self, env):
|
| c = env.get(self.var)
|
| - if SCons.Util.is_String(c) and not '\n' in c:
|
| + if is_String(c) and not '\n' in c:
|
| return CommandAction
|
| return CommandGeneratorAction
|
|
|
| def _generate_cache(self, env):
|
| c = env.get(self.var, '')
|
| - gen_cmd = apply(Action, (c,)+self.gen_args, self.gen_kw)
|
| + #TODO(1.5) gen_cmd = Action(c, **self.gen_kw)
|
| + gen_cmd = apply(Action, (c,), self.gen_kw)
|
| if not gen_cmd:
|
| raise SCons.Errors.UserError("$%s value %s cannot be used to create an Action." % (self.var, repr(c)))
|
| return gen_cmd
|
| @@ -814,29 +877,21 @@
|
| def __call__(self, target, source, env, *args, **kw):
|
| args = (self, target, source, env) + args
|
| c = self.get_parent_class(env)
|
| + #TODO(1.5) return c.__call__(*args, **kw)
|
| return apply(c.__call__, args, kw)
|
|
|
| - def get_contents(self, target, source, env):
|
| + def get_presig(self, target, source, env):
|
| c = self.get_parent_class(env)
|
| - return c.get_contents(self, target, source, env)
|
| + return c.get_presig(self, target, source, env)
|
|
|
|
|
|
|
| class FunctionAction(_ActionAction):
|
| """Class for Python function actions."""
|
|
|
| - def __init__(self, execfunction, cmdstr=_null, *args, **kw):
|
| + def __init__(self, execfunction, kw):
|
| if __debug__: logInstanceCreation(self, 'Action.FunctionAction')
|
|
|
| - if not cmdstr is _null:
|
| - if callable(cmdstr):
|
| - args = (cmdstr,)+args
|
| - elif not (cmdstr is None or SCons.Util.is_String(cmdstr)):
|
| - raise SCons.Errors.UserError(\
|
| - 'Invalid function display variable type. ' \
|
| - 'You must either pass a string or a callback which ' \
|
| - 'accepts (target, source, env) as parameters.')
|
| -
|
| self.execfunction = execfunction
|
| try:
|
| self.funccontents = _callable_contents(execfunction)
|
| @@ -848,12 +903,8 @@
|
| # This is weird, just do the best we can.
|
| self.funccontents = _object_contents(execfunction)
|
|
|
| - apply(_ActionAction.__init__, (self,)+args, kw)
|
| - self.varlist = kw.get('varlist', [])
|
| - if SCons.Util.is_String(self.varlist):
|
| - # prevent varlist="FOO" from being interpreted as ['F', 'O', 'O']
|
| - self.varlist=[self.varlist]
|
| - self.cmdstr = cmdstr
|
| + #TODO(1.5) _ActionAction.__init__(self, **kw)
|
| + apply(_ActionAction.__init__, (self,), kw)
|
|
|
| def function_name(self):
|
| try:
|
| @@ -867,7 +918,7 @@
|
| def strfunction(self, target, source, env):
|
| if self.cmdstr is None:
|
| return None
|
| - if not self.cmdstr is _null:
|
| + if self.cmdstr is not _null:
|
| from SCons.Subst import SUBST_RAW
|
| c = env.subst(self.cmdstr, SUBST_RAW, target, source)
|
| if c:
|
| @@ -903,45 +954,50 @@
|
| return "%s(target, source, env)" % name
|
|
|
| def execute(self, target, source, env):
|
| - rsources = map(rfile, source)
|
| + exc_info = (None,None,None)
|
| try:
|
| - result = self.execfunction(target=target, source=rsources, env=env)
|
| - except EnvironmentError, e:
|
| - # If an IOError/OSError happens, raise a BuildError.
|
| - # Report the name of the file or directory that caused the
|
| - # error, which might be different from the target being built
|
| - # (for example, failure to create the directory in which the
|
| - # target file will appear).
|
| - try: filename = e.filename
|
| - except AttributeError: filename = None
|
| - result = SCons.Errors.BuildError(node=target,
|
| - errstr=e.strerror,
|
| - status=1,
|
| - filename=filename,
|
| - action=self,
|
| - command=self.strfunction(target, source, env))
|
| - else:
|
| + rsources = map(rfile, source)
|
| + try:
|
| + result = self.execfunction(target=target, source=rsources, env=env)
|
| + except KeyboardInterrupt, e:
|
| + raise
|
| + except SystemExit, e:
|
| + raise
|
| + except Exception, e:
|
| + result = e
|
| + exc_info = sys.exc_info()
|
| +
|
| if result:
|
| - msg = "Error %s" % result
|
| - result = SCons.Errors.BuildError(errstr=msg,
|
| - status=result,
|
| - action=self,
|
| - command=self.strfunction(target, source, env))
|
| - return result
|
| + result = SCons.Errors.convert_to_BuildError(result, exc_info)
|
| + result.node=target
|
| + result.action=self
|
| + result.command=self.strfunction(target, source, env)
|
|
|
| - def get_contents(self, target, source, env):
|
| + # FIXME: This maintains backward compatibility with respect to
|
| + # which type of exceptions were returned by raising an
|
| + # exception and which ones were returned by value. It would
|
| + # probably be best to always return them by value here, but
|
| + # some codes do not check the return value of Actions and I do
|
| + # not have the time to modify them at this point.
|
| + if (exc_info[1] and
|
| + not isinstance(exc_info[1],EnvironmentError)):
|
| + raise result
|
| +
|
| + return result
|
| + finally:
|
| + # Break the cycle between the traceback object and this
|
| + # function stack frame. See the sys.exc_info() doc info for
|
| + # more information about this issue.
|
| + del exc_info
|
| +
|
| +
|
| + def get_presig(self, target, source, env):
|
| """Return the signature contents of this callable action."""
|
| try:
|
| - contents = self.gc(target, source, env)
|
| + return self.gc(target, source, env)
|
| except AttributeError:
|
| - contents = self.funccontents
|
| + return self.funccontents
|
|
|
| - result = [contents]
|
| - for v in self.varlist:
|
| - result.append(env.subst('${'+v+'}'))
|
| -
|
| - return string.join(result, '')
|
| -
|
| def get_implicit_deps(self, target, source, env):
|
| return []
|
|
|
| @@ -954,6 +1010,9 @@
|
| return x
|
| return Action(x)
|
| self.list = map(list_of_actions, list)
|
| + # our children will have had any varlist
|
| + # applied; we don't need to do it again
|
| + self.varlist = ()
|
|
|
| def genstring(self, target, source, env):
|
| return string.join(map(lambda a, t=target, s=source, e=env:
|
| @@ -963,12 +1022,12 @@
|
|
|
| def __str__(self):
|
| return string.join(map(str, self.list), '\n')
|
| -
|
| +
|
| def presub_lines(self, env):
|
| return SCons.Util.flatten_sequence(
|
| map(lambda a, env=env: a.presub_lines(env), self.list))
|
|
|
| - def get_contents(self, target, source, env):
|
| + def get_presig(self, target, source, env):
|
| """Return the signature contents of this action list.
|
|
|
| Simple concatenation of the signatures of the elements.
|
| @@ -1006,6 +1065,7 @@
|
| self.parent = parent
|
| self.args = args
|
| self.kw = kw
|
| +
|
| def get_contents(self, target, source, env):
|
| actfunc = self.parent.actfunc
|
| try:
|
| @@ -1021,10 +1081,11 @@
|
| contents = str(actfunc)
|
| contents = remove_set_lineno_codes(contents)
|
| return contents
|
| +
|
| def subst(self, s, target, source, env):
|
| # If s is a list, recursively apply subst()
|
| # to every element in the list
|
| - if SCons.Util.is_List(s):
|
| + if is_List(s):
|
| result = []
|
| for elem in s:
|
| result.append(self.subst(elem, target, source, env))
|
| @@ -1035,27 +1096,35 @@
|
| # was called by using this hard-coded value as a special return.
|
| if s == '$__env__':
|
| return env
|
| - elif SCons.Util.is_String(s):
|
| + elif is_String(s):
|
| return env.subst(s, 1, target, source)
|
| return self.parent.convert(s)
|
| +
|
| def subst_args(self, target, source, env):
|
| return map(lambda x, self=self, t=target, s=source, e=env:
|
| self.subst(x, t, s, e),
|
| self.args)
|
| +
|
| def subst_kw(self, target, source, env):
|
| kw = {}
|
| for key in self.kw.keys():
|
| kw[key] = self.subst(self.kw[key], target, source, env)
|
| return kw
|
| +
|
| def __call__(self, target, source, env):
|
| args = self.subst_args(target, source, env)
|
| kw = self.subst_kw(target, source, env)
|
| + #TODO(1.5) return self.parent.actfunc(*args, **kw)
|
| return apply(self.parent.actfunc, args, kw)
|
| +
|
| def strfunction(self, target, source, env):
|
| args = self.subst_args(target, source, env)
|
| kw = self.subst_kw(target, source, env)
|
| + #TODO(1.5) return self.parent.strfunc(*args, **kw)
|
| return apply(self.parent.strfunc, args, kw)
|
| +
|
| def __str__(self):
|
| + #TODO(1.5) return self.parent.strfunc(*self.args, **self.kw)
|
| return apply(self.parent.strfunc, self.args, self.kw)
|
|
|
| class ActionFactory:
|
| @@ -1071,6 +1140,7 @@
|
| self.actfunc = actfunc
|
| self.strfunc = strfunc
|
| self.convert = convert
|
| +
|
| def __call__(self, *args, **kw):
|
| ac = ActionCaller(self, args, kw)
|
| action = Action(ac, strfunction=ac.strfunction)
|
|
|