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):
import SCons.Node
import time
import SCons.Warnings
+import cPickle
try:
import MD5
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:
"""
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)
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):
"""
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):
"""
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):
"""
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):
"""
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:
import os
import TestSCons
import TestCmd
+import cPickle
test = TestSCons.TestSCons(match = TestCmd.match_re)
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)
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()