Fix a problem when using --cache-show.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 23 Jul 2003 14:20:43 +0000 (14:20 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 23 Jul 2003 14:20:43 +0000 (14:20 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@747 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/CHANGES.txt
src/engine/SCons/Action.py
src/engine/SCons/ActionTests.py
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/FSTests.py
test/option--cs.py

index b84aa61092b52ca8385e7157c6b7c4ace41aafe3..4b8b3303bf84840017d6cb427a8e53c75a8532cd 100644 (file)
@@ -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
index 49b0cb11f873e83dbbdc922fc26092c9fd6d2441..c9186a443d83fd26b86ddb50267d1cfe065b9697 100644 (file)
@@ -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)
index d14edfdf440665ec5cabd9599dd90e928de94dd4..64b5f536c987045893e2b6d557162a1b70d2d805 100644 (file)
@@ -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
         """
index a17cee067f1510974cd7f010e97e4da4d6615e6b..12b88692f47e11c153708c5fddd39ca8a11e5190 100644 (file)
@@ -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:
index 13f171e9ed3bd7ec544234369a7384ef3be28fd8..a80c8f960b242e19a6c6015bc8de0cf3ad8588d5 100644 (file)
@@ -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()
index ff1b221a28c23d4e039d057659d373490109a75e..00ec2f9f58f2853fb93e34424b57cbcb5556eddf 100644 (file)
@@ -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()