summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2004-11-15 01:48:36 (GMT)
committerSteven Knight <knight@baldmt.com>2004-11-15 01:48:36 (GMT)
commit2822ea95237efa0c8a069e764c3560a3ea221cc0 (patch)
tree6acfa7a39b0d9d69bad805e9702bef92df72e5c9
parentf654911b566927cea1761e92e93c93f2943cdd8a (diff)
downloadSCons-2822ea95237efa0c8a069e764c3560a3ea221cc0.zip
SCons-2822ea95237efa0c8a069e764c3560a3ea221cc0.tar.gz
SCons-2822ea95237efa0c8a069e764c3560a3ea221cc0.tar.bz2
Investigate getting rid of LazyCmdGenerator
-rw-r--r--src/engine/SCons/Action.py76
-rw-r--r--src/engine/SCons/ActionTests.py26
-rw-r--r--src/engine/SCons/EnvironmentTests.py2
3 files changed, 66 insertions, 38 deletions
diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py
index 3b62702..a8e6c5b 100644
--- a/src/engine/SCons/Action.py
+++ b/src/engine/SCons/Action.py
@@ -185,8 +185,7 @@ def _do_create_action(act, *args, **kw):
# of that Environment variable, so a user could put something
# like a function or a CommandGenerator in that variable
# instead of a string.
- lcg = LazyCmdGenerator(var)
- return apply(CommandGeneratorAction, (lcg,)+args, kw)
+ return apply(LazyAction, (var,)+args, kw)
commands = string.split(str(act), '\n')
if len(commands) == 1:
return apply(CommandAction, (commands[0],)+args, kw)
@@ -234,7 +233,7 @@ class ActionBase:
# it may call LazyCmdGenerator, 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.
+ # when it calls its _generate method.
self.presub_env = env
lines = string.split(str(self), '\n')
self.presub_env = None # don't need this any more
@@ -431,7 +430,7 @@ class CommandGeneratorAction(ActionBase):
self.generator = generator
self.gen_kw = kw
- def __generate(self, target, source, env, for_signature):
+ 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):
@@ -448,15 +447,15 @@ class CommandGeneratorAction(ActionBase):
env = self.presub_env or {}
except AttributeError:
env = {}
- act = self.__generate([], [], env, 1)
+ 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)
+ return self._generate(target, source, env, 1).genstring(target, source, env)
def __call__(self, target, source, env, errfunc=None, presub=_null,
show=_null, execute=_null, chdir=_null):
- act = self.__generate(target, source, env, 0)
+ act = self._generate(target, source, env, 0)
return act(target, source, env, errfunc, presub,
show, execute, chdir)
@@ -466,30 +465,55 @@ class CommandGeneratorAction(ActionBase):
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)
-
-class LazyCmdGenerator:
- """This is not really an Action, although it kind of looks like one.
- This is really a simple callable class that acts as a command
- generator. It holds on to a key into an Environment dictionary,
- then waits until execution time to see what type it is, then tries
- to create an Action out of it."""
- def __init__(self, var):
+ return self._generate(target, source, env, 1).get_contents(target, source, env, dict=None)
+
+# Ooh, polymorphism -- pretty scary, eh, kids?
+#
+# A LazyCmdAction 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
+# environment. Consequently, we want lazy evaluation and creation of
+# an Action in the case of the function, but that's overkill in the more
+# normal case of expansion to other strings.
+#
+# So we do this with a subclass that's both a generator *and*
+# a command action. The overridden methods all do a quick check
+# of the construction variable, and if it's a string we just call
+# 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.
+
+class LazyAction(CommandGeneratorAction, CommandAction):
+ def __init__(self, var, *args, **kw):
if __debug__: logInstanceCreation(self)
+ apply(CommandAction.__init__, (self, '$'+var)+args, kw)
self.var = SCons.Util.to_String(var)
+ self.gen_kw = kw
- def __str__(self):
- return 'LazyCmdGenerator: %s'%str(self.var)
+ def get_parent_class(self, env):
+ c = env.get(self.var)
+ if SCons.Util.is_String(c) and not '\n' in c:
+ return CommandAction
+ return CommandGeneratorAction
- def __call__(self, target, source, env, for_signature):
- try:
- return env[self.var]
- except KeyError:
- # The variable reference substitutes to nothing.
- return ''
+ def _generate(self, target, source, env, for_signature):
+ 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 __cmp__(self, other):
- return cmp(self.__dict__, other)
+ 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):
+ c = self.get_parent_class(env)
+ return c.get_contents(self, target, source, env, dict)
class FunctionAction(_ActionAction):
"""Class for Python function actions."""
diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py
index 74812df..f52496a 100644
--- a/src/engine/SCons/ActionTests.py
+++ b/src/engine/SCons/ActionTests.py
@@ -298,12 +298,10 @@ class ActionTestCase(unittest.TestCase):
pass
a1 = SCons.Action.Action("$FOO")
- assert isinstance(a1, SCons.Action.CommandGeneratorAction), a1
- assert isinstance(a1.generator, SCons.Action.LazyCmdGenerator), a1.generator
+ assert isinstance(a1, SCons.Action.LazyAction), a1
a2 = SCons.Action.Action("$FOO", strfunction=foo)
- assert isinstance(a2, SCons.Action.CommandGeneratorAction), a2
- assert isinstance(a2.generator, SCons.Action.LazyCmdGenerator), a2.generator
+ assert isinstance(a2, SCons.Action.LazyAction), a2
def test_no_action(self):
"""Test when the Action() factory can't create an action object
@@ -1468,16 +1466,16 @@ class LazyActionTestCase(unittest.TestCase):
def test___init__(self):
"""Test creation of a lazy-evaluation Action
"""
- # Environment variable references should create a special
- # type of CommandGeneratorAction that lazily evaluates the
- # variable.
+ # Environment variable references should create a special type
+ # of LazyAction that lazily evaluates the variable for whether
+ # it's a string or something else before doing anything.
a9 = SCons.Action.Action('$FOO')
- assert isinstance(a9, SCons.Action.CommandGeneratorAction), a9
- assert a9.generator.var == 'FOO', a9.generator.var
+ assert isinstance(a9, SCons.Action.LazyAction), a9
+ assert a9.var == 'FOO', a9.var
a10 = SCons.Action.Action('${FOO}')
- assert isinstance(a9, SCons.Action.CommandGeneratorAction), a10
- assert a10.generator.var == 'FOO', a10.generator.var
+ assert isinstance(a10, SCons.Action.LazyAction), a10
+ assert a10.var == 'FOO', a10.var
def test_genstring(self):
"""Test the lazy-evaluation Action genstring() method
@@ -1487,6 +1485,8 @@ class LazyActionTestCase(unittest.TestCase):
a = SCons.Action.Action('$BAR')
s = a.genstring([], [], env=Environment(BAR=f, s=self))
assert s == "f(target, source, env)", s
+ s = a.genstring([], [], env=Environment(BAR='xxx', s=self))
+ assert s == 'xxx', s
def test_execute(self):
"""Test executing a lazy-evaluation Action
@@ -1498,6 +1498,10 @@ class LazyActionTestCase(unittest.TestCase):
a = SCons.Action.Action('$BAR')
a([], [], env=Environment(BAR = f, s = self))
assert self.test == 1, self.test
+ cmd = r'%s %s %s lazy' % (python, act_py, outfile)
+ a([], [], env=Environment(BAR = cmd, s = self))
+ c = test.read(outfile, 'r')
+ assert c == "act.py: 'lazy'\n", c
def test_get_contents(self):
"""Test fetching the contents of a lazy-evaluation Action
diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py
index 4c9a0be..71383e7 100644
--- a/src/engine/SCons/EnvironmentTests.py
+++ b/src/engine/SCons/EnvironmentTests.py
@@ -1756,7 +1756,7 @@ f5: \
a = env.Action('$FOO')
assert a, a
- assert a.__class__ is SCons.Action.CommandGeneratorAction, a
+ assert a.__class__ is SCons.Action.LazyAction, a
a = env.Action(['$FOO', 'foo'])
assert a, a