Add a strfunction() to Command actions, and add an env argument to the FunctionAction...
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sun, 2 Feb 2003 18:35:15 +0000 (18:35 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sun, 2 Feb 2003 18:35:15 +0000 (18:35 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@570 fdb21ef1-2011-0410-befe-b5e4ea1792b1

doc/man/scons.1
src/CHANGES.txt
src/RELEASE.txt
src/engine/SCons/Action.py
src/engine/SCons/ActionTests.py
src/engine/SCons/Environment.py
src/engine/SCons/Node/FS.py

index b196fac45429a9e1ef3e1e6e54fb80a246e83649..a1eac4cdead3b1a0b8149a6ceb94eaecb1869d0b 100644 (file)
@@ -2993,7 +2993,7 @@ The Python function takes three keyword arguments,
 .B source
 (a Node object representing the source file)
 and
-.BR env
+.B env
 (the construction environment
 used for building the target file).
 The
@@ -3029,17 +3029,30 @@ a = Action(build_it)
 
 The second, optional argument
 is a Python function that returns
-a string to be printed describing the action being executed.
-This function takes two arguments,
-an array of targets to be created by the function action,
-and an array of sources used to create the target(s):
+a string to be printed to describe the action being executed.
+Like the function to build a file,
+this function takes three arguments:
+.B target
+(a Node object representing the target file),
+.B source
+(a Node object representing the source file)
+and
+.BR env
+(a construction environment).
+The
+.B target
+and
+.B source
+arguments may be lists of Node objects if there is
+more than one target file or source file.
+Examples:
 
 .ES
 def build_it(target, source, env):
     # build the target from the source
     return 0
 
-def string_it(target, source):
+def string_it(target, source, env):
     return "building '%s' from '%s'" % (target[0], source[0])
 
 # Use a positional argument.
@@ -3056,7 +3069,7 @@ in the signature of the Action
 when deciding whether a target should
 be rebuilt because the action changed.
 This is necessary whenever you want a target to
-be rebuilt by an action when a specific
+be rebuilt when a specific
 construction variable changes,
 because the underlying Python code for a function
 will not change when the value of the construction variable does.
index 4e8fcee4d4c2f3546e593aa0c02f606f60f01778..b29889e100a187a4cbe1b721a71eec7e83a20705 100644 (file)
@@ -49,6 +49,11 @@ RELEASE 0.11 - XXX
   - Clean up error messages from problems duplicating into read-only
     BuildDir directories or into read-only files.
 
+  - Add a CommandAction.strfunction() method, and add an "env" argument
+    to the FunctionAction.strfunction() method, so that all Action
+    objects have strfunction() methods, and the functions for building
+    and returning a string both take the same arguments.
+
   From Steve Leblanc:
 
   - Fix the output of -c -n when directories are involved, so it
index cc3adc8b8dd1b3381e50d1cf56d7006c6513a0aa..d87808b6b7aab77a8df064477376381ed5bb477e 100644 (file)
@@ -56,6 +56,22 @@ RELEASE 0.10 - Thu, 16 Jan 2003 04:11:46 -0600
 
         env['BUILDERS']['newbuilder'] = foo
 
+  - An "env" argument has been added to the calls to all functions that
+    return a string for a Python function Action.  This makes the string
+    function and build function calls take the same arguments:
+
+        def build_it(target, source, env):
+            # build the target from the source
+            return 0
+
+        def string_it(target, source, env):
+            return "building '%s' from '%s'" % (target[0], source[0])
+
+        a = Action(build_it, string_it)
+
+    If you have defined a strfunction() for a Python function Action,
+    you will need to add a third "env" argument to your function call.
+
   Please note the following important changes since release 0.09:
 
     - The Scanner interface has been changed to make it easier to
index 646ee8dc061c4eeb2302e4461d57d74d69155c17..3ab910b6cb088497420bd8b389ad9609809663a2 100644 (file)
@@ -227,6 +227,11 @@ class CommandAction(ActionBase):
     def __init__(self, cmd):
         self.cmd_list = cmd
 
+    def strfunction(self, target, source, env):
+        dict = self.subst_dict(target, source, env)
+        cmd_list = SCons.Util.scons_subst_list(self.cmd_list, dict, {}, _rm)
+        return map(_string_from_cmd_list, cmd_list)
+
     def __call__(self, target, source, env):
         """Execute a command action.
 
@@ -352,9 +357,11 @@ class FunctionAction(ActionBase):
     def __init__(self, execfunction, strfunction=_null, varlist=[]):
         self.execfunction = execfunction
         if strfunction is _null:
-            def strfunction(target, source, execfunction=execfunction):
+            def strfunction(target, source, env, execfunction=execfunction):
                 def quote(s):
                     return '"' + str(s) + '"'
+                def array(a, q=quote):
+                    return '[' + string.join(map(lambda x, q=q: q(x), a), ", ") + ']'
                 try:
                     name = execfunction.__name__
                 except AttributeError:
@@ -362,14 +369,8 @@ class FunctionAction(ActionBase):
                         name = execfunction.__class__.__name__
                     except AttributeError:
                         name = "unknown_python_function"
-                if len(target) == 1:
-                    tstr = quote(target[0])
-                else:
-                    tstr = str(map(lambda x, q=quote: q(x), target))
-                if len(source) == 1:
-                    sstr = quote(source[0])
-                else:
-                    sstr = str(map(lambda x, q=quote: q(x), source))
+                tstr = len(target) == 1 and quote(target[0]) or array(target)
+                sstr = len(source) == 1 and quote(source[0]) or array(source)
                 return "%s(%s, %s)" % (name, tstr, sstr)
         self.strfunction = strfunction
         self.varlist = varlist
@@ -381,7 +382,7 @@ class FunctionAction(ActionBase):
         if not SCons.Util.is_List(source):
             source = [source]
         if print_actions and self.strfunction:
-            s = self.strfunction(target, source)
+            s = self.strfunction(target, source, env)
             if s:
                 self.show(s)
         if execute_actions:
index 0f96899f4c803e0c8a14fc2df35755f2c820ddae..2d3540c4816cbea2227e934eb84fdd07e24fb668 100644 (file)
@@ -31,6 +31,7 @@ def Func():
     pass
 
 import os
+import StringIO
 import sys
 import types
 import unittest
@@ -70,6 +71,10 @@ outfile2 = test.workpath('outfile2')
 
 scons_env = SCons.Environment.Environment()
 
+# Capture all the stuff the Actions will print,
+# so it doesn't clutter the output.
+sys.stdout = StringIO.StringIO()
+
 class Environment:
     def __init__(self, **kw):
         self.d = {}
@@ -319,6 +324,35 @@ class CommandActionTestCase(unittest.TestCase):
         a = SCons.Action.CommandAction(["xyzzy"])
         assert a.cmd_list == [ "xyzzy" ], a.cmd_list
 
+    def test_strfunction(self):
+        """Test fetching the string representation of command Actions
+        """
+        act = SCons.Action.CommandAction('xyzzy $TARGET $SOURCE')
+        s = act.strfunction([], [], Environment())
+        assert s == ['xyzzy'], s
+        s = act.strfunction(['target'], ['source'], Environment())
+        assert s == ['xyzzy target source'], s
+        s = act.strfunction(['t1', 't2'], ['s1', 's2'], Environment())
+        assert s == ['xyzzy t1 s1'], s
+
+        act = SCons.Action.CommandAction('xyzzy $TARGETS $SOURCES')
+        s = act.strfunction([], [], Environment())
+        assert s == ['xyzzy'], s
+        s = act.strfunction(['target'], ['source'], Environment())
+        assert s == ['xyzzy target source'], s
+        s = act.strfunction(['t1', 't2'], ['s1', 's2'], Environment())
+        assert s == ['xyzzy t1 t2 s1 s2'], s
+
+        act = SCons.Action.CommandAction(['xyzzy',
+                                          '$TARGET', '$SOURCE',
+                                          '$TARGETS', '$SOURCES'])
+        s = act.strfunction([], [], Environment())
+        assert s == ['xyzzy'], s
+        s = act.strfunction(['target'], ['source'], Environment())
+        assert s == ['xyzzy target source target source'], s
+        s = act.strfunction(['t1', 't2'], ['s1', 's2'], Environment())
+        assert s == ['xyzzy t1 s1 t1 t2 s1 s2'], s
+
     def test_execute(self):
         """Test execution of command Actions
 
@@ -663,7 +697,7 @@ class FunctionActionTestCase(unittest.TestCase):
         def build_it(target, source, env, self=self):
             self.build_it = 1
             return 0
-        def string_it(target, source, self=self):
+        def string_it(target, source, env, self=self):
             self.string_it = 1
             return None
         act = SCons.Action.FunctionAction(build_it, string_it)
index f9448bd3dd1d061e064faa02578d36058da748ab..f9c793d775b8740a3437fd4c63b6783d97ef69c1 100644 (file)
@@ -47,7 +47,7 @@ import SCons.Tool
 import SCons.Util
 import SCons.Warnings
 
-def installString(target, source):
+def installString(target, source, env):
     return 'Install file: "%s" as "%s"' % (source[0], target[0])
 
 installAction = SCons.Action.Action(SCons.Node.FS.LinkFunc, installString)
index 0978b574a9f263a62cb50d95b570aa8cde79c953..923615ffc19ce87fdb302a640ca50ab00c291f4c 100644 (file)
@@ -89,7 +89,7 @@ def LinkFunc(target, source, env):
 
 Link = SCons.Action.Action(LinkFunc, None)
 
-def LocalString(target, source):
+def LocalString(target, source, env):
     return 'Local copy of %s from %s' % (target[0], source[0])
 
 LocalCopy = SCons.Action.Action(LinkFunc, LocalString)