- 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
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)
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
"""
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)."""
def store_bsig(self):
pass
+
+ def store_timestamp(self):
+ pass
def builder_sig_adapter(self):
class Adapter:
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()
suite.addTest(TimeStampTestCase())
suite.addTest(CalcTestCase())
suite.addTest(SConsignEntryTestCase())
+ suite.addTest(SConsignFileTestCase())
return suite
if __name__ == "__main__":
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):
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):
"""
if self.max_drift >= 0 and (time.time() - mtime) > self.max_drift:
node.store_csig()
+ node.store_timestamp()
return csig
--- /dev/null
+#!/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()