Fix .sconsign signature storing so that the output files of one scons build can be...
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 23 May 2002 03:47:42 +0000 (03:47 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 23 May 2002 03:47:42 +0000 (03:47 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@378 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/CHANGES.txt
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/NodeTests.py
src/engine/SCons/Node/__init__.py
src/engine/SCons/Sig/SigTests.py
src/engine/SCons/Sig/__init__.py
test/chained-build.py [new file with mode: 0644]

index beb47d7718c626488a2dff0c223cc2bfd2c2980c..0fad2309511eba17e12b4b38a277f00c97767240 100644 (file)
@@ -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
index d18300697c1a18aa5c70b8046fc124a3ca142a09..7c303339ef45656929dd627472aa5d87a338d0d0 100644 (file)
@@ -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)
 
index b67d35207c072fa13e67d661f9d01dd9251a12c8..6f1d53d4fbfda6182ea309753bbf659f13b8e4ab 100644 (file)
@@ -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
         """
index e44006046190fcea598f2737d5eacedd614a3fe2..cf9474d1122d39211e7e990bbd7a5525017d1588 100644 (file)
@@ -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)."""
index cc39656bae19024399824f721d90856e2279227a..1004e6e377ff7001d91428fb952945cbeb38d21f 100644 (file)
@@ -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__":
index 193a3264a66108f484b41e8aecb8216d429893bb..2c8edadab78bd047895bf1798ddb94c0a4cdfc5b 100644 (file)
@@ -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 (file)
index 0000000..98eb992
--- /dev/null
@@ -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()