Refactor so Command() uses an FS.Entry as its target factory.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sun, 12 Feb 2006 06:58:36 +0000 (06:58 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sun, 12 Feb 2006 06:58:36 +0000 (06:58 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@1417 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/engine/SCons/Builder.py
src/engine/SCons/BuilderTests.py
src/engine/SCons/Environment.py
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/FSTests.py
src/engine/SCons/Node/__init__.py
src/engine/SCons/SConfTests.py
src/engine/SCons/Taskmaster.py
src/engine/SCons/TaskmasterTests.py

index 90839855448690976d9c0959ff6ae34c71fb4099..ae24f43f7835b7a80898b24e9c69e9602663c36b 100644 (file)
@@ -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
 
index 233336c731d2215ca2f04ccdcc15b0678d1b0e26..c80f00c672993123426b04c4e3a14a1c34c5f827 100644 (file)
@@ -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):
index 38346364f300dc0068e5b3ab830cfe5ff588bce8..92b1e3d1d7377c5d63a12fe51cd0b5603e028a66 100644 (file)
@@ -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']
index 12606021621bd83d892eceeef67a7f14c1a8bad8..36d84dbdcb1badd768f0f989756db67b115547ae 100644 (file)
@@ -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..."""
index 12be4b9529901e4c698f6a690762ced1820feb72..321deaa30634048e706fc60ab8358cd782661879 100644 (file)
@@ -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):
index 6a0a238058c15681b65c6123f7885ba4fd936417..483e88b2a3c99278cd936354d92bcb77e9a2d7a1 100644 (file)
@@ -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 ''
 
index 961dc21fee2c1f56c459e1e3d72624d028ae60d9..85b469052d5ed451c6048428fb009af3fe597cdc 100644 (file)
@@ -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):
index 5d6898985d9b1b6c09c4b81e8764cbf68fd75b3b..6d5f87cb1fd1529063f90ff0ec3dc51a8d63bf1d 100644 (file)
@@ -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:
index c35a89c1e8914560087632cf72068a96a02eb215..f3cb5f02a863bf8e95fc553edd3b10be53eecedf 100644 (file)
@@ -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: