Support use of strfunction() with all kinds of Action objects.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 28 Apr 2004 17:34:07 +0000 (17:34 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 28 Apr 2004 17:34:07 +0000 (17:34 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@963 fdb21ef1-2011-0410-befe-b5e4ea1792b1

doc/man/scons.1
src/CHANGES.txt
src/engine/SCons/Action.py
src/engine/SCons/ActionTests.py

index e1bcf516866b0c1011d60a70aa9db792c477daf2..ba4e6901043213a0d8205889f24121a3cffd9816 100644 (file)
@@ -6445,19 +6445,31 @@ and emitter functions.
 
 .SS Action Objects
 
-The Builder function will turn its
+The
+.BR Builder()
+function will turn its
 .B action
 keyword argument into an appropriate
 internal Action object.
-Occasionally, it may be more efficient
-to create an explicit Action object
-and use it to initialize multiple
-Builder objects,
-rather than let each separate Builder object
-create a separate Action.
-
-The Action method takes one or two arguments
-and returns an appropriate object for the action
+You can also explicity create Action objects
+using the
+.BR Action ()
+global function,
+which can then be passed to the
+.BR Builder ()
+function.
+This can be used to configure
+an Action object more flexibly,
+or it may simply be more efficient
+than letting each separate Builder object
+create a separate Action
+when multiple
+Builder objects need to do the same thing.
+
+The
+.BR Action ()
+global function
+returns an appropriate object for the action
 represented by the type of the first argument:
 
 .IP Action
@@ -6548,7 +6560,7 @@ a = Action(build_it)
 The second, optional argument
 is a Python function that returns
 a string to be printed to describe the action being executed.
-Like the function to build a file,
+Like a function to build a file,
 this function takes three arguments:
 .B target
 (a Node object representing the target file),
index bba15e73e237d599f025795a3e7f2039c200381c..f34104d9dade5082d50106937a2e0644a115fede 100644 (file)
@@ -98,6 +98,9 @@ RELEASE 0.96 - XXX
     or env.Execute() environment method, or may be used as a Builder
     action or in an env.Command() action list.
 
+  - Add support for the strfunction argument to all types of Actions:
+    CommandAction, ListAction, and CommandGeneratorAction.
+
   From Gary Oberbrunner:
 
   - Add a --debug=presub option to print actions prior to substitution.
index 6b8b184076f4e769febc5898554a5bc43e9f3216..37665b92e74296e5cbd153c048755506e3c290d9 100644 (file)
@@ -153,7 +153,7 @@ class CommandGenerator:
     def __radd__(self, other):
         return _actionAppend(other, self)
 
-def _do_create_action(act, strfunction=_null, varlist=[]):
+def _do_create_action(act, *args, **kw):
     """This is the actual "implementation" for the
     Action factory method, below.  This handles the
     fact that passing lists to Action() itself has
@@ -166,42 +166,42 @@ def _do_create_action(act, strfunction=_null, varlist=[]):
 
     if isinstance(act, ActionBase):
         return act
-    elif SCons.Util.is_List(act):
-        return CommandAction(act)
-    elif isinstance(act, CommandGenerator):
-        return CommandGeneratorAction(act.generator)
-    elif callable(act):
-        return FunctionAction(act, strfunction=strfunction, varlist=varlist)
-    elif SCons.Util.is_String(act):
+    if SCons.Util.is_List(act):
+        return apply(CommandAction, (act,)+args, kw)
+    if isinstance(act, CommandGenerator):
+        return apply(CommandGeneratorAction, (act.generator,)+args, kw)
+    if callable(act):
+        return apply(FunctionAction, (act,)+args, kw)
+    if SCons.Util.is_String(act):
         var=SCons.Util.get_environment_var(act)
         if var:
             # This looks like a string that is purely an Environment
             # variable reference, like "$FOO" or "${FOO}".  We do
             # something special here...we lazily evaluate the contents
-            # of that Environment variable, so a user could but something
+            # of that Environment variable, so a user could put something
             # like a function or a CommandGenerator in that variable
             # instead of a string.
-            return CommandGeneratorAction(LazyCmdGenerator(var))
-        listCmds = map(lambda x: CommandAction(x),
-                       string.split(str(act), '\n'))
-        if len(listCmds) == 1:
-            return listCmds[0]
+            lcg = LazyCmdGenerator(var)
+            return apply(CommandGeneratorAction, (lcg,)+args, kw)
+        commands = string.split(str(act), '\n')
+        if len(commands) == 1:
+            return apply(CommandAction, (commands[0],)+args, kw)
         else:
-            return ListAction(listCmds)
-    else:
-        return None
+            listCmdActions = map(lambda x: CommandAction(x), commands)
+            return apply(ListAction, (listCmdActions,)+args, kw)
+    return None
 
 def Action(act, strfunction=_null, varlist=[]):
     """A factory for action objects."""
     if SCons.Util.is_List(act):
         acts = map(lambda x, s=strfunction, v=varlist:
-                          _do_create_action(x, sv),
+                          _do_create_action(x, strfunction=s, varlist=v),
                    act)
         acts = filter(lambda x: not x is None, acts)
         if len(acts) == 1:
             return acts[0]
         else:
-            return ListAction(acts)
+            return ListAction(acts, strfunction=strfunction, varlist=varlist)
     else:
         return _do_create_action(act, strfunction=strfunction, varlist=varlist)
 
@@ -255,12 +255,14 @@ def _string_from_cmd_list(cmd_list):
 
 class CommandAction(ActionBase):
     """Class for command-execution actions."""
-    def __init__(self, cmd):
+    def __init__(self, cmd, strfunction=_null, varlist=[]):
         # Cmd list can actually be a list or a single item...basically
         # anything that we could pass in as the first arg to
         # Environment.subst_list().
         if __debug__: logInstanceCreation(self)
         self.cmd_list = cmd
+        if not strfunction is _null:
+            self.strfunction = strfunction
 
     def __str__(self):
         return str(self.cmd_list)
@@ -372,9 +374,11 @@ class CommandAction(ActionBase):
 
 class CommandGeneratorAction(ActionBase):
     """Class for command-generator actions."""
-    def __init__(self, generator):
+    def __init__(self, generator, strfunction=_null, varlist=[]):
         if __debug__: logInstanceCreation(self)
         self.generator = generator
+        if not strfunction is _null:
+            self.strfunction = strfunction
 
     def __generate(self, target, source, env, for_signature):
         # ensure that target is a list, to make it easier to write
@@ -539,9 +543,11 @@ class FunctionAction(ActionBase):
 
 class ListAction(ActionBase):
     """Class for lists of other actions."""
-    def __init__(self, list):
+    def __init__(self, list, strfunction=_null, varlist=[]):
         if __debug__: logInstanceCreation(self)
         self.list = map(lambda x: Action(x), list)
+        if not strfunction is _null:
+            self.strfunction = strfunction
 
     def get_actions(self):
         return self.list
index bc8e39f83afcc52fbfdb6d46107294f7e0c0bfbd..3def8574674944efa8933f847fed66bfdd2fe6e5 100644 (file)
@@ -176,9 +176,10 @@ else:
     python = sys.executable
 
 class ActionTestCase(unittest.TestCase):
+    """Test the Action() factory function"""
 
-    def test_factory(self):
-        """Test the Action factory
+    def test_FunctionAction(self):
+        """Test the Action() factory's creation of FunctionAction objects
         """
         def foo():
             pass
@@ -188,61 +189,134 @@ class ActionTestCase(unittest.TestCase):
         assert isinstance(a1, SCons.Action.FunctionAction), a1
         assert a1.execfunction == foo, a1.execfunction
 
-        a2 = SCons.Action.Action("string")
-        assert isinstance(a2, SCons.Action.CommandAction), a2
-        assert a2.cmd_list == "string", a2.cmd_list
+        a11 = SCons.Action.Action(foo, strfunction=bar)
+        assert isinstance(a11, SCons.Action.FunctionAction), a11
+        assert a11.execfunction == foo, a11.execfunction
+        assert a11.strfunction == bar, a11.strfunction
+
+    def test_CommandAction(self):
+        """Test the Action() factory's creation of CommandAction objects
+        """
+        a1 = SCons.Action.Action("string")
+        assert isinstance(a1, SCons.Action.CommandAction), a1
+        assert a1.cmd_list == "string", a1.cmd_list
 
         if hasattr(types, 'UnicodeType'):
-            exec "a3 = SCons.Action.Action(u'string')"
-            exec "assert isinstance(a3, SCons.Action.CommandAction), a3"
+            exec "a2 = SCons.Action.Action(u'string')"
+            exec "assert isinstance(a2, SCons.Action.CommandAction), a2"
+
+        a3 = SCons.Action.Action(["a3"])
+        assert isinstance(a3, SCons.Action.CommandAction), a3
+        assert a3.cmd_list == "a3", a3.cmd_list
+
+        a4 = SCons.Action.Action([[ "explicit", "command", "line" ]])
+        assert isinstance(a4, SCons.Action.CommandAction), a4
+        assert a4.cmd_list == [ "explicit", "command", "line" ], a4.cmd_list
+
+        def foo():
+            pass
 
-        a4 = SCons.Action.Action(["x", "y", "z", [ "a", "b", "c"]])
+        a5 = SCons.Action.Action("string", strfunction=foo)
+        assert isinstance(a5, SCons.Action.CommandAction), a5
+        assert a5.cmd_list == "string", a5.cmd_list
+        assert a5.strfunction == foo, a5.strfunction
+
+    def test_ListAction(self):
+        """Test the Action() factory's creation of ListAction objects
+        """
+        a1 = SCons.Action.Action(["x", "y", "z", [ "a", "b", "c"]])
+        assert isinstance(a1, SCons.Action.ListAction), a1
+        assert isinstance(a1.list[0], SCons.Action.CommandAction), a1.list[0]
+        assert a1.list[0].cmd_list == "x", a1.list[0].cmd_list
+        assert isinstance(a1.list[1], SCons.Action.CommandAction), a1.list[1]
+        assert a1.list[1].cmd_list == "y", a1.list[1].cmd_list
+        assert isinstance(a1.list[2], SCons.Action.CommandAction), a1.list[2]
+        assert a1.list[2].cmd_list == "z", a1.list[2].cmd_list
+        assert isinstance(a1.list[3], SCons.Action.CommandAction), a1.list[3]
+        assert a1.list[3].cmd_list == [ "a", "b", "c" ], a1.list[3].cmd_list
+
+        a2 = SCons.Action.Action("x\ny\nz")
+        assert isinstance(a2, SCons.Action.ListAction), a2
+        assert isinstance(a2.list[0], SCons.Action.CommandAction), a2.list[0]
+        assert a2.list[0].cmd_list == "x", a2.list[0].cmd_list
+        assert isinstance(a2.list[1], SCons.Action.CommandAction), a2.list[1]
+        assert a2.list[1].cmd_list == "y", a2.list[1].cmd_list
+        assert isinstance(a2.list[2], SCons.Action.CommandAction), a2.list[2]
+        assert a2.list[2].cmd_list == "z", a2.list[2].cmd_list
+
+        def foo():
+            pass
+
+        a3 = SCons.Action.Action(["x", foo, "z"])
+        assert isinstance(a3, SCons.Action.ListAction), a3
+        assert isinstance(a3.list[0], SCons.Action.CommandAction), a3.list[0]
+        assert a3.list[0].cmd_list == "x", a3.list[0].cmd_list
+        assert isinstance(a3.list[1], SCons.Action.FunctionAction), a3.list[1]
+        assert a3.list[1].execfunction == foo, a3.list[1].execfunction
+        assert isinstance(a3.list[2], SCons.Action.CommandAction), a3.list[2]
+        assert a3.list[2].cmd_list == "z", a3.list[2].cmd_list
+
+        a4 = SCons.Action.Action(["x", "y"], strfunction=foo)
         assert isinstance(a4, SCons.Action.ListAction), a4
         assert isinstance(a4.list[0], SCons.Action.CommandAction), a4.list[0]
         assert a4.list[0].cmd_list == "x", a4.list[0].cmd_list
         assert isinstance(a4.list[1], SCons.Action.CommandAction), a4.list[1]
         assert a4.list[1].cmd_list == "y", a4.list[1].cmd_list
-        assert isinstance(a4.list[2], SCons.Action.CommandAction), a4.list[2]
-        assert a4.list[2].cmd_list == "z", a4.list[2].cmd_list
-        assert isinstance(a4.list[3], SCons.Action.CommandAction), a4.list[3]
-        assert a4.list[3].cmd_list == [ "a", "b", "c" ], a4.list[3].cmd_list
+        assert a4.strfunction == foo, a4.strfunction
+
+        a5 = SCons.Action.Action("x\ny", strfunction=foo)
+        assert isinstance(a5, SCons.Action.ListAction), a5
+        assert isinstance(a5.list[0], SCons.Action.CommandAction), a5.list[0]
+        assert a5.list[0].cmd_list == "x", a5.list[0].cmd_list
+        assert isinstance(a5.list[1], SCons.Action.CommandAction), a5.list[1]
+        assert a5.list[1].cmd_list == "y", a5.list[1].cmd_list
+        assert a5.strfunction == foo, a5.strfunction
+
+    def test_CommandGeneratorAction(self):
+        """Test the Action() factory's creation of CommandGeneratorAction objects
+        """
+        def foo():
+            pass
+        def bar():
+            pass
+        cg = SCons.Action.CommandGenerator(foo)
+
+        a1 = SCons.Action.Action(cg)
+        assert isinstance(a1, SCons.Action.CommandGeneratorAction), a1
+        assert a1.generator is foo, a1.generator
 
+        a2 = SCons.Action.Action(cg, strfunction=bar)
+        assert isinstance(a2, SCons.Action.CommandGeneratorAction), a2
+        assert a2.generator is foo, a2.generator
+        assert a2.strfunction is bar, a2.strfunction
+
+    def test_LazyCmdGeneratorAction(self):
+        """Test the Action() factory's creation of lazy CommandGeneratorAction objects
+        """
+        def foo():
+            pass
+
+        a1 = SCons.Action.Action("$FOO")
+        assert isinstance(a1, SCons.Action.CommandGeneratorAction), a1
+        assert isinstance(a1.generator, SCons.Action.LazyCmdGenerator), a1.generator
+
+        a2 = SCons.Action.Action("$FOO", strfunction=foo)
+        assert isinstance(a2, SCons.Action.CommandGeneratorAction), a2
+        assert isinstance(a2.generator, SCons.Action.LazyCmdGenerator), a2.generator
+        assert a2.strfunction is foo, a2.strfunction
+
+    def test_no_action(self):
+        """Test when the Action() factory can't create an action object
+        """
         a5 = SCons.Action.Action(1)
         assert a5 is None, a5
 
-        a6 = SCons.Action.Action(a1)
-        assert a6 is a1, a6
-
-        a7 = SCons.Action.Action([[ "explicit", "command", "line" ]])
-        assert isinstance(a7, SCons.Action.CommandAction), a7
-        assert a7.cmd_list == [ "explicit", "command", "line" ], a7.cmd_list
-
-        a8 = SCons.Action.Action(["a8"])
-        assert isinstance(a8, SCons.Action.CommandAction), a8
-        assert a8.cmd_list == "a8", a8.cmd_list
-
-        a9 = SCons.Action.Action("x\ny\nz")
-        assert isinstance(a9, SCons.Action.ListAction), a9
-        assert isinstance(a9.list[0], SCons.Action.CommandAction), a9.list[0]
-        assert a9.list[0].cmd_list == "x", a9.list[0].cmd_list
-        assert isinstance(a9.list[1], SCons.Action.CommandAction), a9.list[1]
-        assert a9.list[1].cmd_list == "y", a9.list[1].cmd_list
-        assert isinstance(a9.list[2], SCons.Action.CommandAction), a9.list[2]
-        assert a9.list[2].cmd_list == "z", a9.list[2].cmd_list
-
-        a10 = SCons.Action.Action(["x", foo, "z"])
-        assert isinstance(a10, SCons.Action.ListAction), a10
-        assert isinstance(a10.list[0], SCons.Action.CommandAction), a10.list[0]
-        assert a10.list[0].cmd_list == "x", a10.list[0].cmd_list
-        assert isinstance(a10.list[1], SCons.Action.FunctionAction), a10.list[1]
-        assert a10.list[1].execfunction == foo, a10.list[1].execfunction
-        assert isinstance(a10.list[2], SCons.Action.CommandAction), a10.list[2]
-        assert a10.list[2].cmd_list == "z", a10.list[2].cmd_list
-
-        a11 = SCons.Action.Action(foo, strfunction=bar)
-        assert isinstance(a11, SCons.Action.FunctionAction), a11
-        assert a11.execfunction == foo, a11.execfunction
-        assert a11.strfunction == bar, a11.strfunction
+    def test_reentrance(self):
+        """Test the Action() factory when the action is already an Action object
+        """
+        a1 = SCons.Action.Action("foo")
+        a2 = SCons.Action.Action(a1)
+        assert a2 is a1, a2
 
 class ActionBaseTestCase(unittest.TestCase):
 
@@ -542,6 +616,12 @@ class CommandActionTestCase(unittest.TestCase):
         s = act.strfunction([t1, t2], [s1, s2], env)
         assert s == ['xyzzy t1 s1 t1 t2 s1 s2'], s
 
+        def sf(target, source, env):
+            return "sf was called"
+        act = SCons.Action.CommandAction('foo', strfunction=sf)
+        s = act.strfunction([], [], env)
+        assert s == "sf was called", s
+
     def test_execute(self):
         """Test execution of command Actions
 
@@ -897,6 +977,12 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
         assert self.dummy == 1, self.dummy
         assert s == ['xyzzy'], s
 
+        def sf(target, source, env):
+            return "sf was called"
+        a = SCons.Action.CommandGeneratorAction(f, strfunction=sf)
+        s = a.strfunction([], [], env=Environment())
+        assert s == "sf was called", s
+
     def test_execute(self):
         """Test executing a command generator Action
         """
@@ -1183,6 +1269,12 @@ class ListActionTestCase(unittest.TestCase):
         s = a.strfunction([], [], Environment())
         assert s == "f([], [])\ng([], [])\nXXX\nf([], [])", s
 
+        def sf(target, source, env):
+            return "sf was called"
+        act = SCons.Action.ListAction([f, g, "XXX", f], strfunction=sf)
+        s = act.strfunction([], [], Environment())
+        assert s == "sf was called", s
+
     def test_execute(self):
         """Test executing a list of subsidiary Actions
         """