def execute(self, **kw):
"""Execute a builder's action to create an output object.
"""
- apply(self.action.execute, (), kw)
+ return apply(self.action.execute, (), kw)
cmd = self.command % kw
if print_actions:
self.show(cmd)
+ ret = 0
if execute_actions:
pid = os.fork()
if not pid:
os.execvpe(args[0], args, ENV)
else:
# Parent process.
- os.waitpid(pid, 0)
+ pid, stat = os.waitpid(pid, 0)
+ ret = stat >> 8
+ return ret
+
class FunctionAction(ActionBase):
# if print_actions:
# XXX: WHAT SHOULD WE PRINT HERE?
if execute_actions:
- self.function(kw)
+ return self.function(kw)
class ListAction(ActionBase):
"""Class for lists of other actions."""
def execute(self, **kw):
for l in self.list:
- apply(l.execute, (), kw)
+ r = apply(l.execute, (), kw)
+ if r != 0:
+ return r
+ return 0
"""Test execution of simple Builder objects
One Builder is a string that executes an external command,
- and one is an internal Python function.
+ one is an internal Python function, one is a list
+ containing one of each.
"""
- cmd = "python %s %s xyzzy" % (act_py, outfile)
- builder = SCons.Builder.Builder(action = cmd)
- builder.execute()
+ cmd1 = "python %s %s xyzzy" % (act_py, outfile)
+ builder = SCons.Builder.Builder(action = cmd1)
+ r = builder.execute()
+ assert r == 0
assert test.read(outfile, 'r') == "act.py: xyzzy\n"
- def function(kw):
- import os, string, sys
+ def function1(kw):
f = open(kw['out'], 'w')
- f.write("function\n")
+ f.write("function1\n")
f.close()
- return not None
-
- builder = SCons.Builder.Builder(action = function)
- builder.execute(out = outfile)
- assert test.read(outfile, 'r') == "function\n"
+ return 1
+
+ builder = SCons.Builder.Builder(action = function1)
+ r = builder.execute(out = outfile)
+ assert r == 1
+ assert test.read(outfile, 'r') == "function1\n"
+
+ cmd2 = "python %s %s syzygy" % (act_py, outfile)
+ def function2(kw):
+ open(kw['out'], 'a').write("function2\n")
+ return 2
+ builder = SCons.Builder.Builder(action = [cmd2, function2])
+ r = builder.execute(out = outfile)
+ assert r == 2
+ assert test.read(outfile, 'r') == "act.py: syzygy\nfunction2\n"
def test_insuffix(self):
"""Test Builder creation with a specified input suffix
+class BuildError(Exception):
+ def __init__(self, node=None, stat=0, *args):
+ self.node = node
+ self.stat = stat
+ self.args = args
+
class InternalError(Exception):
def __init__(self, args=None):
self.args = args
class ErrorsTestCase(unittest.TestCase):
+ def test_BuildError(self):
+ """Test the BuildError exception."""
+ try:
+ raise SCons.Errors.BuildError(node = "n", stat = 7)
+ except SCons.Errors.BuildError, e:
+ assert e.node == "n"
+ assert e.stat == 7
+
def test_InternalError(self):
"""Test the InternalError exception."""
try:
import SCons.Node.FS
+
+
built_it = None
class Builder:
def execute(self, **kw):
global built_it
built_it = 1
+ return 0
class Environment:
def Dictionary(self, *args):
pass
+
+
class FSTestCase(unittest.TestCase):
def runTest(self):
"""Test FS (file system) Node operations
import sys
import unittest
+import SCons.Errors
import SCons.Node
def execute(self, **kw):
global built_it
built_it = 1
+ return 0
+
+class FailBuilder:
+ def execute(self, **kw):
+ return 1
class Environment:
def Dictionary(self, *args):
class NodeTestCase(unittest.TestCase):
+ def test_BuildException(self):
+ """Test throwing an exception on build failure.
+ """
+ node = SCons.Node.Node()
+ node.builder_set(FailBuilder())
+ node.env_set(Environment())
+ try:
+ node.build()
+ except SCons.Errors.BuildError:
+ pass
+ else:
+ raise TestFailed, "did not catch expected BuildError"
+
def test_build(self):
"""Test building a node
"""
+from SCons.Errors import BuildError
import string
def build(self):
sources_str = string.join(map(lambda x: str(x), self.sources))
- self.builder.execute(ENV = self.env.Dictionary('ENV'),
- target = str(self), source = sources_str)
+ stat = self.builder.execute(ENV = self.env.Dictionary('ENV'),
+ target = str(self), source = sources_str)
+ if stat != 0:
+ raise BuildError(node = self, stat = stat)
+ return stat
def builder_set(self, builder):
self.builder = builder
self.target = target
def execute(self):
- self.target.build()
+ try:
+ self.target.build()
+ except BuildError, e:
+ sys.stderr.write("scons: *** [%s] Error %d\n" % (e.node, e.stat))
+ raise
pass
def failed(self, task):
- pass
+ self.num_iterated = len(self.targets)
# Global variables
--- /dev/null
+
+#!/usr/bin/env python
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('one', 'two', 'three')
+
+test.write('build.py', r"""
+import sys
+exitval = int(sys.argv[1])
+if exitval == 0:
+ contents = open(sys.argv[3], 'r').read()
+ file = open(sys.argv[2], 'w')
+ file.write(contents)
+ file.close()
+sys.exit(exitval)
+""")
+
+test.write(['one', 'SConstruct'], """
+B0 = Builder(name = 'B0', action = "python ../build.py 0 %(target)s %(source)s")
+B1 = Builder(name = 'B1', action = "python ../build.py 1 %(target)s %(source)s")
+env = Environment(BUILDERS = [B0, B1])
+env.B1(target = 'f1.out', source = 'f1.in')
+env.B0(target = 'f2.out', source = 'f2.in')
+env.B0(target = 'f3.out', source = 'f3.in')
+""")
+
+test.write(['one', 'f1.in'], "one/f1.in\n")
+test.write(['one', 'f2.in'], "one/f2.in\n")
+test.write(['one', 'f3.in'], "one/f3.in\n")
+
+test.run(chdir = 'one', arguments = "f1.out f2.out f3.out",
+ stderr = "scons: *** [f1.out] Error 1\n")
+
+test.fail_test(os.path.exists(test.workpath('f1.out')))
+test.fail_test(os.path.exists(test.workpath('f2.out')))
+test.fail_test(os.path.exists(test.workpath('f3.out')))
+
+test.write(['two', 'SConstruct'], """
+B0 = Builder(name = 'B0', action = "python ../build.py 0 %(target)s %(source)s")
+B1 = Builder(name = 'B1', action = "python ../build.py 1 %(target)s %(source)s")
+env = Environment(BUILDERS = [B0, B1])
+env.B0(target = 'f1.out', source = 'f1.in')
+env.B1(target = 'f2.out', source = 'f2.in')
+env.B0(target = 'f3.out', source = 'f3.in')
+""")
+
+test.write(['two', 'f1.in'], "two/f1.in\n")
+test.write(['two', 'f2.in'], "two/f2.in\n")
+test.write(['two', 'f3.in'], "two/f3.in\n")
+
+test.run(chdir = 'two', arguments = "f1.out f2.out f3.out",
+ stderr = "scons: *** [f2.out] Error 1\n")
+
+test.fail_test(test.read(['two', 'f1.out']) != "two/f1.in\n")
+test.fail_test(os.path.exists(test.workpath('f2.out')))
+test.fail_test(os.path.exists(test.workpath('f3.out')))
+
+test.write(['three', 'SConstruct'], """
+B0 = Builder(name = 'B0', action = "python ../build.py 0 %(target)s %(source)s")
+B1 = Builder(name = 'B1', action = "python ../build.py 1 %(target)s %(source)s")
+env = Environment(BUILDERS = [B0, B1])
+env.B0(target = 'f1.out', source = 'f1.in')
+env.B0(target = 'f2.out', source = 'f2.in')
+env.B1(target = 'f3.out', source = 'f3.in')
+""")
+
+test.write(['three', 'f1.in'], "three/f1.in\n")
+test.write(['three', 'f2.in'], "three/f2.in\n")
+test.write(['three', 'f3.in'], "three/f3.in\n")
+
+test.run(chdir = 'three', arguments = "f1.out f2.out f3.out",
+ stderr = "scons: *** [f3.out] Error 1\n")
+
+test.fail_test(test.read(['three', 'f1.out']) != "three/f1.in\n")
+test.fail_test(test.read(['three', 'f2.out']) != "three/f2.in\n")
+test.fail_test(os.path.exists(test.workpath('f3.out')))
+
+test.pass_test()
file = open(sys.argv[1], 'w')
file.write(contents)
file.close()
+sys.exit(0)
""")
test.write('SConstruct', """