# Have to call arg2nodes yet again, since it is legal for
# emitters to spit out strings as well as Node instances.
- slist = env.arg2nodes(source, source_factory)
tlist = env.arg2nodes(target, target_factory)
+ slist = env.arg2nodes(source, source_factory)
+
+ tlist = map(lambda n: n.disambiguate(), tlist)
+ slist = map(lambda n: n.disambiguate(), slist)
return tlist, slist
self.builder = None
self.is_explicit = None
self.side_effect = 0
+ def disambiguate(self):
+ return self
def __str__(self):
return self.name
def builder_set(self, builder):
for an action."""
bkw = {
'action' : action,
+ 'target_factory' : self.fs.Entry,
'source_factory' : self.fs.Entry,
}
try: bkw['source_scanner'] = kw['source_scanner']
import SCons.Util
import SCons.Warnings
+from SCons.Debug import Trace
+
# The max_drift value: by default, use a cached signature value for
# any file that's been untouched for more than two days.
default_max_drift = 2*24*60*60
self._proxy = ret
return ret
+ def target_from_source(self, prefix, suffix, splitext=SCons.Util.splitext):
+ return self.dir.Entry(prefix + splitext(self.name)[0] + suffix)
+
class Entry(Base):
"""This is the class for generic Node.FS entries--that is, things
that could be a File or a Dir, but we're just not sure yet.
self.clear()
return File.rfile(self)
- def get_found_includes(self, env, scanner, path):
- """If we're looking for included files, it's because this Entry
- is really supposed to be a File itself."""
- return self.disambiguate().get_found_includes(env, scanner, path)
-
def scanner_key(self):
return self.get_suffix()
return '' # avoid errors for dangling symlinks
raise AttributeError
- def rel_path(self, other):
- return self.disambiguate().rel_path(other)
+ def must_be_a_Dir(self):
+ """Called to make sure a Node is a Dir. Since we're an
+ Entry, we can morph into one."""
+ self.__class__ = Dir
+ self._morph()
+ return self
+
+ # The following methods can get called before the Taskmaster has
+ # had a chance to call disambiguate() directly to see if this Entry
+ # should really be a Dir or a File. We therefore use these to call
+ # disambiguate() transparently (from our caller's point of view).
+ #
+ # Right now, this minimal set of methods has been derived by just
+ # looking at some of the methods that will obviously be called early
+ # in any of the various Taskmasters' calling sequences, and then
+ # empirically figuring out which additional methods are necessary
+ # to make various tests pass.
def exists(self):
"""Return if the Entry exists. Check the file system to see
directory."""
return self.disambiguate().exists()
- def missing(self):
- """Return if the Entry is missing. Check the file system to
- see what we should turn into first. Assume a file if there's
- no directory."""
- return self.disambiguate().missing()
-
- def get_csig(self):
- """Return the entry's content signature. Check the file system
- to see what we should turn into first. Assume a file if there's
- no directory."""
- return self.disambiguate().get_csig()
-
- def calc_signature(self, calc=None):
- """Return the Entry's calculated signature. Check the file
- system to see what we should turn into first. Assume a file if
- there's no directory."""
- return self.disambiguate().calc_signature(calc)
-
- def must_be_a_Dir(self):
- """Called to make sure a Node is a Dir. Since we're an
- Entry, we can morph into one."""
- self.__class__ = Dir
- self._morph()
- return self
+ def rel_path(self, other):
+ d = self.disambiguate()
+ if d.__class__ == Entry:
+ raise "rel_path() could not disambiguate File/Dir"
+ return d.rel_path(other)
# This is for later so we can differentiate between Entry the class and Entry
# the method of the FS class.
diskcheck_match(self, self.fs.isfile,
"File %s found where directory expected.")
- def disambiguate(self):
- return self
-
def __clearRepositoryCache(self, duplicate=None):
"""Called when we change the repository(ies) for a directory.
This clears any cached information that is invalidated by changing
if not hasattr(self, '_local'):
self._local = 0
- def disambiguate(self):
- return self
-
def scanner_key(self):
return self.get_suffix()
dir = os.path.join(self.fs.CachePath, subdir)
return dir, os.path.join(dir, cache_sig)
- def target_from_source(self, prefix, suffix, splitext=SCons.Util.splitext):
- return self.dir.File(prefix + splitext(self.name)[0] + suffix)
-
def must_be_a_Dir(self):
"""Called to make sure a Node is a Dir. Since we're already a
File, this is a TypeError..."""
f.get_string(0)
assert f.get_string(1) == 'baz', f.get_string(1)
+ def test_target_from_source(self):
+ """Test the method for generating target nodes from sources"""
+ fs = self.fs
+
x = fs.File('x.c')
t = x.target_from_source('pre-', '-suf')
assert str(t) == 'pre-x-suf', str(t)
+ assert t.__class__ == SCons.Node.FS.Entry
y = fs.File('dir/y')
t = y.target_from_source('pre-', '-suf')
assert str(t) == os.path.join('dir', 'pre-y-suf'), str(t)
+ assert t.__class__ == SCons.Node.FS.Entry
z = fs.File('zz')
t = z.target_from_source('pre-', '-suf', lambda x: x[:-1])
assert str(t) == 'pre-z-suf', str(t)
+ assert t.__class__ == SCons.Node.FS.Entry
+
+ d = fs.Dir('ddd')
+ t = d.target_from_source('pre-', '-suf')
+ assert str(t) == 'pre-ddd-suf', str(t)
+ assert t.__class__ == SCons.Node.FS.Entry
+
+ e = fs.Entry('eee')
+ t = e.target_from_source('pre-', '-suf')
+ assert str(t) == 'pre-eee-suf', str(t)
+ assert t.__class__ == SCons.Node.FS.Entry
def test_same_name(self):
"""Test that a local same-named file isn't found for a Dir lookup"""
e1.rfile()
assert e1.__class__ is SCons.Node.FS.File, e1.__class__
- e2 = fs.Entry('e2')
- e2.get_found_includes(None, None, None)
- assert e2.__class__ is SCons.Node.FS.File, e2.__class__
-
test.subdir('e3d')
test.write('e3f', "e3f\n")
test.subdir('e5d')
test.write('e5f', "e5f\n")
- e5d = fs.Entry('e5d')
- sig = e5d.calc_signature(MyCalc(555))
- assert e5d.__class__ is SCons.Node.FS.Dir, e5d.__class__
- # Node has builder (MkDirBuilder), so executor will calculate
- # the build signature.
- assert sig == 777, sig
-
e5f = fs.Entry('e5f')
sig = e5f.calc_signature(MyCalc(666))
assert e5f.__class__ is SCons.Node.FS.File, e5f.__class__
self.fs.Entry('#topdir')
self.fs.Entry('#topdir/a/b/c')
- def test_missing(self):
- """Test that the Entry.missing() method disambiguates node types"""
- test = TestCmd(workdir='')
- # FS doesn't like the cwd to be something other than its root.
- os.chdir(test.workpath(""))
-
- fs = SCons.Node.FS.FS()
-
- test.subdir('emd')
- test.write('emf', "emf\n")
-
- emd = fs.Entry('emd')
- missing = emd.missing()
- assert emd.__class__ is SCons.Node.FS.Dir, emd.__class__
- assert not missing
-
- emf = fs.Entry('emf')
- missing = emf.missing()
- assert emf.__class__ is SCons.Node.FS.File, emf.__class__
- assert not missing
-
- emn = fs.Entry('emn')
- missing = emn.missing()
- assert emn.__class__ is SCons.Node.FS.File, emn.__class__
- assert missing
-
- def test_get_csig(self):
- """Test that the Entry.get_csig() method disambiguates node types"""
- test = TestCmd(workdir='')
- # FS doesn't like the cwd to be something other than its root.
- os.chdir(test.workpath(""))
-
- fs = SCons.Node.FS.FS()
-
- test.subdir('egcd')
- test.write('egcf', "egcf\n")
-
- egcd = fs.Entry('egcd')
- egcd.get_csig()
- assert egcd.__class__ is SCons.Node.FS.Dir, egcd.__class__
-
- egcf = fs.Entry('egcf')
- egcf.get_csig()
- assert egcf.__class__ is SCons.Node.FS.File, egcf.__class__
-
- egcn = fs.Entry('egcn')
- egcn.get_csig()
- assert egcn.__class__ is SCons.Node.FS.File, egcn.__class__
-
class FileTestCase(_tempdirTestCase):
# what line in what file created the node, for example).
Annotate(self)
+ def disambiguate(self):
+ return self
+
def get_suffix(self):
return ''
self.state = None
self.side_effects = []
self.builder = None
+ def disambiguate(self):
+ return self
def has_builder(self):
return 1
def add_pre_action(self, *actions):
"""
self.out_of_date = []
for t in self.targets:
- if t.current():
+ if t.disambiguate().current():
t.set_state(SCons.Node.up_to_date)
else:
self.out_of_date.append(t)
T = self.trace
while self.candidates:
- node = self.candidates.pop()
+ node = self.candidates.pop().disambiguate()
state = node.get_state()
if CollectStats:
self._bsig_val = None
self._current_val = 0
+ def disambiguate(self):
+ return self
+
def retrieve_from_cache(self):
global cache_text
if self.cached: