entry[key] = entry[key] + 1
except KeyError:
entry[key] = 1
+ return '%s:%d(%s)' % func_shorten(key)
def dump_caller_counts(file=sys.stdout):
keys = caller_dicts.keys()
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.
bsig = None
+ def __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
+
+ We hung onto the node that we refer to so that we can translate
+ the lists of bsources, bdepends and bimplicit Nodes into strings
+ relative to the node, but we don't want to write out that Node
+ itself to the .sconsign file, so we delete the attribute in
+ preparation.
+ """
+ rel_path = self.node.rel_path
+ delattr(self, 'node')
+ for attr in ['bsources', 'bdepends', 'bimplicit']:
+ try:
+ val = getattr(self, attr)
+ except AttributeError:
+ pass
+ else:
+ setattr(self, attr, map(rel_path, val))
+ def convert_from_sconsign(self, dir, name):
+ """Convert a newly-read BuildInfo object for in-SCons use
+
+ An on-disk BuildInfo comes without a reference to the node
+ for which it's intended, so we have to convert the arguments
+ and add back a self.node attribute. The bsources, bdepends and
+ bimplicit lists all come from disk as paths relative to that node,
+ so convert them to actual Nodes for use by the rest of SCons.
+ """
+ self.node = dir.Entry(name)
+ Entry_func = self.node.dir.Entry
+ for attr in ['bsources', 'bdepends', 'bimplicit']:
+ try:
+ val = getattr(self, attr)
+ except AttributeError:
+ pass
+ else:
+ setattr(self, attr, map(Entry_func, val))
class File(Base):
"""A class for files in a file system.
try:
stored = self.dir.sconsign().get_entry(self.name)
except (KeyError, OSError):
- return BuildInfo()
+ return self.new_binfo()
else:
if isinstance(stored, BuildInfo):
return stored
# 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 = BuildInfo()
+ binfo = self.new_binfo()
for key, val in stored.__dict__.items():
setattr(binfo, key, val)
return binfo
def get_stored_implicit(self):
binfo = self.get_stored_info()
- try: implicit = binfo.bimplicit
+ try: return binfo.bimplicit
except AttributeError: return None
- else: return map(self.dir.Entry, implicit)
def rel_path(self, other):
return self.dir.rel_path(other)
return Base.exists(self)
def new_binfo(self):
- return BuildInfo()
+ return BuildInfo(self)
def del_cinfo(self):
try:
if calc.max_drift >= 0:
old = self.get_stored_info()
else:
- old = BuildInfo()
+ old = self.new_binfo()
try:
mtime = self.get_timestamp()
return None
else:
old = self.get_stored_info()
- return (old == self.binfo)
+ return (self.binfo == old)
def rfile(self):
"__cacheable__"
"""Test generating a build information structure
"""
node = SCons.Node.Node()
- binfo = node.gen_binfo(Calculator(666))
+ d = SCons.Node.Node()
+ i = SCons.Node.Node()
+ node.depends = [d]
+ node.implicit = [i]
+ binfo = node.gen_binfo(Calculator(1998))
assert isinstance(binfo, SCons.Node.BuildInfo), binfo
assert hasattr(binfo, 'bsources')
assert hasattr(binfo, 'bsourcesigs')
- assert hasattr(binfo, 'bdepends')
+ assert binfo.bdepends == [d]
assert hasattr(binfo, 'bdependsigs')
- assert hasattr(binfo, 'bimplicit')
+ assert binfo.bimplicit == [i]
assert hasattr(binfo, 'bimplicitsigs')
- assert binfo.bsig == 666, binfo.bsig
-
- def test_rel_path(self):
- """Test the rel_path() method
- """
- node = SCons.Node.Node()
- other = SCons.Node.Node()
- other.__str__ = lambda: "xyzzy"
- r = node.rel_path(other)
- assert r == "xyzzy", r
+ assert binfo.bsig == 5994, binfo.bsig
def test_explain(self):
"""Test explaining why a Node must be rebuilt
def calc_signature(node, calc=calc):
return node.calc_signature(calc)
- bsources = executor.process_sources(self.rel_path, self.ignore)
+ sources = executor.process_sources(None, self.ignore)
sourcesigs = executor.process_sources(calc_signature, self.ignore)
depends = self.depends
binfo.bactsig = calc.module.signature(executor)
sigs.append(binfo.bactsig)
- binfo.bsources = bsources
- binfo.bdepends = map(self.rel_path, depends)
- binfo.bimplicit = map(self.rel_path, implicit)
+ binfo.bsources = sources
+ binfo.bdepends = depends
+ binfo.bimplicit = implicit
binfo.bsourcesigs = sourcesigs
binfo.bdependsigs = dependsigs
return binfo
- def rel_path(self, other):
- # Using other.__str__() instead of str(other) lets the Memoizer
- # get the right method for the underlying Node object, not the
- # __str__() method for the Memoizer wrapper object.
- return other.__str__()
-
def del_cinfo(self):
try:
del self.binfo.csig
result = None # -> 0/None -> no error, != 0 error
string = None # the stdout / stderr output when building the target
- def __init__(self, result, string, sig):
+ def __init__(self, node, result, string, sig):
+ SCons.Node.FS.BuildInfo.__init__(self, node)
self.result = result
self.string = string
self.bsig = sig
for t in self.targets:
sig = t.calc_signature(sconf.calc)
string = s.getvalue()
- t.dir.sconsign().set_entry(t.name,
- SConfBuildInfo(1,string,sig))
+ binfo = SConfBuildInfo(t,1,string,sig)
+ t.dir.sconsign().set_entry(t.name, binfo)
raise
else:
for t in self.targets:
sig = t.calc_signature(sconf.calc)
string = s.getvalue()
- t.dir.sconsign().set_entry(t.name,
- SConfBuildInfo(0,string,sig))
+ binfo = SConfBuildInfo(t,0,string,sig)
+ t.dir.sconsign().set_entry(t.name, binfo)
class SConf:
"""This is simply a class to represent a configure context. After
raise TypeError
except KeyboardInterrupt:
raise
- except:
+ except Exception, e:
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
- "Ignoring corrupt sconsign entry : %s"%self.dir.tpath)
+ "Ignoring corrupt sconsign entry : %s (%s)\n"%(self.dir.tpath, e))
+ for key, entry in self.entries.items():
+ entry.convert_from_sconsign(dir, key)
if mode == "r":
# This directory is actually under a repository, which means
# the Repository; we only write to our own .sconsign file,
# not to .sconsign files in Repositories.
path = norm_entry(self.dir.path)
+ for key, entry in self.entries.items():
+ entry.convert_to_sconsign()
db[path] = cPickle.dumps(self.entries, 1)
if sync:
global sig_files
sig_files.append(self)
+ def get_entry(self, filename):
+ """
+ Fetch the specified entry attribute, converting from .sconsign
+ format to in-memory format.
+ """
+ entry = Dir.get_entry(self, filename)
+ entry.convert_from_sconsign(self.dir, filename)
+ return entry
+
def write(self, sync=1):
"""
Write the .sconsign file to disk.
fname = self.sconsign
except IOError:
return
+ for key, entry in self.entries.items():
+ entry.convert_to_sconsign()
cPickle.dump(self.entries, file, 1)
file.close()
if fname != self.sconsign:
class BuildInfo:
def __init__(self, name):
self.name = name
+ def convert_to_sconsign(self):
+ self.c_to_s = 1
+ def convert_from_sconsign(self, dir, name):
+ self.c_from_s = 1
class DummyModule:
def to_string(self, sig):
class SConsignDirFileTestCase(SConsignTestCase):
def runTest(self):
- foo = BuildInfo('foo')
- bar = BuildInfo('bar')
+ bi_foo = BuildInfo('foo')
+ bi_bar = BuildInfo('bar')
f = SCons.SConsign.DirFile(DummyNode(), DummyModule())
- f.set_entry('foo', foo)
- f.set_entry('bar', bar)
+ f.set_entry('foo', bi_foo)
+ f.set_entry('bar', bi_bar)
e = f.get_entry('foo')
- assert e == foo, e
+ assert e == bi_foo, e
assert e.name == 'foo', e.name
+ assert bi_foo.c_from_s, bi_foo.c_from_s
+
e = f.get_entry('bar')
- assert e == bar, e
+ assert e == bi_bar, e
assert e.name == 'bar', e.name
assert not hasattr(e, 'arg'), e
+ assert bi_bar.c_from_s, bi_bar.c_from_s
+
bbb = BuildInfo('bbb')
bbb.arg = 'bbb arg'
f.set_entry('bar', bbb)
f = SCons.SConsign.DB(DummyNode(), DummyModule())
- f.set_entry('foo', BuildInfo('foo'))
- f.set_entry('bar', BuildInfo('bar'))
+ bi_foo = BuildInfo('foo')
+ bi_bar = BuildInfo('bar')
+ f.set_entry('foo', bi_foo)
+ f.set_entry('bar', bi_bar)
SCons.SConsign.write()
+ assert bi_foo.c_to_s, bi_foo.c_to_s
+ assert bi_bar.c_to_s, bi_bar.c_to_s
+
assert fake_dbm.sync_count == 1, fake_dbm.sync_count
bsig = None
csig = None
implicit = None
+ def convert_to_sconsign(self):
+ pass
+ def convert_from_sconsign(self, dir, name):
+ pass
class Calculator:
"""