From b45c22529885e6bd490105f433d594ae5dea45fb Mon Sep 17 00:00:00 2001 From: stevenknight Date: Thu, 23 May 2002 03:47:42 +0000 Subject: [PATCH] Fix .sconsign signature storing so that the output files of one scons build can be safely used as the inputs to another scons build. (Anthony Roach) git-svn-id: http://scons.tigris.org/svn/scons/trunk@378 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- src/CHANGES.txt | 3 ++ src/engine/SCons/Node/FS.py | 15 +++---- src/engine/SCons/Node/NodeTests.py | 14 ++++++- src/engine/SCons/Node/__init__.py | 5 +++ src/engine/SCons/Sig/SigTests.py | 28 +++++++++++++ src/engine/SCons/Sig/__init__.py | 61 +++++++++++++++++++--------- test/chained-build.py | 65 ++++++++++++++++++++++++++++++ 7 files changed, 161 insertions(+), 30 deletions(-) create mode 100644 test/chained-build.py diff --git a/src/CHANGES.txt b/src/CHANGES.txt index beb47d77..0fad2309 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -49,6 +49,9 @@ RELEASE 0.08 - - Fix interrupt handling to guarantee that a single interrupt will halt SCons both when using -j and not. + - Fix .sconsign signature storage so that output files of one build + can be safely used as input files to another build. + From Zed Shaw: - Add an Append() method to Environments, to append values to diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index d1830069..7c303339 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -562,22 +562,17 @@ class File(Entry): return 0 def store_csig(self): - old = self.get_prevsiginfo() - self.dir.sconsign().set(self.name, - self.get_timestamp(), - old[1], - self.get_csig()) + self.dir.sconsign().set_csig(self.name, self.get_csig()) def store_bsig(self): - old = self.get_prevsiginfo() - self.dir.sconsign().set(self.name, - self.get_timestamp(), - self.get_bsig(), - old[2]) + self.dir.sconsign().set_bsig(self.name, self.get_bsig()) def store_implicit(self): self.dir.sconsign().set_implicit(self.name, self.implicit) + def store_timestamp(self): + self.dir.sconsign().set_timestamp(self.name, self.get_timestamp()) + def get_prevsiginfo(self): return self.dir.sconsign().get(self.name) diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py index b67d3520..6f1d53d4 100644 --- a/src/engine/SCons/Node/NodeTests.py +++ b/src/engine/SCons/Node/NodeTests.py @@ -276,12 +276,24 @@ class NodeTestCase(unittest.TestCase): node = SCons.Node.Node() node.store_bsig() - def test_store_sigs(self): + def test_store_csig(self): """Test calling the method to store a content signature """ node = SCons.Node.Node() node.store_csig() + def test_get_timestamp(self): + """Test calling the method to fetch a Node's timestamp + """ + node = SCons.Node.Node() + assert node.get_timestamp() == 0 + + def test_store_timestamp(self): + """Test calling the method to store a timestamp + """ + node = SCons.Node.Node() + node.store_timestamp() + def test_set_precious(self): """Test setting a Node's precious value """ diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index e4400604..cf9474d1 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -267,6 +267,11 @@ class Node: def get_timestamp(self): return 0 + def store_timestamp(self): + """Make the timestamp permanent (that is, store it in the + .sconsign file or equivalent).""" + pass + def store_implicit(self): """Make the implicit deps permanent (that is, store them in the .sconsign file or equivalent).""" diff --git a/src/engine/SCons/Sig/SigTests.py b/src/engine/SCons/Sig/SigTests.py index cc39656b..1004e6e3 100644 --- a/src/engine/SCons/Sig/SigTests.py +++ b/src/engine/SCons/Sig/SigTests.py @@ -122,6 +122,9 @@ class DummyNode: def store_bsig(self): pass + + def store_timestamp(self): + pass def builder_sig_adapter(self): class Adapter: @@ -492,6 +495,30 @@ class SConsignEntryTestCase(unittest.TestCase): assert e.get_implicit() == ['foo bletch', 'bar'] assert e.render(m) == "123 456 789 foo bletch\0bar" +class SConsignFileTestCase(unittest.TestCase): + + def runTest(self): + class DummyModule: + def to_string(self, sig): + return str(sig) + + def from_string(self, sig): + return int(sig) + + class DummyNode: + path = 'not_a_valid_path' + + f = SCons.Sig.SConsignFile(DummyNode(), DummyModule()) + f.set_bsig('foo', 1) + assert f.get('foo') == (None, 1, None) + f.set_csig('foo', 2) + assert f.get('foo') == (None, 1, 2) + f.set_timestamp('foo', 3) + assert f.get('foo') == (3, 1, 2) + f.set_implicit('foo', ['bar']) + assert f.get('foo') == (3, 1, 2) + assert f.get_implicit('foo') == ['bar'] + def suite(): suite = unittest.TestSuite() @@ -499,6 +526,7 @@ def suite(): suite.addTest(TimeStampTestCase()) suite.addTest(CalcTestCase()) suite.addTest(SConsignEntryTestCase()) + suite.addTest(SConsignFileTestCase()) return suite if __name__ == "__main__": diff --git a/src/engine/SCons/Sig/__init__.py b/src/engine/SCons/Sig/__init__.py index 193a3264..2c8edada 100644 --- a/src/engine/SCons/Sig/__init__.py +++ b/src/engine/SCons/Sig/__init__.py @@ -132,35 +132,61 @@ class SConsignFile: Get the .sconsign entry for a file filename - the filename whose signature will be returned - returns - (timestamp, bsig, csig, implicit) + returns - (timestamp, bsig, csig) """ try: entry = self.entries[filename] return (entry.timestamp, entry.bsig, entry.csig) except KeyError: return (None, None, None) - - def set(self, filename, timestamp, bsig = None, csig = None): + + def create_entry(self, filename): """ - Set the .sconsign entry for a file - - filename - the filename whose signature will be set - timestamp - the timestamp - module - the signature module being used - bsig - the file's build signature - csig - the file's content signature + Create an entry for the filename and return it, or if one already exists, + then return it. """ - try: entry = self.entries[filename] except KeyError: entry = SConsignEntry(self.module) self.entries[filename] = entry + + return entry - entry.timestamp = timestamp - entry.bsig = bsig + def set_csig(self, filename, csig): + """ + Set the csig .sconsign entry for a file + + filename - the filename whose signature will be set + csig - the file's content signature + """ + + entry = self.create_entry(filename) entry.csig = csig + self.dirty = 1 + + def set_bsig(self, filename, bsig): + """ + Set the csig .sconsign entry for a file + + filename - the filename whose signature will be set + bsig - the file's built signature + """ + + entry = self.create_entry(filename) + entry.bsig = bsig + self.dirty = 1 + + def set_timestamp(self, filename, timestamp): + """ + Set the csig .sconsign entry for a file + + filename - the filename whose signature will be set + timestamp - the file's timestamp + """ + entry = self.create_entry(filename) + entry.timestamp = timestamp self.dirty = 1 def get_implicit(self, filename): @@ -173,13 +199,9 @@ class SConsignFile: def set_implicit(self, filename, implicit): """Cache the implicit dependencies for 'filename'.""" - try: - entry = self.entries[filename] - except KeyError: - entry = SConsignEntry(self.module) - self.entries[filename] = entry - + entry = self.create_entry(filename) entry.set_implicit(implicit) + self.dirty = 1 def write(self): """ @@ -325,6 +347,7 @@ class Calculator: if self.max_drift >= 0 and (time.time() - mtime) > self.max_drift: node.store_csig() + node.store_timestamp() return csig diff --git a/test/chained-build.py b/test/chained-build.py new file mode 100644 index 00000000..98eb9922 --- /dev/null +++ b/test/chained-build.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# +# Copyright (c) 2001, 2002 Steven Knight +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write('SConstruct1', """ +def build(env, target, source): + open(str(target[0]), 'wt').write(open(str(source[0]), 'rt').read()) + print "built %s"%target[0] + +env=Environment(BUILDERS=[Builder(name='B', action=build)]) +env.B('foo.mid', 'foo.in') +""") + +test.write('SConstruct2', """ +def build(env, target, source): + open(str(target[0]), 'wt').write(open(str(source[0]), 'rt').read()) + print "built %s"%target[0] + +env=Environment(BUILDERS=[Builder(name='B', action=build)]) +env.B('foo.out', 'foo.mid') +""") + +test.write('foo.in', "foo.in") + +test.run(arguments="--max-drift=0 -f SConstruct1 foo.mid", stdout='built foo.mid\n') +test.run(arguments="--max-drift=0 -f SConstruct2 foo.out", stdout='built foo.out\n') + +test.run(arguments="--max-drift=0 -f SConstruct1 foo.mid", stdout='scons: "foo.mid" is up to date.\n') +test.run(arguments="--max-drift=0 -f SConstruct2 foo.out", stdout='scons: "foo.out" is up to date.\n') + +test.write('foo.in', "foo.in 2") + +test.run(arguments="--max-drift=0 -f SConstruct1 foo.mid", stdout='built foo.mid\n') +test.run(arguments="--max-drift=0 -f SConstruct2 foo.out", stdout='built foo.out\n') + +test.run(arguments="--max-drift=0 -f SConstruct1 foo.mid", stdout='scons: "foo.mid" is up to date.\n') +test.run(arguments="--max-drift=0 -f SConstruct2 foo.out", stdout='scons: "foo.out" is up to date.\n') + +test.pass_test() -- 2.26.2