Push files to the CacheDir() before calling the superclass built() method, which...
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Mon, 3 Mar 2003 08:10:04 +0000 (08:10 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Mon, 3 Mar 2003 08:10:04 +0000 (08:10 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@606 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/CHANGES.txt
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/FSTests.py
test/CacheDir.py

index f4fa6acc3a18f0d8236a51ee5b3ed11fe130ab59..2824e8f0f116f9143f3844f1b70889ead5799162 100644 (file)
@@ -54,6 +54,14 @@ RELEASE 0.12 - XXX
   - Don't silently swallow exceptions thrown by Scanners (or other
     exceptions while finding a node's dependent children).
 
+  - Push files to CacheDir() before calling the superclass built()
+    method (which may clear the build signature as part of clearing
+    cached implicit dependencies, if the file has a source scanner).
+    (Bug reported by Jeff Petkau.)
+
+  - Raise an internal error if we attempt to push a file to CacheDir()
+    with a build signature of None.
+
   From Lachlan O'Dea:
 
   - Add SharedObject() support to the masm tool.
index a6dd7ae648c618ccaa659d6a8cffce2b5761285d..551ae064d4621c656e3426f5695f822b5eea989c 100644 (file)
@@ -1037,9 +1037,13 @@ class File(Entry):
         SCons.Node.Node.build(self)
 
     def built(self):
-        SCons.Node.Node.built(self)
+        """Called just after this node is sucessfully built."""
+        # Push this file out to cache before the superclass Node.built()
+        # method has a chance to clear the build signature, which it
+        # will do if this file has a source scanner.
         if self.fs.CachePath and os.path.exists(self.path):
             CachePush(self, None, None)
+        SCons.Node.Node.built(self)
         self.found_includes = {}
         if hasattr(self, '_exists'):
             delattr(self, '_exists')
@@ -1160,7 +1164,10 @@ class File(Entry):
 
     def cachepath(self):
         if self.fs.CachePath:
-            bsig = str(self.get_bsig())
+            bsig = self.get_bsig()
+            if bsig is None:
+                raise SCons.Errors.InternalError, "cachepath(%s) found a bsig of None" % self.path
+            bsig = str(bsig)
             subdir = string.upper(bsig[0])
             dir = os.path.join(self.fs.CachePath, subdir)
             return dir, os.path.join(dir, bsig)
index 5e4bb528d25a8fd79cb28f7264d7ba015c82342d..10e4676bbdf0177250fbe22204e66a432f8a1264 100644 (file)
@@ -1336,7 +1336,6 @@ class CacheDirTestCase(unittest.TestCase):
             SCons.Node.FS.CacheRetrieveSilent = save_CacheRetrieveSilent
 
         save_CachePush = SCons.Node.FS.CachePush
-        self.pushed = []
         def push(target, source, env, self=self):
             self.pushed.append(target)
             return 0
@@ -1345,6 +1344,8 @@ class CacheDirTestCase(unittest.TestCase):
         try:
             test = TestCmd(workdir='')
 
+            self.pushed = []
+
             cd_f3 = test.workpath("cd.f3")
             f3 = fs.File(cd_f3)
             f3.built()
@@ -1375,6 +1376,16 @@ class CacheDirTestCase(unittest.TestCase):
         filename = os.path.join(dirname, 'a_fake_bsig')
         assert cp == (dirname, filename), cp
 
+        f6 = fs.File("cd.f6")
+        f5.set_bsig(None)
+        exc_caught = 0
+        try:
+            cp = f5.cachepath()
+        except SCons.Errors.InternalError:
+            exc_caught = 1
+        assert exc_caught
+
+
 
 if __name__ == "__main__":
     suite = unittest.TestSuite()
index ffe74440357cd1e06d896f13f468157aa4606121..24c7e60a0ff58f8c559f78d216d10d9387edce37 100644 (file)
@@ -35,9 +35,14 @@ import TestSCons
 
 test = TestSCons.TestSCons()
 
-test.subdir('cache', 'src')
+test.subdir('cache1', 'cache2', 'cache3', 'src', 'subdir')
 
-test.write(['src', 'SConstruct'], """
+test.write(['src', 'SConstruct'], """\
+CacheDir(r'%s')
+SConscript('SConscript')
+""" % test.workpath('cache1'))
+
+test.write(['src', 'SConscript'], """\
 def cat(env, source, target):
     target = str(target[0])
     open('cat.out', 'ab').write(target + "\\n")
@@ -51,13 +56,13 @@ env.Cat('aaa.out', 'aaa.in')
 env.Cat('bbb.out', 'bbb.in')
 env.Cat('ccc.out', 'ccc.in')
 env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out'])
-CacheDir(r'%s')
-""" % 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")
 
+#############################################################################
 # Verify that a normal build works correctly, and clean up.
 # This should populate the cache with our derived files.
 test.run(chdir = 'src', arguments = '.')
@@ -126,5 +131,143 @@ test.fail_test(test.read(['src', 'cat.out']) != "bbb.out\nall\n")
 
 test.up_to_date(chdir = 'src', arguments = '.')
 
+#############################################################################
+# Now we try out BuildDir() functionality.
+# This is largely cut-and-paste of the above,
+# with appropriate directory modifications.
+
+build_aaa_out = os.path.join('build', 'aaa.out')
+build_bbb_out = os.path.join('build', 'bbb.out')
+build_ccc_out = os.path.join('build', 'ccc.out')
+build_all = os.path.join('build', 'all')
+
+# First, clean up the source directory and start over with fresh files.
+test.run(chdir = 'src', arguments = '-c .')
+
+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('SConstruct', """\
+CacheDir(r'%s')
+BuildDir('build', 'src', duplicate=0)
+SConscript('build/SConscript')
+""" % test.workpath('cache2'))
+
+# Verify that a normal build works correctly, and clean up.
+# This should populate the cache with our derived files.
+test.run()
+
+test.fail_test(test.read(['build', 'all']) != "aaa.in\nbbb.in\nccc.in\n")
+test.fail_test(test.read('cat.out') != "%s\n%s\n%s\n%s\n" % (build_aaa_out, build_bbb_out, build_ccc_out, build_all))
+
+test.up_to_date(arguments = '.')
+
+test.run(arguments = '-c .')
+test.unlink('cat.out')
+
+# Verify that we now retrieve the derived files from cache,
+# not rebuild them.  Then clean up.
+test.run(stdout = test.wrap_stdout("""\
+Retrieved `%s' from cache
+Retrieved `%s' from cache
+Retrieved `%s' from cache
+Retrieved `%s' from cache
+""" % (build_aaa_out, build_bbb_out, build_ccc_out, build_all)))
+
+test.fail_test(os.path.exists(test.workpath('cat.out')))
+
+test.up_to_date(arguments = '.')
+
+test.run(arguments = '-c .')
+
+# Verify that rebuilding with -n reports that everything was retrieved
+# from the cache, but that nothing really was.
+test.run(arguments = '-n .', stdout = test.wrap_stdout("""\
+Retrieved `%s' from cache
+Retrieved `%s' from cache
+Retrieved `%s' from cache
+Retrieved `%s' from cache
+""" % (build_aaa_out, build_bbb_out, build_ccc_out, build_all)))
+
+test.fail_test(os.path.exists(test.workpath('build', 'aaa.out')))
+test.fail_test(os.path.exists(test.workpath('build', 'bbb.out')))
+test.fail_test(os.path.exists(test.workpath('build', 'ccc.out')))
+test.fail_test(os.path.exists(test.workpath('build', 'all')))
+
+# Verify that rebuilding with -s retrieves everything from the cache
+# even though it doesn't report anything.
+test.run(arguments = '-s .', stdout = "")
+
+test.fail_test(test.read(['build', 'all']) != "aaa.in\nbbb.in\nccc.in\n")
+test.fail_test(os.path.exists(test.workpath('cat.out')))
+
+test.up_to_date(arguments = '.')
+
+test.run(arguments = '-c .')
+
+# Verify that updating one input file builds its derived file and
+# dependency but that the other files are retrieved from cache.
+test.write(['src', 'bbb.in'], "bbb.in 2\n")
+
+test.run(stdout = test.wrap_stdout("""\
+Retrieved `%s' from cache
+cat("%s", "%s")
+Retrieved `%s' from cache
+cat("%s", ["%s", "%s", "%s"])
+""" % (build_aaa_out,
+       build_bbb_out, os.path.join('src', 'bbb.in'),
+       build_ccc_out,
+       build_all, build_aaa_out, build_bbb_out, build_ccc_out)))
+
+test.fail_test(test.read(['build', 'all']) != "aaa.in\nbbb.in 2\nccc.in\n")
+test.fail_test(test.read('cat.out') != "%s\n%s\n" % (build_bbb_out, build_all))
+
+test.up_to_date(arguments = '.')
+
+#############################################################################
+# Test the case (reported by Jeff Petkau, bug #694744) where a target
+# is source for another target with a scanner, which used to cause us
+# to push the file to the CacheDir after the build signature had already
+# been cleared (as a sign that the built file should now be rescanned).
+
+test.write(['subdir', 'SConstruct'], """\
+import SCons
+
+CacheDir(r'%s')
+
+def docopy(target,source,env):
+    data = source[0].get_contents()
+    f = open(target[0].rfile().abspath, "wb")
+    f.write(data)
+    f.close()
+
+def sillyScanner(node, env, dirs):
+    print 'This is never called (unless we build file.out)'
+    return []
+
+SillyScanner = SCons.Scanner.Base(function = sillyScanner, skeys = ['.res'])
+
+env = Environment(tools=[],
+                  SCANNERS = [SillyScanner],
+                  BUILDERS = {})
+
+r = env.Command('file.res', 'file.ma', docopy)
+
+env.Command('file.out', r, docopy)
+
+# make r the default. Note that we don't even try to build file.out,
+# and so SillyScanner never runs. The bug is the same if we build
+# file.out, though.
+Default(r)
+""" % test.workpath('cache3'))
+
+test.write(['subdir', 'file.ma'], "subdir/file.ma\n")
+
+test.run(chdir = 'subdir')
+
+test.fail_test(os.path.exists(test.workpath('cache3', 'N', 'None')))
+
 # All done.
 test.pass_test()