From 21bb88f9525d49538abf37a6491202acf3c1f362 Mon Sep 17 00:00:00 2001 From: stevenknight Date: Mon, 3 Mar 2003 08:10:04 +0000 Subject: [PATCH] Push files to the CacheDir() before calling the superclass built() method, which may clear the build signature. git-svn-id: http://scons.tigris.org/svn/scons/trunk@606 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- src/CHANGES.txt | 8 ++ src/engine/SCons/Node/FS.py | 11 ++- src/engine/SCons/Node/FSTests.py | 13 ++- test/CacheDir.py | 151 ++++++++++++++++++++++++++++++- 4 files changed, 176 insertions(+), 7 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index f4fa6acc..2824e8f0 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -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. diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index a6dd7ae6..551ae064 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -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) diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index 5e4bb528..10e4676b 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -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() diff --git a/test/CacheDir.py b/test/CacheDir.py index ffe74440..24c7e60a 100644 --- a/test/CacheDir.py +++ b/test/CacheDir.py @@ -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() -- 2.26.2