From 9e4766b23bc76aa8147df825d024af06efe8007c Mon Sep 17 00:00:00 2001 From: stevenknight Date: Sun, 12 Feb 2006 06:58:36 +0000 Subject: [PATCH] Refactor so Command() uses an FS.Entry as its target factory. git-svn-id: http://scons.tigris.org/svn/scons/trunk@1417 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- src/engine/SCons/Builder.py | 5 +- src/engine/SCons/BuilderTests.py | 2 + src/engine/SCons/Environment.py | 1 + src/engine/SCons/Node/FS.py | 67 ++++++++++--------------- src/engine/SCons/Node/FSTests.py | 77 +++++++---------------------- src/engine/SCons/Node/__init__.py | 3 ++ src/engine/SCons/SConfTests.py | 2 + src/engine/SCons/Taskmaster.py | 4 +- src/engine/SCons/TaskmasterTests.py | 3 ++ 9 files changed, 61 insertions(+), 103 deletions(-) diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index 90839855..ae24f43f 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -535,8 +535,11 @@ class BuilderBase: # 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 diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py index 233336c7..c80f00c6 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -157,6 +157,8 @@ class MyNode_without_target_from_source: 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): diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index 38346364..92b1e3d1 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -1263,6 +1263,7 @@ class Base(SubstitutionEnvironment): for an action.""" bkw = { 'action' : action, + 'target_factory' : self.fs.Entry, 'source_factory' : self.fs.Entry, } try: bkw['source_scanner'] = kw['source_scanner'] diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 12606021..36d84dbd 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -53,6 +53,8 @@ import SCons.Subst 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 @@ -668,6 +670,9 @@ class Base(SCons.Node.Node): 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. @@ -697,11 +702,6 @@ class Entry(Base): 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() @@ -723,8 +723,23 @@ class Entry(Base): 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 @@ -732,30 +747,11 @@ class Entry(Base): 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. @@ -1204,9 +1200,6 @@ class Dir(Base): 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 @@ -1706,9 +1699,6 @@ class File(Base): if not hasattr(self, '_local'): self._local = 0 - def disambiguate(self): - return self - def scanner_key(self): return self.get_suffix() @@ -2054,9 +2044,6 @@ class File(Base): 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...""" diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index 12be4b95..321deaa3 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -1369,17 +1369,34 @@ class FSTestCase(_tempdirTestCase): 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""" @@ -1836,10 +1853,6 @@ class EntryTestCase(_tempdirTestCase): 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") @@ -1892,13 +1905,6 @@ class EntryTestCase(_tempdirTestCase): 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__ @@ -1917,55 +1923,6 @@ class EntryTestCase(_tempdirTestCase): 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): diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index 6a0a2380..483e88b2 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -212,6 +212,9 @@ class Node: # what line in what file created the node, for example). Annotate(self) + def disambiguate(self): + return self + def get_suffix(self): return '' diff --git a/src/engine/SCons/SConfTests.py b/src/engine/SCons/SConfTests.py index 961dc21f..85b46905 100644 --- a/src/engine/SCons/SConfTests.py +++ b/src/engine/SCons/SConfTests.py @@ -164,6 +164,8 @@ class SConfTestCase(unittest.TestCase): 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): diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py index 5d689898..6d5f87cb 100644 --- a/src/engine/SCons/Taskmaster.py +++ b/src/engine/SCons/Taskmaster.py @@ -227,7 +227,7 @@ class Task: """ 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) @@ -308,7 +308,7 @@ class Taskmaster: T = self.trace while self.candidates: - node = self.candidates.pop() + node = self.candidates.pop().disambiguate() state = node.get_state() if CollectStats: diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py index c35a89c1..f3cb5f02 100644 --- a/src/engine/SCons/TaskmasterTests.py +++ b/src/engine/SCons/TaskmasterTests.py @@ -62,6 +62,9 @@ class Node: self._bsig_val = None self._current_val = 0 + def disambiguate(self): + return self + def retrieve_from_cache(self): global cache_text if self.cached: -- 2.26.2