other objects (Builders, Executors, etc.) This provides the
common methods for manipulating and combining those actions."""
+ __metaclass__ = SCons.Memoize.Memoized_Metaclass
+
def __cmp__(self, other):
return cmp(self.__dict__, other)
def presub_lines(self, env):
# CommandGeneratorAction needs a real environment
# in order to return the proper string here, since
- # it may call LazyCmdGenerator, which looks up a key
+ # it may call LazyAction, which looks up a key
# in that env. So we temporarily remember the env here,
# and CommandGeneratorAction will use this env
# when it calls its _generate method.
self.presub_env = None # don't need this any more
return lines
+if not SCons.Memoize.has_metaclass:
+ _Base = ActionBase
+ class ActionBase(SCons.Memoize.Memoizer, _Base):
+ "Cache-backed version of ActionBase"
+ def __init__(self, *args, **kw):
+ apply(_Base.__init__, (self,)+args, kw)
+ SCons.Memoize.Memoizer.__init__(self)
+
class _ActionAction(ActionBase):
"""Base class for actions that create output objects."""
# factory above does). cmd will be passed to
# Environment.subst_list() for substituting environment
# variables.
- if __debug__: logInstanceCreation(self)
+ if __debug__: logInstanceCreation(self, 'Action.CommandAction')
apply(_ActionAction.__init__, (self,)+args, kw)
if SCons.Util.is_List(cmd):
if filter(SCons.Util.is_List, cmd):
return result
return 0
- def get_contents(self, target, source, env, dict=None):
+ def get_contents(self, target, source, env):
"""Return the signature contents of this action's command line.
This strips $(-$) and everything in between the string,
cmd = string.join(map(str, cmd))
else:
cmd = str(cmd)
- return env.subst_target_source(cmd, SCons.Util.SUBST_SIG, target, source, dict)
+ return env.subst_target_source(cmd, SCons.Util.SUBST_SIG, target, source)
class CommandGeneratorAction(ActionBase):
"""Class for command-generator actions."""
def __init__(self, generator, *args, **kw):
- if __debug__: logInstanceCreation(self)
+ if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction')
self.generator = generator
self.gen_kw = kw
return act(target, source, env, errfunc, presub,
show, execute, chdir)
- def get_contents(self, target, source, env, dict=None):
+ def get_contents(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, dict=None)
+ return self._generate(target, source, env, 1).get_contents(target, source, env)
-# Ooh, polymorphism -- pretty scary, eh, kids?
-#
-# A LazyCmdAction is a kind of hybrid generator and command action for
+
+
+# A LazyAction is a kind of hybrid generator and command action for
# strings of the form "$VAR". These strings normally expand to other
# strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also
# want to be able to replace them with functions in the construction
# the corresponding CommandAction method to do the heavy lifting.
# If not, then we call the same-named CommandGeneratorAction method.
# The CommandGeneratorAction methods work by using the overridden
-# _generate() method, uses our own way of handling "generation" of an
-# action based on what's in the construction variable.
+# _generate() method, that is, our own way of handling "generation" of
+# an action based on what's in the construction variable.
class LazyAction(CommandGeneratorAction, CommandAction):
+
+ __metaclass__ = SCons.Memoize.Memoized_Metaclass
+
def __init__(self, var, *args, **kw):
- if __debug__: logInstanceCreation(self)
+ if __debug__: logInstanceCreation(self, 'Action.LazyAction')
apply(CommandAction.__init__, (self, '$'+var)+args, kw)
self.var = SCons.Util.to_String(var)
self.gen_kw = kw
return CommandAction
return CommandGeneratorAction
- def _generate(self, target, source, env, for_signature):
+ def _generate_cache(self, env):
+ """__cacheable__"""
c = env.get(self.var, '')
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
+ def _generate(self, target, source, env, for_signature):
+ 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)
return apply(c.__call__, args, kw)
- def get_contents(self, target, source, env, dict=None):
+ def get_contents(self, target, source, env):
c = self.get_parent_class(env)
- return c.get_contents(self, target, source, env, dict)
+ return c.get_contents(self, target, source, env)
+
+if not SCons.Memoize.has_metaclass:
+ _Base = LazyAction
+ class LazyAction(SCons.Memoize.Memoizer, _Base):
+ def __init__(self, *args, **kw):
+ SCons.Memoize.Memoizer.__init__(self)
+ apply(_Base.__init__, (self,)+args, kw)
+
+
class FunctionAction(_ActionAction):
"""Class for Python function actions."""
def __init__(self, execfunction, *args, **kw):
- if __debug__: logInstanceCreation(self)
+ if __debug__: logInstanceCreation(self, 'Action.FunctionAction')
self.execfunction = execfunction
apply(_ActionAction.__init__, (self,)+args, kw)
self.varlist = kw.get('varlist', [])
return "%s(%s, %s)" % (name, tstr, sstr)
def __str__(self):
- return "%s(target, source, env)" % self.function_name()
+ name = self.function_name()
+ if name == 'ActionCaller':
+ return str(self.execfunction)
+ return "%s(target, source, env)" % name
def execute(self, target, source, env):
rsources = map(rfile, source)
raise SCons.Errors.BuildError(node=target, errstr=e.strerror)
return result
- def get_contents(self, target, source, env, dict=None):
+ def get_contents(self, target, source, env):
"""Return the signature contents of this callable action.
By providing direct access to the code object of the
# This is weird, just do the best we can.
contents = str(self.execfunction)
else:
- contents = gc(target, source, env, dict)
+ contents = gc(target, source, env)
return contents + env.subst(string.join(map(lambda v: '${'+v+'}',
self.varlist)))
class ListAction(ActionBase):
"""Class for lists of other actions."""
def __init__(self, list):
- if __debug__: logInstanceCreation(self)
+ if __debug__: logInstanceCreation(self, 'Action.ListAction')
def list_of_actions(x):
if isinstance(x, ActionBase):
return x
a.presub_lines(env),
self.list))
- def get_contents(self, target, source, env, dict=None):
+ def get_contents(self, target, source, env):
"""Return the signature contents of this action list.
Simple concatenation of the signatures of the elements.
"""
- dict = SCons.Util.subst_dict(target, source)
- return string.join(map(lambda x, t=target, s=source, e=env, d=dict:
- x.get_contents(t, s, e, d),
+ return string.join(map(lambda x, t=target, s=source, e=env:
+ x.get_contents(t, s, e),
self.list),
"")
self.parent = parent
self.args = args
self.kw = kw
- def get_contents(self, target, source, env, dict=None):
+ def get_contents(self, target, source, env):
actfunc = self.parent.actfunc
try:
# "self.actfunc" is a function.
# or something like that. Do the best we can.
contents = str(actfunc)
return contents
+ def subst(self, s, target, source, env):
+ # Special-case hack: Let a custom function wrapped in an
+ # ActionCaller get at the environment through which the action
+ # was called by using this hard-coded value as a special return.
+ if s == '$__env__':
+ return env
+ else:
+ return env.subst(s, 0, target, source)
def subst_args(self, target, source, env):
- return map(lambda x, e=env, t=target, s=source:
- e.subst(x, 0, t, s),
+ 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] = env.subst(self.kw[key], 0, target, source)
+ 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)
args = self.subst_args(target, source, env)
kw = self.subst_kw(target, source, env)
return apply(self.parent.strfunc, args, kw)
+ def __str__(self):
+ return apply(self.parent.strfunc, self.args, self.kw)
class ActionFactory:
"""A factory class that will wrap up an arbitrary function
def __call__(self, *args, **kw):
ac = ActionCaller(self, args, kw)
action = Action(ac, strfunction=ac.strfunction)
- # action will be a FunctionAction; if left to its own devices,
- # a genstr or str of this action will just show
- # "ActionCaller(target, source, env)". Override that with the
- # description from strfunc. Note that the apply is evaluated
- # right now; __str__ is set to a (lambda) function that just
- # returns the stored result of the evaluation whenever called.
- action.__str__ = lambda name=apply(self.strfunc, args, kw): name
return action