diff options
| author | Steven Knight <knight@baldmt.com> | 2002-03-20 16:45:30 (GMT) |
|---|---|---|
| committer | Steven Knight <knight@baldmt.com> | 2002-03-20 16:45:30 (GMT) |
| commit | a9272652019c6d0cad2f20737e210f820ec9394d (patch) | |
| tree | 6c66bb13fa20cbd1e46b837e2ab734039cb68b6e /src/engine/SCons/Node | |
| parent | 70d4bf67b7fefce28d76d451c959ba633720214e (diff) | |
| download | SCons-a9272652019c6d0cad2f20737e210f820ec9394d.zip SCons-a9272652019c6d0cad2f20737e210f820ec9394d.tar.gz SCons-a9272652019c6d0cad2f20737e210f820ec9394d.tar.bz2 | |
Fix subtle problems in end cases with using multiple scanners on a Node.
Diffstat (limited to 'src/engine/SCons/Node')
| -rw-r--r-- | src/engine/SCons/Node/FS.py | 21 | ||||
| -rw-r--r-- | src/engine/SCons/Node/FSTests.py | 32 | ||||
| -rw-r--r-- | src/engine/SCons/Node/NodeTests.py | 207 | ||||
| -rw-r--r-- | src/engine/SCons/Node/__init__.py | 74 |
4 files changed, 209 insertions, 125 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index f7e1f44..362559c 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -417,7 +417,7 @@ class Dir(Entry): else: return self.entries['..'].root() - def children(self): + 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) @@ -446,7 +446,7 @@ class Dir(Entry): """If all of our children were up-to-date, then this directory was up-to-date, too.""" state = 0 - for kid in self.children(): + for kid in self.children(None): s = kid.get_state() if s and (not state or s > state): state = s @@ -523,13 +523,13 @@ class File(Entry): .sconsign entry.""" return self.dir.sconsign().get(self.name) - def scan(self): - if self.env: - for scn in self.scanners: - if not self.scanned.has_key(scn): - deps = scn.scan(self, self.env) - self.add_implicit(deps,scn) - self.scanned[scn] = 1 + 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 exists(self): if self.duplicate and not self.created: @@ -542,6 +542,9 @@ class File(Entry): file_link(self.srcpath, self.path) return Entry.exists(self) + def scanner_key(self): + return os.path.splitext(self.name)[1] + def __createDir(self): # ensure that the directories for this node are # created. diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index b132b12..e9e24ec 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -257,13 +257,13 @@ class FSTestCase(unittest.TestCase): fs.Dir(string.join(['ddd', 'd1'], sep)) fs.Dir(string.join(['ddd', 'd1', 'f4'], sep)) fs.Dir(string.join(['ddd', 'd1', 'f5'], sep)) - kids = map(lambda x: x.path, dir.children()) + 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')] - kids = map(lambda x: x.path_, dir.children()) + kids = map(lambda x: x.path_, dir.children(None)) kids.sort() assert kids == [os.path.join('ddd', 'd1', ''), os.path.join('ddd', 'f1'), @@ -383,16 +383,23 @@ class FSTestCase(unittest.TestCase): match(e13.path, "subdir/subdir/e13") # Test scanning - scn = Scanner() - f1.scanners = [ scn ] - f1.scan() - assert f1.implicit[scn][0].path_ == os.path.join("d1", "f1") - del f1.implicit[scn] - f1.scan() + 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[scn] - f1.scan() - assert f1.implicit[scn][0].path_ == os.path.join("d1", "f1") + 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) + assert f2.implicit[scn1][0].path_ == 'subdir/f2', f2.implicit[scn1][0].path_ + assert f2.implicit[scn2][0].path_ == 'subdir/f2', f2.implicit[scn2][0].path_ # Test building a file whose directory is not there yet... f1 = fs.File(test.workpath("foo/bar/baz/ack")) @@ -468,6 +475,9 @@ class FSTestCase(unittest.TestCase): #XXX test get_prevsiginfo() + assert fs.File('foo.x').scanner_key() == '.x' + assert fs.File('foo.xyz').scanner_key() == '.xyz' + class find_fileTestCase(unittest.TestCase): def runTest(self): diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py index 574e9cd..ec506aa 100644 --- a/src/engine/SCons/Node/NodeTests.py +++ b/src/engine/SCons/Node/NodeTests.py @@ -416,57 +416,126 @@ class NodeTestCase(unittest.TestCase): pass ds=DummyScanner() node = SCons.Node.Node() - assert node.scanners == [], node.scanners + assert node.scanner == None, node.scanner node.scanner_set(ds) - assert node.scanners == [ ds ], node.scanners - node.scan() + 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 + + def test_scanner_key(self): + """Test that a scanner_key() method exists""" + assert SCons.Node.Node().scanner_key() == None + def test_children(self): """Test fetching the non-ignored "children" of a Node. """ node = SCons.Node.Node() - one = SCons.Node.Node() - two = SCons.Node.Node() - three = SCons.Node.Node() - four = SCons.Node.Node() - five = SCons.Node.Node() - six = SCons.Node.Node() - - node.add_source([one, two, three]) - node.add_dependency([four, five, six]) - node.add_ignore([two, five]) - kids = node.children() - assert len(kids) == 4 - assert one in kids - assert not two in kids - assert three in kids - assert four in kids - assert not five in kids - assert six in kids + n1 = SCons.Node.Node() + n2 = SCons.Node.Node() + n3 = SCons.Node.Node() + n4 = SCons.Node.Node() + n5 = SCons.Node.Node() + n6 = SCons.Node.Node() + n7 = SCons.Node.Node() + n8 = SCons.Node.Node() + n9 = SCons.Node.Node() + n10 = SCons.Node.Node() + n11 = SCons.Node.Node() + n12 = SCons.Node.Node() + + 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_ignore([n2, n5, n8, n11]) + + kids = node.children(None) + 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. """ node = SCons.Node.Node() - one = SCons.Node.Node() - two = SCons.Node.Node() - three = SCons.Node.Node() - four = SCons.Node.Node() - five = SCons.Node.Node() - six = SCons.Node.Node() - - node.add_source([one, two, three]) - node.add_dependency([four, five, six]) - node.add_ignore([two, five]) - kids = node.all_children() - assert len(kids) == 6 - assert one in kids - assert two in kids - assert three in kids - assert four in kids - assert five in kids - assert six in kids + n1 = SCons.Node.Node() + n2 = SCons.Node.Node() + n3 = SCons.Node.Node() + n4 = SCons.Node.Node() + n5 = SCons.Node.Node() + n6 = SCons.Node.Node() + n7 = SCons.Node.Node() + n8 = SCons.Node.Node() + n9 = SCons.Node.Node() + n10 = SCons.Node.Node() + n11 = SCons.Node.Node() + n12 = SCons.Node.Node() + + 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_ignore([n2, n5, n8, n11]) + + kids = node.all_children(None) + 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 @@ -558,55 +627,59 @@ class NodeTestCase(unittest.TestCase): n4.add_source([n3]) n3.add_source([n1, n2]) - assert not n4.children_are_executed() - assert not n3.children_are_executed() - assert n2.children_are_executed() - assert n1.children_are_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) n1.set_state(SCons.Node.executed) - assert not n4.children_are_executed() - assert not n3.children_are_executed() - assert n2.children_are_executed() - assert n1.children_are_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() - assert n3.children_are_executed() - assert n2.children_are_executed() - assert n1.children_are_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() - assert n3.children_are_executed() - assert n2.children_are_executed() - assert n1.children_are_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 nodes are rescanned.""" + """Test that built node implicit dependencies are cleared + to be rescanned.""" class DummyScanner: pass class TestNode(SCons.Node.Node): - def scan(self): - for scn in self.scanners: - if not self.scanned.has_key(scn): - n=SCons.Node.Node() - n.scanner_set(scn) - self.add_implicit([ n ], scn) - self.scanned[scn] = 1 + 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.scanner_set(ds) - tn.scan() + 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 - for dep in tn.implicit[ds]: - assert dep.scanned[ds] == 1 if __name__ == "__main__": suite = unittest.makeSuite(NodeTestCase, 'test_') diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index ef12c6e..e8d45e1 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -62,10 +62,11 @@ class Node: self.ignore = [] # dependencies to ignore self.parents = {} self.wkids = None # Kids yet to walk, when it's an array - self.builder = None - self.scanners = [] - self.scanned = {} - self.env = None + 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.env = None self.state = None self.bsig = None self.csig = None @@ -96,28 +97,11 @@ class Node: self.found_includes = {} - # If we succesfully build a node, then we need to rescan for + # If we successfully build a node, then we need to rescan for # implicit dependencies, since it might have changed on us. + self.scanned = {} - # XXX Modify this so we only rescan using the scanner(s) relevant - # to this build. - for scn in self.scanners: - try: - del self.scanned[scn] - except KeyError: - pass - - self.scan() - - for scn in self.scanners: - try: - for dep in self.implicit[scn]: - w=Walker(dep) - while not w.is_done(): - w.next().scan() - except KeyError: - pass - return stat + return stat def builder_set(self, builder): self.builder = builder @@ -144,12 +128,21 @@ class Node: return Adapter(self) def scanner_set(self, scanner): - if not scanner in self.scanners: - self.scanners.append(scanner) + self.scanner = scanner - def scan(self): - for scn in self.scanners: - self.scanned[scn] = 1 + 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 scanner_key(self): + return None def env_set(self, env, safe=0): if safe and self.env: @@ -222,17 +215,22 @@ class Node: if self.wkids != None: self.wkids.append(wkid) - def children(self): + def children(self, scanner): """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()) + return filter(lambda x, i=self.ignore: x not in i, + self.all_children(scanner)) - def all_children(self): + def all_children(self, scanner): """Return a list of all the node's direct children.""" #XXX Need to remove duplicates from this - return self.sources \ - + self.depends \ - + reduce(lambda x, y: x + y, self.implicit.values(), []) + 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 def get_parents(self): return self.parents.keys() @@ -246,14 +244,14 @@ class Node: def current(self): return None - def children_are_executed(self): + 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(), + self.children(scanner), 1) -def get_children(node, parent): return node.children() +def get_children(node, parent): return node.children(None) def ignore_cycle(node, stack): pass def do_nothing(node, parent): pass |
