# 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.
+from __future__ import generators ### KEEP FOR COMPATIBILITY FIXERS
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import cPickle
import dis
import os
-import os.path
-import string
+import re
import sys
import subprocess
else:
result.append(c)
i = i+1
- return string.join(result, '')
+ return ''.join(result)
+
+strip_quotes = re.compile('^[\'"](.*)[\'"]$')
def _callable_contents(obj):
# 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:]),',') + ')')
+ contents.append(',(' + ','.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
# function result.
- contents.append(',(' + string.join(map(_object_contents,code.co_names),',') + ')')
+ contents.append(',(' + ','.join(map(_object_contents,code.co_names)) + ')')
# The code contents depends on its actual code!!!
contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')')
- return string.join(contents, '')
+ return ''.join(contents)
def _function_contents(func):
# The function contents depends on the value of defaults arguments
if func.func_defaults:
- contents.append(',(' + string.join(map(_object_contents,func.func_defaults),',') + ')')
+ contents.append(',(' + ','.join(map(_object_contents,func.func_defaults)) + ')')
else:
contents.append(',()')
#xxx = [_object_contents(x.cell_contents) for x in closure]
try:
- xxx = map(lambda x: _object_contents(x.cell_contents), closure)
+ xxx = [_object_contents(x.cell_contents) for x in closure]
except AttributeError:
xxx = []
- contents.append(',(' + string.join(xxx, ',') + ')')
+ contents.append(',(' + ','.join(xxx) + ')')
- return string.join(contents, '')
+ return ''.join(contents)
def _actionAppend(act1, act2):
if is_List(act):
#TODO(1.5) return CommandAction(act, **kw)
- return apply(CommandAction, (act,), kw)
+ return CommandAction(act, **kw)
if callable(act):
try:
# like a function or a CommandGenerator in that variable
# instead of a string.
return LazyAction(var, kw)
- commands = string.split(str(act), '\n')
+ commands = str(act).split('\n')
if len(commands) == 1:
#TODO(1.5) return CommandAction(commands[0], **kw)
- return apply(CommandAction, (commands[0],), kw)
+ return 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)
aa = _do_create_action(a, kw)
if aa is not None: acts.append(aa)
if not acts:
- return None
+ return ListAction([])
elif len(acts) == 1:
return acts[0]
else:
def __cmp__(self, other):
return cmp(self.__dict__, other)
+ def no_batch_key(self, env, target, source):
+ return None
+
+ batch_key = no_batch_key
+
def genstring(self, target, source, env):
return str(self)
# 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
+ vl = self.get_varlist(target, source, env)
if is_String(vl): vl = (vl,)
for v in vl:
result.append(env.subst('${'+v+'}'))
- return string.join(result, '')
+ return ''.join(result)
def __add__(self, other):
return _actionAppend(self, other)
# and CommandGeneratorAction will use this env
# when it calls its _generate method.
self.presub_env = env
- lines = string.split(str(self), '\n')
+ lines = str(self).split('\n')
self.presub_env = None # don't need this any more
return lines
- def get_executor(self, env, overrides, tlist, slist, executor_kw):
- """Return the Executor for this Action."""
- return SCons.Executor.Executor(self, env, overrides,
- tlist, slist, executor_kw)
+ def get_varlist(self, target, source, env, executor=None):
+ return self.varlist
+
+ def get_targets(self, env, executor):
+ """
+ Returns the type of targets ($TARGETS, $CHANGED_TARGETS) used
+ by this action.
+ """
+ return self.targets
class _ActionAction(ActionBase):
"""Base class for actions that create output objects."""
def __init__(self, cmdstr=_null, strfunction=_null, varlist=(),
presub=_null, chdir=None, exitstatfunc=None,
+ batch_key=None, targets='$TARGETS',
**kw):
self.cmdstr = cmdstr
if strfunction is not _null:
exitstatfunc = default_exitstatfunc
self.exitstatfunc = exitstatfunc
+ self.targets = targets
+
+ if batch_key:
+ if not callable(batch_key):
+ # They have set batch_key, but not to their own
+ # callable. The default behavior here will batch
+ # *all* targets+sources using this action, separated
+ # for each construction environment.
+ def default_batch_key(self, env, target, source):
+ return (id(self), id(env))
+ batch_key = default_batch_key
+ SCons.Util.AddMethod(self, batch_key, 'batch_key')
+
def print_cmd_line(self, s, target, source, env):
sys.stdout.write(s + "\n")
presub=_null,
show=_null,
execute=_null,
- chdir=_null):
+ chdir=_null,
+ executor=None):
if not is_List(target):
target = [target]
if not is_List(source):
chdir = str(chdir.abspath)
except AttributeError:
if not is_String(chdir):
- chdir = str(target[0].dir)
+ if executor:
+ chdir = str(executor.batches[0].targets[0].dir)
+ else:
+ chdir = str(target[0].dir)
if presub:
- t = string.join(map(str, target), ' and ')
- l = string.join(self.presub_lines(env), '\n ')
+ if executor:
+ target = executor.get_all_targets()
+ source = executor.get_all_sources()
+ t = ' and '.join(map(str, target))
+ l = '\n '.join(self.presub_lines(env))
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:
+ if executor:
+ target = executor.get_all_targets()
+ source = executor.get_all_sources()
+ try:
+ cmd = self.strfunction(target, source, env, executor)
+ except TypeError:
+ 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:
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:
os.chdir(chdir)
try:
- stat = self.execute(target, source, env)
+ stat = self.execute(target, source, env, executor=executor)
if isinstance(stat, SCons.Errors.BuildError):
s = exitstatfunc(stat.status)
if s:
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
if ' ' in arg or '\t' in arg:
arg = '"' + arg + '"'
cl.append(arg)
- return string.join(cl)
+ return ' '.join(cl)
# 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
# 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"""
- ### TODO: allow std{in,out,err} to be "'devnull'" (see issue 2228)
+ """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')
# Figure out what shell environment to use
ENV = kw.get('env', None)
# because that's a pretty common list-like value to stick
# in an environment variable:
value = SCons.Util.flatten_sequence(value)
- new_env[key] = string.join(map(str, value), os.pathsep)
+ new_env[key] = os.pathsep.join(map(str, value))
else:
# 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*
try:
#FUTURE return subprocess.Popen(cmd, **kw)
- return apply(subprocess.Popen, (cmd,), kw)
+ return subprocess.Popen(cmd, **kw)
except EnvironmentError, e:
if error == 'raise': raise
# return a dummy Popen instance that only returns error
if __debug__: logInstanceCreation(self, 'Action.CommandAction')
#TODO(1.5) _ActionAction.__init__(self, **kw)
- apply(_ActionAction.__init__, (self,), kw)
+ _ActionAction.__init__(self, **kw)
if is_List(cmd):
- if filter(is_List, cmd):
+ if list(filter(is_List, cmd)):
raise TypeError, "CommandAction should be given only " \
"a single command"
self.cmd_list = cmd
def __str__(self):
if is_List(self.cmd_list):
- return string.join(map(str, self.cmd_list), ' ')
+ return ' '.join(map(str, self.cmd_list))
return str(self.cmd_list)
- def process(self, target, source, env):
- result = env.subst_list(self.cmd_list, 0, target, source)
+ def process(self, target, source, env, executor=None):
+ if executor:
+ result = env.subst_list(self.cmd_list, 0, executor=executor)
+ else:
+ result = env.subst_list(self.cmd_list, 0, target, source)
silent = None
ignore = None
- while 1:
+ while True:
try: c = result[0][0][0]
except IndexError: c = None
if c == '@': silent = 1
pass
return result, ignore, silent
- def strfunction(self, target, source, env):
+ def strfunction(self, target, source, env, executor=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 executor:
+ c = env.subst(self.cmdstr, SUBST_RAW, executor=executor)
+ else:
+ c = env.subst(self.cmdstr, SUBST_RAW, target, source)
if c:
return c
- cmd_list, ignore, silent = self.process(target, source, env)
+ cmd_list, ignore, silent = self.process(target, source, env, executor)
if silent:
return ''
return _string_from_cmd_list(cmd_list[0])
- def execute(self, target, source, env):
+ def execute(self, target, source, env, executor=None):
"""Execute a command action.
This will handle lists of commands as well as individual commands,
# path list, because that's a pretty common list-like
# value to stick in an environment variable:
value = flatten_sequence(value)
- ENV[key] = string.join(map(str, value), os.pathsep)
+ ENV[key] = os.pathsep.join(map(str, value))
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
# reasonable for just about everything else:
ENV[key] = str(value)
- cmd_list, ignore, silent = self.process(target, map(rfile, source), env)
+ if executor:
+ target = executor.get_all_targets()
+ source = executor.get_all_sources()
+ cmd_list, ignore, silent = self.process(target, list(map(rfile, source)), env, executor)
# Use len() to filter out any "command" that's zero-length.
for cmd_line in filter(len, cmd_list):
command=cmd_line)
return 0
- def get_presig(self, target, source, env):
+ def get_presig(self, target, source, env, executor=None):
"""Return the signature contents of this action's command line.
This strips $(-$) and everything in between the string,
from SCons.Subst import SUBST_SIG
cmd = self.cmd_list
if is_List(cmd):
- cmd = string.join(map(str, cmd))
+ cmd = ' '.join(map(str, cmd))
else:
cmd = str(cmd)
- return env.subst_target_source(cmd, SUBST_SIG, target, source)
+ if executor:
+ return env.subst_target_source(cmd, SUBST_SIG, executor=executor)
+ else:
+ return env.subst_target_source(cmd, SUBST_SIG, target, source)
- def get_implicit_deps(self, target, source, env):
+ def get_implicit_deps(self, target, source, env, executor=None):
icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True)
if is_String(icd) and icd[:1] == '$':
icd = env.subst(icd)
if not icd or icd in ('0', 'None'):
return []
from SCons.Subst import SUBST_SIG
- cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source)
+ if executor:
+ cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, executor=executor)
+ else:
+ cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source)
res = []
for cmd_line in cmd_list:
if cmd_line:
- d = env.WhereIs(str(cmd_line[0]))
+ d = str(cmd_line[0])
+ m = strip_quotes.match(d)
+ if m:
+ d = m.group(1)
+ d = env.WhereIs(d)
if d:
res.append(env.fs.File(d))
return res
self.generator = generator
self.gen_kw = kw
self.varlist = kw.get('varlist', ())
+ self.targets = kw.get('targets', '$TARGETS')
- def _generate(self, target, source, env, for_signature):
+ def _generate(self, target, source, env, for_signature, executor=None):
# ensure that target is a list, to make it easier to write
# generator functions:
if not is_List(target):
target = [target]
- ret = self.generator(target=target, source=source, env=env, for_signature=for_signature)
+ if executor:
+ target = executor.get_all_targets()
+ source = executor.get_all_sources()
+ ret = self.generator(target=target,
+ source=source,
+ env=env,
+ for_signature=for_signature)
#TODO(1.5) gen_cmd = Action(ret, **self.gen_kw)
- gen_cmd = apply(Action, (ret,), self.gen_kw)
+ gen_cmd = 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
act = self._generate([], [], env, 1)
return str(act)
- def genstring(self, target, source, env):
- return self._generate(target, source, env, 1).genstring(target, source, env)
+ def batch_key(self, env, target, source):
+ return self._generate(target, source, env, 1).batch_key(env, target, source)
+
+ def genstring(self, target, source, env, executor=None):
+ return self._generate(target, source, env, 1, executor).genstring(target, source, env)
def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
- show=_null, execute=_null, chdir=_null):
- act = self._generate(target, source, env, 0)
+ show=_null, execute=_null, chdir=_null, executor=None):
+ act = self._generate(target, source, env, 0, executor)
+ if act is None:
+ raise UserError("While building `%s': "
+ "Cannot deduce file extension from source files: %s"
+ % (repr(list(map(str, target))), repr(list(map(str, source)))))
return act(target, source, env, exitstatfunc, presub,
- show, execute, chdir)
+ show, execute, chdir, executor)
- def get_presig(self, target, source, env):
+ def get_presig(self, target, source, env, executor=None):
"""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_presig(target, source, env)
+ return self._generate(target, source, env, 1, executor).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)
+ def get_implicit_deps(self, target, source, env, executor=None):
+ return self._generate(target, source, env, 1, executor).get_implicit_deps(target, source, env)
+
+ def get_varlist(self, target, source, env, executor=None):
+ return self._generate(target, source, env, 1, executor).get_varlist(target, source, env, executor)
+
+ def get_targets(self, env, executor):
+ return self._generate(None, None, env, 1, executor).get_targets(env, executor)
def __init__(self, var, kw):
if __debug__: logInstanceCreation(self, 'Action.LazyAction')
#FUTURE CommandAction.__init__(self, '${'+var+'}', **kw)
- apply(CommandAction.__init__, (self, '${'+var+'}'), kw)
+ CommandAction.__init__(self, '${'+var+'}', **kw)
self.var = SCons.Util.to_String(var)
self.gen_kw = kw
return CommandGeneratorAction
def _generate_cache(self, env):
- c = env.get(self.var, '')
+ if env:
+ c = env.get(self.var, '')
+ else:
+ c = ''
#TODO(1.5) gen_cmd = Action(c, **self.gen_kw)
- gen_cmd = apply(Action, (c,), self.gen_kw)
+ gen_cmd = 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
- def _generate(self, target, source, env, for_signature):
+ def _generate(self, target, source, env, for_signature, executor=None):
return self._generate_cache(env)
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)
+ return c.__call__(self, target, source, env, *args, **kw)
def get_presig(self, target, source, env):
c = self.get_parent_class(env)
return c.get_presig(self, target, source, env)
+ def get_varlist(self, target, source, env, executor=None):
+ c = self.get_parent_class(env)
+ return c.get_varlist(self, target, source, env, executor)
class FunctionAction(_ActionAction):
self.funccontents = _object_contents(execfunction)
#TODO(1.5) _ActionAction.__init__(self, **kw)
- apply(_ActionAction.__init__, (self,), kw)
+ _ActionAction.__init__(self, **kw)
def function_name(self):
try:
except AttributeError:
return "unknown_python_function"
- def strfunction(self, target, source, env):
+ def strfunction(self, target, source, env, executor=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 executor:
+ c = env.subst(self.cmdstr, SUBST_RAW, executor=executor)
+ else:
+ c = env.subst(self.cmdstr, SUBST_RAW, target, source)
if c:
return c
def array(a):
else:
s = str_for_display()
return s
- return '[' + string.join(map(quote, a), ", ") + ']'
+ return '[' + ", ".join(map(quote, a)) + ']'
try:
strfunc = self.execfunction.strfunction
except AttributeError:
return str(self.execfunction)
return "%s(target, source, env)" % name
- def execute(self, target, source, env):
+ def execute(self, target, source, env, executor=None):
exc_info = (None,None,None)
try:
- rsources = map(rfile, source)
+ if executor:
+ target = executor.get_all_targets()
+ source = executor.get_all_sources()
+ rsources = list(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()
result = SCons.Errors.convert_to_BuildError(result, exc_info)
result.node=target
result.action=self
- result.command=self.strfunction(target, source, env)
+ try:
+ result.command=self.strfunction(target, source, env, executor)
+ except TypeError:
+ result.command=self.strfunction(target, source, env)
# FIXME: This maintains backward compatibility with respect to
# which type of exceptions were returned by raising an
# 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
+ if (exc_info[1] and
not isinstance(exc_info[1],EnvironmentError)):
raise result
class ListAction(ActionBase):
"""Class for lists of other actions."""
- def __init__(self, list):
+ def __init__(self, actionlist):
if __debug__: logInstanceCreation(self, 'Action.ListAction')
def list_of_actions(x):
if isinstance(x, ActionBase):
return x
return Action(x)
- self.list = map(list_of_actions, list)
+ self.list = list(map(list_of_actions, actionlist))
# our children will have had any varlist
# applied; we don't need to do it again
self.varlist = ()
+ self.targets = '$TARGETS'
def genstring(self, target, source, env):
- return string.join(map(lambda a, t=target, s=source, e=env:
- a.genstring(t, s, e),
- self.list),
- '\n')
+ return '\n'.join([a.genstring(target, source, env) for a in self.list])
def __str__(self):
- return string.join(map(str, self.list), '\n')
+ return '\n'.join(map(str, self.list))
def presub_lines(self, env):
return SCons.Util.flatten_sequence(
- map(lambda a, env=env: a.presub_lines(env), self.list))
+ [a.presub_lines(env) for a in self.list])
def get_presig(self, target, source, env):
"""Return the signature contents of this action list.
Simple concatenation of the signatures of the elements.
"""
- return string.join(map(lambda x, t=target, s=source, e=env:
- x.get_contents(t, s, e),
- self.list),
- "")
+ return "".join([x.get_contents(target, source, env) for x in self.list])
def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
- show=_null, execute=_null, chdir=_null):
+ show=_null, execute=_null, chdir=_null, executor=None):
+ if executor:
+ target = executor.get_all_targets()
+ source = executor.get_all_sources()
for act in self.list:
stat = act(target, source, env, exitstatfunc, presub,
- show, execute, chdir)
+ show, execute, chdir, executor)
if stat:
return stat
return 0
result.extend(act.get_implicit_deps(target, source, env))
return result
+ def get_varlist(self, target, source, env, executor=None):
+ result = SCons.Util.OrderedDict()
+ for act in self.list:
+ for var in act.get_varlist(target, source, env, executor):
+ result[var] = True
+ return result.keys()
+
class ActionCaller:
"""A class for delaying calling an Action function with specific
(positional and keyword) arguments until the Action is actually
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)
+ return [self.subst(x, target, source, env) for x in self.args]
def subst_kw(self, target, source, env):
kw = {}
kw[key] = self.subst(self.kw[key], target, source, env)
return kw
- def __call__(self, target, source, env):
+ def __call__(self, target, source, env, executor=None):
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)
+ return 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)
+ return 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)
+ return self.parent.strfunc(*self.args, **self.kw)
class ActionFactory:
"""A factory class that will wrap up an arbitrary function
ac = ActionCaller(self, args, kw)
action = Action(ac, strfunction=ac.strfunction)
return action
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: