summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons/Node
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2002-03-20 16:45:30 (GMT)
committerSteven Knight <knight@baldmt.com>2002-03-20 16:45:30 (GMT)
commita9272652019c6d0cad2f20737e210f820ec9394d (patch)
tree6c66bb13fa20cbd1e46b837e2ab734039cb68b6e /src/engine/SCons/Node
parent70d4bf67b7fefce28d76d451c959ba633720214e (diff)
downloadSCons-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.py21
-rw-r--r--src/engine/SCons/Node/FSTests.py32
-rw-r--r--src/engine/SCons/Node/NodeTests.py207
-rw-r--r--src/engine/SCons/Node/__init__.py74
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