def show(self, string):
print string
+ def get_actions(self):
+ return [self]
+
def subst_dict(self, target, source, env):
"""Create a dictionary for substitution of construction
variables.
self.cmd_list = cmd
def execute(self, target, source, env):
+ """Execute a command action.
+
+ This will handle lists of commands as well as individual commands,
+ because construction variable substitution may turn a single
+ "command" into a list. This means that this class can actually
+ handle lists of commands, even though that's not how we use it
+ externally.
+ """
escape = env.get('ESCAPE', lambda x: x)
import SCons.Errors
raise SCons.Errors.UserError('Missing SPAWN construction variable.')
dict = self.subst_dict(target, source, env)
- import SCons.Util
cmd_list = SCons.Util.scons_subst_list(self.cmd_list, dict, {}, _rm)
for cmd_line in cmd_list:
if len(cmd_line):
def __init__(self, list):
self.list = map(lambda x: Action(x), list)
+ def get_actions(self):
+ return self.list
+
def execute(self, target, source, env):
for l in self.list:
r = l.execute(target, source, env)
class ActionTestCase(unittest.TestCase):
- def runTest(self):
+ def test_factory(self):
"""Test the Action factory
"""
def foo():
a2 = SCons.Action.Action("string")
assert isinstance(a2, SCons.Action.CommandAction), a2
+ assert a2.cmd_list == ["string"], a2.cmd_list
if hasattr(types, 'UnicodeType'):
exec "a3 = SCons.Action.Action(u'string')"
a4 = SCons.Action.Action(["x", "y", "z", [ "a", "b", "c"]])
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 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
+
class ActionBaseTestCase(unittest.TestCase):
def test_cmp(self):
assert a1 != a3
assert a2 != a3
+ 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_subst_dict(self):
"""Test substituting dictionary values in an Action
"""
assert str(d['SOURCES']) == 's', d['SOURCES']
assert str(d['SOURCE']) == 's', d['SOURCE']
-
d = a.subst_dict(target = ['t1', 't2'], source = ['s1', 's2'], env=Environment({}))
TARGETS = map(lambda x: str(x), d['TARGETS'])
TARGETS.sort()
"""
a = SCons.Action.CommandAction(["|", "$(", "$foo", "|", "$bar",
"$)", "|"])
- c = a.get_contents(target=[], source=[],
- foo = 'FFF', bar = 'BBB')
- assert c == "| $( FFF | BBB $) |"
+ c = a.get_raw_contents(target=[], source=[],
+ env=Environment({'foo':'FFF', 'bar':'BBB'}))
+ assert c == "| $( FFF | BBB $) |", c
def test_get_contents(self):
"""Test fetching the contents of a command Action
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_execute(self):
"""Test executing a list of subsidiary Actions
"""
assert a10.generator.var == 'FOO', a10.generator.var
def test_execute(self):
- """Test executing a lazy-evalueation Action
+ """Test executing a lazy-evaluation Action
"""
def f(target, source, env):
s = env['s']
if __name__ == "__main__":
suite = unittest.TestSuite()
- suite.addTest(ActionTestCase())
- suite.addTest(ActionBaseTestCase("test_cmp"))
- suite.addTest(ActionBaseTestCase("test_subst_dict"))
- for tclass in [CommandActionTestCase,
- CommandGeneratorActionTestCase,
- FunctionActionTestCase,
- ListActionTestCase,
- LazyActionTestCase]:
- for func in ["test_init", "test_execute", "test_get_contents"]:
- suite.addTest(tclass(func))
+ tclasses = [ ActionTestCase,
+ ActionBaseTestCase,
+ CommandActionTestCase,
+ CommandGeneratorActionTestCase,
+ FunctionActionTestCase,
+ ListActionTestCase,
+ LazyActionTestCase]
+ for tclass in tclasses:
+ names = unittest.getTestCaseNames(tclass, 'test_')
+ suite.addTests(map(tclass, names))
if not unittest.TextTestRunner().run(suite).wasSuccessful():
sys.exit(1)
return tlist
+ def get_actions(self):
+ return self.action.get_actions()
+
def execute(self, target, source, env):
"""Execute a builder's action to create an output object.
"""
r = builder.execute([],[],Environment(out = outfile))
assert r == expect_nonexecutable, "r == %d" % r
+ def test_get_actions(self):
+ """Test fetching the Builder's Action list
+
+ Verify that we call the underlying Action's method
+ """
+ builder = SCons.Builder.Builder(name="builder", action=SCons.Action.ListAction(["x", "y", "z"]))
+ a = builder.get_actions()
+ assert len(a) == 3, a
+ assert isinstance(a[0], SCons.Action.CommandAction), a[0]
+ assert isinstance(a[1], SCons.Action.CommandAction), a[1]
+ assert isinstance(a[2], SCons.Action.CommandAction), a[2]
+
def test_get_contents(self):
"""Test returning the signature contents of a Builder
"""
kids.sort(c)
return kids + SCons.Node.Node.all_children(self, 0)
+ def get_actions(self):
+ """A null "builder" for directories."""
+ return []
+
def build(self):
"""A null "builder" for directories."""
pass
exc_caught = 1
assert exc_caught, "Should have caught a StopError."
+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
+
if __name__ == "__main__":
suite = unittest.TestSuite()
suite.addTest(find_fileTestCase())
suite.addTest(StringDirTestCase())
suite.addTest(prepareTestCase())
+ suite.addTest(get_actionsTestCase())
if not unittest.TextTestRunner().run(suite).wasSuccessful():
sys.exit(1)
built_source = source
built_args = env
return 0
+ def get_actions(self):
+ return 'xyzzy'
def get_contents(self, target, source, env):
return 7
node.env_set(e)
assert node.env == e
+ def test_get_actions(self):
+ """Test fetching a Node's action list
+ """
+ node = SCons.Node.Node()
+ node.builder_set(Builder())
+ a = node.get_actions()
+ assert a == 'xyzzy', a
+
def test_set_bsig(self):
"""Test setting a Node's signature
"""
def generate_build_env(self):
return self.env.Override(self.overrides)
+ def get_actions(self):
+ """Fetch the action list to build."""
+ return self.builder.get_actions()
+
def build(self):
"""Actually build the node. Return the status from the build."""
# This method is called from multiple threads in a parallel build,
class BuildTask(SCons.Taskmaster.Task):
"""An SCons build task."""
def execute(self):
- t = self.targets[0]
- if t.get_state() == SCons.Node.up_to_date:
- if self.top and t.builder:
- display('scons: "%s" is up to date.' % str(self.targets[0]))
- else:
+ target = self.targets[0]
+ if target.get_state() == SCons.Node.up_to_date:
+ if self.top and target.builder:
+ display('scons: "%s" is up to date.' % str(target))
+ elif target.builder and not hasattr(target.builder, 'status'):
+ action_list = target.get_actions()
+ if not action_list:
+ return
+ env = target.generate_build_env()
if print_time:
start_time = time.time()
- self.targets[0].build()
+ try:
+ for action in action_list:
+ stat = action.execute(self.targets, target.sources, env)
+ if stat:
+ raise BuildError(node = target,
+ errstr = "Error %d" % stat)
+ except KeyboardInterrupt:
+ raise
+ except UserError:
+ raise
+ except BuildError:
+ raise
+ except:
+ raise BuildError(target, "Exception",
+ sys.exc_type,
+ sys.exc_value,
+ sys.exc_traceback)
if print_time:
finish_time = time.time()
global command_time
self.top = top
self.node = node
-
def prepare(self):
- """Called just before the task is executed."""
+ """Called just before the task is executed.
+
+ This unlinks all targets and makes all directories before
+ building anything."""
if self.targets[0].get_state() != SCons.Node.up_to_date:
- self.targets[0].prepare()
+ for t in self.targets:
+ t.prepare()
def execute(self):
"""Called to execute the task.
self.bsig = None
self.csig = None
self.state = None
+ self.prepared = None
self.parents = []
self.side_effect = 0
self.side_effects = []
built_text = built_text + " really"
def prepare(self):
- pass
+ self.prepared = 1
def children(self):
if not self.scanned:
def test_executed(self):
pass
+ def test_prepare(self):
+ """Test preparation of multiple Nodes for a task
+
+ """
+ n1 = Node("n1")
+ n2 = Node("n2")
+ tm = SCons.Taskmaster.Taskmaster([n1, n2])
+ t = tm.next_task()
+ # This next line is moderately bogus. We're just reaching
+ # in and setting the targets for this task to an array. The
+ # "right" way to do this would be to have the next_task() call
+ # set it up by having something that approximates a real Builder
+ # return this list--but that's more work than is probably
+ # warranted right now.
+ t.targets = [n1, n2]
+ t.prepare()
+ assert n1.prepared
+ assert n2.prepared
+
if __name__ == "__main__":
stderr = """scons: \*\*\* \[exit.out\] Exception
Traceback \((most recent call|innermost) last\):
- File ".+", line \d+, in .+
- File ".+", line \d+, in .+
- File ".+", line \d+, in .+
- File ".+", line \d+, in .+
- .+
-.+
+ File ".+", line \d+, in \S+
+ [^\n]+
+ File ".+", line \d+, in \S+
+ [^\n]+
+ File ".+", line \d+, in \S+
+ [^\n]+
+\S.+
"""
test.run(arguments='foo.out exit.out', stderr=stderr, status=2)
test.run(arguments = "foo.out", stderr = """scons: \*\*\* \[foo.out\] Exception
Traceback \((most recent call|innermost) last\):
- File ".+", line \d+, in .+
- File ".+", line \d+, in .+
- File ".+", line \d+, in .+
+ File ".+", line \d+, in \S+
+ [^\n]+
+ File ".+", line \d+, in \S+
+ [^\n]+
File "SConstruct", line 3, in func
raise "func exception"
func exception
expected_command_time = num(r'Command execution time: (\d+\.\d+) seconds', cmdline[0])
expected_command_time = expected_command_time + num(r'Command execution time: (\d+\.\d+) seconds', cmdline[1])
expected_command_time = expected_command_time + num(r'Command execution time: (\d+\.\d+) seconds', cmdline[2])
-expected_command_time = expected_command_time + num(r'Command execution time: (\d+\.\d+) seconds', cmdline[3])
totalline = filter(lambda x: x[:6] == "Total ", line)