diff options
-rw-r--r-- | src/CHANGES.txt | 5 | ||||
-rw-r--r-- | src/engine/SCons/Node/FS.py | 40 | ||||
-rw-r--r-- | src/engine/SCons/Node/FSTests.py | 7 | ||||
-rw-r--r-- | src/engine/SCons/Node/NodeTests.py | 60 | ||||
-rw-r--r-- | src/engine/SCons/Node/__init__.py | 23 | ||||
-rw-r--r-- | src/engine/SCons/Taskmaster.py | 5 | ||||
-rw-r--r-- | src/engine/SCons/TaskmasterTests.py | 11 | ||||
-rw-r--r-- | test/Alias.py | 11 | ||||
-rw-r--r-- | test/Options.py | 4 |
9 files changed, 138 insertions, 28 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt index c73a6b1..14db4fb 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -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 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): diff --git a/test/Alias.py b/test/Alias.py index c966933..f965071 100644 --- a/test/Alias.py +++ b/test/Alias.py @@ -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() diff --git a/test/Options.py b/test/Options.py index a34e5ca..4f979df 100644 --- a/test/Options.py +++ b/test/Options.py @@ -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)) """) |