summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2005-06-07 11:32:40 (GMT)
committerSteven Knight <knight@baldmt.com>2005-06-07 11:32:40 (GMT)
commit086a115a4add32f83be62140e9c0677cfdb90d73 (patch)
treed6cd2aac66041c1064740f28d018220815d9a210 /src
parent7a75ef62e1067b6c8af61f1656c54f5d6853432c (diff)
downloadSCons-086a115a4add32f83be62140e9c0677cfdb90d73.zip
SCons-086a115a4add32f83be62140e9c0677cfdb90d73.tar.gz
SCons-086a115a4add32f83be62140e9c0677cfdb90d73.tar.bz2
Split Node-specific stuff from BuildInfo into a separate NodeInfo class. Add size info to the File information we collect.
Diffstat (limited to 'src')
-rw-r--r--src/CHANGES.txt5
-rw-r--r--src/RELEASE.txt7
-rw-r--r--src/engine/SCons/Node/FS.py147
-rw-r--r--src/engine/SCons/Node/FSTests.py75
-rw-r--r--src/engine/SCons/Node/NodeTests.py131
-rw-r--r--src/engine/SCons/Node/Python.py8
-rw-r--r--src/engine/SCons/Node/PythonTests.py8
-rw-r--r--src/engine/SCons/Node/__init__.py133
-rw-r--r--src/engine/SCons/SConf.py6
-rw-r--r--src/engine/SCons/SConsign.py1
-rw-r--r--src/engine/SCons/Sig/SigTests.py10
-rw-r--r--src/engine/SCons/Sig/__init__.py12
-rw-r--r--src/script/sconsign.py54
13 files changed, 425 insertions, 172 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 8abf25b..d246dae 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -291,6 +291,11 @@ RELEASE 0.97 - XXX
- Print various --debug= stats even if we exit early (e.g. using -h).
+ - Really only use the cached content signature value if the file
+ is older than --max-drift, not just if --max-drift is set.
+
+ - Remove support for conversion from old (pre 0.96) .sconsign formats.
+
From Wayne Lee:
- Avoid "maximum recursion limit" errors when removing $(-$) pairs
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index bbf0a3a..5b95aa7 100644
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -130,6 +130,13 @@ RELEASE 0.97 - XXX
Python function Actions (including various pre-supplied
SCons Actions) be rebuilt.
+ -- REMOVED CONVERSION FROM PRE-0.96 .sconsign FORMATS
+
+ Because this release involves so many other signature
+ changes that cause rebuilds, the support for automatically
+ converting signature information from .sconsign files
+ written by SCons versions prior to 0.96 has been removed.
+
-- CACHED Configure() RESULTS ARE STORED IN A DIFFERENT FILE
The Configure() subsystem now stores its cached results in a
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index c728ece..3b4e77f 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -482,7 +482,18 @@ class Base(SCons.Node.Node):
return self.rfile().exists()
def getmtime(self):
- return self.stat()[stat.ST_MTIME]
+ st = self.stat()
+ if st:
+ return self.stat()[stat.ST_MTIME]
+ else:
+ return None
+
+ def getsize(self):
+ st = self.stat()
+ if st:
+ return self.stat()[stat.ST_SIZE]
+ else:
+ return None
def isdir(self):
st = self.stat()
@@ -686,6 +697,8 @@ class LocalFS:
return os.path.exists(path)
def getmtime(self, path):
return os.path.getmtime(path)
+ def getsize(self, path):
+ return os.path.getsize(path)
def isdir(self, path):
return os.path.isdir(path)
def isfile(self, path):
@@ -1464,17 +1477,21 @@ class RootDir(Dir):
def src_builder(self):
return _null
-class BuildInfo:
- # bsig needs to stay here, if it's initialized in __init__() then
- # the assignment overwrites any values read from .sconsign files.
+class NodeInfo(SCons.Node.NodeInfo):
+ # The bsig attributes needs to stay here, if it's initialized in
+ # __init__() then the assignment seems to overwrite any values
+ # unpickled from .sconsign files.
bsig = None
+ def __cmp__(self, other):
+ return cmp(self.bsig, other.bsig)
+ def update(self, node):
+ self.timestamp = node.get_timestamp()
+ self.size = node.getsize()
+
+class BuildInfo(SCons.Node.BuildInfo):
def __init__(self, node):
+ SCons.Node.BuildInfo.__init__(self, node)
self.node = node
- def __cmp__(self, other):
- try:
- return cmp(self.bsig, other.bsig)
- except AttributeError:
- return 1
def convert_to_sconsign(self):
"""Convert this BuildInfo object for writing to a .sconsign file
@@ -1568,8 +1585,7 @@ class File(Base):
# in one build (SConstruct file) is a source in a different build.
# See test/chained-build.py for the use case.
entry = self.get_stored_info()
- for key, val in obj.__dict__.items():
- entry.__dict__[key] = val
+ entry.merge(obj)
self.dir.sconsign().set_entry(self.name, entry)
def get_stored_info(self):
@@ -1579,17 +1595,17 @@ class File(Base):
except (KeyError, OSError):
return self.new_binfo()
else:
- if isinstance(stored, BuildInfo):
- return stored
- # The stored build information isn't a BuildInfo object.
- # This probably means it's an old SConsignEntry from SCons
- # 0.95 or before. The relevant attribute names are the same,
- # though, so just copy the attributes over to an object of
- # the correct type.
- binfo = self.new_binfo()
- for key, val in stored.__dict__.items():
- setattr(binfo, key, val)
- return binfo
+ if not hasattr(stored, 'ninfo'):
+ # Transition: The .sconsign file entry has no NodeInfo
+ # object, which means it's a slightly older BuildInfo.
+ # Copy over the relevant attributes.
+ ninfo = stored.ninfo = self.new_ninfo()
+ for attr in ninfo.__dict__.keys():
+ try:
+ setattr(ninfo, attr, getattr(stored, attr))
+ except AttributeError:
+ pass
+ return stored
def get_stored_implicit(self):
binfo = self.get_stored_info()
@@ -1765,20 +1781,19 @@ class File(Base):
self.do_duplicate(src)
return Base.exists(self)
+ #
+ # SIGNATURE SUBSYSTEM
+ #
+
def new_binfo(self):
return BuildInfo(self)
- def del_cinfo(self):
- try:
- del self.binfo.csig
- except AttributeError:
- pass
- try:
- del self.binfo.timestamp
- except AttributeError:
- pass
+ def new_ninfo(self):
+ ninfo = NodeInfo()
+ ninfo.update(self)
+ return ninfo
- def calc_csig(self, calc=None):
+ def get_csig(self, calc=None):
"""
Generate a node's content signature, the digested signature
of its content.
@@ -1787,45 +1802,44 @@ class File(Base):
cache - alternate node to use for the signature cache
returns - the content signature
"""
- if calc is None:
- calc = self.calculator()
-
try:
- return self.binfo.csig
+ return self.binfo.ninfo.csig
except AttributeError:
pass
-
- if calc.max_drift >= 0:
- old = self.get_stored_info()
- else:
- old = self.new_binfo()
- try:
- mtime = self.get_timestamp()
- except OSError:
- mtime = 0
- raise SCons.Errors.UserError, "no such %s" % self
+ if calc is None:
+ calc = self.calculator()
- try:
- if (old.timestamp and old.csig and old.timestamp == mtime):
- # use the signature stored in the .sconsign file
- csig = old.csig
- else:
- csig = calc.module.signature(self)
- except AttributeError:
- csig = calc.module.signature(self)
+ mtime = self.get_timestamp()
- if calc.max_drift >= 0 and (time.time() - mtime) > calc.max_drift:
+ use_stored = calc.max_drift >= 0 and \
+ (time.time() - mtime) > calc.max_drift
+
+ csig = None
+ if use_stored:
+ old = self.get_stored_info().ninfo
try:
- binfo = self.binfo
+ if old.timestamp and old.csig and old.timestamp == mtime:
+ csig = old.csig
except AttributeError:
- binfo = self.binfo = self.new_binfo()
- binfo.csig = csig
- binfo.timestamp = mtime
+ pass
+ if csig is None:
+ csig = calc.module.signature(self)
+
+ binfo = self.get_binfo()
+ ninfo = binfo.ninfo
+ ninfo.csig = csig
+ ninfo.update(self)
+
+ if use_stored:
self.store_info(binfo)
return csig
+ #
+ #
+ #
+
def current(self, calc=None):
self.binfo = self.gen_binfo(calc)
return self._cur2()
@@ -1839,17 +1853,19 @@ class File(Base):
if r != self:
# ...but there is one in a Repository...
old = r.get_stored_info()
- if old == self.binfo:
+ new = self.get_binfo()
+ if new == old:
# ...and it's even up-to-date...
if self._local:
# ...and they'd like a local copy.
LocalCopy(self, r, None)
- self.store_info(self.binfo)
+ self.store_info(new)
return 1
return None
else:
old = self.get_stored_info()
- return (self.binfo == old)
+ new = self.get_binfo()
+ return (new == old)
def rfile(self):
"__cacheable__"
@@ -1870,12 +1886,15 @@ class File(Base):
def cachepath(self):
if not self.fs.CachePath:
return None, None
- if self.binfo.bsig is None:
+ ninfo = self.get_binfo().ninfo
+ if not hasattr(ninfo, 'bsig'):
+ raise SCons.Errors.InternalError, "cachepath(%s) found no bsig" % self.path
+ elif ninfo.bsig is None:
raise SCons.Errors.InternalError, "cachepath(%s) found a bsig of None" % self.path
# Add the path to the cache signature, because multiple
# targets built by the same action will all have the same
# build signature, and we have to differentiate them somehow.
- cache_sig = SCons.Sig.MD5.collect([self.binfo.bsig, self.path])
+ cache_sig = SCons.Sig.MD5.collect([ninfo.bsig, self.path])
subdir = string.upper(cache_sig[0])
dir = os.path.join(self.fs.CachePath, subdir)
return dir, os.path.join(dir, cache_sig)
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 6185de8..f7a2a63 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -627,6 +627,24 @@ class BaseTestCase(_tempdirTestCase):
file = fs.Entry('file')
assert file.getmtime()
+ file = fs.Entry('nonexistent')
+ mtime = file.getmtime()
+ assert mtime is None, mtime
+
+ def test_getsize(self):
+ """Test the Base.getsize() method"""
+ test = self.test
+ test.write("file", "file\n")
+ fs = SCons.Node.FS.FS()
+
+ file = fs.Entry('file')
+ size = file.getsize()
+ assert size == 5, size
+
+ file = fs.Entry('nonexistent')
+ size = file.getsize()
+ assert size is None, size
+
def test_isdir(self):
"""Test the Base.isdir() method"""
test = self.test
@@ -680,6 +698,52 @@ class BaseTestCase(_tempdirTestCase):
nonexistent = fs.Entry('nonexistent')
assert not nonexistent.islink()
+class NodeInfoTestCase(_tempdirTestCase):
+ def test___init__(self):
+ """Test NodeInfo initialization"""
+ ni = SCons.Node.FS.NodeInfo()
+ assert hasattr(ni, 'bsig')
+
+ def test___cmp__(self):
+ """Test comparing NodeInfo objects"""
+ ni1 = SCons.Node.FS.NodeInfo()
+ ni2 = SCons.Node.FS.NodeInfo()
+
+ assert cmp(ni1, ni2) == 0, "ni1 %s != ni2 %s" % (ni1, ni2)
+
+ ni1.bsig = 777
+ assert cmp(ni1, ni2) != 0, "ni1 %s == ni2 %s" % (ni1, ni2)
+
+ ni2.bsig = 777
+ assert cmp(ni1, ni2) == 0, "ni1 %s != ni2 %s" % (ni1, ni2)
+
+ def test_update(self):
+ """Test updating a NodeInfo with on-disk information"""
+ test = self.test
+ test.write('fff', "fff\n")
+ fff = self.fs.File('fff')
+
+ ni = SCons.Node.FS.NodeInfo()
+ assert not hasattr(ni, 'timestamp')
+ assert not hasattr(ni, 'size')
+
+ ni.update(fff)
+ assert ni.timestamp == os.path.getmtime('fff'), ni.timestamp
+ assert ni.size == os.path.getsize('fff'), ni.size
+
+class BuildInfoTestCase(_tempdirTestCase):
+ def test___init__(self):
+ """Test BuildInfo initialization"""
+ fff = self.fs.File('fff')
+ bi = SCons.Node.FS.BuildInfo(fff)
+ assert bi.node is fff, bi.node
+
+ def test_convert_to_sconsign(self):
+ """Test converting to .sconsign file format"""
+
+ def test_convert_from_sconsign(self):
+ """Test converting from .sconsign file format"""
+
class FSTestCase(_tempdirTestCase):
def test_runTest(self):
"""Test FS (file system) Node operations
@@ -2084,7 +2148,7 @@ class StringDirTestCase(unittest.TestCase):
class stored_infoTestCase(unittest.TestCase):
def runTest(self):
- """Test how storing build information"""
+ """Test how we store build information"""
test = TestCmd(workdir = '')
test.subdir('sub')
fs = SCons.Node.FS.FS(test.workpath(''))
@@ -2092,7 +2156,8 @@ class stored_infoTestCase(unittest.TestCase):
d = fs.Dir('sub')
f = fs.File('file1', d)
bi = f.get_stored_info()
- assert bi.bsig == None, bi.bsig
+ assert bi.ninfo.timestamp == 0, bi.ninfo.timestamp
+ assert bi.ninfo.size == None, bi.ninfo.size
class MySConsign:
class Null:
@@ -2343,7 +2408,7 @@ class CacheDirTestCase(unittest.TestCase):
try:
f5 = fs.File("cd.f5")
f5.binfo = f5.new_binfo()
- f5.binfo.bsig = 'a_fake_bsig'
+ f5.binfo.ninfo.bsig = 'a_fake_bsig'
cp = f5.cachepath()
dirname = os.path.join('cache', 'A')
filename = os.path.join(dirname, 'a_fake_bsig')
@@ -2378,7 +2443,7 @@ class CacheDirTestCase(unittest.TestCase):
test.write(cd_f7, "cd.f7\n")
f7 = fs.File(cd_f7)
f7.binfo = f7.new_binfo()
- f7.binfo.bsig = 'f7_bsig'
+ f7.binfo.ninfo.bsig = 'f7_bsig'
warn_caught = 0
try:
@@ -2729,6 +2794,8 @@ if __name__ == "__main__":
suite.addTest(SaveStringsTestCase())
tclasses = [
BaseTestCase,
+ BuildInfoTestCase,
+ NodeInfoTestCase,
FSTestCase,
DirTestCase,
RepositoryTestCase,
diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py
index 3be1d6b..8c2e6ea 100644
--- a/src/engine/SCons/Node/NodeTests.py
+++ b/src/engine/SCons/Node/NodeTests.py
@@ -214,6 +214,104 @@ class Calculator:
+class NodeInfoTestCase(unittest.TestCase):
+
+ def test___cmp__(self):
+ """Test comparing NodeInfo objects"""
+ ni1 = SCons.Node.NodeInfo()
+ ni2 = SCons.Node.NodeInfo()
+
+ assert ni1 == ni2, "%s != %s" % (ni1.__dict__, ni2.__dict__)
+
+ ni1.foo = 777
+ assert ni1 != ni2, "%s == %s" % (ni1.__dict__, ni2.__dict__)
+
+ ni2.foo = 888
+ assert ni1 != ni2, "%s == %s" % (ni1.__dict__, ni2.__dict__)
+
+ ni1.foo = 888
+ assert ni1 == ni2, "%s != %s" % (ni1.__dict__, ni2.__dict__)
+
+ def test_merge(self):
+ """Test merging NodeInfo attributes"""
+ ni1 = SCons.Node.NodeInfo()
+ ni2 = SCons.Node.NodeInfo()
+
+ ni1.a1 = 1
+ ni1.a2 = 2
+
+ ni2.a2 = 222
+ ni2.a3 = 333
+
+ ni1.merge(ni2)
+ assert ni1.__dict__ == {'a1':1, 'a2':222, 'a3':333}, ni1.__dict__
+
+ def test_update(self):
+ """Test the update() method"""
+ ni = SCons.Node.NodeInfo()
+ ni.update(SCons.Node.Node())
+
+
+
+class BuildInfoTestCase(unittest.TestCase):
+
+ def test___init__(self):
+ """Test BuildInfo initialization"""
+ bi = SCons.Node.BuildInfo(SCons.Node.Node())
+ assert hasattr(bi, 'ninfo')
+
+ class MyNode(SCons.Node.Node):
+ def new_ninfo(self):
+ return 'ninfo initialization'
+ bi = SCons.Node.BuildInfo(MyNode())
+ assert bi.ninfo == 'ninfo initialization', bi.ninfo
+
+ def test___cmp__(self):
+ """Test comparing BuildInfo objects"""
+ bi1 = SCons.Node.BuildInfo(SCons.Node.Node())
+ bi2 = SCons.Node.BuildInfo(SCons.Node.Node())
+
+ assert bi1 == bi2, "%s != %s" % (bi1.__dict__, bi2.__dict__)
+
+ bi1.ninfo.foo = 777
+ assert bi1 != bi2, "%s == %s" % (bi1.__dict__, bi2.__dict__)
+
+ bi2.ninfo.foo = 888
+ assert bi1 != bi2, "%s == %s" % (bi1.__dict__, bi2.__dict__)
+
+ bi1.ninfo.foo = 888
+ assert bi1 == bi2, "%s != %s" % (bi1.__dict__, bi2.__dict__)
+
+ bi1.foo = 999
+ assert bi1 == bi2, "%s != %s" % (bi1.__dict__, bi2.__dict__)
+
+ def test_merge(self):
+ """Test merging BuildInfo attributes"""
+ bi1 = SCons.Node.BuildInfo(SCons.Node.Node())
+ bi2 = SCons.Node.BuildInfo(SCons.Node.Node())
+
+ bi1.a1 = 1
+ bi1.a2 = 2
+
+ bi2.a2 = 222
+ bi2.a3 = 333
+
+ bi1.ninfo.a4 = 4
+ bi1.ninfo.a5 = 5
+ bi2.ninfo.a5 = 555
+ bi2.ninfo.a6 = 666
+
+ bi1.merge(bi2)
+ assert bi1.a1 == 1, bi1.a1
+ assert bi1.a2 == 222, bi1.a2
+ assert bi1.a3 == 333, bi1.a3
+ assert bi1.ninfo.a4 == 4, bi1.ninfo.a4
+ assert bi1.ninfo.a5 == 555, bi1.ninfo.a5
+ assert bi1.ninfo.a6 == 666, bi1.ninfo.a6
+
+
+
+
class NodeTestCase(unittest.TestCase):
def test_build(self):
@@ -481,24 +579,36 @@ class NodeTestCase(unittest.TestCase):
a = node.builder.get_actions()
assert isinstance(a[0], MyAction), a[0]
- def test_calc_bsig(self):
+ def test_get_bsig(self):
"""Test generic build signature calculation
"""
node = SCons.Node.Node()
- result = node.calc_bsig(Calculator(222))
+ result = node.get_bsig(Calculator(222))
assert result == 222, result
- result = node.calc_bsig(Calculator(333))
+ result = node.get_bsig(Calculator(333))
assert result == 222, result
- def test_calc_csig(self):
+ def test_get_csig(self):
"""Test generic content signature calculation
"""
node = SCons.Node.Node()
- result = node.calc_csig(Calculator(444))
+ result = node.get_csig(Calculator(444))
assert result == 444, result
- result = node.calc_csig(Calculator(555))
+ result = node.get_csig(Calculator(555))
assert result == 444, result
+ def test_get_binfo(self):
+ """Test fetching/creating a build information structure
+ """
+ node = SCons.Node.Node()
+
+ binfo = node.get_binfo()
+ assert isinstance(binfo, SCons.Node.BuildInfo), binfo
+
+ node.binfo = 777
+ binfo = node.get_binfo()
+ assert binfo == 777, binfo
+
def test_gen_binfo(self):
"""Test generating a build information structure
"""
@@ -507,7 +617,8 @@ class NodeTestCase(unittest.TestCase):
i = SCons.Node.Node()
node.depends = [d]
node.implicit = [i]
- binfo = node.gen_binfo(Calculator(1998))
+ node.gen_binfo(Calculator(666))
+ binfo = node.binfo
assert isinstance(binfo, SCons.Node.BuildInfo), binfo
assert hasattr(binfo, 'bsources')
assert hasattr(binfo, 'bsourcesigs')
@@ -515,7 +626,7 @@ class NodeTestCase(unittest.TestCase):
assert hasattr(binfo, 'bdependsigs')
assert binfo.bimplicit == [i]
assert hasattr(binfo, 'bimplicitsigs')
- assert binfo.bsig == 5994, binfo.bsig
+ assert binfo.ninfo.bsig == 1998, binfo.ninfo.bsig
def test_explain(self):
"""Test explaining why a Node must be rebuilt
@@ -1206,7 +1317,9 @@ class NodeListTestCase(unittest.TestCase):
if __name__ == "__main__":
suite = unittest.TestSuite()
- tclasses = [ NodeTestCase,
+ tclasses = [ BuildInfoTestCase,
+ NodeInfoTestCase,
+ NodeTestCase,
NodeListTestCase ]
for tclass in tclasses:
names = unittest.getTestCaseNames(tclass, 'test_')
diff --git a/src/engine/SCons/Node/Python.py b/src/engine/SCons/Node/Python.py
index cabc162..0e1c985 100644
--- a/src/engine/SCons/Node/Python.py
+++ b/src/engine/SCons/Node/Python.py
@@ -62,7 +62,7 @@ class Value(SCons.Node.Node):
contents = contents + kid.get_contents()
return contents
- def calc_csig(self, calc=None):
+ def get_csig(self, calc=None):
"""Because we're a Python value node and don't have a real
timestamp, we get to ignore the calculator and just use the
value contents."""
@@ -71,8 +71,8 @@ class Value(SCons.Node.Node):
except AttributeError:
binfo = self.binfo = self.new_binfo()
try:
- return binfo.csig
+ return binfo.ninfo.csig
except AttributeError:
- binfo.csig = self.get_contents()
+ binfo.ninfo.csig = self.get_contents()
self.store_info(binfo)
- return binfo.csig
+ return binfo.ninfo.csig
diff --git a/src/engine/SCons/Node/PythonTests.py b/src/engine/SCons/Node/PythonTests.py
index 0fe22a5..78cbf68 100644
--- a/src/engine/SCons/Node/PythonTests.py
+++ b/src/engine/SCons/Node/PythonTests.py
@@ -45,19 +45,19 @@ class ValueTestCase(unittest.TestCase):
assert not v1 is v2
assert v1.value == v2.value
- def test_calc_csig(self):
+ def test_get_csig(self):
"""Test calculating the content signature of a Value() object
"""
v1 = SCons.Node.Python.Value('aaa')
- csig = v1.calc_csig(None)
+ csig = v1.get_csig(None)
assert csig == 'aaa', csig
v2 = SCons.Node.Python.Value(7)
- csig = v2.calc_csig(None)
+ csig = v2.get_csig(None)
assert csig == '7', csig
v3 = SCons.Node.Python.Value(None)
- csig = v3.calc_csig(None)
+ csig = v3.get_csig(None)
assert csig == 'None', csig
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 627d020..b04284d 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -95,9 +95,55 @@ def do_nothing(node): pass
Annotate = do_nothing
-class BuildInfo:
+# Classes for signature info for Nodes.
+
+class NodeInfo:
+ """
+ A generic class for signature information for a Node.
+
+ We actually expect that modules containing Node subclasses will also
+ subclass NodeInfo, to provide their own logic for dealing with their
+ own Node-specific signature information.
+ """
+ def __init__(self):
+ """A null initializer so that subclasses have a superclass
+ initialization method to call for future use.
+ """
+ pass
def __cmp__(self, other):
return cmp(self.__dict__, other.__dict__)
+ def update(self, node):
+ pass
+ def merge(self, other):
+ for key, val in other.__dict__.items():
+ self.__dict__[key] = val
+
+class BuildInfo:
+ """
+ The generic build information for a Node.
+
+ This is what gets stored in a .sconsign file for each target file.
+ It contains a NodeInfo instance for this node (signature information
+ that's specific to the type of Node) and direct attributes for the
+ generic build stuff we have to track: sources, explicit dependencies,
+ implicit dependencies, and action information.
+ """
+ def __init__(self, node):
+ self.ninfo = node.new_ninfo()
+ self.bsourcesigs = []
+ self.bdependsigs = []
+ self.bimplicitsigs = []
+ self.bactsig = None
+ def __cmp__(self, other):
+ return cmp(self.ninfo, other.ninfo)
+ def merge(self, other):
+ for key, val in other.__dict__.items():
+ try:
+ merge = self.__dict__[key].merge
+ except (AttributeError, KeyError):
+ self.__dict__[key] = val
+ else:
+ merge(val)
class Node:
"""The base Node class, for entities that we know how to
@@ -241,28 +287,27 @@ class Node:
parent.del_binfo()
try:
- new_binfo = self.binfo
+ new = self.binfo
except AttributeError:
# Node arrived here without build info; apparently it
# doesn't need it, so don't bother calculating or storing
# it.
- new_binfo = None
+ new = None
# Reset this Node's cached state since it was just built and
# various state has changed.
self.clear()
-
- # Had build info, so it should be stored in the signature
- # cache. However, if the build info included a content
- # signature then it should be recalculated before being
- # stored.
- if new_binfo:
- if hasattr(new_binfo, 'csig'):
- new_binfo = self.gen_binfo() # sets self.binfo
+ if new:
+ # It had build info, so it should be stored in the signature
+ # cache. However, if the build info included a content
+ # signature then it must be recalculated before being stored.
+ if hasattr(new.ninfo, 'csig'):
+ self.get_csig()
else:
- self.binfo = new_binfo
- self.store_info(new_binfo)
+ new.ninfo.update(self)
+ self.binfo = new
+ self.store_info(self.binfo)
def add_to_waiting_parents(self, node):
self.waiting_parents.append(node)
@@ -285,7 +330,6 @@ class Node:
"""
self.executor_cleanup()
self.del_binfo()
- self.del_cinfo()
try:
delattr(self, '_calculated_sig')
except AttributeError:
@@ -504,6 +548,10 @@ class Node:
return
self.env = env
+ #
+ # SIGNATURE SUBSYSTEM
+ #
+
def calculator(self):
import SCons.Defaults
@@ -524,27 +572,30 @@ class Node:
env = self.env or SCons.Defaults.DefaultEnvironment()
if env.use_build_signature():
- return self.calc_bsig(calc)
+ return self.get_bsig(calc)
elif not self.rexists():
return None
- return self.calc_csig(calc)
+ return self.get_csig(calc)
+
+ def new_ninfo(self):
+ return NodeInfo()
def new_binfo(self):
- return BuildInfo()
+ return BuildInfo(self)
- def del_binfo(self):
- """Delete the bsig from this node."""
+ def get_binfo(self):
try:
- delattr(self, 'binfo')
+ return self.binfo
except AttributeError:
- pass
+ self.binfo = self.new_binfo()
+ return self.binfo
- def calc_bsig(self, calc=None):
+ def del_binfo(self):
+ """Delete the build info from this node."""
try:
- return self.binfo.bsig
+ delattr(self, 'binfo')
except AttributeError:
- self.binfo = self.gen_binfo(calc)
- return self.binfo.bsig
+ pass
def gen_binfo(self, calc=None, scan=1):
"""
@@ -565,7 +616,7 @@ class Node:
if calc is None:
calc = self.calculator()
- binfo = self.new_binfo()
+ binfo = self.get_binfo()
if scan:
self.scan()
@@ -602,29 +653,27 @@ class Node:
binfo.bdependsigs = dependsigs
binfo.bimplicitsigs = implicitsigs
- binfo.bsig = calc.module.collect(filter(None, sigs))
+ binfo.ninfo.bsig = calc.module.collect(filter(None, sigs))
return binfo
- def del_cinfo(self):
+ def get_bsig(self, calc=None):
+ binfo = self.get_binfo()
try:
- del self.binfo.csig
+ return binfo.ninfo.bsig
except AttributeError:
- pass
+ self.binfo = self.gen_binfo(calc)
+ return self.binfo.ninfo.bsig
- def calc_csig(self, calc=None):
- try:
- binfo = self.binfo
- except AttributeError:
- binfo = self.binfo = self.new_binfo()
+ def get_csig(self, calc=None):
+ binfo = self.get_binfo()
try:
- return binfo.csig
+ return binfo.ninfo.csig
except AttributeError:
if calc is None:
calc = self.calculator()
- binfo.csig = calc.module.signature(self)
- self.store_info(binfo)
- return binfo.csig
+ csig = binfo.ninfo.csig = calc.module.signature(self)
+ return csig
def store_info(self, obj):
"""Make the build signature permanent (that is, store it in the
@@ -638,6 +687,10 @@ class Node:
"""Fetch the stored implicit dependencies"""
return None
+ #
+ #
+ #
+
def set_precious(self, precious = 1):
"""Set the Node's precious value."""
self.precious = precious
@@ -915,7 +968,7 @@ class Node:
except AttributeError:
return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self
- new = self.binfo
+ new = self.get_binfo()
nsig = {}
dictify(nsig, new.bsources, new.bsourcesigs)
diff --git a/src/engine/SCons/SConf.py b/src/engine/SCons/SConf.py
index 3d1a145..168add9 100644
--- a/src/engine/SCons/SConf.py
+++ b/src/engine/SCons/SConf.py
@@ -163,7 +163,7 @@ class SConfBuildInfo(SCons.Node.FS.BuildInfo):
SCons.Node.FS.BuildInfo.__init__(self, node)
self.result = result
self.string = string
- self.bsig = sig
+ self.ninfo.bsig = sig
class Streamer:
@@ -253,9 +253,9 @@ class SConfBuildTask(SCons.Taskmaster.Task):
else:
new_bsig = t.calc_signature(sconf_global.calc)
if t.env.use_build_signature():
- old_bsig = bi.bsig
+ old_bsig = bi.ninfo.bsig
else:
- old_bsig = bi.csig
+ old_bsig = bi.ninfo.csig
is_up_to_date = (is_up_to_date and new_bsig == old_bsig)
cached_error = cached_error or bi.result
else:
diff --git a/src/engine/SCons/SConsign.py b/src/engine/SCons/SConsign.py
index 073cfc4..10bb98d 100644
--- a/src/engine/SCons/SConsign.py
+++ b/src/engine/SCons/SConsign.py
@@ -36,7 +36,6 @@ import string
import time
import SCons.dblite
-import SCons.Node
import SCons.Sig
import SCons.Warnings
diff --git a/src/engine/SCons/Sig/SigTests.py b/src/engine/SCons/Sig/SigTests.py
index 8964c5c..6b7c83f 100644
--- a/src/engine/SCons/Sig/SigTests.py
+++ b/src/engine/SCons/Sig/SigTests.py
@@ -27,15 +27,6 @@ import unittest
import SCons.Sig
import sys
-class SConsignEntryTestCase(unittest.TestCase):
-
- def runTest(self):
- se = SCons.Sig.SConsignEntry()
- assert hasattr(se, 'timestamp'), "no timestamp attribute"
- assert hasattr(se, 'bsig'), "no bsig attribute"
- assert hasattr(se, 'csig'), "no csig attribute"
- assert hasattr(se, 'implicit'), "no implicit attribute"
-
class CalculatorTestCase(unittest.TestCase):
def runTest(self):
@@ -47,7 +38,6 @@ class CalculatorTestCase(unittest.TestCase):
def suite():
suite = unittest.TestSuite()
- suite.addTest(SConsignEntryTestCase())
suite.addTest(CalculatorTestCase())
return suite
diff --git a/src/engine/SCons/Sig/__init__.py b/src/engine/SCons/Sig/__init__.py
index d746dfa..00c2b83 100644
--- a/src/engine/SCons/Sig/__init__.py
+++ b/src/engine/SCons/Sig/__init__.py
@@ -40,18 +40,6 @@ except ImportError:
# since it's really something about files.
default_max_drift = 2*24*60*60
-class SConsignEntry:
- """The old SConsignEntry format.
- We keep this around to handle conversions from old .sconsign files."""
- timestamp = None
- bsig = None
- csig = None
- implicit = None
- def convert_to_sconsign(self):
- pass
- def convert_from_sconsign(self, dir, name):
- pass
-
class Calculator:
"""
Encapsulates signature calculations and .sconsign file generating
diff --git a/src/script/sconsign.py b/src/script/sconsign.py
index 3303916..6145ad6 100644
--- a/src/script/sconsign.py
+++ b/src/script/sconsign.py
@@ -241,23 +241,30 @@ map_name = {
'implicit' : 'bkids',
}
-def printfield(name, entry):
- def field(name, verbose=Verbose, entry=entry):
- if not Print_Flags[name]:
- return None
- fieldname = map_name.get(name, name)
- mapper = map_field.get(fieldname, default_mapper)
- val = mapper(entry, name)
- if verbose:
- val = name + ": " + val
- return val
-
- fieldlist = ["timestamp", "bsig", "csig"]
- outlist = [name+":"] + filter(None, map(field, fieldlist))
- sep = Verbose and "\n " or " "
- print string.join(outlist, sep)
-
- outlist = field("implicit", 0)
+def field(name, entry, verbose=Verbose):
+ if not Print_Flags[name]:
+ return None
+ fieldname = map_name.get(name, name)
+ mapper = map_field.get(fieldname, default_mapper)
+ val = mapper(entry, name)
+ if verbose:
+ val = name + ": " + val
+ return val
+
+def nodeinfo_string(name, entry, prefix=""):
+ fieldlist = ["bsig", "csig", "timestamp", "size"]
+ f = lambda x, e=entry, v=Verbose: field(x, e, v)
+ outlist = [name+":"] + filter(None, map(f, fieldlist))
+ if Verbose:
+ sep = "\n " + prefix
+ else:
+ sep = " "
+ return string.join(outlist, sep)
+
+def printfield(name, entry, prefix=""):
+ print nodeinfo_string(name, entry.ninfo, prefix)
+
+ outlist = field("implicit", entry, 0)
if outlist:
if Verbose:
print " implicit:"
@@ -273,8 +280,10 @@ def printentries(entries):
else:
printfield(name, entry)
else:
- for name, e in entries.items():
- printfield(name, e)
+ names = entries.keys()
+ names.sort()
+ for name in names:
+ printfield(name, entries[name])
class Do_SConsignDB:
def __init__(self, dbm_name, dbm):
@@ -362,14 +371,15 @@ Options:
-h, --help Print this message and exit.
-i, --implicit Print implicit dependency information.
-r, --readable Print timestamps in human-readable form.
+ -s, --size Print file sizes human-readable form.
-t, --timestamp Print timestamp information.
-v, --verbose Verbose, describe each field.
"""
-opts, args = getopt.getopt(sys.argv[1:], "bcd:e:f:hirtv",
+opts, args = getopt.getopt(sys.argv[1:], "bcd:e:f:hirstv",
['bsig', 'csig', 'dir=', 'entry=',
'format=', 'help', 'implicit',
- 'readable', 'timestamp', 'verbose'])
+ 'readable', 'size', 'timestamp', 'verbose'])
for o, a in opts:
@@ -402,6 +412,8 @@ for o, a in opts:
Print_Flags['implicit'] = 1
elif o in ('-r', '--readable'):
Readable = 1
+ elif o in ('-s', '--size'):
+ Print_Flags['size'] = 1
elif o in ('-t', '--timestamp'):
Print_Flags['timestamp'] = 1
elif o in ('-v', '--verbose'):