def Func():
pass
+import os
import sys
import types
import unittest
+import UserDict
import SCons.Action
-import TestCmd
+import SCons.Environment
import SCons.Errors
-import UserDict
+import TestCmd
-import SCons.Environment
-def Environment(dict):
- return apply(SCons.Environment.Environment, (), dict)
+# Initial setup of the common environment for all tests,
+# a temporary working directory containing a
+# script for writing arguments to an output file.
+#
+# We don't do this as a setUp() method because it's
+# unnecessary to create a separate directory and script
+# for each test, they can just use the one.
+test = TestCmd.TestCmd(workdir = '')
+
+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:
+ if sys.argv[3]:
+ f.write("act.py: '" + os.environ[sys.argv[3]] + "'\\n")
+except:
+ pass
+f.close()
+sys.exit(0)
+""")
+
+act_py = test.workpath('act.py')
+
+outfile = test.workpath('outfile')
+outfile2 = test.workpath('outfile2')
+
+scons_env = SCons.Environment.Environment()
+
+class Environment:
+ def __init__(self, **kw):
+ self.d = {}
+ self.d['SHELL'] = scons_env['SHELL']
+ self.d['SPAWN'] = scons_env['SPAWN']
+ self.d['ESCAPE'] = scons_env['ESCAPE']
+ for k, v in kw.items():
+ self.d[k] = v
+ def subst(self, s):
+ if not SCons.Util.is_String(s):
+ return s
+ try:
+ if s[0] == '$':
+ return self.d.get(s[1:], '')
+ except IndexError:
+ pass
+ return self.d.get(s, s)
+ def __getitem__(self, item):
+ return self.d[item]
+ def has_key(self, item):
+ return self.d.has_key(item)
+ def get(self, key, value):
+ return self.d.get(key, value)
+ def items(self):
+ return self.d.items()
+
+python = sys.executable
class ActionTestCase(unittest.TestCase):
pass
a1 = SCons.Action.Action(foo)
assert isinstance(a1, SCons.Action.FunctionAction), a1
+ assert a1.function == foo, a1.function
a2 = SCons.Action.Action("string")
assert isinstance(a2, SCons.Action.CommandAction), a2
assert isinstance(a9.list[2], SCons.Action.CommandAction), a9.list[2]
assert a9.list[2].cmd_list == ["z"], a9.list[2].cmd_list
+ a10 = SCons.Action.Action(["x", foo, "z"])
+ assert isinstance(a10, SCons.Action.ListAction), a10
+ assert isinstance(a10.list[0], SCons.Action.CommandAction), a10.list[0]
+ assert a10.list[0].cmd_list == ["x"], a10.list[0].cmd_list
+ assert isinstance(a10.list[1], SCons.Action.FunctionAction), a10.list[1]
+ assert a10.list[1].function == foo, a10.list[1].function
+ assert isinstance(a10.list[2], SCons.Action.CommandAction), a10.list[2]
+ assert a10.list[2].cmd_list == ["z"], a10.list[2].cmd_list
+
class ActionBaseTestCase(unittest.TestCase):
def test_cmp(self):
"""
a = SCons.Action.Action("x")
- d = a.subst_dict([],[],Environment({'a' : 'A', 'b' : 'B'}))
+ d = a.subst_dict([], [], Environment(a = 'A', b = 'B'))
assert d['a'] == 'A', d
assert d['b'] == 'B', d
- d = a.subst_dict(target = 't', source = 's',env=Environment({}))
+ d = a.subst_dict(target = 't', source = 's', env = Environment())
assert str(d['TARGETS']) == 't', d['TARGETS']
assert str(d['TARGET']) == 't', d['TARGET']
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({}))
+ d = a.subst_dict(target = ['t1', 't2'],
+ source = ['s1', 's2'],
+ env = Environment())
TARGETS = map(lambda x: str(x), d['TARGETS'])
TARGETS.sort()
assert TARGETS == ['t1', 't2'], d['TARGETS']
def rstr(self):
return 'rstr-' + self.name
- d = a.subst_dict(target = [N('t3'), 't4'], source = ['s3', N('s4')], env=Environment({}))
+ d = a.subst_dict(target = [N('t3'), 't4'],
+ source = ['s3', N('s4')],
+ env = Environment())
TARGETS = map(lambda x: str(x), d['TARGETS'])
TARGETS.sort()
assert TARGETS == ['t3', 't4'], d['TARGETS']
assert a.cmd_list == [ "xyzzy" ], a.cmd_list
def test_execute(self):
- """Test executing a command Action
+ """Test execution of command Actions
+
"""
- self.test_set_handler()
- pass
+ cmd1 = r'%s %s %s xyzzy' % (python, act_py, outfile)
+
+ act = SCons.Action.CommandAction(cmd1)
+ r = act.execute([], [], Environment())
+ assert r == 0
+ c = test.read(outfile, 'r')
+ assert c == "act.py: 'xyzzy'\n", c
+
+ cmd2 = r'%s %s %s $TARGET' % (python, act_py, outfile)
+
+ act = SCons.Action.CommandAction(cmd2)
+ r = act.execute('foo', [], Environment())
+ assert r == 0
+ c = test.read(outfile, 'r')
+ assert c == "act.py: 'foo'\n", c
+
+ cmd3 = r'%s %s %s ${TARGETS}' % (python, act_py, outfile)
+
+ act = SCons.Action.CommandAction(cmd3)
+ r = act.execute(['aaa', 'bbb'], [], Environment())
+ assert r == 0
+ c = test.read(outfile, 'r')
+ assert c == "act.py: 'aaa' 'bbb'\n", c
+
+ cmd4 = r'%s %s %s $SOURCES' % (python, act_py, outfile)
+
+ act = SCons.Action.CommandAction(cmd4)
+ r = act.execute([], ['one', 'two'], Environment())
+ assert r == 0
+ c = test.read(outfile, 'r')
+ assert c == "act.py: 'one' 'two'\n", c
+
+ cmd4 = r'%s %s %s ${SOURCES[:2]}' % (python, act_py, outfile)
+
+ act = SCons.Action.CommandAction(cmd4)
+ r = act.execute([],
+ source = ['three', 'four', 'five'],
+ env = Environment())
+ assert r == 0
+ c = test.read(outfile, 'r')
+ assert c == "act.py: 'three' 'four'\n", c
+
+ cmd5 = r'%s %s %s $TARGET XYZZY' % (python, act_py, outfile)
+
+ act = SCons.Action.CommandAction(cmd5)
+ r = act.execute(target = 'out5',
+ source = [],
+ env = Environment(ENV = {'XYZZY' : 'xyzzy'}))
+ assert r == 0
+ c = test.read(outfile, 'r')
+ assert c == "act.py: 'out5' 'XYZZY'\nact.py: 'xyzzy'\n", c
+
+ class Obj:
+ def __init__(self, str):
+ self._str = str
+ def __str__(self):
+ return self._str
+
+ cmd6 = r'%s %s %s ${TARGETS[1]} $TARGET ${SOURCES[:2]}' % (python, act_py, outfile)
+
+ act = SCons.Action.CommandAction(cmd6)
+ r = act.execute(target = [Obj('111'), Obj('222')],
+ source = [Obj('333'), Obj('444'), Obj('555')],
+ env = Environment())
+ assert r == 0
+ c = test.read(outfile, 'r')
+ assert c == "act.py: '222' '111' '333' '444'\n", c
+
+ cmd7 = '%s %s %s one\n\n%s %s %s two' % (python, act_py, outfile,
+ python, act_py, outfile)
+ expect7 = '%s %s %s one\n%s %s %s two\n' % (python, act_py, outfile,
+ python, act_py, outfile)
+
+ act = SCons.Action.CommandAction(cmd7)
+
+ global show_string
+ show_string = ""
+ def my_show(string):
+ global show_string
+ show_string = show_string + string + "\n"
+ act.show = my_show
+
+ r = act.execute([], [], Environment())
+ assert r == 0
+ assert show_string == expect7, show_string
+
+ if os.name == 'nt':
+ # NT treats execs of directories and non-executable files
+ # as "file not found" errors
+ expect_nonexistent = 1
+ expect_nonexecutable = 1
+ else:
+ expect_nonexistent = 127
+ expect_nonexecutable = 126
+
+ # Test that a nonexistent command returns 127
+ act = SCons.Action.CommandAction(python + "_XyZzY_")
+ r = act.execute([], [], Environment(out = outfile))
+ assert r == expect_nonexistent, "r == %d" % r
+
+ # Test that trying to execute a directory returns 126
+ dir, tail = os.path.split(python)
+ act = SCons.Action.CommandAction(dir)
+ r = act.execute([], [], Environment(out = outfile))
+ assert r == expect_nonexecutable, "r == %d" % r
+
+ # Test that trying to execute a non-executable file returns 126
+ act = SCons.Action.CommandAction(outfile)
+ r = act.execute([], [], Environment(out = outfile))
+ assert r == expect_nonexecutable, "r == %d" % r
def test_set_handler(self):
"""Test setting the command handler...
assert 0, "should have gotten user error"
a = SCons.Action.CommandAction(["xyzzy"])
- a.execute([],[],Environment({'SPAWN':func}))
+ a.execute([], [], Environment(SPAWN = func))
assert t.executed == [ 'xyzzy' ]
a = SCons.Action.CommandAction(["xyzzy"])
- a.execute([],[],Environment({'SPAWN':func, 'SHELL':'fake shell'}))
+ a.execute([], [], Environment(SPAWN = func, SHELL = 'fake shell'))
assert t.executed == [ 'xyzzy' ]
assert t.shell == 'fake shell'
a = SCons.Action.CommandAction([ LiteralStr("xyzzy") ])
- a.execute([],[],Environment({'SPAWN':func, 'ESCAPE':escape_func}))
+ a.execute([], [], Environment(SPAWN = func, ESCAPE = escape_func))
assert t.executed == [ '**xyzzy**' ], t.executed
def test_get_raw_contents(self):
a = SCons.Action.CommandAction(["|", "$(", "$foo", "|", "$bar",
"$)", "|"])
c = a.get_raw_contents(target=[], source=[],
- env=Environment({'foo':'FFF', 'bar':'BBB'}))
+ env=Environment(foo = 'FFF', bar = 'BBB'))
assert c == "| $( FFF | BBB $) |", c
def test_get_contents(self):
a = SCons.Action.CommandAction(["|", "$(", "$foo", "|", "$bar",
"$)", "|"])
c = a.get_contents(target=[], source=[],
- env=Environment({'foo':'FFF', 'bar':'BBB'}))
+ env=Environment(foo = 'FFF', bar = 'BBB'))
assert c == "| |", c
class CommandGeneratorActionTestCase(unittest.TestCase):
def f(target, source, env, for_signature, self=self):
dummy = env['dummy']
self.dummy = dummy
- s = env.subst("$FOO $( bar $) baz")
- assert s == 'foo baz\nbar ack bar baz', s
- s = env.subst("$FOO $( bar $) baz", raw=1)
- assert s == 'foo baz\nbar ack $( bar $) baz', s
- s = env.subst_list("$FOO $( bar $) baz")
- assert s == [[ 'foo', 'baz' ], [ 'bar', 'ack', 'bar', 'baz' ]], s
- s = env.subst_list("$FOO $( bar $) baz", raw=1)
- assert s == [[ 'foo', 'baz' ],
- [ 'bar', 'ack', '$(', 'bar', '$)', 'baz' ]], s
+ s = env.subst("$FOO")
+ assert s == 'foo baz\nbar ack', s
return "$FOO"
def func_action(target, source, env, self=self):
dummy=env['dummy']
- s = env.subst('$foo $( bar $)')
- assert s == 'bar bar', s
- s = env.subst('$foo $( bar $)', raw=1)
- assert s == 'bar $( bar $)', s
- s = env.subst_list([ '$foo', '$(', 'bar', '$)' ])
- assert s == [[ 'bar', 'bar' ]], s
- s = env.subst_list([ '$foo', '$(', 'bar', '$)' ], raw=1)
- assert s == [[ 'bar', '$(', 'bar', '$)' ]], s
+ s = env.subst('$foo')
+ assert s == 'bar', s
self.dummy=dummy
def f2(target, source, env, for_signature, f=func_action):
return f
self.dummy = 0
self.cmd = []
self.args = []
- a.execute([],[],env=Environment({ 'FOO' : 'foo baz\nbar ack',
- 'dummy' : 1,
- 'SPAWN':ch}))
+ a.execute([], [], env=Environment(FOO = 'foo baz\nbar ack',
+ dummy = 1,
+ SPAWN = ch))
assert self.dummy == 1, self.dummy
assert self.cmd == ['foo', 'bar'], self.cmd
assert self.args == [[ 'foo', 'baz' ], [ 'bar', 'ack' ]], self.args
- b=SCons.Action.CommandGeneratorAction(f2)
+ b = SCons.Action.CommandGeneratorAction(f2)
self.dummy = 0
- b.execute(target=[], source=[], env=Environment({ 'foo' : 'bar',
- 'dummy' : 2 }))
+ b.execute(target=[], source=[], env=Environment(foo = 'bar',
+ dummy = 2 ))
assert self.dummy==2, self.dummy
del self.dummy
self.t.rfile_called = 1
def f3(target, source, env, for_signature):
return ''
- c=SCons.Action.CommandGeneratorAction(f3)
- c.execute(target=[], source=DummyFile(self), env=Environment({}))
+ c = SCons.Action.CommandGeneratorAction(f3)
+ c.execute(target=[], source=DummyFile(self), env=Environment())
assert self.rfile_called
def test_get_contents(self):
a = SCons.Action.CommandGeneratorAction(f)
c = a.get_contents(target=[], source=[],
- env=Environment({'foo':'FFF', 'bar' : 'BBB'}))
+ env=Environment(foo = 'FFF', bar = 'BBB'))
assert c == "guux FFF BBB", c
s.inc = s.inc + 1
s.target = target
s.source=source
- assert env.subst("foo$BAR") == 'foofoo bar', env.subst("foo$BAR")
- assert env.subst_list("foo$BAR") == [ [ 'foofoo', 'bar' ] ], \
- env.subst_list("foo$BAR")
+ assert env.subst("$BAR") == 'foo bar', env.subst("$BAR")
return 0
a = SCons.Action.FunctionAction(f)
- a.execute(target=1, source=2, env=Environment({'BAR':'foo bar','s':self}))
+ a.execute(target=1, source=2, env=Environment(BAR = 'foo bar',
+ s = self))
assert self.inc == 1, self.inc
assert self.source == [2], self.source
assert self.target == [1], self.target
+ global count
+ count = 0
+ def function1(target, source, env):
+ global count
+ count = count + 1
+ for t in target:
+ open(t, 'w').write("function1\n")
+ return 1
+
+ act = SCons.Action.FunctionAction(function1)
+ r = None
+ try:
+ r = act.execute(target = [outfile, outfile2],
+ source=[],
+ env=Environment())
+ except SCons.Errors.BuildError:
+ pass
+ assert r == 1
+ assert count == 1
+ c = test.read(outfile, 'r')
+ assert c == "function1\n", c
+ c = test.read(outfile2, 'r')
+ assert c == "function1\n", c
+
+ class class1a:
+ def __init__(self, target, source, env):
+ open(env['out'], 'w').write("class1a\n")
+
+ act = SCons.Action.FunctionAction(class1a)
+ r = act.execute([], [], Environment(out = outfile))
+ assert r.__class__ == class1a
+ c = test.read(outfile, 'r')
+ assert c == "class1a\n", c
+
+ class class1b:
+ def __call__(self, target, source, env):
+ open(env['out'], 'w').write("class1b\n")
+ return 2
+
+ act = SCons.Action.FunctionAction(class1b())
+ r = act.execute([], [], Environment(out = outfile))
+ assert r == 2
+ c = test.read(outfile, 'r')
+ assert c == "class1b\n", c
+
def test_get_contents(self):
"""Test fetching the contents of a function Action
"""
a = SCons.Action.FunctionAction(Func)
- c = a.get_contents(target=[], source=[], env=Environment({}))
+ c = a.get_contents(target=[], source=[], env=Environment())
assert c == "\177\036\000\177\037\000d\000\000S", repr(c)
class ListActionTestCase(unittest.TestCase):
s = env['s']
s.inc = s.inc + 1
a = SCons.Action.ListAction([f, f, f])
- a.execute([],[],Environment({'s':self}))
+ a.execute([], [], Environment(s = self))
assert self.inc == 3, self.inc
+ cmd2 = r'%s %s %s syzygy' % (python, act_py, outfile)
+
+ def function2(target, source, env):
+ open(env['out'], 'a').write("function2\n")
+ return 0
+
+ class class2a:
+ def __call__(self, target, source, env):
+ open(env['out'], 'a').write("class2a\n")
+ return 0
+
+ class class2b:
+ def __init__(self, target, source, env):
+ open(env['out'], 'a').write("class2b\n")
+ act = SCons.Action.ListAction([cmd2, function2, class2a(), class2b])
+ r = act.execute([], [], Environment(out = outfile))
+ assert r.__class__ == class2b
+ c = test.read(outfile, 'r')
+ assert c == "act.py: 'syzygy'\nfunction2\nclass2a\nclass2b\n", c
+
def test_get_contents(self):
"""Test fetching the contents of a list of subsidiary Actions
"""
a = SCons.Action.ListAction(["x",
SCons.Action.CommandGenerator(gen),
"z"])
- c = a.get_contents(target=[], source=[], env=Environment({'s':self}))
+ c = a.get_contents(target=[], source=[], env=Environment(s = self))
assert self.foo==1, self.foo
assert c == "xyz", c
s.test=1
return 0
a = SCons.Action.Action('$BAR')
- a.execute([],[], env=Environment({'BAR':f,'s':self}))
+ a.execute([], [], env=Environment(BAR = f, s = self))
assert self.test == 1, self.test
def test_get_contents(self):
"""
a = SCons.Action.Action("${FOO}")
c = a.get_contents(target=[], source=[],
- env=Environment({'FOO':[["This", "is", "$(", "a", "$)", "test"]]}))
+ env = Environment(FOO = [["This", "is", "$(", "a", "$)", "test"]]))
assert c == "This is test", c
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.
- """
- return self.action.execute(target, source, env)
-
def get_raw_contents(self, target, source, env):
"""Fetch the "contents" of the builder's action.
"""
self.multi = builder.multi
self.name = "ListBuilder(%s)"%builder.name
- def execute(self, target, source, env):
- if hasattr(self, 'status'):
- return self.status
- for t in self.tlist:
- # unlink all targets and make all directories
- # before building anything
- t.prepare()
- target = self.tlist
- self.status = self.builder.execute(target, source, env)
- for t in self.tlist:
- if not t is target:
- t.build()
- return self.status
-
def targets(self, node):
"""Return the list of targets for this builder instance.
"""
# for each test, they can just use the one.
test = TestCmd.TestCmd(workdir = '')
-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:
- if sys.argv[3]:
- f.write("act.py: '" + os.environ[sys.argv[3]] + "'\\n")
-except:
- pass
-f.close()
-sys.exit(0)
-""")
-
-act_py = test.workpath('act.py')
outfile = test.workpath('outfile')
outfile2 = test.workpath('outfile2')
show_string = None
env_scanner = None
-count = 0
scons_env = SCons.Environment.Environment()
builder = SCons.Builder.Builder(name="builder", action="foo")
assert builder.action.cmd_list == ["foo"]
+ def func():
+ pass
+ builder = SCons.Builder.Builder(name="builder", action=func)
+ assert builder.action.function == func
+
def test_generator(self):
"""Test Builder creation given a generator function."""
assert b1 != b3
assert b2 != b3
- def test_execute(self):
- """Test execution of simple Builder objects
-
- One Builder is a string that executes an external command,
- one is an internal Python function, one is a list
- containing one of each.
- """
-
- def MyBuilder(**kw):
- builder = apply(SCons.Builder.Builder, (), kw)
- def no_show(str):
- pass
- builder.action.show = no_show
- return builder
-
- python = sys.executable
-
- cmd1 = r'%s %s %s xyzzy' % (python, act_py, outfile)
-
- builder = MyBuilder(action = cmd1, name = "cmd1")
- r = builder.execute([],[],Environment())
- assert r == 0
- c = test.read(outfile, 'r')
- assert c == "act.py: 'xyzzy'\n", c
-
- cmd2 = r'%s %s %s $TARGET' % (python, act_py, outfile)
-
- builder = MyBuilder(action = cmd2, name = "cmd2")
- r = builder.execute('foo', [], Environment())
- assert r == 0
- c = test.read(outfile, 'r')
- assert c == "act.py: 'foo'\n", c
-
- cmd3 = r'%s %s %s ${TARGETS}' % (python, act_py, outfile)
-
- builder = MyBuilder(action = cmd3, name = "cmd3")
- r = builder.execute(['aaa', 'bbb'], [], Environment())
- assert r == 0
- c = test.read(outfile, 'r')
- assert c == "act.py: 'aaa' 'bbb'\n", c
-
- cmd4 = r'%s %s %s $SOURCES' % (python, act_py, outfile)
-
- builder = MyBuilder(action = cmd4, name = "cmd4")
- r = builder.execute([], ['one', 'two'], Environment())
- assert r == 0
- c = test.read(outfile, 'r')
- assert c == "act.py: 'one' 'two'\n", c
-
- cmd4 = r'%s %s %s ${SOURCES[:2]}' % (python, act_py, outfile)
-
- builder = MyBuilder(action = cmd4, name = "cmd4")
- r = builder.execute([], source = ['three', 'four', 'five'], env=Environment())
- assert r == 0
- c = test.read(outfile, 'r')
- assert c == "act.py: 'three' 'four'\n", c
-
- cmd5 = r'%s %s %s $TARGET XYZZY' % (python, act_py, outfile)
-
- builder = MyBuilder(action = cmd5, name = "cmd5")
- r = builder.execute(target = 'out5', source = [], env = Environment(ENV={'XYZZY' : 'xyzzy'}))
- assert r == 0
- c = test.read(outfile, 'r')
- assert c == "act.py: 'out5' 'XYZZY'\nact.py: 'xyzzy'\n", c
-
- class Obj:
- def __init__(self, str):
- self._str = str
- def __str__(self):
- return self._str
-
- cmd6 = r'%s %s %s ${TARGETS[1]} $TARGET ${SOURCES[:2]}' % (python, act_py, outfile)
-
- builder = MyBuilder(action = cmd6, name = "cmd6")
- r = builder.execute(target = [Obj('111'), Obj('222')],
- source = [Obj('333'), Obj('444'), Obj('555')],
- env = Environment())
- assert r == 0
- c = test.read(outfile, 'r')
- assert c == "act.py: '222' '111' '333' '444'\n", c
-
- cmd7 = '%s %s %s one\n\n%s %s %s two' % (python, act_py, outfile,
- python, act_py, outfile)
- expect7 = '%s %s %s one\n%s %s %s two\n' % (python, act_py, outfile,
- python, act_py, outfile)
-
- builder = MyBuilder(action = cmd7, name = "cmd7")
-
- global show_string
- show_string = ""
- def my_show(string):
- global show_string
- show_string = show_string + string + "\n"
- for action in builder.action.list:
- action.show = my_show
-
- r = builder.execute([],[],Environment())
- assert r == 0
- assert show_string == expect7, show_string
-
- global count
- count = 0
- def function1(target, source, env):
- global count
- count = count + 1
- for t in target:
- open(t, 'w').write("function1\n")
- return 1
-
- builder = MyBuilder(action = function1, name = "function1")
- try:
- r = builder.execute(target = [outfile, outfile2], source=[], env=Environment())
- except SCons.Errors.BuildError:
- pass
- assert r == 1
- assert count == 1
- c = test.read(outfile, 'r')
- assert c == "function1\n", c
- c = test.read(outfile2, 'r')
- assert c == "function1\n", c
-
- class class1a:
- def __init__(self, target, source, env):
- open(env['out'], 'w').write("class1a\n")
-
- builder = MyBuilder(action = class1a, name = "class1a")
- r = builder.execute([],[],Environment(out = outfile))
- assert r.__class__ == class1a
- c = test.read(outfile, 'r')
- assert c == "class1a\n", c
-
- class class1b:
- def __call__(self, target, source, env):
- open(env['out'], 'w').write("class1b\n")
- return 2
-
- builder = MyBuilder(action = class1b(), name = "class1b")
- r = builder.execute([],[],Environment(out = outfile))
- assert r == 2
- c = test.read(outfile, 'r')
- assert c == "class1b\n", c
-
- cmd2 = r'%s %s %s syzygy' % (python, act_py, outfile)
-
- def function2(target, source, env):
- open(env['out'], 'a').write("function2\n")
- return 0
-
- class class2a:
- def __call__(self, target, source, env):
- open(env['out'], 'a').write("class2a\n")
- return 0
-
- class class2b:
- def __init__(self, target, source, env):
- open(env['out'], 'a').write("class2b\n")
-
- builder = MyBuilder(action = SCons.Action.ListAction([cmd2, function2, class2a(), class2b]), name = "clist")
- r = builder.execute([],[],Environment(out = outfile))
- assert r.__class__ == class2b
- c = test.read(outfile, 'r')
- assert c == "act.py: 'syzygy'\nfunction2\nclass2a\nclass2b\n", c
-
- if os.name == 'nt':
- # NT treats execs of directories and non-executable files
- # as "file not found" errors
- expect_nonexistent = 1
- expect_nonexecutable = 1
- else:
- expect_nonexistent = 127
- expect_nonexecutable = 126
-
- # Test that a nonexistent command returns 127
- builder = MyBuilder(action = python + "_XyZzY_", name="badcmd")
- r = builder.execute([],[],Environment(out = outfile))
- assert r == expect_nonexistent, "r == %d" % r
-
- # Test that trying to execute a directory returns 126
- dir, tail = os.path.split(python)
- builder = MyBuilder(action = dir, name = "dir")
- r = builder.execute([],[],Environment(out = outfile))
- assert r == expect_nonexecutable, "r == %d" % r
-
- # Test that trying to execute a non-executable file returns 126
- builder = MyBuilder(action = outfile, name = "badfile")
- 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"]))
+ def func():
+ pass
+ builder = SCons.Builder.Builder(name="builder",
+ action=SCons.Action.ListAction(["x",
+ func,
+ "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[1], SCons.Action.FunctionAction), a[1]
assert isinstance(a[2], SCons.Action.CommandAction), a[2]
def test_get_contents(self):
def test_ListBuilder(self):
"""Testing ListBuilder class."""
- global count
- count = 0
def function2(target, source, env, tlist = [outfile, outfile2], **kw):
- global count
- count = count + 1
for t in target:
open(str(t), 'w').write("function2\n")
for t in tlist:
builder = SCons.Builder.Builder(action = function2, name = "function2")
tgts = builder(env, target = [outfile, outfile2], source = 'foo')
+ for t in tgts:
+ t.prepare()
try:
- r = tgts[0].builder.execute(tgts, 'foo', env)
+ tgts[0].build()
except SCons.Errors.BuildError:
pass
c = test.read(outfile, 'r')
assert c == "function2\n", c
c = test.read(outfile2, 'r')
assert c == "function2\n", c
- r = tgts[1].builder.execute(tgts[1], 'foo', env)
- assert r == 1, r
- assert count == 1, count
sub1_out = test.workpath('sub1', 'out')
sub2_out = test.workpath('sub2', 'out')
- count = 0
def function3(target, source, env, tlist = [sub1_out, sub2_out]):
- global count
- count = count + 1
for t in target:
open(str(t), 'w').write("function3\n")
for t in tlist:
builder = SCons.Builder.Builder(action = function3, name = "function3")
tgts = builder(env, target = [sub1_out, sub2_out], source = 'foo')
+ for t in tgts:
+ t.prepare()
try:
- r = tgts[0].builder.execute(tgts, 'foo', env)
- except:
+ tgts[0].build()
+ except SCons.Errors.BuildError:
pass
- assert r == 1, r
c = test.read(sub1_out, 'r')
assert c == "function3\n", c
c = test.read(sub2_out, 'r')
flag = 1
assert flag, "UserError should be thrown when we build targets with files of different suffixes."
-
def test_build_scanner(self):
"""Testing ability to set a target scanner through a builder."""
global instanced
assert src.source_scanner == env_scanner
def test_Builder_Args(self):
- """Testing passing extra agrs to a builder."""
+ """Testing passing extra args to a builder."""
def buildFunc(target, source, env, s=self):
s.foo=env['foo']
s.bar=env['bar']
def __init__(self, factory):
self.factory = factory
- def execute(self, target, source, env):
- global built_it
- built_it = 1
- return 0
+ def get_actions(self):
+ class Action:
+ def execute(self, targets, sources, env):
+ global built_it
+ built_it = 1
+ return 0
+ return [Action()]
+
+ def targets(self, t):
+ return [t]
def source_factory(self, name):
return self.factory(name)
fs.chdir(fs.Dir('..'))
# Test scanning
+ f1.builder_set(Builder(fs.File))
+ f1.env_set(Environment())
f1.target_scanner = Scanner()
f1.scan()
assert f1.implicit[0].path_ == os.path.join("d1", "f1")
built_source = None
cycle_detected = None
-class Builder:
+class MyAction:
def execute(self, target, source, env):
global built_it, built_target, built_source, built_args
built_it = 1
built_source = source
built_args = env
return 0
+
+class Builder:
+ def targets(self, t):
+ return [t]
def get_actions(self):
- return 'xyzzy'
+ return [MyAction()]
def get_contents(self, target, source, env):
return 7
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"
-
- node = SCons.Node.Node()
- node.builder_set(ExceptBuilder())
- node.env_set(Environment())
- try:
- node.build()
- except SCons.Errors.BuildError:
- pass
- else:
- raise TestFailed, "did not catch expected BuildError"
-
- node = SCons.Node.Node()
- node.builder_set(ExceptBuilder2())
- node.env_set(Environment())
- try:
- node.build()
- except SCons.Errors.BuildError, e:
- # On a generic (non-BuildError) exception from a Builder,
- # the Node should throw a BuildError exception with
- # the args set to the exception value, type, and traceback.
- assert len(e.args) == 3, `e.args`
- assert e.args[0] == 'foo', e.args[0]
- assert e.args[1] is None
- assert type(e.args[2]) is type(sys.exc_traceback), e.args[2]
- else:
- raise TestFailed, "did not catch expected BuildError"
-
def test_build(self):
"""Test building a node
"""
global built_it
class MyNode(SCons.Node.Node):
- def __init__(self, **kw):
- apply(SCons.Node.Node.__init__, (self,), kw)
- self.prepare_count = 0
def __str__(self):
return self.path
- def prepare(self):
- self.prepare_count = self.prepare_count+ 1
# Make sure it doesn't blow up if no builder is set.
node = MyNode()
node.build()
node.sources = ["yyy", "zzz"]
node.build()
assert built_it
- assert type(built_target) == type(MyNode()), type(built_target)
- assert str(built_target) == "xxx", str(built_target)
+ assert type(built_target[0]) == type(MyNode()), type(built_target[0])
+ assert str(built_target[0]) == "xxx", str(built_target[0])
assert built_source == ["yyy", "zzz"], built_source
built_it = None
node.overrides = { "foo" : 1, "bar" : 2 }
node.build()
assert built_it
- assert type(built_target) == type(MyNode()), type(built_target)
- assert str(built_target) == "qqq", str(built_target)
+ assert type(built_target[0]) == type(MyNode()), type(built_target[0])
+ assert str(built_target[0]) == "qqq", str(built_target[0])
assert built_source == ["rrr", "sss"], built_source
assert built_args["foo"] == 1, built_args
assert built_args["bar"] == 2, built_args
fff.sources = ["hhh", "iii"]
ggg.sources = ["hhh", "iii"]
- built_it = None
- fff.build()
- assert built_it
- ggg.build()
- assert ggg.prepare_count== 1, ggg.prepare_count
- assert type(built_target) == type(MyNode()), type(built_target)
- assert str(built_target) == "fff", str(built_target)
- assert built_source == ["hhh", "iii"], built_source
-
- delattr(lb, 'status')
- fff.prepare_count = 0
- ggg.prepare_count = 0
-
- built_it = None
- ggg.build()
- #assert built_it
- fff.build()
- assert fff.prepare_count== 1, fff.prepare_count
- assert type(built_target) == type(MyNode()), type(built_target)
- assert str(built_target) == "fff", str(built_target)
- assert built_source == ["hhh", "iii"], built_source
-
def test_depends_on(self):
parent = SCons.Node.Node()
child = SCons.Node.Node()
"""
node = SCons.Node.Node()
node.builder_set(Builder())
- a = node.get_actions()
- assert a == 'xyzzy', a
+ a = node.builder.get_actions()
+ assert isinstance(a[0], MyAction), a[0]
def test_set_bsig(self):
"""Test setting a Node's signature
-import string
-import types
import copy
-import sys
-import SCons.Sig
+import types
-from SCons.Errors import BuildError, UserError
+import SCons.Sig
import SCons.Util
# Node states
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,
- # so only do thread safe stuff here. Do thread unsafe stuff in built().
+ """Actually build the node.
+
+ This method is called from multiple threads in a parallel build,
+ so only do thread safe stuff here. Do thread unsafe stuff in
+ built().
+ """
if not self.builder:
return None
- try:
- # If this Builder instance has already been called,
- # there will already be an associated status.
- stat = self.builder.status
- except AttributeError:
- try:
- stat = self.builder.execute(self, self.sources, self.generate_build_env())
- except KeyboardInterrupt:
- raise
- except UserError:
- raise
- except BuildError:
- raise
- except:
- raise BuildError(self, "Exception",
- sys.exc_type,
- sys.exc_value,
- sys.exc_traceback)
- if stat:
- raise BuildError(node = self, errstr = "Error %d" % stat)
-
- return stat
+ action_list = self.builder.get_actions()
+ if not action_list:
+ return
+ targets = self.builder.targets(self)
+ env = self.generate_build_env()
+ for action in action_list:
+ stat = action.execute(targets, self.sources, env)
+ if stat:
+ raise SCons.Errors.BuildError(node = self,
+ errstr = "Error %d" % stat)
def built(self):
"""Called just after this node is sucessfully built."""
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()
- 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)
+ SCons.Taskmaster.Task.execute(self)
if print_time:
finish_time = time.time()
global command_time
SCons.Taskmaster.Task.executed(self)
else:
SCons.Taskmaster.Task.executed(self)
-
+
# print the tree here instead of in execute() because
# this method is serialized, but execute isn't:
if print_tree and self.top:
print SCons.Util.render_tree(self.targets[0], get_derived_children)
def failed(self):
- global exit_status
-
e = sys.exc_value
if sys.exc_type == BuildError:
sys.stderr.write("scons: *** [%s] %s\n" % (e.node, e.errstr))
if e.errstr == 'Exception':
- traceback.print_exception(e.args[0], e.args[1],
- e.args[2])
+ traceback.print_exception(e.args[0], e.args[1], e.args[2])
elif sys.exc_type == UserError:
# We aren't being called out of a user frame, so
# don't try to walk the stack, just print the error.
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
-
-
+import copy
+import string
+import sys
import SCons.Node
-import string
import SCons.Errors
-import copy
class Task:
"""Default SCons build engine task.
def execute(self):
"""Called to execute the task.
-
- This methods is called from multiple threads in
- a parallel build, so only do thread safe stuff here.
- Do thread unsafe stuff in prepare(), executed() or failed()."""
- if self.targets[0].get_state() != SCons.Node.up_to_date:
+
+ This method is called from multiple threads in a parallel build,
+ so only do thread safe stuff here. Do thread unsafe stuff in
+ prepare(), executed() or failed()."""
+ try:
self.targets[0].build()
+ except KeyboardInterrupt:
+ raise
+ except SCons.Errors.UserError:
+ raise
+ except SCons.Errors.BuildError:
+ raise
+ except:
+ raise SCons.Errors.BuildError(self.targets[0],
+ "Exception",
+ sys.exc_type,
+ sys.exc_value,
+ sys.exc_traceback)
def get_target(self):
"""Fetch the target being built or updated by this task.
return self.name
+class OtherError(Exception):
+ pass
+
+
class TaskmasterTestCase(unittest.TestCase):
def test_next_task(self):
assert not tm.next_task()
t.executed()
-
def test_cycle_detection(self):
+ """Test detecting dependency cycles
+
+ """
n1 = Node("n1")
n2 = Node("n2", [n1])
n3 = Node("n3", [n2])
assert tm.next_task() is None
def test_executed(self):
+ """Test when a task has been executed
+ """
pass
def test_prepare(self):
assert n1.prepared
assert n2.prepared
+ def test_execute(self):
+ """Test executing a task
+
+ """
+ global built_text
+
+ n1 = Node("n1")
+ tm = SCons.Taskmaster.Taskmaster([n1])
+ t = tm.next_task()
+ t.execute()
+ assert built_text == "n1 built", built_text
+
+ def raise_UserError():
+ raise SCons.Errors.UserError
+ n2 = Node("n2")
+ n2.build = raise_UserError
+ tm = SCons.Taskmaster.Taskmaster([n2])
+ t = tm.next_task()
+ try:
+ t.execute()
+ except SCons.Errors.UserError:
+ pass
+ else:
+ raise TestFailed, "did not catch expected UserError"
+
+ def raise_BuildError():
+ raise SCons.Errors.BuildError
+ n3 = Node("n3")
+ n3.build = raise_BuildError
+ tm = SCons.Taskmaster.Taskmaster([n3])
+ t = tm.next_task()
+ try:
+ t.execute()
+ except SCons.Errors.BuildError:
+ pass
+ else:
+ raise TestFailed, "did not catch expected BuildError"
+
+ def raise_OtherError():
+ raise OtherError
+ n4 = Node("n4")
+ n4.build = raise_OtherError
+ tm = SCons.Taskmaster.Taskmaster([n4])
+ t = tm.next_task()
+ try:
+ t.execute()
+ except SCons.Errors.BuildError, e:
+ # On a generic (non-BuildError) exception from a Builder,
+ # the target should throw a BuildError exception with the
+ # args set to the exception value, instance, and traceback.
+ assert e.node == n4, e.node
+ assert e.errstr == "Exception", e.errstr
+ assert len(e.args) == 3, `e.args`
+ assert e.args[0] == OtherError, e.args[0]
+ assert isinstance(e.args[1], OtherError), type(e.args[1])
+ assert type(e.args[2]) == type(sys.exc_traceback), e.args[2]
+ else:
+ raise TestFailed, "did not catch expected BuildError"
+
+
if __name__ == "__main__":