diff options
-rw-r--r-- | src/CHANGES.txt | 4 | ||||
-rw-r--r-- | src/engine/SCons/Action.py | 28 | ||||
-rw-r--r-- | src/engine/SCons/ActionTests.py | 33 | ||||
-rw-r--r-- | src/engine/SCons/Node/FS.py | 11 | ||||
-rw-r--r-- | src/engine/SCons/Node/FSTests.py | 30 | ||||
-rw-r--r-- | test/option--cs.py | 100 |
6 files changed, 168 insertions, 38 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt index b84aa61..4b8b330 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -46,6 +46,10 @@ RELEASE 0.XX - XXX - Cache the computed list of Node children minus those being Ignored so it's only calculated once. + - Fix use of the --cache-show option when building a Program() + (or using any other arbitrary action) by making sure all Action + instances have strfunction() methods. + From Gary Oberbrunner: - Report the target being built in error messages when building diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py index 49b0cb1..c9186a4 100644 --- a/src/engine/SCons/Action.py +++ b/src/engine/SCons/Action.py @@ -299,6 +299,13 @@ class CommandGeneratorAction(ActionBase): raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret)) return gen_cmd + def strfunction(self, target, source, env): + if not SCons.Util.is_List(source): + source = [source] + rsources = map(rfile, source) + act = self.__generate(target, source, env, 0) + return act.strfunction(target, rsources, env) + def __call__(self, target, source, env): if not SCons.Util.is_List(source): source = [source] @@ -322,10 +329,17 @@ class LazyCmdGenerator: def __init__(self, var): self.var = SCons.Util.to_String(var) + def strfunction(self, target, source, env): + try: + return env[self.var] + except KeyError: + # The variable reference substitutes to nothing. + return '' + def __call__(self, target, source, env, for_signature): - if env.has_key(self.var): + try: return env[self.var] - else: + except KeyError: # The variable reference substitutes to nothing. return '' @@ -394,6 +408,16 @@ class ListAction(ActionBase): def get_actions(self): return self.list + def strfunction(self, target, source, env): + s = [] + for l in self.list: + if l.strfunction: + x = l.strfunction(target, source, env) + if not SCons.Util.is_List(x): + x = [x] + s.extend(x) + return string.join(s, "\n") + def __call__(self, target, source, env): for l in self.list: r = l(target, source, env) diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py index d14edfd..64b5f53 100644 --- a/src/engine/SCons/ActionTests.py +++ b/src/engine/SCons/ActionTests.py @@ -764,6 +764,19 @@ class CommandGeneratorActionTestCase(unittest.TestCase): a = SCons.Action.CommandGeneratorAction(f) assert a.generator == f + def test_strfunction(self): + """Test the command generator Action string function + """ + def f(target, source, env, for_signature, self=self): + dummy = env['dummy'] + self.dummy = dummy + return "$FOO" + a = SCons.Action.CommandGeneratorAction(f) + self.dummy = 0 + s = a.strfunction([], [], env=Environment(FOO='xyzzy', dummy=1)) + assert self.dummy == 1, self.dummy + assert s == ['xyzzy'], s + def test_execute(self): """Test executing a command generator Action """ @@ -980,6 +993,17 @@ class ListActionTestCase(unittest.TestCase): g = l[1].get_actions() assert g == [l[1]], g + def test_strfunction(self): + """Test the string function for a list of subsidiary Actions + """ + def f(target,source,env): + pass + def g(target,source,env): + pass + a = SCons.Action.ListAction([f, g, "XXX", f]) + s = a.strfunction([], [], Environment()) + assert s == "f([], [])\ng([], [])\nXXX\nf([], [])", s + def test_execute(self): """Test executing a list of subsidiary Actions """ @@ -1041,6 +1065,15 @@ class LazyActionTestCase(unittest.TestCase): assert isinstance(a9, SCons.Action.CommandGeneratorAction), a10 assert a10.generator.var == 'FOO', a10.generator.var + def test_strfunction(self): + """Test the lazy-evaluation Action string function + """ + def f(target, source, env): + pass + a = SCons.Action.Action('$BAR') + s = a.strfunction([], [], env=Environment(BAR=f, s=self)) + assert s == "f([], [])", s + def test_execute(self): """Test executing a lazy-evaluation Action """ diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index a17cee0..12b8869 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -1246,11 +1246,12 @@ class File(Entry): if self.fs.cache_show: if CacheRetrieveSilent(self, None, None) == 0: def do_print(action, targets, sources, env, self=self): - al = action.strfunction(targets, self.sources, env) - if not SCons.Util.is_List(al): - al = [al] - for a in al: - action.show(a) + if action.strfunction: + al = action.strfunction(targets, self.sources, env) + if not SCons.Util.is_List(al): + al = [al] + for a in al: + action.show(a) self._for_each_action(do_print) return elif CacheRetrieve(self, None, None) == 0: diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index 13f171e..a80c8f9 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -86,11 +86,11 @@ class Action: return [self] class Builder: - def __init__(self, factory): + def __init__(self, factory, action=Action()): self.factory = factory self.env = Environment() self.overrides = {} - self.action = Action() + self.action = action def get_actions(self): return [self] @@ -1499,6 +1499,32 @@ class CacheDirTestCase(unittest.TestCase): SCons.Warnings.warningAsException(old_warn_exceptions) SCons.Warnings.suppressWarningClass(SCons.Warnings.CacheWriteErrorWarning) + # Verify that we don't blow up if there's no strfunction() + # for an action. + act = Action() + act.strfunction = None + f8 = fs.File("cd.f8") + f8.builder_set(Builder(fs.File, action=act)) + f8.env_set(Environment()) + try: + SCons.Node.FS.CacheRetrieveSilent = retrieve_succeed + self.retrieved = [] + built_it = None + + f8.build() + assert self.retrieved == [f8], self.retrieved + assert built_it is None, built_it + + SCons.Node.FS.CacheRetrieveSilent = retrieve_fail + self.retrieved = [] + built_it = None + + f8.build() + assert self.retrieved == [f8], self.retrieved + assert built_it, built_it + finally: + SCons.Node.FS.CacheRetrieveSilent = save_CacheRetrieveSilent + class clearTestCase(unittest.TestCase): def runTest(self): fs = SCons.Node.FS.FS() diff --git a/test/option--cs.py b/test/option--cs.py index ff1b221..00ec2f9 100644 --- a/test/option--cs.py +++ b/test/option--cs.py @@ -35,12 +35,14 @@ import shutil import TestSCons python = TestSCons.python +_exe = TestSCons._exe +_obj = TestSCons._obj test = TestSCons.TestSCons() -test.subdir('cache', 'src') +test.subdir('cache', 'src1', 'src2') -test.write(['src', 'build.py'], r""" +test.write(['src1', 'build.py'], r""" import sys open('cat.out', 'ab').write(sys.argv[1] + "\n") file = open(sys.argv[1], 'wb') @@ -49,7 +51,7 @@ for src in sys.argv[2:]: file.close() """) -test.write(['src', 'SConstruct'], """ +test.write(['src1', 'SConstruct'], """ def cat(env, source, target): target = str(target[0]) open('cat.out', 'ab').write(target + "\\n") @@ -67,41 +69,41 @@ env.Internal('all', ['aaa.out', 'bbb.out', 'ccc.out']) CacheDir(r'%s') """ % (python, test.workpath('cache'))) -test.write(['src', 'aaa.in'], "aaa.in\n") -test.write(['src', 'bbb.in'], "bbb.in\n") -test.write(['src', 'ccc.in'], "ccc.in\n") +test.write(['src1', 'aaa.in'], "aaa.in\n") +test.write(['src1', 'bbb.in'], "bbb.in\n") +test.write(['src1', 'ccc.in'], "ccc.in\n") # Verify that a normal build works correctly, and clean up. # This should populate the cache with our derived files. -test.run(chdir = 'src', arguments = '.') +test.run(chdir = 'src1', arguments = '.') -test.fail_test(test.read(['src', 'all']) != "aaa.in\nbbb.in\nccc.in\n") +test.fail_test(test.read(['src1', 'all']) != "aaa.in\nbbb.in\nccc.in\n") -test.fail_test(test.read(['src', 'cat.out']) != "aaa.out\nbbb.out\nccc.out\nall\n") +test.fail_test(test.read(['src1', 'cat.out']) != "aaa.out\nbbb.out\nccc.out\nall\n") -test.up_to_date(chdir = 'src', arguments = '.') +test.up_to_date(chdir = 'src1', arguments = '.') -test.run(chdir = 'src', arguments = '-c .') -test.unlink(['src', 'cat.out']) +test.run(chdir = 'src1', arguments = '-c .') +test.unlink(['src1', 'cat.out']) # Verify that we now retrieve the derived files from cache, # not rebuild them. Then clean up. -test.run(chdir = 'src', arguments = '.', stdout = test.wrap_stdout("""\ +test.run(chdir = 'src1', arguments = '.', stdout = test.wrap_stdout("""\ Retrieved `aaa.out' from cache Retrieved `bbb.out' from cache Retrieved `ccc.out' from cache Retrieved `all' from cache """)) -test.fail_test(os.path.exists(test.workpath('src', 'cat.out'))) +test.fail_test(os.path.exists(test.workpath('src1', 'cat.out'))) -test.up_to_date(chdir = 'src', arguments = '.') +test.up_to_date(chdir = 'src1', arguments = '.') -test.run(chdir = 'src', arguments = '-c .') +test.run(chdir = 'src1', arguments = '-c .') # Verify that using --cache-show reports the files as being rebuilt, # even though we actually fetch them from the cache. Then clean up. -test.run(chdir = 'src', +test.run(chdir = 'src1', arguments = '--cache-show .', stdout = test.wrap_stdout("""\ %s build.py aaa.out aaa.in @@ -110,16 +112,16 @@ cat("ccc.out", "ccc.in") cat("all", ["aaa.out", "bbb.out", "ccc.out"]) """ % (python, python))) -test.fail_test(os.path.exists(test.workpath('src', 'cat.out'))) +test.fail_test(os.path.exists(test.workpath('src1', 'cat.out'))) -test.up_to_date(chdir = 'src', arguments = '.') +test.up_to_date(chdir = 'src1', arguments = '.') -test.run(chdir = 'src', arguments = '-c .') +test.run(chdir = 'src1', arguments = '-c .') # Verify that using --cache-show -n reports the files as being rebuilt, # even though we don't actually fetch them from the cache. No need to # clean up. -test.run(chdir = 'src', +test.run(chdir = 'src1', arguments = '--cache-show -n .', stdout = test.wrap_stdout("""\ %s build.py aaa.out aaa.in @@ -128,21 +130,61 @@ cat("ccc.out", "ccc.in") cat("all", ["aaa.out", "bbb.out", "ccc.out"]) """ % (python, python))) -test.fail_test(os.path.exists(test.workpath('src', 'cat.out'))) +test.fail_test(os.path.exists(test.workpath('src1', 'cat.out'))) -test.fail_test(os.path.exists(test.workpath('src', 'aaa.out'))) -test.fail_test(os.path.exists(test.workpath('src', 'bbb.out'))) -test.fail_test(os.path.exists(test.workpath('src', 'ccc.out'))) -test.fail_test(os.path.exists(test.workpath('src', 'all'))) +test.fail_test(os.path.exists(test.workpath('src1', 'aaa.out'))) +test.fail_test(os.path.exists(test.workpath('src1', 'bbb.out'))) +test.fail_test(os.path.exists(test.workpath('src1', 'ccc.out'))) +test.fail_test(os.path.exists(test.workpath('src1', 'all'))) # Verify that using --cache-show -s doesn't report anything, even though # we do fetch the files from the cache. No need to clean up. -test.run(chdir = 'src', +test.run(chdir = 'src1', arguments = '--cache-show -s .', stdout = "") -test.fail_test(test.read(['src', 'all']) != "aaa.in\nbbb.in\nccc.in\n") -test.fail_test(os.path.exists(test.workpath('src', 'cat.out'))) +test.fail_test(test.read(['src1', 'all']) != "aaa.in\nbbb.in\nccc.in\n") +test.fail_test(os.path.exists(test.workpath('src1', 'cat.out'))) + +# +hello_exe = 'hello' + _exe +hello_obj = 'hello' + _obj +src2_hello = test.workpath('src2', hello_exe) + +test.write(['src2', 'SConstruct'], """ +env = Environment() +env.Program('hello.c') +CacheDir(r'%s') +""" % (test.workpath('cache'))) + +test.write(['src2', 'hello.c'], r"""\ +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("src2/hello.c\n"); + exit (0); +} +""") + +# Normal build. +test.run(chdir = 'src2', arguments = '.') + +test.run(program = src2_hello, stdout = "src2/hello.c\n") + +test.up_to_date(chdir = 'src2', arguments = '.') + +test.run(chdir = 'src2', arguments = '-c .') + +# Verify that using --cache-show doesn't blow up. +# Don't bother checking the output, since we verified the correct +# behavior above. We just want to make sure the canonical Program() +# invocation works with --cache-show. +test.run(chdir = 'src2', arguments = '--cache-show .') + +test.run(program = src2_hello, stdout = "src2/hello.c\n") + +test.up_to_date(chdir = 'src2', arguments = '.') # All done. test.pass_test() |