From c7dcf9e7a31681c4a0d7043f2c4406be4e7648e9 Mon Sep 17 00:00:00 2001 From: Steven Knight Date: Sun, 2 Feb 2003 18:35:15 +0000 Subject: Add a strfunction() to Command actions, and add an env argument to the FunctionAction.strfunction(). --- doc/man/scons.1 | 27 ++++++++++++++++++++------- src/CHANGES.txt | 5 +++++ src/RELEASE.txt | 16 ++++++++++++++++ src/engine/SCons/Action.py | 21 +++++++++++---------- src/engine/SCons/ActionTests.py | 36 +++++++++++++++++++++++++++++++++++- src/engine/SCons/Environment.py | 2 +- src/engine/SCons/Node/FS.py | 2 +- 7 files changed, 89 insertions(+), 20 deletions(-) diff --git a/doc/man/scons.1 b/doc/man/scons.1 index b196fac..a1eac4c 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -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. diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 4e8fcee..b29889e 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -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 diff --git a/src/RELEASE.txt b/src/RELEASE.txt index cc3adc8..d87808b 100644 --- a/src/RELEASE.txt +++ b/src/RELEASE.txt @@ -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 diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py index 646ee8d..3ab910b 100644 --- a/src/engine/SCons/Action.py +++ b/src/engine/SCons/Action.py @@ -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: diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py index 0f96899..2d3540c 100644 --- a/src/engine/SCons/ActionTests.py +++ b/src/engine/SCons/ActionTests.py @@ -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) diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index f9448bd..f9c793d 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -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) diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 0978b57..923615f 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -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) -- cgit v0.12