diff options
| author | Steven Knight <knight@baldmt.com> | 2002-04-04 09:07:00 (GMT) |
|---|---|---|
| committer | Steven Knight <knight@baldmt.com> | 2002-04-04 09:07:00 (GMT) |
| commit | 6603cc0d6643e529da45fef6f85fcc1a0fc02ea4 (patch) | |
| tree | 4a27de7c3fd70e5af0f257ccc73aab38e343f156 /src/engine/SCons/Node | |
| parent | a7669bc6a02999a3375c7e732a27ded5f9bb9935 (diff) | |
| download | SCons-6603cc0d6643e529da45fef6f85fcc1a0fc02ea4.zip SCons-6603cc0d6643e529da45fef6f85fcc1a0fc02ea4.tar.gz SCons-6603cc0d6643e529da45fef6f85fcc1a0fc02ea4.tar.bz2 | |
Fix --debug=tree for directory targets (Anthony Roach)
Diffstat (limited to 'src/engine/SCons/Node')
| -rw-r--r-- | src/engine/SCons/Node/FS.py | 71 | ||||
| -rw-r--r-- | src/engine/SCons/Node/FSTests.py | 89 | ||||
| -rw-r--r-- | src/engine/SCons/Node/NodeTests.py | 363 | ||||
| -rw-r--r-- | src/engine/SCons/Node/__init__.py | 130 |
4 files changed, 245 insertions, 408 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 1be5e81..0f8425f 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -114,7 +114,7 @@ class FS: def getcwd(self): self.__setTopLevelDir() - return self._cwd + return self._cwd def __checkClass(self, node, klass): if klass == Entry: @@ -132,9 +132,9 @@ class FS: """This method differs from the File and Dir factory methods in one important way: the meaning of the directory parameter. In this method, if directory is None or not supplied, the supplied - name is expected to be an absolute path. If you try to look up a - relative path with directory=None, then an AssertionError will be - raised.""" + name is expected to be an absolute path. If you try to look up a + relative path with directory=None, then an AssertionError will be + raised.""" if not name: # This is a stupid hack to compensate for the fact @@ -280,12 +280,12 @@ class Entry(SCons.Node.Node): """ def __init__(self, name, directory): - """Initialize a generic file system Entry. - - Call the superclass initialization, take care of setting up - our relative and absolute paths, identify our parent - directory, and indicate that this node should use - signatures.""" + """Initialize a generic file system Entry. + + Call the superclass initialization, take care of setting up + our relative and absolute paths, identify our parent + directory, and indicate that this node should use + signatures.""" SCons.Node.Node.__init__(self) self.name = name @@ -302,9 +302,10 @@ class Entry(SCons.Node.Node): self.path_ = self.path self.abspath_ = self.abspath self.dir = directory - self.use_signature = 1 + self.use_signature = 1 self.__doSrcpath(self.duplicate) self.srcpath_ = self.srcpath + self.cwd = None # will hold the SConscript directory for target nodes def get_dir(self): return self.dir @@ -320,7 +321,7 @@ class Entry(SCons.Node.Node): self.srcpath = self.dir.srcpath_ + self.name def __str__(self): - """A FS node's string representation is its path name.""" + """A FS node's string representation is its path name.""" if self.duplicate or self.builder: return self.path else: @@ -374,17 +375,17 @@ class Dir(Entry): def __init__(self, name, directory): Entry.__init__(self, name, directory) - self._morph() + self._morph() def _morph(self): - """Turn a file system node (either a freshly initialized - directory object or a separate Entry object) into a - proper directory object. - - Modify our paths to add the trailing slash that indicates - a directory. Set up this directory's entries and hook it - into the file system tree. Specify that directories (this - node) don't use signatures for currency calculation.""" + """Turn a file system node (either a freshly initialized + directory object or a separate Entry object) into a + proper directory object. + + Modify our paths to add the trailing slash that indicates + a directory. Set up this directory's entries and hook it + into the file system tree. Specify that directories (this + node) don't use signatures for currency calculation.""" self.path_ = self.path + os.sep self.abspath_ = self.abspath + os.sep @@ -423,18 +424,18 @@ class Dir(Entry): else: return self.entries['..'].root() - def children(self, scanner): - #XXX --random: randomize "dependencies?" - keys = filter(lambda k: k != '.' and k != '..', self.entries.keys()) - kids = map(lambda x, s=self: s.entries[x], keys) - def c(one, two): + def all_children(self, scanner): + #XXX --random: randomize "dependencies?" + keys = filter(lambda k: k != '.' and k != '..', self.entries.keys()) + kids = map(lambda x, s=self: s.entries[x], keys) + def c(one, two): if one.abspath < two.abspath: return -1 if one.abspath > two.abspath: return 1 return 0 - kids.sort(c) - return kids + kids.sort(c) + return kids def build(self): """A null "builder" for directories.""" @@ -529,14 +530,12 @@ class File(Entry): .sconsign entry.""" return self.dir.sconsign().get(self.name) - def scan(self, scanner = None): - if not scanner: - scanner = self.scanner - if scanner and not self.scanned.has_key(scanner): - deps = scanner.scan(self, self.env) - self.add_implicit(deps, scanner) - self.scanned[scanner] = 1 - + def get_implicit_deps(self, env, scanner, target): + if scanner: + return scanner.scan(self, env, target) + else: + return [] + def exists(self): if self.duplicate and not self.created: self.created = 1 diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index 98abcfc..fe9ea61 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -48,7 +48,7 @@ class Scanner: global scanner_count scanner_count = scanner_count + 1 self.hash = scanner_count - def scan(self, node, env): + def scan(self, node, env, target): return [node] def __hash__(self): return self.hash @@ -191,7 +191,7 @@ class FSTestCase(unittest.TestCase): up_path = strip_slash(up_path_) name = string.split(abspath, os.sep)[-1] - assert dir.name == name, \ + assert dir.name == name, \ "dir.name %s != expected name %s" % \ (dir.name, name) assert dir.path == path, \ @@ -230,16 +230,16 @@ class FSTestCase(unittest.TestCase): try: f2 = fs.File(string.join(['f1', 'f2'], sep), directory = d1) except TypeError, x: - assert str(x) == ("Tried to lookup File '%s' as a Dir." % - d1_f1), x + assert str(x) == ("Tried to lookup File '%s' as a Dir." % + d1_f1), x except: raise try: dir = fs.Dir(string.join(['d1', 'f1'], sep)) except TypeError, x: - assert str(x) == ("Tried to lookup File '%s' as a Dir." % - d1_f1), x + assert str(x) == ("Tried to lookup File '%s' as a Dir." % + d1_f1), x except: raise @@ -249,7 +249,7 @@ class FSTestCase(unittest.TestCase): assert str(x) == ("Tried to lookup Dir '%s' as a File." % 'd1'), x except: - raise + raise # Test Dir.children() dir = fs.Dir('ddd') @@ -262,9 +262,9 @@ class FSTestCase(unittest.TestCase): kids = map(lambda x: x.path, dir.children(None)) kids.sort() assert kids == [os.path.join('ddd', 'd1'), - os.path.join('ddd', 'f1'), - os.path.join('ddd', 'f2'), - os.path.join('ddd', 'f3')] + os.path.join('ddd', 'f1'), + os.path.join('ddd', 'f2'), + os.path.join('ddd', 'f3')] kids = map(lambda x: x.path_, dir.children(None)) kids.sort() assert kids == [os.path.join('ddd', 'd1', ''), @@ -302,50 +302,50 @@ class FSTestCase(unittest.TestCase): expect = string.replace(expect, '/', os.sep) assert path == expect, "path %s != expected %s" % (path, expect) - e1 = fs.Entry("d1") - assert e1.__class__.__name__ == 'Dir' + e1 = fs.Entry("d1") + assert e1.__class__.__name__ == 'Dir' match(e1.path, "d1") match(e1.path_, "d1/") match(e1.dir.path, ".") - e2 = fs.Entry("d1/f1") - assert e2.__class__.__name__ == 'File' + e2 = fs.Entry("d1/f1") + assert e2.__class__.__name__ == 'File' match(e2.path, "d1/f1") match(e2.path_, "d1/f1") match(e2.dir.path, "d1") - e3 = fs.Entry("e3") - assert e3.__class__.__name__ == 'Entry' + e3 = fs.Entry("e3") + assert e3.__class__.__name__ == 'Entry' match(e3.path, "e3") match(e3.path_, "e3") match(e3.dir.path, ".") - e4 = fs.Entry("d1/e4") - assert e4.__class__.__name__ == 'Entry' + e4 = fs.Entry("d1/e4") + assert e4.__class__.__name__ == 'Entry' match(e4.path, "d1/e4") match(e4.path_, "d1/e4") match(e4.dir.path, "d1") - e5 = fs.Entry("e3/e5") - assert e3.__class__.__name__ == 'Dir' + e5 = fs.Entry("e3/e5") + assert e3.__class__.__name__ == 'Dir' match(e3.path, "e3") match(e3.path_, "e3/") match(e3.dir.path, ".") - assert e5.__class__.__name__ == 'Entry' + assert e5.__class__.__name__ == 'Entry' match(e5.path, "e3/e5") match(e5.path_, "e3/e5") match(e5.dir.path, "e3") - e6 = fs.Dir("d1/e4") - assert e6 is e4 - assert e4.__class__.__name__ == 'Dir' + e6 = fs.Dir("d1/e4") + assert e6 is e4 + assert e4.__class__.__name__ == 'Dir' match(e4.path, "d1/e4") match(e4.path_, "d1/e4/") match(e4.dir.path, "d1") - e7 = fs.File("e3/e5") - assert e7 is e5 - assert e5.__class__.__name__ == 'File' + e7 = fs.File("e3/e5") + assert e7 is e5 + assert e5.__class__.__name__ == 'File' match(e5.path, "e3/e5") match(e5.path_, "e3/e5") match(e5.dir.path, "e3") @@ -383,23 +383,12 @@ class FSTestCase(unittest.TestCase): match(e13.path, "subdir/subdir/e13") # Test scanning - scn1 = Scanner() - f1.scan(scn1) - assert f1.implicit[scn1][0].path_ == os.path.join("d1", "f1") - del f1.implicit[scn1] - f1.scan(scn1) - assert len(f1.implicit) == 0, f1.implicit - del f1.scanned[scn1] - f1.scan(scn1) - assert f1.implicit[scn1][0].path_ == os.path.join("d1", "f1") - - # Test multiple scanners - scn2 = Scanner() - f2 = fs.File("f2") - f2.scan(scn1) - f2.scan(scn2) - match(f2.implicit[scn1][0].path_, 'subdir/f2') - match(f2.implicit[scn2][0].path_, 'subdir/f2') + f1.target_scanner = Scanner() + f1.scan() + assert f1.implicit[0].path_ == os.path.join("d1", "f1") + f1.implicit = [] + f1.scan() + assert f1.implicit[0].path_ == os.path.join("d1", "f1") # Test building a file whose directory is not there yet... f1 = fs.File(test.workpath("foo/bar/baz/ack")) @@ -410,13 +399,13 @@ class FSTestCase(unittest.TestCase): os.chdir('..') - # Test getcwd() + # Test getcwd() fs = SCons.Node.FS.FS() - assert str(fs.getcwd()) == ".", str(fs.getcwd()) - fs.chdir(fs.Dir('subdir')) - assert str(fs.getcwd()) == "subdir", str(fs.getcwd()) - fs.chdir(fs.Dir('../..')) - assert str(fs.getcwd()) == test.workdir, str(fs.getcwd()) + assert str(fs.getcwd()) == ".", str(fs.getcwd()) + fs.chdir(fs.Dir('subdir')) + assert str(fs.getcwd()) == "subdir", str(fs.getcwd()) + fs.chdir(fs.Dir('../..')) + assert str(fs.getcwd()) == test.workdir, str(fs.getcwd()) f1 = fs.File(test.workpath("do_i_exist")) assert not f1.exists() diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py index 16c5548..ef98a41 100644 --- a/src/engine/SCons/Node/NodeTests.py +++ b/src/engine/SCons/Node/NodeTests.py @@ -41,7 +41,7 @@ cycle_detected = None class Builder: def execute(self, **kw): global built_it, built_target, built_source - built_it = 1 + built_it = 1 built_target = kw['target'] built_source = kw['source'] return 0 @@ -87,17 +87,17 @@ class Environment: class NodeTestCase(unittest.TestCase): def test_BuildException(self): - """Test throwing an exception on build failure. - """ - node = SCons.Node.Node() - node.builder_set(FailBuilder()) - node.env_set(Environment()) - try: - node.build() - except SCons.Errors.BuildError: - pass - else: - raise TestFailed, "did not catch expected BuildError" + """Test throwing an exception on build failure. + """ + node = SCons.Node.Node() + node.builder_set(FailBuilder()) + node.env_set(Environment()) + try: + node.build() + except SCons.Errors.BuildError: + pass + else: + raise TestFailed, "did not catch expected BuildError" node = SCons.Node.Node() node.builder_set(ExceptBuilder()) @@ -126,8 +126,8 @@ class NodeTestCase(unittest.TestCase): raise TestFailed, "did not catch expected BuildError" def test_build(self): - """Test building a node - """ + """Test building a node + """ global built_it class MyNode(SCons.Node.Node): @@ -138,18 +138,18 @@ class NodeTestCase(unittest.TestCase): return self.path def prepare(self): self.prepare_count = self.prepare_count+ 1 - # Make sure it doesn't blow up if no builder is set. + # Make sure it doesn't blow up if no builder is set. node = MyNode() - node.build() - assert built_it == None + node.build() + assert built_it == None node = MyNode() - node.builder_set(Builder()) - node.env_set(Environment()) + node.builder_set(Builder()) + node.env_set(Environment()) node.path = "xxx" node.sources = ["yyy", "zzz"] - node.build() - assert built_it + node.build() + assert built_it assert type(built_target) == type(MyNode()), type(built_target) assert str(built_target) == "xxx", str(built_target) assert built_source == ["yyy", "zzz"], built_source @@ -201,13 +201,19 @@ class NodeTestCase(unittest.TestCase): assert str(built_target) == "fff", str(built_target) assert built_source == ["hhh", "iii"], built_source + def test_depends_on(self): + parent = SCons.Node.Node() + child = SCons.Node.Node() + parent.add_dependency([child]) + assert parent.depends_on([child]) + def test_builder_set(self): - """Test setting a Node's Builder - """ - node = SCons.Node.Node() - b = Builder() - node.builder_set(b) - assert node.builder == b + """Test setting a Node's Builder + """ + node = SCons.Node.Node() + b = Builder() + node.builder_set(b) + assert node.builder == b def test_builder_sig_adapter(self): """Test the node's adapter for builder signatures @@ -225,12 +231,12 @@ class NodeTestCase(unittest.TestCase): assert node.current() is None def test_env_set(self): - """Test setting a Node's Environment - """ - node = SCons.Node.Node() - e = Environment() - node.env_set(e) - assert node.env == e + """Test setting a Node's Environment + """ + node = SCons.Node.Node() + e = Environment() + node.env_set(e) + assert node.env == e def test_set_bsig(self): """Test setting a Node's signature @@ -276,16 +282,16 @@ class NodeTestCase(unittest.TestCase): assert node.precious == 7 def test_add_dependency(self): - """Test adding dependencies to a Node's list. - """ - node = SCons.Node.Node() - assert node.depends == [] + """Test adding dependencies to a Node's list. + """ + node = SCons.Node.Node() + assert node.depends == [] zero = SCons.Node.Node() try: - node.add_dependency(zero) - except TypeError: - pass + node.add_dependency(zero) + except TypeError: + pass else: assert 0 @@ -309,42 +315,10 @@ class NodeTestCase(unittest.TestCase): def test_add_source(self): - """Test adding sources to a Node's list. - """ - node = SCons.Node.Node() - assert node.sources == [] - - zero = SCons.Node.Node() - try: - node.add_source(zero) - except TypeError: - pass - else: - assert 0 - - one = SCons.Node.Node() - two = SCons.Node.Node() - three = SCons.Node.Node() - four = SCons.Node.Node() - - node.add_source([one]) - assert node.sources == [one] - node.add_source([two, three]) - assert node.sources == [one, two, three] - node.add_source([three, four, one]) - assert node.sources == [one, two, three, four] - - assert zero.get_parents() == [] - assert one.get_parents() == [node] - assert two.get_parents() == [node] - assert three.get_parents() == [node] - assert four.get_parents() == [node] - - def test_add_implicit(self): - """Test adding implicit (scanned) dependencies to a Node's list. + """Test adding sources to a Node's list. """ node = SCons.Node.Node() - assert node.implicit == {} + assert node.sources == [] zero = SCons.Node.Node() try: @@ -359,12 +333,12 @@ class NodeTestCase(unittest.TestCase): three = SCons.Node.Node() four = SCons.Node.Node() - node.add_implicit([one], 1) - assert node.implicit[1] == [one] - node.add_implicit([two, three], 1) - assert node.implicit[1] == [one, two, three] - node.add_implicit([three, four, one], 1) - assert node.implicit[1] == [one, two, three, four] + node.add_source([one]) + assert node.sources == [one] + node.add_source([two, three]) + assert node.sources == [one, two, three] + node.add_source([three, four, one]) + assert node.sources == [one, two, three, four] assert zero.get_parents() == [] assert one.get_parents() == [node] @@ -372,15 +346,6 @@ class NodeTestCase(unittest.TestCase): assert three.get_parents() == [node] assert four.get_parents() == [node] - node.add_implicit([one], 2) - node.add_implicit([two, three], 3) - node.add_implicit([three, four, one], 4) - - assert node.implicit[1] == [one, two, three, four] - assert node.implicit[2] == [one] - assert node.implicit[3] == [two, three] - assert node.implicit[4] == [three, four, one] - def test_add_ignore(self): """Test adding files whose dependencies should be ignored. """ @@ -419,42 +384,9 @@ class NodeTestCase(unittest.TestCase): pass ds=DummyScanner() node = SCons.Node.Node() - assert node.scanner == None, node.scanner - node.scanner_set(ds) - assert node.scanner == ds, node.scanner - node.scan(ds) - assert node.scanned[ds] == 1, node.scanned - - def test_src_scanner_set(self): - """Test setting source-file Scanners""" - class DummyScanner: - pass - ds1=DummyScanner() - ds2=DummyScanner() - node = SCons.Node.Node() - assert node.src_scanners == {}, node.src_scanners - node.src_scanner_set('a', ds1) - assert node.src_scanners['a'] == ds1, node.src_scanners - node.src_scanner_set('b', ds2) - assert node.src_scanners['b'] == ds2, node.src_scanners - - def test_src_scanner_set(self): - """Test setting source-file Scanners""" - class DummyScanner: - pass - ds1=DummyScanner() - ds2=DummyScanner() - node = SCons.Node.Node() - node.src_scanner_set('a', ds1) - node.src_scanner_set('b', ds2) - s = node.src_scanner_get(None) - assert s == None, s - s = node.src_scanner_get('a') - assert s == ds1, s - s = node.src_scanner_get('b') - assert s == ds2, s - s = node.src_scanner_get('c') - assert s == None, s + assert node.target_scanner == None, node.target_scanner + node.target_scanner = ds + node.scan() def test_scanner_key(self): """Test that a scanner_key() method exists""" @@ -463,7 +395,7 @@ class NodeTestCase(unittest.TestCase): def test_children(self): """Test fetching the non-ignored "children" of a Node. """ - node = SCons.Node.Node() + node = SCons.Node.Node() n1 = SCons.Node.Node() n2 = SCons.Node.Node() n3 = SCons.Node.Node() @@ -479,28 +411,16 @@ class NodeTestCase(unittest.TestCase): node.add_source([n1, n2, n3]) node.add_dependency([n4, n5, n6]) - node.add_implicit([n7, n8, n9], 'key1') - node.add_implicit([n10, n11, n12], 'key2') + node._add_child(node.implicit, [n7, n8, n9]) + node._add_child(node.implicit, [n10, n11, n12]) node.add_ignore([n2, n5, n8, n11]) - kids = node.children(None) + kids = node.children() for kid in [n1, n3, n4, n6, n7, n9, n10, n12]: assert kid in kids, kid for kid in [n2, n5, n8, n11]: assert not kid in kids, kid - kids = node.children('key1') - for kid in [n1, n3, n4, n6, n7, n9]: - assert kid in kids, kid - for kid in [n2, n5, n8, n10, n11, n12]: - assert not kid in kids, kid - - kids = node.children('key2') - for kid in [n1, n3, n4, n6, n10, n12]: - assert kid in kids, kid - for kid in [n2, n5, n7, n8, n9, n11]: - assert not kid in kids, kid - def test_all_children(self): """Test fetching all the "children" of a Node. """ @@ -520,29 +440,17 @@ class NodeTestCase(unittest.TestCase): node.add_source([n1, n2, n3]) node.add_dependency([n4, n5, n6]) - node.add_implicit([n7, n8, n9], 'key1') - node.add_implicit([n10, n11, n12], 'key2') + node._add_child(node.implicit, [n7, n8, n9]) + node._add_child(node.implicit, [n10, n11, n12]) node.add_ignore([n2, n5, n8, n11]) - kids = node.all_children(None) + kids = node.all_children() for kid in [n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12]: assert kid in kids - kids = node.all_children('key1') - for kid in [n1, n2, n3, n4, n5, n6, n7, n8, n9]: - assert kid in kids - for kid in [n10, n11, n12]: - assert not kid in kids - - kids = node.all_children('key2') - for kid in [n1, n2, n3, n4, n5, n6, n10, n11, n12]: - assert kid in kids - for kid in [n7, n8, n9]: - assert not kid in kids - def test_state(self): - """Test setting and getting the state of a node - """ + """Test setting and getting the state of a node + """ node = SCons.Node.Node() assert node.get_state() == None node.set_state(SCons.Node.executing) @@ -553,51 +461,51 @@ class NodeTestCase(unittest.TestCase): assert SCons.Node.executed < SCons.Node.failed def test_walker(self): - """Test walking a Node tree. - """ + """Test walking a Node tree. + """ - class MyNode(SCons.Node.Node): - def __init__(self, name): - SCons.Node.Node.__init__(self) - self.name = name + class MyNode(SCons.Node.Node): + def __init__(self, name): + SCons.Node.Node.__init__(self) + self.name = name - n1 = MyNode("n1") + n1 = MyNode("n1") - nw = SCons.Node.Walker(n1) + nw = SCons.Node.Walker(n1) assert not nw.is_done() - assert nw.next().name == "n1" + assert nw.next().name == "n1" assert nw.is_done() - assert nw.next() == None - - n2 = MyNode("n2") - n3 = MyNode("n3") - n1.add_source([n2, n3]) - - nw = SCons.Node.Walker(n1) - assert nw.next().name == "n2" - assert nw.next().name == "n3" - assert nw.next().name == "n1" - assert nw.next() == None - - n4 = MyNode("n4") - n5 = MyNode("n5") - n6 = MyNode("n6") - n7 = MyNode("n7") - n2.add_source([n4, n5]) - n3.add_dependency([n6, n7]) - - nw = SCons.Node.Walker(n1) - assert nw.next().name == "n4" - assert nw.next().name == "n5" + assert nw.next() == None + + n2 = MyNode("n2") + n3 = MyNode("n3") + n1.add_source([n2, n3]) + + nw = SCons.Node.Walker(n1) + assert nw.next().name == "n2" + assert nw.next().name == "n3" + assert nw.next().name == "n1" + assert nw.next() == None + + n4 = MyNode("n4") + n5 = MyNode("n5") + n6 = MyNode("n6") + n7 = MyNode("n7") + n2.add_source([n4, n5]) + n3.add_dependency([n6, n7]) + + nw = SCons.Node.Walker(n1) + assert nw.next().name == "n4" + assert nw.next().name == "n5" assert nw.history.has_key(n2) - assert nw.next().name == "n2" - assert nw.next().name == "n6" - assert nw.next().name == "n7" + assert nw.next().name == "n2" + assert nw.next().name == "n6" + assert nw.next().name == "n7" assert nw.history.has_key(n3) - assert nw.next().name == "n3" + assert nw.next().name == "n3" assert nw.history.has_key(n1) - assert nw.next().name == "n1" - assert nw.next() == None + assert nw.next().name == "n1" + assert nw.next() == None n8 = MyNode("n8") n8.add_dependency([n3]) @@ -621,69 +529,6 @@ class NodeTestCase(unittest.TestCase): n = nw.next() assert nw.next() == None - def test_children_are_executed(self): - n1 = SCons.Node.Node() - n2 = SCons.Node.Node() - n3 = SCons.Node.Node() - n4 = SCons.Node.Node() - - n4.add_source([n3]) - n3.add_source([n1, n2]) - - assert not n4.children_are_executed(None) - assert not n3.children_are_executed(None) - assert n2.children_are_executed(None) - assert n1.children_are_executed(None) - - n1.set_state(SCons.Node.executed) - assert not n4.children_are_executed(None) - assert not n3.children_are_executed(None) - assert n2.children_are_executed(None) - assert n1.children_are_executed(None) - - n2.set_state(SCons.Node.executed) - assert not n4.children_are_executed(None) - assert n3.children_are_executed(None) - assert n2.children_are_executed(None) - assert n1.children_are_executed(None) - - n3.set_state(SCons.Node.executed) - assert n4.children_are_executed(None) - assert n3.children_are_executed(None) - assert n2.children_are_executed(None) - assert n1.children_are_executed(None) - - def test_rescan(self): - """Test that built node implicit dependencies are cleared - to be rescanned.""" - class DummyScanner: - pass - - class TestNode(SCons.Node.Node): - def scan(self, scanner): - if not self.scanned.has_key(scanner): - n=SCons.Node.Node() - n.scanner_set(scanner) - self.add_implicit([ n ], scanner) - self.scanned[scanner] = 1 - tn=TestNode() - tn.builder_set(Builder()) - tn.env_set(Environment()) - ds = DummyScanner() - tn.scan(ds) - map(lambda x: x.scan(), tn.depends) - assert tn.scanned[ds] - assert len(tn.implicit[ds]) == 1, tn.implicit - tn.scan(ds) - assert tn.scanned[ds] - assert len(tn.implicit[ds]) == 1, tn.implicit - tn.build() - assert not tn.scanned.has_key(ds) - assert len(tn.implicit[ds]) == 1, tn.implicit - tn.scan(ds) - assert tn.scanned[ds] - assert len(tn.implicit[ds]) == 2, tn.implicit - def test_arg2nodes(self): """Test the arg2nodes function.""" dict = {} @@ -779,4 +624,4 @@ class NodeTestCase(unittest.TestCase): if __name__ == "__main__": suite = unittest.makeSuite(NodeTestCase, 'test_') if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + sys.exit(1) diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index 98b2d50..db11e55 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -51,6 +51,7 @@ executing = 2 up_to_date = 3 executed = 4 failed = 5 +stack = 6 # nodes that are in the current Taskmaster execution stack class Node: """The base Node class, for entities that we know how to @@ -60,14 +61,13 @@ class Node: def __init__(self): self.sources = [] # source files used to build node self.depends = [] # explicit dependencies (from Depends) - self.implicit = {} # implicit (scanned) dependencies - self.ignore = [] # dependencies to ignore + self.implicit = [] # implicit (scanned) dependencies + self.ignore = [] # dependencies to ignore self.parents = {} self.wkids = None # Kids yet to walk, when it's an array self.builder = None - self.scanner = None # explicit scanner from this node's Builder - self.scanned = {} # cached scanned values - self.src_scanners = {} # scanners for this node's source files + self.source_scanner = None # implicit scanner from scanner map + self.target_scanner = None # explicit scanner from this node's Builder self.env = None self.state = None self.bsig = None @@ -75,11 +75,14 @@ class Node: self.use_signature = 1 self.precious = None self.found_includes = {} + self.includes = None def build(self): """Actually build the node. Return the status from the build.""" - if not self.builder: - return None + # This method is called from multiple threads in a parallel build, + # so only do thread safe stuff here. Do thread unsafe stuff in built(). + if not self.builder: + return None try: # If this Builder instance has already been called, # there will already be an associated status. @@ -103,16 +106,33 @@ class Node: if stat: raise BuildError(node = self, errstr = "Error %d" % stat) - self.found_includes = {} - - # If we successfully build a node, then we need to rescan for - # implicit dependencies, since it might have changed on us. - self.scanned = {} - return stat + def built(self): + """Called just after this node is sucessfully built.""" + # Clear out the implicit dependency caches: + # XXX this really should somehow be made more general and put + # under the control of the scanners. + if self.source_scanner: + self.found_includes = {} + self.includes = None + + def get_parents(node, parent): return node.get_parents() + def clear_cache(node, parent): + node.implicit = [] + w = Walker(self, get_parents, ignore_cycle, clear_cache) + while w.next(): pass + + def depends_on(self, nodes): + """Does this node depend on any of 'nodes'?""" + for node in nodes: + if node in self.children(): + return 1 + + return 0 + def builder_set(self, builder): - self.builder = builder + self.builder = builder def builder_sig_adapter(self): """Create an adapter for calculating a builder's signature. @@ -136,19 +156,21 @@ class Node: return self.node.builder.get_contents(env = dict) return Adapter(self) - def scanner_set(self, scanner): - self.scanner = scanner - - def src_scanner_set(self, key, scanner): - self.src_scanners[key] = scanner - - def src_scanner_get(self, key): - return self.src_scanners.get(key, None) - - def scan(self, scanner = None): - if not scanner: - scanner = self.scanner - self.scanned[scanner] = 1 + def get_implicit_deps(self, env, scanner, target): + """Return a list of implicit dependencies for this node""" + return [] + + def scan(self): + """Scan this node's dependents for implicit dependencies.""" + # Don't bother scanning non-derived files, because we don't + # care what their dependencies are. + # Don't scan again, if we already have scanned. + if self.builder and not self.implicit: + for child in self.children(scan=0): + self._add_child(self.implicit, child.get_implicit_deps(self.env, child.source_scanner, self)) + + # scan this node itself for implicit dependencies + self._add_child(self.implicit, self.get_implicit_deps(self.env, self.target_scanner, self)) def scanner_key(self): return None @@ -156,7 +178,7 @@ class Node: def env_set(self, env, safe=0): if safe and self.env: return - self.env = env + self.env = env def get_bsig(self): """Get the node's build signature (based on the signatures @@ -190,7 +212,7 @@ class Node: pass def add_dependency(self, depend): - """Adds dependencies. The depend argument must be a list.""" + """Adds dependencies. The depend argument must be a list.""" self._add_child(self.depends, depend) def add_ignore(self, depend): @@ -198,23 +220,16 @@ class Node: self._add_child(self.ignore, depend) def add_source(self, source): - """Adds sources. The source argument must be a list.""" + """Adds sources. The source argument must be a list.""" self._add_child(self.sources, source) - def add_implicit(self, implicit, key): - """Adds implicit (scanned) dependencies. The implicit - argument must be a list.""" - if not self.implicit.has_key(key): - self.implicit[key] = [] - self._add_child(self.implicit[key], implicit) - def _add_child(self, collection, child): """Adds 'child' to 'collection'. The 'child' argument must be a list""" if type(child) is not type([]): raise TypeError("child must be a list") - child = filter(lambda x, s=collection: x not in s, child) - if child: - collection.extend(child) + child = filter(lambda x, s=collection: x not in s, child) + if child: + collection.extend(child) for c in child: c.parents[self] = 1 @@ -224,22 +239,18 @@ class Node: if self.wkids != None: self.wkids.append(wkid) - def children(self, scanner): + def children(self, scan=1): """Return a list of the node's direct children, minus those that are ignored by this node.""" return filter(lambda x, i=self.ignore: x not in i, - self.all_children(scanner)) + self.all_children(scan)) - def all_children(self, scanner): + def all_children(self, scan=1): """Return a list of all the node's direct children.""" #XXX Need to remove duplicates from this - if not self.implicit.has_key(scanner): - self.scan(scanner) - if scanner: - implicit = self.implicit[scanner] - else: - implicit = reduce(lambda x, y: x + y, self.implicit.values(), []) - return self.sources + self.depends + implicit + if scan and not self.implicit: + self.scan() + return self.sources + self.depends + self.implicit def get_parents(self): return self.parents.keys() @@ -253,14 +264,7 @@ class Node: def current(self): return None - def children_are_executed(self, scanner): - return reduce(lambda x,y: ((y.get_state() == executed - or y.get_state() == up_to_date) - and x), - self.children(scanner), - 1) - -def get_children(node, parent): return node.children(None) +def get_children(node, parent): return node.children() def ignore_cycle(node, stack): pass def do_nothing(node, parent): pass @@ -290,13 +294,13 @@ class Walker: self.history[node] = None def next(self): - """Return the next node for this walk of the tree. + """Return the next node for this walk of the tree. - This function is intentionally iterative, not recursive, - to sidestep any issues of stack size limitations. - """ + This function is intentionally iterative, not recursive, + to sidestep any issues of stack size limitations. + """ - while self.stack: + while self.stack: if self.stack[-1].wkids: node = self.stack[-1].wkids.pop(0) if not self.stack[-1].wkids: |
