summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2004-05-06 06:21:43 (GMT)
committerSteven Knight <knight@baldmt.com>2004-05-06 06:21:43 (GMT)
commitb155ebc4a869e0669ee2f7124531e0b5950c7528 (patch)
tree520cb5708efb85d177a120155048cd8e1361796e
parent2a9941e968724723c70f106401fe8b984add626a (diff)
downloadSCons-b155ebc4a869e0669ee2f7124531e0b5950c7528.zip
SCons-b155ebc4a869e0669ee2f7124531e0b5950c7528.tar.gz
SCons-b155ebc4a869e0669ee2f7124531e0b5950c7528.tar.bz2
Refactor .sconsign management into its own module.
-rw-r--r--src/engine/MANIFEST.in1
-rw-r--r--src/engine/SCons/Environment.py3
-rw-r--r--src/engine/SCons/EnvironmentTests.py8
-rw-r--r--src/engine/SCons/Node/FS.py4
-rw-r--r--src/engine/SCons/Node/__init__.py4
-rw-r--r--src/engine/SCons/SConfTests.py4
-rw-r--r--src/engine/SCons/SConsign.py323
-rw-r--r--src/engine/SCons/SConsignTests.py180
-rw-r--r--src/engine/SCons/Script/__init__.py2
-rw-r--r--src/engine/SCons/Sig/SigTests.py138
-rw-r--r--src/engine/SCons/Sig/__init__.py290
-rw-r--r--src/script/sconsign.py4
12 files changed, 521 insertions, 440 deletions
diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in
index 4942be8..1b8a06f 100644
--- a/src/engine/MANIFEST.in
+++ b/src/engine/MANIFEST.in
@@ -40,6 +40,7 @@ SCons/Scanner/Fortran.py
SCons/Scanner/IDL.py
SCons/Scanner/Prog.py
SCons/SConf.py
+SCons/SConsign.py
SCons/Script/SConscript.py
SCons/Script/__init__.py
SCons/Sig/__init__.py
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index d4279d1..b920643 100644
--- a/src/engine/SCons/Environment.py
+++ b/src/engine/SCons/Environment.py
@@ -53,6 +53,7 @@ import SCons.Node.Alias
import SCons.Node.FS
import SCons.Node.Python
import SCons.Platform
+import SCons.SConsign
import SCons.Sig
import SCons.Sig.MD5
import SCons.Sig.TimeStamp
@@ -1164,7 +1165,7 @@ class Base:
name = self.subst(name)
if not os.path.isabs(name):
name = os.path.join(str(self.fs.SConstruct_dir), name)
- SCons.Sig.SConsignFile(name, dbm_module)
+ SCons.SConsign.File(name, dbm_module)
def SideEffect(self, side_effect, target):
"""Tell scons that side_effects are built as side
diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py
index 8bab246..8ac43cb 100644
--- a/src/engine/SCons/EnvironmentTests.py
+++ b/src/engine/SCons/EnvironmentTests.py
@@ -2214,7 +2214,7 @@ class EnvironmentTestCase(unittest.TestCase):
def test_SConsignFile(self):
"""Test the SConsignFile() method"""
- import SCons.Sig
+ import SCons.SConsign
class MyFS:
SConstruct_dir = os.sep + 'dir'
@@ -2230,8 +2230,8 @@ class EnvironmentTestCase(unittest.TestCase):
fnames.append(name)
dbms.append(dbm_module)
- save_Sig_SConsignFile = SCons.Sig.SConsignFile
- SCons.Sig.SConsignFile = capture
+ save_SConsign_File = SCons.SConsign.File
+ SCons.SConsign.File = capture
env.SConsignFile('foo')
assert fnames[0] == os.path.join(os.sep, 'dir', 'foo'), fnames
@@ -2257,7 +2257,7 @@ class EnvironmentTestCase(unittest.TestCase):
assert fnames[5] == os.path.join(os.sep, 'dir', '.sconsign'), fnames
assert dbms[5] == None, dbms
finally:
- SCons.Sig.SConsignFile = save_Sig_SConsignFile
+ SCons.SConsign.File = save_SConsign_File
def test_SideEffect(self):
"""Test the SideEffect() method"""
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index 008976b..0c6627c 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -1316,8 +1316,8 @@ class Dir(Base):
"""Return the .sconsign file info for this directory,
creating it first if necessary."""
if not self._sconsign:
- import SCons.Sig
- self._sconsign = SCons.Sig.SConsignForDirectory(self)
+ import SCons.SConsign
+ self._sconsign = SCons.SConsign.ForDirectory(self)
return self._sconsign
def srcnode(self):
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 9a4162c..6790cb5 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -49,7 +49,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import copy
from SCons.Debug import logInstanceCreation
-import SCons.Sig
+import SCons.SConsign
import SCons.Util
# Node states
@@ -565,7 +565,7 @@ class Node:
def get_prevsiginfo(self):
"""Fetch the previous signature information from the
.sconsign entry."""
- return SCons.Sig._SConsign.null_siginfo
+ return SCons.SConsign.Base.null_siginfo
def get_timestamp(self):
return 0
diff --git a/src/engine/SCons/SConfTests.py b/src/engine/SCons/SConfTests.py
index b8502b0..8bc11ad 100644
--- a/src/engine/SCons/SConfTests.py
+++ b/src/engine/SCons/SConfTests.py
@@ -52,8 +52,8 @@ class SConfTestCase(unittest.TestCase):
def _resetSConfState(self):
# Ok, this is tricky, and i do not know, if everything is sane.
# We try to reset scons' state (including all global variables)
- import SCons.Sig
- SCons.Sig.write() # simulate normal scons-finish
+ import SCons.SConsign
+ SCons.SConsign.write() # simulate normal scons-finish
for n in sys.modules.keys():
if string.split(n, '.')[0] == 'SCons':
m = sys.modules[n]
diff --git a/src/engine/SCons/SConsign.py b/src/engine/SCons/SConsign.py
new file mode 100644
index 0000000..a91817b
--- /dev/null
+++ b/src/engine/SCons/SConsign.py
@@ -0,0 +1,323 @@
+"""SCons.SConsign
+
+Writing and reading information to the .sconsign file or files.
+
+"""
+
+#
+# __COPYRIGHT__
+#
+# 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 cPickle
+import os
+import os.path
+import time
+
+import SCons.Sig
+import SCons.Node
+import SCons.Warnings
+
+#XXX Get rid of the global array so this becomes re-entrant.
+sig_files = []
+
+database = None
+
+def write():
+ global sig_files
+ for sig_file in sig_files:
+ sig_file.write()
+
+
+class Entry:
+
+ """Objects of this type are pickled to the .sconsign file, so it
+ should only contain simple builtin Python datatypes and no methods.
+
+ This class is used to store cache information about nodes between
+ scons runs for efficiency, and to store the build signature for
+ nodes so that scons can determine if they are out of date. """
+
+ # setup the default value for various attributes:
+ # (We make the class variables so the default values won't get pickled
+ # with the instances, which would waste a lot of space)
+ timestamp = None
+ bsig = None
+ csig = None
+ implicit = None
+ bkids = []
+ bkidsigs = []
+ bact = None
+ bactsig = None
+
+class Base:
+ """
+ This is the controlling class for the signatures for the collection of
+ entries associated with a specific directory. The actual directory
+ association will be maintained by a subclass that is specific to
+ the underlying storage method. This class provides a common set of
+ methods for fetching and storing the individual bits of information
+ that make up signature entry.
+ """
+ def __init__(self, module=None):
+ """
+ module - the signature module being used
+ """
+
+ self.module = module or SCons.Sig.default_calc.module
+ self.entries = {}
+ self.dirty = 0
+
+ # A null .sconsign entry. We define this here so that it will
+ # be easy to keep this in sync if/whenever we change the type of
+ # information returned by the get() method, below.
+ null_siginfo = (None, None, None)
+
+ def get(self, filename):
+ """
+ Get the .sconsign entry for a file
+
+ filename - the filename whose signature will be returned
+ returns - (timestamp, bsig, csig)
+ """
+ entry = self.get_entry(filename)
+ return (entry.timestamp, entry.bsig, entry.csig)
+
+ def get_entry(self, filename):
+ """
+ Create an entry for the filename and return it, or if one already exists,
+ then return it.
+ """
+ try:
+ return self.entries[filename]
+ except (KeyError, AttributeError):
+ return Entry()
+
+ def set_entry(self, filename, entry):
+ """
+ Set the entry.
+ """
+ self.entries[filename] = entry
+ self.dirty = 1
+
+ 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.get_entry(filename)
+ entry.csig = csig
+ self.set_entry(filename, entry)
+
+ def set_binfo(self, filename, bsig, bkids, bkidsigs, bact, bactsig):
+ """
+ Set the build info .sconsign entry for a file
+
+ filename - the filename whose signature will be set
+ bsig - the file's built signature
+ """
+
+ entry = self.get_entry(filename)
+ entry.bsig = bsig
+ entry.bkids = bkids
+ entry.bkidsigs = bkidsigs
+ entry.bact = bact
+ entry.bactsig = bactsig
+ self.set_entry(filename, entry)
+
+ def set_timestamp(self, filename, timestamp):
+ """
+ Set the timestamp .sconsign entry for a file
+
+ filename - the filename whose signature will be set
+ timestamp - the file's timestamp
+ """
+
+ entry = self.get_entry(filename)
+ entry.timestamp = timestamp
+ self.set_entry(filename, entry)
+
+ def get_implicit(self, filename):
+ """Fetch the cached implicit dependencies for 'filename'"""
+ entry = self.get_entry(filename)
+ return entry.implicit
+
+ def set_implicit(self, filename, implicit):
+ """Cache the implicit dependencies for 'filename'."""
+ entry = self.get_entry(filename)
+ if not SCons.Util.is_List(implicit):
+ implicit = [implicit]
+ implicit = map(str, implicit)
+ entry.implicit = implicit
+ self.set_entry(filename, entry)
+
+ def get_binfo(self, filename):
+ """Fetch the cached implicit dependencies for 'filename'"""
+ entry = self.get_entry(filename)
+ return entry.bsig, entry.bkids, entry.bkidsigs, entry.bact, entry.bactsig
+
+class DB(Base):
+ """
+ A Base subclass that reads and writes signature information
+ from a global .sconsign.dbm file.
+ """
+ def __init__(self, dir, module=None):
+ Base.__init__(self, module)
+
+ self.dir = dir
+
+ try:
+ global database
+ rawentries = database[self.dir.path]
+ except KeyError:
+ pass
+ else:
+ try:
+ self.entries = cPickle.loads(rawentries)
+ if type(self.entries) is not type({}):
+ self.entries = {}
+ raise TypeError
+ except KeyboardInterrupt:
+ raise
+ except:
+ SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
+ "Ignoring corrupt sconsign entry : %s"%self.dir.path)
+
+ global sig_files
+ sig_files.append(self)
+
+ def write(self):
+ if self.dirty:
+ global database
+ database[self.dir.path] = cPickle.dumps(self.entries, 1)
+ try:
+ database.sync()
+ except AttributeError:
+ # Not all anydbm modules have sync() methods.
+ pass
+
+class Dir(Base):
+ def __init__(self, fp=None, module=None):
+ """
+ fp - file pointer to read entries from
+ module - the signature module being used
+ """
+ Base.__init__(self, module)
+
+ if fp:
+ self.entries = cPickle.load(fp)
+ if type(self.entries) is not type({}):
+ self.entries = {}
+ raise TypeError
+
+class DirFile(Dir):
+ """
+ Encapsulates reading and writing a per-directory .sconsign file.
+ """
+ def __init__(self, dir, module=None):
+ """
+ dir - the directory for the file
+ module - the signature module being used
+ """
+
+ self.dir = dir
+ self.sconsign = os.path.join(dir.path, '.sconsign')
+
+ try:
+ fp = open(self.sconsign, 'rb')
+ except IOError:
+ fp = None
+
+ try:
+ Dir.__init__(self, fp, module)
+ except KeyboardInterrupt:
+ raise
+ except:
+ SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
+ "Ignoring corrupt .sconsign file: %s"%self.sconsign)
+
+ global sig_files
+ sig_files.append(self)
+
+ def write(self):
+ """
+ Write the .sconsign file to disk.
+
+ Try to write to a temporary file first, and rename it if we
+ succeed. If we can't write to the temporary file, it's
+ probably because the directory isn't writable (and if so,
+ how did we build anything in this directory, anyway?), so
+ try to write directly to the .sconsign file as a backup.
+ If we can't rename, try to copy the temporary contents back
+ to the .sconsign file. Either way, always try to remove
+ the temporary file at the end.
+ """
+ if self.dirty:
+ temp = os.path.join(self.dir.path, '.scons%d' % os.getpid())
+ try:
+ file = open(temp, 'wb')
+ fname = temp
+ except IOError:
+ try:
+ file = open(self.sconsign, 'wb')
+ fname = self.sconsign
+ except IOError:
+ return
+ cPickle.dump(self.entries, file, 1)
+ file.close()
+ if fname != self.sconsign:
+ try:
+ mode = os.stat(self.sconsign)[0]
+ os.chmod(self.sconsign, 0666)
+ os.unlink(self.sconsign)
+ except OSError:
+ pass
+ try:
+ os.rename(fname, self.sconsign)
+ except OSError:
+ open(self.sconsign, 'wb').write(open(fname, 'rb').read())
+ os.chmod(self.sconsign, mode)
+ try:
+ os.unlink(temp)
+ except OSError:
+ pass
+
+ForDirectory = DirFile
+
+def File(name, dbm_module=None):
+ """
+ Arrange for all signatures to be stored in a global .sconsign.dbm
+ file.
+ """
+ global database
+ if database is None:
+ if dbm_module is None:
+ import SCons.dblite
+ dbm_module = SCons.dblite
+ database = dbm_module.open(name, "c")
+
+ global ForDirectory
+ ForDirectory = DB
diff --git a/src/engine/SCons/SConsignTests.py b/src/engine/SCons/SConsignTests.py
new file mode 100644
index 0000000..5f8e981
--- /dev/null
+++ b/src/engine/SCons/SConsignTests.py
@@ -0,0 +1,180 @@
+#
+# __COPYRIGHT__
+#
+# 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 unittest
+import TestCmd
+import SCons.SConsign
+import sys
+
+class SConsignEntryTestCase(unittest.TestCase):
+
+ def runTest(self):
+ e = SCons.SConsign.Entry()
+ assert e.timestamp == None
+ assert e.csig == None
+ assert e.bsig == None
+ assert e.implicit == None
+
+class BaseTestCase(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.SConsign.Base()
+ f.set_binfo('foo', 1, ['f1'], ['f2'], 'foo act', 'foo actsig')
+ 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']
+
+ f = SCons.SConsign.Base(DummyModule())
+ f.set_binfo('foo', 1, ['f1'], ['f2'], 'foo act', 'foo actsig')
+ 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']
+
+class SConsignDBTestCase(unittest.TestCase):
+
+ def runTest(self):
+ class DummyNode:
+ def __init__(self, path):
+ self.path = path
+ save_database = SCons.SConsign.database
+ SCons.SConsign.database = {}
+ try:
+ d1 = SCons.SConsign.DB(DummyNode('dir1'))
+ d1.set_timestamp('foo', 1)
+ d1.set_binfo('foo', 2, ['f1'], ['f2'], 'foo act', 'foo actsig')
+ d1.set_csig('foo', 3)
+ d1.set_timestamp('bar', 4)
+ d1.set_binfo('bar', 5, ['b1'], ['b2'], 'bar act', 'bar actsig')
+ d1.set_csig('bar', 6)
+ assert d1.get('foo') == (1, 2, 3)
+ assert d1.get('bar') == (4, 5, 6)
+
+ d2 = SCons.SConsign.DB(DummyNode('dir1'))
+ d2.set_timestamp('foo', 7)
+ d2.set_binfo('foo', 8, ['f3'], ['f4'], 'foo act', 'foo actsig')
+ d2.set_csig('foo', 9)
+ d2.set_timestamp('bar', 10)
+ d2.set_binfo('bar', 11, ['b3'], ['b4'], 'bar act', 'bar actsig')
+ d2.set_csig('bar', 12)
+ assert d2.get('foo') == (7, 8, 9)
+ assert d2.get('bar') == (10, 11, 12)
+ finally:
+ SCons.SConsign.database = save_database
+
+class SConsignDirFileTestCase(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.SConsign.DirFile(DummyNode(), DummyModule())
+ f.set_binfo('foo', 1, ['f1'], ['f2'], 'foo act', 'foo actsig')
+ 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']
+
+class SConsignFileTestCase(unittest.TestCase):
+
+ def runTest(self):
+ test = TestCmd.TestCmd(workdir = '')
+ file = test.workpath('sconsign_file')
+
+ assert SCons.SConsign.database is None, SCons.SConsign.database
+
+ SCons.SConsign.File(file)
+
+ assert not SCons.SConsign.database is SCons.dblite, SCons.SConsign.database
+
+ class Fake_DBM:
+ def open(self, name, mode):
+ self.name = name
+ self.mode = mode
+ return self
+
+ fake_dbm = Fake_DBM()
+
+ SCons.SConsign.File(file, fake_dbm)
+
+ assert not SCons.SConsign.database is None, SCons.SConsign.database
+ assert not hasattr(fake_dbm, 'name'), fake_dbm
+ assert not hasattr(fake_dbm, 'mode'), fake_dbm
+
+ SCons.SConsign.database = None
+
+ SCons.SConsign.File(file, fake_dbm)
+
+ assert not SCons.SConsign.database is None, SCons.SConsign.database
+ assert fake_dbm.name == file, fake_dbm.name
+ assert fake_dbm.mode == "c", fake_dbm.mode
+
+
+
+def suite():
+ suite = unittest.TestSuite()
+ suite.addTest(SConsignEntryTestCase())
+ suite.addTest(BaseTestCase())
+ suite.addTest(SConsignDBTestCase())
+ suite.addTest(SConsignDirFileTestCase())
+ suite.addTest(SConsignFileTestCase())
+ return suite
+
+if __name__ == "__main__":
+ runner = unittest.TextTestRunner()
+ result = runner.run(suite())
+ if not result.wasSuccessful():
+ sys.exit(1)
+
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index ee1ec81..3a7d4c1 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -1114,7 +1114,7 @@ def _main(args, parser):
else:
progress_display("scons: " + closing_message)
if not options.noexec:
- SCons.Sig.write()
+ SCons.SConsign.write()
if not memory_stats is None:
memory_stats.append(SCons.Debug.memory())
diff --git a/src/engine/SCons/Sig/SigTests.py b/src/engine/SCons/Sig/SigTests.py
index 76cd931..009addd 100644
--- a/src/engine/SCons/Sig/SigTests.py
+++ b/src/engine/SCons/Sig/SigTests.py
@@ -393,139 +393,6 @@ class CalcTestCase(unittest.TestCase):
nn.always_build = 1
assert not self.calc.current(nn, 33)
-class SConsignEntryTestCase(unittest.TestCase):
-
- def runTest(self):
- e = SCons.Sig.SConsignEntry()
- assert e.timestamp == None
- assert e.csig == None
- assert e.bsig == None
- assert e.implicit == None
-
-class _SConsignTestCase(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._SConsign()
- f.set_binfo('foo', 1, ['f1'], ['f2'], 'foo act', 'foo actsig')
- 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']
-
- f = SCons.Sig._SConsign(DummyModule())
- f.set_binfo('foo', 1, ['f1'], ['f2'], 'foo act', 'foo actsig')
- 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']
-
-class SConsignDBTestCase(unittest.TestCase):
-
- def runTest(self):
- class DummyNode:
- def __init__(self, path):
- self.path = path
- save_SConsign_db = SCons.Sig.SConsign_db
- SCons.Sig.SConsign_db = {}
- try:
- d1 = SCons.Sig.SConsignDB(DummyNode('dir1'))
- d1.set_timestamp('foo', 1)
- d1.set_binfo('foo', 2, ['f1'], ['f2'], 'foo act', 'foo actsig')
- d1.set_csig('foo', 3)
- d1.set_timestamp('bar', 4)
- d1.set_binfo('bar', 5, ['b1'], ['b2'], 'bar act', 'bar actsig')
- d1.set_csig('bar', 6)
- assert d1.get('foo') == (1, 2, 3)
- assert d1.get('bar') == (4, 5, 6)
-
- d2 = SCons.Sig.SConsignDB(DummyNode('dir1'))
- d2.set_timestamp('foo', 7)
- d2.set_binfo('foo', 8, ['f3'], ['f4'], 'foo act', 'foo actsig')
- d2.set_csig('foo', 9)
- d2.set_timestamp('bar', 10)
- d2.set_binfo('bar', 11, ['b3'], ['b4'], 'bar act', 'bar actsig')
- d2.set_csig('bar', 12)
- assert d2.get('foo') == (7, 8, 9)
- assert d2.get('bar') == (10, 11, 12)
- finally:
- SCons.Sig.SConsign_db = save_SConsign_db
-
-class SConsignDirFileTestCase(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.SConsignDirFile(DummyNode(), DummyModule())
- f.set_binfo('foo', 1, ['f1'], ['f2'], 'foo act', 'foo actsig')
- 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']
-
-class SConsignFileTestCase(unittest.TestCase):
-
- def runTest(self):
- test = TestCmd.TestCmd(workdir = '')
- file = test.workpath('sconsign_file')
-
- assert SCons.Sig.SConsign_db is None, SCons.Sig.SConsign_db
-
- SCons.Sig.SConsignFile(file)
-
- assert not SCons.Sig.SConsign_db is SCons.dblite, SCons.Sig.SConsign_db
-
- class Fake_DBM:
- def open(self, name, mode):
- self.name = name
- self.mode = mode
- return self
-
- fake_dbm = Fake_DBM()
-
- SCons.Sig.SConsignFile(file, fake_dbm)
-
- assert not SCons.Sig.SConsign_db is None, SCons.Sig.SConsign_db
- assert not hasattr(fake_dbm, 'name'), fake_dbm
- assert not hasattr(fake_dbm, 'mode'), fake_dbm
-
- SCons.Sig.SConsign_db = None
-
- SCons.Sig.SConsignFile(file, fake_dbm)
-
- assert not SCons.Sig.SConsign_db is None, SCons.Sig.SConsign_db
- assert fake_dbm.name == file, fake_dbm.name
- assert fake_dbm.mode == "c", fake_dbm.mode
-
def suite():
@@ -533,11 +400,6 @@ def suite():
suite.addTest(MD5TestCase())
suite.addTest(TimeStampTestCase())
suite.addTest(CalcTestCase())
- suite.addTest(SConsignEntryTestCase())
- suite.addTest(_SConsignTestCase())
- suite.addTest(SConsignDBTestCase())
- suite.addTest(SConsignDirFileTestCase())
- 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 dac3f6c..271f252 100644
--- a/src/engine/SCons/Sig/__init__.py
+++ b/src/engine/SCons/Sig/__init__.py
@@ -46,293 +46,6 @@ except ImportError:
default_max_drift = 2*24*60*60
-#XXX Get rid of the global array so this becomes re-entrant.
-sig_files = []
-
-SConsign_db = None
-
-def write():
- global sig_files
- for sig_file in sig_files:
- sig_file.write()
-
-
-class SConsignEntry:
-
- """Objects of this type are pickled to the .sconsign file, so it
- should only contain simple builtin Python datatypes and no methods.
-
- This class is used to store cache information about nodes between
- scons runs for efficiency, and to store the build signature for
- nodes so that scons can determine if they are out of date. """
-
- # setup the default value for various attributes:
- # (We make the class variables so the default values won't get pickled
- # with the instances, which would waste a lot of space)
- timestamp = None
- bsig = None
- csig = None
- implicit = None
- bkids = []
- bkidsigs = []
- bact = None
- bactsig = None
-
-class _SConsign:
- """
- This is the controlling class for the signatures for the collection of
- entries associated with a specific directory. The actual directory
- association will be maintained by a subclass that is specific to
- the underlying storage method. This class provides a common set of
- methods for fetching and storing the individual bits of information
- that make up signature entry.
- """
- def __init__(self, module=None):
- """
- module - the signature module being used
- """
-
- if module is None:
- self.module = default_calc.module
- else:
- self.module = module
- self.entries = {}
- self.dirty = 0
-
- # A null .sconsign entry. We define this here so that it will
- # be easy to keep this in sync if/whenever we change the type of
- # information returned by the get() method, below.
- null_siginfo = (None, None, None)
-
- def get(self, filename):
- """
- Get the .sconsign entry for a file
-
- filename - the filename whose signature will be returned
- returns - (timestamp, bsig, csig)
- """
- entry = self.get_entry(filename)
- return (entry.timestamp, entry.bsig, entry.csig)
-
- def get_entry(self, filename):
- """
- Create an entry for the filename and return it, or if one already exists,
- then return it.
- """
- try:
- return self.entries[filename]
- except (KeyError, AttributeError):
- return SConsignEntry()
-
- def set_entry(self, filename, entry):
- """
- Set the entry.
- """
- self.entries[filename] = entry
- self.dirty = 1
-
- 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.get_entry(filename)
- entry.csig = csig
- self.set_entry(filename, entry)
-
- def set_binfo(self, filename, bsig, bkids, bkidsigs, bact, bactsig):
- """
- Set the build info .sconsign entry for a file
-
- filename - the filename whose signature will be set
- bsig - the file's built signature
- """
-
- entry = self.get_entry(filename)
- entry.bsig = bsig
- entry.bkids = bkids
- entry.bkidsigs = bkidsigs
- entry.bact = bact
- entry.bactsig = bactsig
- self.set_entry(filename, entry)
-
- def set_timestamp(self, filename, timestamp):
- """
- Set the timestamp .sconsign entry for a file
-
- filename - the filename whose signature will be set
- timestamp - the file's timestamp
- """
-
- entry = self.get_entry(filename)
- entry.timestamp = timestamp
- self.set_entry(filename, entry)
-
- def get_implicit(self, filename):
- """Fetch the cached implicit dependencies for 'filename'"""
- entry = self.get_entry(filename)
- return entry.implicit
-
- def set_implicit(self, filename, implicit):
- """Cache the implicit dependencies for 'filename'."""
- entry = self.get_entry(filename)
- if not SCons.Util.is_List(implicit):
- implicit = [implicit]
- implicit = map(str, implicit)
- entry.implicit = implicit
- self.set_entry(filename, entry)
-
- def get_binfo(self, filename):
- """Fetch the cached implicit dependencies for 'filename'"""
- entry = self.get_entry(filename)
- return entry.bsig, entry.bkids, entry.bkidsigs, entry.bact, entry.bactsig
-
-class SConsignDB(_SConsign):
- """
- A _SConsign subclass that reads and writes signature information
- from a global .sconsign.dbm file.
- """
- def __init__(self, dir, module=None):
- _SConsign.__init__(self, module)
-
- self.dir = dir
-
- try:
- global SConsign_db
- rawentries = SConsign_db[self.dir.path]
- except KeyError:
- pass
- else:
- try:
- self.entries = cPickle.loads(rawentries)
- if type(self.entries) is not type({}):
- self.entries = {}
- raise TypeError
- except KeyboardInterrupt:
- raise
- except:
- SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
- "Ignoring corrupt sconsign entry : %s"%self.dir.path)
-
- global sig_files
- sig_files.append(self)
-
- def write(self):
- if self.dirty:
- global SConsign_db
- SConsign_db[self.dir.path] = cPickle.dumps(self.entries, 1)
- try:
- SConsign_db.sync()
- except AttributeError:
- # Not all anydbm modules have sync() methods.
- pass
-
-class SConsignDir(_SConsign):
- def __init__(self, fp=None, module=None):
- """
- fp - file pointer to read entries from
- module - the signature module being used
- """
- _SConsign.__init__(self, module)
-
- if fp:
- self.entries = cPickle.load(fp)
- if type(self.entries) is not type({}):
- self.entries = {}
- raise TypeError
-
-class SConsignDirFile(SConsignDir):
- """
- Encapsulates reading and writing a per-directory .sconsign file.
- """
- def __init__(self, dir, module=None):
- """
- dir - the directory for the file
- module - the signature module being used
- """
-
- self.dir = dir
- self.sconsign = os.path.join(dir.path, '.sconsign')
-
- try:
- fp = open(self.sconsign, 'rb')
- except IOError:
- fp = None
-
- try:
- SConsignDir.__init__(self, fp, module)
- except KeyboardInterrupt:
- raise
- except:
- SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
- "Ignoring corrupt .sconsign file: %s"%self.sconsign)
-
- global sig_files
- sig_files.append(self)
-
- def write(self):
- """
- Write the .sconsign file to disk.
-
- Try to write to a temporary file first, and rename it if we
- succeed. If we can't write to the temporary file, it's
- probably because the directory isn't writable (and if so,
- how did we build anything in this directory, anyway?), so
- try to write directly to the .sconsign file as a backup.
- If we can't rename, try to copy the temporary contents back
- to the .sconsign file. Either way, always try to remove
- the temporary file at the end.
- """
- if self.dirty:
- temp = os.path.join(self.dir.path, '.scons%d' % os.getpid())
- try:
- file = open(temp, 'wb')
- fname = temp
- except IOError:
- try:
- file = open(self.sconsign, 'wb')
- fname = self.sconsign
- except IOError:
- return
- cPickle.dump(self.entries, file, 1)
- file.close()
- if fname != self.sconsign:
- try:
- mode = os.stat(self.sconsign)[0]
- os.chmod(self.sconsign, 0666)
- os.unlink(self.sconsign)
- except OSError:
- pass
- try:
- os.rename(fname, self.sconsign)
- except OSError:
- open(self.sconsign, 'wb').write(open(fname, 'rb').read())
- os.chmod(self.sconsign, mode)
- try:
- os.unlink(temp)
- except OSError:
- pass
-
-SConsignForDirectory = SConsignDirFile
-
-def SConsignFile(name, dbm_module=None):
- """
- Arrange for all signatures to be stored in a global .sconsign.dbm
- file.
- """
- global SConsign_db
- if SConsign_db is None:
- if dbm_module is None:
- import SCons.dblite
- dbm_module = SCons.dblite
- SConsign_db = dbm_module.open(name, "c")
-
- global SConsignForDirectory
- SConsignForDirectory = SConsignDB
-
class Calculator:
"""
Encapsulates signature calculations and .sconsign file generating
@@ -420,7 +133,8 @@ class Calculator:
if self.max_drift >= 0:
oldtime, oldbsig, oldcsig = node.get_prevsiginfo()
else:
- oldtime, oldbsig, oldcsig = _SConsign.null_siginfo
+ import SCons.SConsign
+ oldtime, oldbsig, oldcsig = SCons.SConsign.Base.null_siginfo
mtime = node.get_timestamp()
diff --git a/src/script/sconsign.py b/src/script/sconsign.py
index e3905ce..2204927 100644
--- a/src/script/sconsign.py
+++ b/src/script/sconsign.py
@@ -146,7 +146,7 @@ import imp
import string
import whichdb
-import SCons.Sig
+import SCons.SConsign
def my_whichdb(filename):
try:
@@ -286,7 +286,7 @@ def Do_SConsignDir(name):
sys.stderr.write("sconsign: %s\n" % (e))
return
try:
- sconsign = SCons.Sig.SConsignDir(fp)
+ sconsign = SCons.SConsign.Dir(fp)
except:
sys.stderr.write("sconsign: ignoring invalid .sconsign file `%s'\n" % name)
return