summaryrefslogtreecommitdiffstats
path: root/src/engine
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2003-03-28 03:29:11 (GMT)
committerSteven Knight <knight@baldmt.com>2003-03-28 03:29:11 (GMT)
commite94e7726d2602503cd6ea7ba1acb37558821827e (patch)
tree3c312aac30b8d44b5e898a1ff9ec15b5003b98e7 /src/engine
parentf63429682eca0f75ba22c2e01f155bb8d986bd85 (diff)
downloadSCons-e94e7726d2602503cd6ea7ba1acb37558821827e.zip
SCons-e94e7726d2602503cd6ea7ba1acb37558821827e.tar.gz
SCons-e94e7726d2602503cd6ea7ba1acb37558821827e.tar.bz2
Fix erroneous dependency-cycle errors when an Alias source doesn't exist. (Anthony Roach)
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/SCons/Node/FS.py40
-rw-r--r--src/engine/SCons/Node/FSTests.py7
-rw-r--r--src/engine/SCons/Node/NodeTests.py60
-rw-r--r--src/engine/SCons/Node/__init__.py23
-rw-r--r--src/engine/SCons/Taskmaster.py5
-rw-r--r--src/engine/SCons/TaskmasterTests.py11
6 files changed, 120 insertions, 26 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index d6b7b53..0afc3d8 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -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."""
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 11146eb..dd04fe4 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -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"""
diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py
index f282860..9da74d3 100644
--- a/src/engine/SCons/Node/NodeTests.py
+++ b/src/engine/SCons/Node/NodeTests.py
@@ -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.
"""
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 222cd1f..c458026 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -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."""
diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py
index bc53024..b58e09f 100644
--- a/src/engine/SCons/Taskmaster.py
+++ b/src/engine/SCons/Taskmaster.py
@@ -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.
diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py
index 89c53c7..3616370 100644
--- a/src/engine/SCons/TaskmasterTests.py
+++ b/src/engine/SCons/TaskmasterTests.py
@@ -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):