From: stevenknight Date: Wed, 28 Apr 2004 17:34:07 +0000 (+0000) Subject: Support use of strfunction() with all kinds of Action objects. X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=86c3bb495127bc53ded91bab7e49fa0486e0cbe8;p=scons.git Support use of strfunction() with all kinds of Action objects. git-svn-id: http://scons.tigris.org/svn/scons/trunk@963 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/doc/man/scons.1 b/doc/man/scons.1 index e1bcf516..ba4e6901 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -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), diff --git a/src/CHANGES.txt b/src/CHANGES.txt index bba15e73..f34104d9 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -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. diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py index 6b8b1840..37665b92 100644 --- a/src/engine/SCons/Action.py +++ b/src/engine/SCons/Action.py @@ -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, s, v), + _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 diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py index bc8e39f8..3def8574 100644 --- a/src/engine/SCons/ActionTests.py +++ b/src/engine/SCons/ActionTests.py @@ -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 """