summaryrefslogtreecommitdiffstats
path: root/src/engine
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2005-04-26 04:14:40 (GMT)
committerSteven Knight <knight@baldmt.com>2005-04-26 04:14:40 (GMT)
commit5673cd1804e24700a0216bda0f426afeb678881a (patch)
tree4469aa200175c39f9d91eb1f655997a2aa87ced5 /src/engine
parent561e09d2d6cbda130f2af848b6ff22da1694c5e7 (diff)
downloadSCons-5673cd1804e24700a0216bda0f426afeb678881a.zip
SCons-5673cd1804e24700a0216bda0f426afeb678881a.tar.gz
SCons-5673cd1804e24700a0216bda0f426afeb678881a.tar.bz2
More flexible (and Make-like) ignoring command exit status, and suppressing printing of a command.
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/SCons/Action.py49
-rw-r--r--src/engine/SCons/ActionTests.py83
-rw-r--r--src/engine/SCons/Executor.py10
-rw-r--r--src/engine/SCons/Node/__init__.py8
4 files changed, 122 insertions, 28 deletions
diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py
index 3b0230c..353ead3 100644
--- a/src/engine/SCons/Action.py
+++ b/src/engine/SCons/Action.py
@@ -124,6 +124,9 @@ def rfile(n):
except AttributeError:
return n
+def default_exitstatfunc(s):
+ return s
+
def _actionAppend(act1, act2):
# This function knows how to slap two actions together.
# Mainly, it handles ListActions by concatenating into
@@ -245,19 +248,22 @@ if not SCons.Memoize.has_metaclass:
class _ActionAction(ActionBase):
"""Base class for actions that create output objects."""
- def __init__(self, strfunction=_null, presub=_null, chdir=None, **kw):
+ def __init__(self, strfunction=_null, presub=_null, chdir=None, exitstatfunc=None, **kw):
if not strfunction is _null:
self.strfunction = strfunction
if presub is _null:
presub = print_actions_presub
self.presub = presub
self.chdir = chdir
+ if not exitstatfunc:
+ exitstatfunc = default_exitstatfunc
+ self.exitstatfunc = exitstatfunc
def print_cmd_line(self, s, target, source, env):
sys.stdout.write(s + "\n")
def __call__(self, target, source, env,
- errfunc=None,
+ exitstatfunc=_null,
presub=_null,
show=_null,
execute=_null,
@@ -266,6 +272,7 @@ class _ActionAction(ActionBase):
target = [target]
if not SCons.Util.is_List(source):
source = [source]
+ if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
if presub is _null: presub = self.presub
if show is _null: show = print_actions
if execute is _null: execute = execute_actions
@@ -304,8 +311,7 @@ class _ActionAction(ActionBase):
os.chdir(chdir)
try:
stat = self.execute(target, source, env)
- if stat and errfunc:
- errfunc(stat)
+ stat = exitstatfunc(stat)
finally:
if save_cwd:
os.chdir(save_cwd)
@@ -350,12 +356,32 @@ class CommandAction(_ActionAction):
return string.join(map(str, self.cmd_list), ' ')
return str(self.cmd_list)
+ def process(self, target, source, env):
+ result = env.subst_list(self.cmd_list, 0, target, source)
+ silent = None
+ ignore = None
+ while 1:
+ try: c = result[0][0][0]
+ except IndexError: c = None
+ if c == '@': silent = 1
+ elif c == '-': ignore = 1
+ else: break
+ result[0][0] = result[0][0][1:]
+ try:
+ if not result[0][0]:
+ result[0] = result[0][1:]
+ except IndexError:
+ pass
+ return result, ignore, silent
+
def strfunction(self, target, source, env):
if not self.cmdstr is None:
c = env.subst(self.cmdstr, 0, target, source)
if c:
return c
- cmd_list = env.subst_list(self.cmd_list, 0, target, source)
+ cmd_list, ignore, silent = self.process(target, source, env)
+ if silent:
+ return ''
return _string_from_cmd_list(cmd_list[0])
def execute(self, target, source, env):
@@ -406,15 +432,14 @@ class CommandAction(_ActionAction):
# reasonable for just about everything else:
ENV[key] = str(value)
- cmd_list = env.subst_list(self.cmd_list, 0, target,
- map(rfile, source))
+ cmd_list, ignore, silent = self.process(target, map(rfile, source), env)
# Use len() to filter out any "command" that's zero-length.
for cmd_line in filter(len, cmd_list):
# Escape the command line for the interpreter we are using.
cmd_line = escape_list(cmd_line, escape)
result = spawn(shell, escape, cmd_line[0], cmd_line, ENV)
- if result:
+ if not ignore and result:
return result
return 0
@@ -461,10 +486,10 @@ class CommandGeneratorAction(ActionBase):
def genstring(self, target, source, env):
return self._generate(target, source, env, 1).genstring(target, source, env)
- def __call__(self, target, source, env, errfunc=None, presub=_null,
+ def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
show=_null, execute=_null, chdir=_null):
act = self._generate(target, source, env, 0)
- return act(target, source, env, errfunc, presub,
+ return act(target, source, env, exitstatfunc, presub,
show, execute, chdir)
def get_contents(self, target, source, env):
@@ -650,10 +675,10 @@ class ListAction(ActionBase):
self.list),
"")
- def __call__(self, target, source, env, errfunc=None, presub=_null,
+ def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
show=_null, execute=_null, chdir=_null):
for act in self.list:
- stat = act(target, source, env, errfunc, presub,
+ stat = act(target, source, env, exitstatfunc, presub,
show, execute, chdir)
if stat:
return stat
diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py
index 3790c8c..890abb2 100644
--- a/src/engine/SCons/ActionTests.py
+++ b/src/engine/SCons/ActionTests.py
@@ -58,7 +58,8 @@ import TestCmd
# for each test, they can just use the one.
test = TestCmd.TestCmd(workdir = '')
-test.write('act.py', """import os, string, sys
+test.write('act.py', """\
+import os, string, sys
f = open(sys.argv[1], 'w')
f.write("act.py: '" + string.join(sys.argv[2:], "' '") + "'\\n")
try:
@@ -81,7 +82,13 @@ if os.environ.has_key( 'ACTPY_PIPE' ):
sys.exit(0)
""")
+test.write('exit.py', """\
+import sys
+sys.exit(int(sys.argv[1]))
+""")
+
act_py = test.workpath('act.py')
+exit_py = test.workpath('exit.py')
outfile = test.workpath('outfile')
outfile2 = test.workpath('outfile2')
@@ -319,7 +326,6 @@ class ActionBaseTestCase(unittest.TestCase):
pass
class _ActionActionTestCase(unittest.TestCase):
-
def test__init__(self):
"""Test creation of _ActionAction objects
@@ -527,18 +533,19 @@ class _ActionActionTestCase(unittest.TestCase):
assert s == '', s
sys.stdout = save_stdout
- errfunc_result = []
+ exitstatfunc_result = []
- def errfunc(stat, result=errfunc_result):
+ def exitstatfunc(stat, result=exitstatfunc_result):
result.append(stat)
+ return stat
- result = a("out", "in", env, errfunc=errfunc)
+ result = a("out", "in", env, exitstatfunc=exitstatfunc)
assert result == 0, result
- assert errfunc_result == [], errfunc_result
+ assert exitstatfunc_result == [], exitstatfunc_result
- result = a("out", "in", env, execute=1, errfunc=errfunc)
+ result = a("out", "in", env, execute=1, exitstatfunc=exitstatfunc)
assert result == 7, result
- assert errfunc_result == [7], errfunc_result
+ assert exitstatfunc_result == [7], exitstatfunc_result
SCons.Action.execute_actions = 1
@@ -830,6 +837,38 @@ class CommandActionTestCase(unittest.TestCase):
s = act4.strfunction([t1], [s1], env)
assert s is None, s
+ act = SCons.Action.CommandAction("@foo bar")
+ s = act.strfunction([], [], env)
+ assert s == "", s
+
+ act = SCons.Action.CommandAction("@-foo bar")
+ s = act.strfunction([], [], env)
+ assert s == "", s
+
+ act = SCons.Action.CommandAction("-@foo bar")
+ s = act.strfunction([], [], env)
+ assert s == "", s
+
+ act = SCons.Action.CommandAction("-foo bar")
+ s = act.strfunction([], [], env)
+ assert s == "foo bar", s
+
+ act = SCons.Action.CommandAction("@ foo bar")
+ s = act.strfunction([], [], env)
+ assert s == "", s
+
+ act = SCons.Action.CommandAction("@- foo bar")
+ s = act.strfunction([], [], env)
+ assert s == "", s
+
+ act = SCons.Action.CommandAction("-@ foo bar")
+ s = act.strfunction([], [], env)
+ assert s == "", s
+
+ act = SCons.Action.CommandAction("- foo bar")
+ s = act.strfunction([], [], env)
+ assert s == "foo bar", s
+
def test_execute(self):
"""Test execution of command Actions
@@ -952,6 +991,34 @@ class CommandActionTestCase(unittest.TestCase):
r = act([], [], env.Copy(out = outfile))
assert r == expect_nonexecutable, "r == %d" % r
+ act = SCons.Action.CommandAction('%s %s 1' % (python, exit_py))
+ r = act([], [], env)
+ assert r == 1, r
+
+ act = SCons.Action.CommandAction('@%s %s 1' % (python, exit_py))
+ r = act([], [], env)
+ assert r == 1, r
+
+ act = SCons.Action.CommandAction('@-%s %s 1' % (python, exit_py))
+ r = act([], [], env)
+ assert r == 0, r
+
+ act = SCons.Action.CommandAction('-%s %s 1' % (python, exit_py))
+ r = act([], [], env)
+ assert r == 0, r
+
+ act = SCons.Action.CommandAction('@ %s %s 1' % (python, exit_py))
+ r = act([], [], env)
+ assert r == 1, r
+
+ act = SCons.Action.CommandAction('@- %s %s 1' % (python, exit_py))
+ r = act([], [], env)
+ assert r == 0, r
+
+ act = SCons.Action.CommandAction('- %s %s 1' % (python, exit_py))
+ r = act([], [], env)
+ assert r == 0, r
+
def _DO_NOT_EXECUTE_test_pipe_execute(self):
"""Test capturing piped output from an action
diff --git a/src/engine/SCons/Executor.py b/src/engine/SCons/Executor.py
index afe817a..afd6c49 100644
--- a/src/engine/SCons/Executor.py
+++ b/src/engine/SCons/Executor.py
@@ -93,21 +93,21 @@ class Executor:
result.update(kw)
return result
- def do_nothing(self, target, errfunc, kw):
+ def do_nothing(self, target, exitstatfunc, kw):
pass
- def do_execute(self, target, errfunc, kw):
+ def do_execute(self, target, exitstatfunc, kw):
"""Actually execute the action list."""
apply(self.action,
- (self.targets, self.sources, self.get_build_env(), errfunc),
+ (self.targets, self.sources, self.get_build_env(), exitstatfunc),
self.get_kw(kw))
# use extra indirection because with new-style objects (Python 2.2
# and above) we can't override special methods, and nullify() needs
# to be able to do this.
- def __call__(self, target, errfunc, **kw):
- self.do_execute(target, errfunc, kw)
+ def __call__(self, target, exitstatfunc, **kw):
+ self.do_execute(target, exitstatfunc, kw)
def cleanup(self):
"__reset_cache__"
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 28f1c19..f9390ea 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -227,10 +227,12 @@ class Node:
so only do thread safe stuff here. Do thread unsafe stuff in
built().
"""
- def errfunc(stat, node=self):
- raise SCons.Errors.BuildError(node=node, errstr="Error %d" % stat)
+ def exitstatfunc(stat, node=self):
+ if stat:
+ msg = "Error %d" % stat
+ raise SCons.Errors.BuildError(node=node, errstr=msg)
executor = self.get_executor()
- apply(executor, (self, errfunc), kw)
+ apply(executor, (self, exitstatfunc), kw)
def built(self):
"""Called just after this node is successfully built."""