diff options
author | Steven Knight <knight@baldmt.com> | 2004-09-27 21:23:04 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2004-09-27 21:23:04 (GMT) |
commit | 23113a29aa006beb04c9675fc0f7a02564ac5a80 (patch) | |
tree | f43576c3c7ddce67d169ed799471c6d385b5cbba /src/engine | |
parent | 3b0b62cb7fa049ae5d87268f4d2e6a8832166d9e (diff) | |
download | SCons-23113a29aa006beb04c9675fc0f7a02564ac5a80.zip SCons-23113a29aa006beb04c9675fc0f7a02564ac5a80.tar.gz SCons-23113a29aa006beb04c9675fc0f7a02564ac5a80.tar.bz2 |
Add support for changing directory when executing Actions (the to the target directory by default).
Diffstat (limited to 'src/engine')
-rw-r--r-- | src/engine/SCons/Action.py | 76 | ||||
-rw-r--r-- | src/engine/SCons/ActionTests.py | 64 | ||||
-rw-r--r-- | src/engine/SCons/Builder.py | 24 | ||||
-rw-r--r-- | src/engine/SCons/Executor.py | 16 | ||||
-rw-r--r-- | src/engine/SCons/ExecutorTests.py | 15 | ||||
-rw-r--r-- | src/engine/SCons/Node/FS.py | 4 | ||||
-rw-r--r-- | src/engine/SCons/Node/FSTests.py | 16 |
7 files changed, 117 insertions, 98 deletions
diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py index 927e3d5..ba1c240 100644 --- a/src/engine/SCons/Action.py +++ b/src/engine/SCons/Action.py @@ -191,29 +191,29 @@ def _do_create_action(act, *args, **kw): return apply(ListAction, (listCmdActions,)+args, kw) return None -def Action(act, strfunction=_null, varlist=[], presub=_null): +def Action(act, *args, **kw): """A factory for action objects.""" if SCons.Util.is_List(act): - acts = map(lambda x, s=strfunction, v=varlist, ps=presub: - _do_create_action(x, strfunction=s, varlist=v, presub=ps), + acts = map(lambda a, args=args, kw=kw: + apply(_do_create_action, (a,)+args, kw), act) - acts = filter(lambda x: not x is None, acts) + acts = filter(None, acts) if len(acts) == 1: return acts[0] else: - return ListAction(acts, strfunction=strfunction, varlist=varlist, presub=presub) + return apply(ListAction, (acts,)+args, kw) else: - return _do_create_action(act, strfunction=strfunction, varlist=varlist, presub=presub) + return apply(_do_create_action, (act,)+args, kw) class ActionBase: """Base class for actions that create output objects.""" - def __init__(self, strfunction=_null, presub=_null, **kw): + def __init__(self, strfunction=_null, presub=_null, chdir=None, **kw): if not strfunction is _null: self.strfunction = strfunction if presub is _null: - self.presub = print_actions_presub - else: - self.presub = presub + presub = print_actions_presub + self.presub = presub + self.chdir = chdir def __cmp__(self, other): return cmp(self.__dict__, other) @@ -225,7 +225,8 @@ class ActionBase: errfunc=None, presub=_null, show=_null, - execute=_null): + execute=_null, + chdir=_null): if not SCons.Util.is_List(target): target = [target] if not SCons.Util.is_List(source): @@ -233,14 +234,26 @@ class ActionBase: if presub is _null: presub = self.presub if show is _null: show = print_actions if execute is _null: execute = execute_actions + if chdir is _null: chdir = self.chdir + save_cwd = None + if chdir: + save_cwd = os.getcwd() + try: + chdir = str(chdir.abspath) + except AttributeError: + if not SCons.Util.is_String(chdir): + chdir = str(target[0].dir) if presub: t = string.join(map(str, target), 'and') l = string.join(self.presub_lines(env), '\n ') out = "Building %s with action(s):\n %s\n" % (t, l) sys.stdout.write(out) + s = None if show and self.strfunction: s = self.strfunction(target, source, env) if s: + if chdir: + s = ('os.chdir(%s)\n' % repr(chdir)) + s try: get = env.get except AttributeError: @@ -250,13 +263,20 @@ class ActionBase: if not print_func: print_func = self.print_cmd_line print_func(s, target, source, env) + stat = 0 if execute: - stat = self.execute(target, source, env) - if stat and errfunc: - errfunc(stat) - return stat - else: - return 0 + if chdir: + os.chdir(chdir) + try: + stat = self.execute(target, source, env) + if stat and errfunc: + errfunc(stat) + finally: + if save_cwd: + os.chdir(save_cwd) + if s and save_cwd: + print_func('os.chdir(%s)' % repr(save_cwd), target, source, env) + return stat def presub_lines(self, env): # CommandGeneratorAction needs a real environment @@ -273,9 +293,6 @@ class ActionBase: def genstring(self, target, source, env): return str(self) - def get_actions(self): - return [self] - def __add__(self, other): return _actionAppend(self, other) @@ -294,12 +311,12 @@ def _string_from_cmd_list(cmd_list): class CommandAction(ActionBase): """Class for command-execution actions.""" - def __init__(self, cmd, **kw): + def __init__(self, cmd, *args, **kw): # 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) - apply(ActionBase.__init__, (self,), kw) + apply(ActionBase.__init__, (self,)+args, kw) self.cmd_list = cmd def __str__(self): @@ -383,9 +400,9 @@ class CommandAction(ActionBase): class CommandGeneratorAction(ActionBase): """Class for command-generator actions.""" - def __init__(self, generator, **kw): + def __init__(self, generator, *args, **kw): if __debug__: logInstanceCreation(self) - apply(ActionBase.__init__, (self,), kw) + apply(ActionBase.__init__, (self,)+args, kw) self.generator = generator def __generate(self, target, source, env, for_signature): @@ -467,10 +484,10 @@ class LazyCmdGenerator: class FunctionAction(ActionBase): """Class for Python function actions.""" - def __init__(self, execfunction, **kw): + def __init__(self, execfunction, *args, **kw): if __debug__: logInstanceCreation(self) self.execfunction = execfunction - apply(ActionBase.__init__, (self,), kw) + apply(ActionBase.__init__, (self,)+args, kw) self.varlist = kw.get('varlist', []) def function_name(self): @@ -540,14 +557,11 @@ class FunctionAction(ActionBase): class ListAction(ActionBase): """Class for lists of other actions.""" - def __init__(self, list, **kw): + def __init__(self, list, *args, **kw): if __debug__: logInstanceCreation(self) - apply(ActionBase.__init__, (self,), kw) + apply(ActionBase.__init__, (self,)+args, kw) self.list = map(lambda x: Action(x), list) - def get_actions(self): - return self.list - def __str__(self): s = [] for l in self.list: diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py index bc2387a..af03cd5 100644 --- a/src/engine/SCons/ActionTests.py +++ b/src/engine/SCons/ActionTests.py @@ -324,7 +324,10 @@ class ActionBaseTestCase(unittest.TestCase): """Test creation of ActionBase objects """ - def func(): + def func1(): + pass + + def func2(): pass a = SCons.Action.ActionBase() @@ -334,11 +337,19 @@ class ActionBaseTestCase(unittest.TestCase): assert not hasattr(a, 'strfunction') assert not hasattr(a, 'kwarg') - a = SCons.Action.ActionBase(func) - assert a.strfunction is func, a.strfunction + a = SCons.Action.ActionBase(strfunction=func1) + assert a.strfunction is func1, a.strfunction + + a = SCons.Action.ActionBase(presub=func1) + assert a.presub is func1, a.presub + + a = SCons.Action.ActionBase(chdir=1) + assert a.chdir is 1, a.chdir - a = SCons.Action.ActionBase(strfunction=func) - assert a.strfunction is func, a.strfunction + a = SCons.Action.ActionBase(func1, func2, 'x') + assert a.strfunction is func1, a.strfunction + assert a.presub is func2, a.presub + assert a.chdir is 'x', a.chdir def test___cmp__(self): """Test Action comparison @@ -379,6 +390,10 @@ class ActionBaseTestCase(unittest.TestCase): save_execute_actions = SCons.Action.execute_actions #SCons.Action.print_actions = 0 + test = TestCmd.TestCmd(workdir = '') + test.subdir('sub', 'xyz') + os.chdir(test.workpath()) + try: env = Environment() @@ -395,6 +410,25 @@ class ActionBaseTestCase(unittest.TestCase): s = sio.getvalue() assert s == 'execfunc(["out"], ["in"])\n', s + a.chdir = 'xyz' + expect = 'os.chdir(\'%s\')\nexecfunc(["out"], ["in"])\nos.chdir(\'%s\')\n' + + sio = StringIO.StringIO() + sys.stdout = sio + result = a("out", "in", env) + assert result == 7, result + s = sio.getvalue() + assert s == expect % ('xyz', test.workpath()), s + + sio = StringIO.StringIO() + sys.stdout = sio + result = a("out", "in", env, chdir='sub') + assert result == 7, result + s = sio.getvalue() + assert s == expect % ('sub', test.workpath()), s + + a.chdir = None + SCons.Action.execute_actions = 0 sio = StringIO.StringIO() @@ -503,13 +537,6 @@ class ActionBaseTestCase(unittest.TestCase): s = a.presub_lines(Environment(ACT = 'expanded action')) assert s == ['expanded action'], s - def test_get_actions(self): - """Test the get_actions() method - """ - a = SCons.Action.Action("x") - l = a.get_actions() - assert l == [a], l - def test_add(self): """Test adding Actions to stuff.""" # Adding actions to other Actions or to stuff that can @@ -1336,19 +1363,6 @@ class ListActionTestCase(unittest.TestCase): assert isinstance(a.list[2], SCons.Action.ListAction) assert a.list[2].list[0].cmd_list == 'y' - def test_get_actions(self): - """Test the get_actions() method for ListActions - """ - a = SCons.Action.ListAction(["x", "y"]) - l = a.get_actions() - assert len(l) == 2, l - assert isinstance(l[0], SCons.Action.CommandAction), l[0] - g = l[0].get_actions() - assert g == [l[0]], g - assert isinstance(l[1], SCons.Action.CommandAction), l[1] - g = l[1].get_actions() - assert g == [l[1]], g - def test___str__(self): """Test the __str__() method for a list of subsidiary Actions """ diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index 7a96aed..8e46332 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -274,7 +274,7 @@ def Builder(**kw): return ret -def _init_nodes(builder, env, overrides, tlist, slist): +def _init_nodes(builder, env, overrides, executor_kw, tlist, slist): """Initialize lists of target and source nodes with all of the proper Builder information. """ @@ -335,7 +335,8 @@ def _init_nodes(builder, env, overrides, tlist, slist): env or builder.env, [builder.overrides, overrides], tlist, - slist) + slist, + executor_kw) # Now set up the relevant information in the target Nodes themselves. for t in tlist: @@ -410,6 +411,7 @@ class BuilderBase: env = None, single_source = 0, name = None, + chdir = _null, **overrides): if __debug__: logInstanceCreation(self, 'BuilderBase') self.action = SCons.Action.Action(action) @@ -443,6 +445,9 @@ class BuilderBase: # that don't get attached to construction environments. if name: self.name = name + self.executor_kw = {} + if not chdir is _null: + self.executor_kw['chdir'] = chdir def __nonzero__(self): raise InternalError, "Do not test for the Node.builder attribute directly; use Node.has_builder() instead" @@ -547,7 +552,7 @@ class BuilderBase: return tlist, slist - def _execute(self, env, target = None, source = _null, overwarn={}): + def _execute(self, env, target=None, source=_null, overwarn={}, executor_kw={}): if source is _null: source = target target = None @@ -572,12 +577,17 @@ class BuilderBase: builder = self else: builder = ListBuilder(self, env, tlist) - _init_nodes(builder, env, overwarn.data, tlist, slist) + _init_nodes(builder, env, overwarn.data, executor_kw, tlist, slist) return tlist - def __call__(self, env, target = None, source = _null, **kw): - return self._execute(env, target, source, OverrideWarner(kw)) + def __call__(self, env, target=None, source=_null, chdir=_null, **kw): + if chdir is _null: + ekw = self.executor_kw + else: + ekw = self.executor_kw.copy() + ekw['chdir'] = chdir + return self._execute(env, target, source, OverrideWarner(kw), ekw) def adjust_suffix(self, suff): if suff and not suff[0] in [ '.', '_', '$' ]: @@ -692,7 +702,7 @@ class MultiStepBuilder(BuilderBase): self.sdict = {} self.cached_src_suffixes = {} # source suffixes keyed on id(env) - def _execute(self, env, target = None, source = _null, overwarn={}): + def _execute(self, env, target = None, source = _null, overwarn={}, executor_kw={}): if source is _null: source = target target = None diff --git a/src/engine/SCons/Executor.py b/src/engine/SCons/Executor.py index b9d9897..47a72de 100644 --- a/src/engine/SCons/Executor.py +++ b/src/engine/SCons/Executor.py @@ -43,15 +43,17 @@ class Executor: and sources for later processing as needed. """ - def __init__(self, action, env=None, overridelist=[], targets=[], sources=[]): + def __init__(self, action, env=None, overridelist=[], + targets=[], sources=[], builder_kw={}): if __debug__: logInstanceCreation(self) + if not action: + raise SCons.Errors.UserError, "Executor must have an action." self.action = action self.env = env self.overridelist = overridelist self.targets = targets self.sources = sources[:] - if not action: - raise SCons.Errors.UserError, "Executor must have an action." + self.builder_kw = builder_kw def get_build_env(self): """Fetch or create the appropriate build Environment @@ -96,11 +98,7 @@ class Executor: involved, so only one target's pre- and post-actions will win, anyway. This is probably a bug we should fix... """ - try: - al = self.action_list - except AttributeError: - al = self.action.get_actions() - self.action_list = al + al = [self.action] try: # XXX shouldn't reach into node attributes like this return target.pre_actions + al + target.post_actions @@ -113,6 +111,8 @@ class Executor: if not action_list: return env = self.get_build_env() + kw = kw.copy() + kw.update(self.builder_kw) for action in action_list: apply(action, (self.targets, self.sources, env, errfunc), kw) diff --git a/src/engine/SCons/ExecutorTests.py b/src/engine/SCons/ExecutorTests.py index cfa2dcd..e259012 100644 --- a/src/engine/SCons/ExecutorTests.py +++ b/src/engine/SCons/ExecutorTests.py @@ -46,8 +46,9 @@ class MyEnvironment: class MyAction: def __init__(self, actions=['action1', 'action2']): self.actions = actions - def get_actions(self): - return self.actions + def __call__(self, target, source, env, errfunc, **kw): + for action in self.actions: + action(target, source, env, errfunc) def strfunction(self, target, source, env): return string.join(['STRFUNCTION'] + self.actions + target + source) def genstring(self, target, source, env): @@ -120,15 +121,15 @@ class ExecutorTestCase(unittest.TestCase): def test_get_action_list(self): """Test fetching and generating an action list""" x = SCons.Executor.Executor('b', 'e', 'o', 't', 's') - x.action_list = ['aaa'] al = x.get_action_list(MyNode([], [])) - assert al == ['aaa'], al + assert al == ['b'], al al = x.get_action_list(MyNode(['PRE'], ['POST'])) - assert al == ['PRE', 'aaa', 'POST'], al + assert al == ['PRE', 'b', 'POST'], al - x = SCons.Executor.Executor(MyAction(), None, {}, 't', 's') + a = MyAction() + x = SCons.Executor.Executor(a, None, {}, 't', 's') al = x.get_action_list(MyNode(['pre'], ['post'])) - assert al == ['pre', 'action1', 'action2', 'post'], al + assert al == ['pre', a, 'post'], al def test__call__(self): """Test calling an Executor""" diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 5cdece1..2bd68e1 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -1263,10 +1263,6 @@ class Dir(Base): kids.sort(c) self._add_child(self.implicit, self.implicit_dict, kids) - def get_actions(self): - """A null "builder" for directories.""" - return [] - def build(self, **kw): """A null "builder" for directories.""" global MkdirBuilder diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index 4501cf1..ca14c3b 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -87,9 +87,6 @@ class Action: pass def strfunction(self, targets, sources, env): return "" - def get_actions(self): - return [self] - class Builder: def __init__(self, factory, action=Action()): self.factory = factory @@ -97,9 +94,6 @@ class Builder: self.overrides = {} self.action = action - def get_actions(self): - return [self] - def targets(self, t): return [t] @@ -1541,15 +1535,6 @@ class prepareTestCase(unittest.TestCase): dir = fs.Dir("dir") dir.prepare() -class get_actionsTestCase(unittest.TestCase): - def runTest(self): - """Test the Dir's get_action() method""" - - fs = SCons.Node.FS.FS() - dir = fs.Dir('.') - a = dir.get_actions() - assert a == [], a - class SConstruct_dirTestCase(unittest.TestCase): def runTest(self): """Test setting the SConstruct directory""" @@ -2013,7 +1998,6 @@ if __name__ == "__main__": suite.addTest(stored_infoTestCase()) suite.addTest(has_src_builderTestCase()) suite.addTest(prepareTestCase()) - suite.addTest(get_actionsTestCase()) suite.addTest(SConstruct_dirTestCase()) suite.addTest(CacheDirTestCase()) suite.addTest(clearTestCase()) |