summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2002-12-11 06:41:04 (GMT)
committerSteven Knight <knight@baldmt.com>2002-12-11 06:41:04 (GMT)
commit415da53eb50ff3efadc22abfeeba1e7eb1042f71 (patch)
tree425bf1e84c7f7d029ef34c7c71258dcc2ab3aa98
parenteec2b45582390844927b2332ebd7b2dda05045a4 (diff)
downloadSCons-415da53eb50ff3efadc22abfeeba1e7eb1042f71.zip
SCons-415da53eb50ff3efadc22abfeeba1e7eb1042f71.tar.gz
SCons-415da53eb50ff3efadc22abfeeba1e7eb1042f71.tar.bz2
Use pickle for .sconsign. (Anthony Roach)
-rw-r--r--etc/TestSCons.py4
-rw-r--r--src/CHANGES.txt3
-rw-r--r--src/RELEASE.txt11
-rw-r--r--src/engine/SCons/Sig/SigTests.py94
-rw-r--r--src/engine/SCons/Sig/__init__.py149
-rw-r--r--test/sconsign.py12
6 files changed, 76 insertions, 197 deletions
diff --git a/etc/TestSCons.py b/etc/TestSCons.py
index 997104b..c97fd48 100644
--- a/etc/TestSCons.py
+++ b/etc/TestSCons.py
@@ -125,8 +125,8 @@ class TestSCons(TestCmd.TestCmd):
if _failed(self, status):
expect = ''
if status != 0:
- expect = " (expected %d)" % status
- print "%s returned %d%s" % (self.program, _status(self), expect)
+ expect = " (expected %s)" % str(status)
+ print "%s returned %s%s" % (self.program, str(_status(self)), expect)
print "STDOUT ============"
print self.stdout()
print "STDERR ============"
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index e3c4859..ee47871 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -19,6 +19,9 @@ RELEASE 0.10 - XXX
- Add SetJobs() and GetJobs() methods to allow configuration of the
number of default jobs (still overridden by -j).
+ - Convert the .sconsign file format from ASCII to a pickled Python
+ data structure.
+
RELEASE 0.09 - Thu, 5 Dec 2002 04:48:25 -0600
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index 3647944..15f4ca9 100644
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -27,7 +27,16 @@ RELEASE 0.10 - XXX
Please note the following important changes since release 0.09:
- - XXX
+ - The .sconsign file format has been changed from ASCII to a pickled
+ Python data structure. This improves performance and future
+ extensibility, but means that the first time you execute SCons
+ 0.10 on an already-existing source tree, for every .sconsign
+ file in the tree it will report:
+
+ SCons warning: Ignoring corrupt .sconsign file: xxx
+
+ These warnings are normal in this situation and can be safely
+ ignored.
Please note the following important changes since release 0.08:
diff --git a/src/engine/SCons/Sig/SigTests.py b/src/engine/SCons/Sig/SigTests.py
index 37413aa..ccd5897 100644
--- a/src/engine/SCons/Sig/SigTests.py
+++ b/src/engine/SCons/Sig/SigTests.py
@@ -385,101 +385,11 @@ class CalcTestCase(unittest.TestCase):
class SConsignEntryTestCase(unittest.TestCase):
def runTest(self):
- class DummyModule:
- def to_string(self, sig):
- return str(sig)
-
- def from_string(self, sig):
- return int(sig)
-
- m = DummyModule()
- e = SCons.Sig.SConsignEntry(m)
- assert e.timestamp == None
- assert e.csig == None
- assert e.bsig == None
- assert e.get_implicit() == None
- assert e.render(m) == "- - - -"
-
- e = SCons.Sig.SConsignEntry(m, "- - - -")
- assert e.timestamp == None
- assert e.csig == None
- assert e.bsig == None
- assert e.get_implicit() == None
- assert e.render(m) == "- - - -"
-
- # Check backward compatability with pre-0.07 format:
- e = SCons.Sig.SConsignEntry(m, "- - - ")
+ e = SCons.Sig.SConsignEntry()
assert e.timestamp == None
assert e.csig == None
assert e.bsig == None
- assert e.get_implicit() == []
- assert e.render(m) == "- - - \0\0\0\0"
-
- # Check backward compatability with pre-0.07 format:
- e = SCons.Sig.SConsignEntry(m, "- - -")
- assert e.timestamp == None
- assert e.csig == None
- assert e.bsig == None
- assert e.get_implicit() == None
- assert e.render(m) == "- - - -"
-
- e = SCons.Sig.SConsignEntry(m, "- - - \0\0\0\0")
- assert e.timestamp == None
- assert e.csig == None
- assert e.bsig == None
- assert e.get_implicit() == []
- assert e.render(m) == "- - - \0\0\0\0"
-
- # Check backward compatability with pre-0.08 format:
- e = SCons.Sig.SConsignEntry(m, "- - - foo\0bar")
- assert e.timestamp == None
- assert e.csig == None
- assert e.bsig == None
- assert e.get_implicit() == ['foo', 'bar']
- assert e.render(m) == "- - - \0\0foo\0bar\0\0"
-
- e = SCons.Sig.SConsignEntry(m, "- - - \0\0foo\0bar\0\0")
- assert e.timestamp == None
- assert e.csig == None
- assert e.bsig == None
- assert e.get_implicit() == ['foo', 'bar']
- assert e.render(m) == "- - - \0\0foo\0bar\0\0"
-
- e = SCons.Sig.SConsignEntry(m, "123 456 789 \0\0foo bletch\0bar\0\0")
- assert e.timestamp == 123
- assert e.bsig == 456
- assert e.csig == 789
- assert e.get_implicit() == ['foo bletch', 'bar']
- assert e.render(m) == "123 456 789 \0\0foo bletch\0bar\0\0"
-
- # Check backward compatability with pre-0.07 format:
- e = SCons.Sig.SConsignEntry(m, "987 654 321")
- assert e.timestamp == 987
- assert e.bsig == 654
- assert e.csig == 321
- assert e.get_implicit() == None
- assert e.render(m) == "987 654 321 -"
-
- e.set_implicit(None)
- assert e.get_implicit() == None, e.get_implicit()
-
- e.set_implicit('')
- assert e.get_implicit() == [], e.get_implicit()
-
- e.set_implicit('foo')
- assert e.get_implicit() == ['foo'], e.get_implicit()
-
- e.set_implicit('foo bar')
- assert e.get_implicit() == ['foo bar'], e.get_implicit()
-
- e.set_implicit(['foo'])
- assert e.get_implicit() == ['foo'], e.get_implicit()
-
- e.set_implicit(['foo bar'])
- assert e.get_implicit() == ['foo bar'], e.get_implicit()
-
- e.set_implicit(['foo', 'bar'])
- assert e.get_implicit() == ['foo', 'bar'], e.get_implicit()
+ assert e.implicit == None
class SConsignFileTestCase(unittest.TestCase):
diff --git a/src/engine/SCons/Sig/__init__.py b/src/engine/SCons/Sig/__init__.py
index 9a4c846..5de89fa 100644
--- a/src/engine/SCons/Sig/__init__.py
+++ b/src/engine/SCons/Sig/__init__.py
@@ -35,6 +35,7 @@ import string
import SCons.Node
import time
import SCons.Warnings
+import cPickle
try:
import MD5
@@ -56,61 +57,21 @@ def write():
sig_file.write()
class SConsignEntry:
- def __init__(self, module, entry=None):
- self.timestamp = self.csig = self.bsig = self.implicit = None
+ """Objects of this type are pickled to the .sconsign file, so it
+ should only contain simple builtin Python datatypes and no methods.
- if not entry is None:
- arr = map(string.strip, string.split(entry, " ", 3))
-
- try:
- if arr[0] == '-': self.timestamp = None
- else: self.timestamp = int(arr[0])
-
- if arr[1] == '-': self.bsig = None
- else: self.bsig = module.from_string(arr[1])
-
- if arr[2] == '-': self.csig = None
- else: self.csig = module.from_string(arr[2])
-
- if len(arr) < 4: self.implicit = None # pre-0.07 format
- elif arr[3] == '': self.implicit = '' # pre-0.08 format
- elif arr[3] == '-': self.implicit = None
- else: self.implicit = string.replace(arr[3], '\0\0', '')
- except IndexError:
- pass
-
- def render(self, module):
- if self.timestamp is None: timestamp = '-'
- else: timestamp = "%d"%self.timestamp
-
- if self.bsig is None: bsig = '-'
- else: bsig = module.to_string(self.bsig)
-
- if self.csig is None: csig = '-'
- else: csig = module.to_string(self.csig)
-
- if self.implicit is None: implicit = '-'
- else: implicit = '\0\0%s\0\0'%self.implicit
-
- return '%s %s %s %s' % (timestamp, bsig, csig, implicit)
-
- def get_implicit(self):
- if self.implicit is None:
- return None
- elif self.implicit == '':
- return []
- else:
- return string.split(self.implicit, '\0')
-
- def set_implicit(self, implicit):
- if implicit is None:
- self.implicit = None
- else:
- if SCons.Util.is_String(implicit):
- implicit = [implicit]
- self.implicit = string.join(map(str, implicit), '\0')
+ 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
class SConsignFile:
"""
@@ -131,22 +92,22 @@ class SConsignFile:
self.module = module
self.sconsign = os.path.join(dir.path, '.sconsign')
self.entries = {}
- self.dirty = None
+ self.dirty = 0
try:
- file = open(self.sconsign, 'rt')
+ file = open(self.sconsign, 'rb')
except:
pass
else:
- for line in file.readlines():
- try:
- filename, rest = map(string.strip, string.split(line, ":", 1))
- self.entries[filename] = SConsignEntry(self.module, rest)
- except ValueError:
- SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
- "Ignoring corrupt .sconsign file: %s"%self.sconsign)
+ try:
+ self.entries = cPickle.load(file)
+ if type(self.entries) is not type({}):
self.entries = {}
-
+ raise TypeError
+ except:
+ SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
+ "Ignoring corrupt .sconsign file: %s"%self.sconsign)
+
global sig_files
sig_files.append(self)
@@ -157,24 +118,25 @@ class SConsignFile:
filename - the filename whose signature will be returned
returns - (timestamp, bsig, csig)
"""
- try:
- entry = self.entries[filename]
- return (entry.timestamp, entry.bsig, entry.csig)
- except KeyError:
- return (None, None, None)
-
- def create_entry(self, filename):
+ 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:
- entry = self.entries[filename]
- except KeyError:
- entry = SConsignEntry(self.module)
- self.entries[filename] = entry
-
- return entry
+ return self.entries[filename]
+ except:
+ return SConsignEntry()
+
+ def set_entry(self, filename, entry):
+ """
+ Set the entry.
+ """
+ self.entries[filename] = entry
+ self.dirty = 1
def set_csig(self, filename, csig):
"""
@@ -184,9 +146,9 @@ class SConsignFile:
csig - the file's content signature
"""
- entry = self.create_entry(filename)
+ entry = self.get_entry(filename)
entry.csig = csig
- self.dirty = 1
+ self.set_entry(filename, entry)
def set_bsig(self, filename, bsig):
"""
@@ -196,9 +158,9 @@ class SConsignFile:
bsig - the file's built signature
"""
- entry = self.create_entry(filename)
+ entry = self.get_entry(filename)
entry.bsig = bsig
- self.dirty = 1
+ self.set_entry(filename, entry)
def set_timestamp(self, filename, timestamp):
"""
@@ -208,23 +170,23 @@ class SConsignFile:
timestamp - the file's timestamp
"""
- entry = self.create_entry(filename)
+ entry = self.get_entry(filename)
entry.timestamp = timestamp
- self.dirty = 1
+ self.set_entry(filename, entry)
def get_implicit(self, filename):
"""Fetch the cached implicit dependencies for 'filename'"""
- try:
- entry = self.entries[filename]
- return entry.get_implicit()
- except KeyError:
- return None
+ entry = self.get_entry(filename)
+ return entry.implicit
def set_implicit(self, filename, implicit):
"""Cache the implicit dependencies for 'filename'."""
- entry = self.create_entry(filename)
- entry.set_implicit(implicit)
- self.dirty = 1
+ entry = self.get_entry(filename)
+ if SCons.Util.is_String(implicit):
+ implicit = [implicit]
+ implicit = map(str, implicit)
+ entry.implicit = implicit
+ self.set_entry(filename, entry)
def write(self):
"""
@@ -242,18 +204,15 @@ class SConsignFile:
if self.dirty:
temp = os.path.join(self.dir.path, '.scons%d' % os.getpid())
try:
- file = open(temp, 'wt')
+ file = open(temp, 'wb')
fname = temp
except:
try:
- file = open(self.sconsign, 'wt')
+ file = open(self.sconsign, 'wb')
fname = self.sconsign
except:
return
- keys = self.entries.keys()
- keys.sort()
- for name in keys:
- file.write("%s: %s\n" % (name, self.entries[name].render(self.module)))
+ cPickle.dump(self.entries, file, 1)
file.close()
if fname != self.sconsign:
try:
diff --git a/test/sconsign.py b/test/sconsign.py
index 6da6717..ca8792d 100644
--- a/test/sconsign.py
+++ b/test/sconsign.py
@@ -27,6 +27,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os
import TestSCons
import TestCmd
+import cPickle
test = TestSCons.TestSCons(match = TestCmd.match_re)
@@ -59,8 +60,8 @@ sub1__sconsign = test.workpath('sub1', '.sconsign')
sub2__sconsign = test.workpath('sub2', '.sconsign')
sub3__sconsign = test.workpath('sub3', '.sconsign')
-test.write(sub1__sconsign, "")
-test.write(sub2__sconsign, "")
+cPickle.dump({}, open(sub1__sconsign, 'wb'), 1)
+cPickle.dump({}, open(sub2__sconsign, 'wb'), 1)
os.chmod(sub1__sconsign, 0444)
@@ -89,14 +90,11 @@ SCons warning: Ignoring corrupt .sconsign file: sub1..sconsign
stdout = test.wrap_stdout('foo.in->sub1.foo.out\n')
-test.write(sub1__sconsign, 'garbage')
-test.run(arguments = '.', stderr=stderr, stdout=stdout)
-
test.write(sub1__sconsign, 'not:a:sconsign:file')
-test.run(arguments = '.', stderr=stderr, stdout=stdout)
+test.run(arguments = '.', stderr=stderr, stdout=stdout, status=2)
test.write(sub1__sconsign, '\0\0\0\0\0\0\0\0\0\0\0\0\0\0')
-test.run(arguments = '.', stderr=stderr, stdout=stdout)
+test.run(arguments = '.', stderr=stderr, stdout=stdout, status=2)
test.pass_test()