Fix erroneous dependency-cycle errors when an Alias source doesn't exist. (Anthony...
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Fri, 28 Mar 2003 03:29:11 +0000 (03:29 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Fri, 28 Mar 2003 03:29:11 +0000 (03:29 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@626 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/CHANGES.txt
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/FSTests.py
src/engine/SCons/Node/NodeTests.py
src/engine/SCons/Node/__init__.py
src/engine/SCons/Taskmaster.py
src/engine/SCons/TaskmasterTests.py
test/Alias.py
test/Options.py

index c73a6b18d72f7593ab8bf7ff61938859acbeadcd..14db4fba4deb0812e0fd703a2ccca1baf7064254 100644 (file)
@@ -100,6 +100,11 @@ RELEASE 0.12 - XXX
   - Avoid partial copies of built files in a CacheDir() by copying
     to a temporary file and renaming.
 
+  From Anthony Roach:
+
+  - Fix incorrect dependency-cycle errors when an Aliased source doesn't
+    exist.
+
 
 
 RELEASE 0.11 - Tue, 11 Feb 2003 05:24:33 -0600
index d6b7b532fdbe925dffe8fb4c8e8c96d963587427..0afc3d8b8fc372d5d648f7cd3a9627680ef24550 100644 (file)
@@ -892,6 +892,9 @@ class Dir(Entry):
         """Return a fixed "contents" value of a directory."""
         return ''
 
+    def prepare(self):
+        pass
+
     def current(self, calc):
         """If all of our children were up-to-date, then this
         directory was up-to-date, too."""
@@ -971,7 +974,6 @@ class File(Entry):
         
     def _morph(self):
         """Turn a file system node into a File object."""
-        self.linked = 0
         self.scanner_paths = {}
         self.found_includes = {}
         if not hasattr(self, '_local'):
@@ -1196,28 +1198,24 @@ class File(Entry):
     def prepare(self):
         """Prepare for this file to be created."""
 
-        def missing(node):
-            return not node.has_builder() and not node.linked and not node.rexists() and not node.has_src_builder()
-        missing_sources = filter(missing, self.children())
-        if missing_sources:
-            desc = "No Builder for target `%s', needed by `%s'." % (missing_sources[0], self)
-            raise SCons.Errors.StopError, desc
+        SCons.Node.Node.prepare(self)
 
-        if self.exists():
-            if self.has_builder() and not self.precious:
+        if self.get_state() != SCons.Node.up_to_date:
+            if self.exists():
+                if self.has_builder() and not self.precious:
+                    try:
+                        Unlink(self, None, None)
+                    except OSError, e:
+                        raise SCons.Errors.BuildError(node = self,
+                                                      errstr = e.strerror)
+                    if hasattr(self, '_exists'):
+                        delattr(self, '_exists')
+            else:
                 try:
-                    Unlink(self, None, None)
-                except OSError, e:
-                    raise SCons.Errors.BuildError(node = self,
-                                                  errstr = e.strerror)
-                if hasattr(self, '_exists'):
-                    delattr(self, '_exists')
-        else:
-            try:
-                self._createDir()
-            except SCons.Errors.StopError, drive:
-                desc = "No drive `%s' for target `%s'." % (drive, self)
-                raise SCons.Errors.StopError, desc
+                    self._createDir()
+                except SCons.Errors.StopError, drive:
+                    desc = "No drive `%s' for target `%s'." % (drive, self)
+                    raise SCons.Errors.StopError, desc
 
     def remove(self):
         """Remove this file."""
index 11146eb5a73057c8629d0f6436908ad6d333e442..dd04fe4073d5b0eb943dbca4a6141285c982cff9 100644 (file)
@@ -1267,11 +1267,18 @@ class prepareTestCase(unittest.TestCase):
 
         file = fs.File(os.path.join("new_dir", "xyz"))
         try:
+            file.set_state(SCons.Node.up_to_date)
+            file.prepare()
+            assert dir_made == [], dir_made
+            file.set_state(0)
             file.prepare()
             assert dir_made[0].path == "new_dir", dir_made[0].path
         finally:
             SCons.Node.FS.Mkdir = save_Mkdir
 
+        dir = fs.Dir("dir")
+        dir.prepare()
+
 class get_actionsTestCase(unittest.TestCase):
     def runTest(self):
         """Test the Dir's get_action() method"""
index f2828609255e4f70c23d96f5b2809f52ab43867b..9da74d3d1dcc129a877083e379a3997fda08be4a 100644 (file)
@@ -377,6 +377,66 @@ class NodeTestCase(unittest.TestCase):
         node.set_precious(7)
         assert node.precious == 7
 
+    def test_exists(self):
+        """Test evaluating whether a Node exists.
+        """
+        node = SCons.Node.Node()
+        e = node.exists()
+        assert e == 1, e
+
+    def test_exists(self):
+        """Test evaluating whether a Node exists locally or in a repository.
+        """
+        node = SCons.Node.Node()
+        e = node.rexists()
+        assert e == 1, e
+
+        class MyNode(SCons.Node.Node):
+            def exists(self):
+                return 'xyz'
+
+        node = MyNode()
+        e = node.rexists()
+        assert e == 'xyz', e
+
+    def test_prepare(self):
+        """Test preparing a node to be built
+        """
+        node = SCons.Node.Node()
+
+        n1 = SCons.Node.Node()
+        n1.builder_set(Builder())
+        node.implicit = []
+        node._add_child(node.implicit, [n1])
+
+        node.prepare()  # should not throw an exception
+
+        n2 = SCons.Node.Node()
+        n2.linked = 1
+        node.implicit = []
+        node._add_child(node.implicit, [n2])
+
+        node.prepare()  # should not throw an exception
+
+        n3 = SCons.Node.Node()
+        node.implicit = []
+        node._add_child(node.implicit, [n3])
+
+        node.prepare()  # should not throw an exception
+
+        class MyNode(SCons.Node.Node):
+            def rexists(self):
+                return None
+        n4 = MyNode()
+        node.implicit = []
+        node._add_child(node.implicit, [n4]) 
+        exc_caught = 0
+        try:
+            node.prepare()
+        except SCons.Errors.StopError:
+            exc_caught = 1
+        assert exc_caught, "did not catch expected StopError"
+
     def test_add_dependency(self):
         """Test adding dependencies to a Node's list.
         """
index 222cd1f1139b3b599a184045cf140ad0612fb420..c4580263d1d2900c209c63ba6898851b9f900329 100644 (file)
@@ -115,6 +115,7 @@ class Node:
         self.side_effects = [] # the side effects of building this target
         self.pre_actions = []
         self.post_actions = []
+        self.linked = 0 # is this node linked to the build directory? 
 
         # Let the interface in which the build engine is embedded
         # annotate this Node with its own info (like a description of
@@ -451,9 +452,27 @@ class Node:
         """Set the Node's precious value."""
         self.precious = precious
 
+    def exists(self):
+        """Does this node exists?"""
+        # All node exist by default:
+        return 1
+    
+    def rexists(self):
+        """Does this node exist locally or in a repositiory?"""
+        # There are no repositories by default:
+        return self.exists()
+    
     def prepare(self):
-        """Prepare for this Node to be created:  no-op by default."""
-        pass
+        """Prepare for this Node to be created.
+        The default implemenation checks that all children either exist
+        or are derived.
+        """
+        def missing(node):
+            return not node.is_derived() and not node.linked and not node.rexists()
+        missing_sources = filter(missing, self.children())
+        if missing_sources:
+            desc = "No Builder for target `%s', needed by `%s'." % (missing_sources[0], self)
+            raise SCons.Errors.StopError, desc
 
     def remove(self):
         """Remove this Node:  no-op by default."""
index bc53024d1be4d80340a3592ce30e4365b8619085..b58e09f2a19c28ff4c5751307c43e7a0c234b394 100644 (file)
@@ -78,9 +78,8 @@ class Task:
             self.display(self.tm.message)
             self.tm.message = None
 
-        if self.targets[0].get_state() != SCons.Node.up_to_date:
-            for t in self.targets:
-                t.prepare()
+        for t in self.targets:
+            t.prepare()
 
     def execute(self):
         """Called to execute the task.
index 89c53c74a436cd0f0491533621f68ef9c71c723e..361637059e42d8834e0ad37ca345b1bdcd701f64 100644 (file)
@@ -551,6 +551,17 @@ class TaskmasterTestCase(unittest.TestCase):
         assert n1.prepared
         assert n2.prepared
 
+        n3 = Node("n3")
+        n4 = Node("n4")
+        tm = SCons.Taskmaster.Taskmaster([n3, n4])
+        t = tm.next_task()
+        # More bogus reaching in and setting the targets.
+        n3.set_state(SCons.Node.up_to_date)
+        t.targets = [n3, n4]
+        t.prepare()
+        assert n3.prepared
+        assert n4.prepared
+
         # If the Node has had an exception recorded while it was getting
         # prepared, then prepare() should raise that exception.
         class MyException(Exception):
index c9669338f093237a0863eb554bfbf6975ced117d..f965071a4d806f67befca4291aa0f489fe9036cb 100644 (file)
@@ -155,5 +155,16 @@ test.run(arguments = 'f1.out',
 
 test.up_to_date(arguments = 'f1.out')
 
+test.write('SConstruct', """
+env=Environment()
+SetBuildSignatureType('content')
+env.Alias('C', 'D')
+env.Alias('B', 'C')
+env.Alias('A', 'B')
+""")
+
+test.run(arguments='A',
+         stderr="scons: \\*\\*\\* No Builder for target `D', needed by `C'.  Stop.\n",
+         status=2)
 
 test.pass_test()
index a34e5ca94c479fb0ff2cf0b1ebc17a56287ad82a..4f979df31a428954fac9342d6de7eafb9b1dabea 100644 (file)
@@ -33,7 +33,7 @@ test.write('SConstruct', """
 env = Environment()
 print env['CC']
 print env['CCFLAGS']
-Default(env.Alias('dummy'))
+Default(env.Alias('dummy', None))
 """)
 test.run()
 cc, ccflags = string.split(test.stdout(), '\n')[1:3]
@@ -87,7 +87,7 @@ opts = Options()
 opts.Update(env)
 assert env['RELEASE_BUILD'] == r
 
-Default(env.Alias('dummy'))
+Default(env.Alias('dummy', None))
         
 """)