summaryrefslogtreecommitdiffstats
path: root/src/engine
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2004-09-27 21:23:04 (GMT)
committerSteven Knight <knight@baldmt.com>2004-09-27 21:23:04 (GMT)
commit23113a29aa006beb04c9675fc0f7a02564ac5a80 (patch)
treef43576c3c7ddce67d169ed799471c6d385b5cbba /src/engine
parent3b0b62cb7fa049ae5d87268f4d2e6a8832166d9e (diff)
downloadSCons-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.py76
-rw-r--r--src/engine/SCons/ActionTests.py64
-rw-r--r--src/engine/SCons/Builder.py24
-rw-r--r--src/engine/SCons/Executor.py16
-rw-r--r--src/engine/SCons/ExecutorTests.py15
-rw-r--r--src/engine/SCons/Node/FS.py4
-rw-r--r--src/engine/SCons/Node/FSTests.py16
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())