summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons/Node
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2002-04-04 09:07:00 (GMT)
committerSteven Knight <knight@baldmt.com>2002-04-04 09:07:00 (GMT)
commit6603cc0d6643e529da45fef6f85fcc1a0fc02ea4 (patch)
tree4a27de7c3fd70e5af0f257ccc73aab38e343f156 /src/engine/SCons/Node
parenta7669bc6a02999a3375c7e732a27ded5f9bb9935 (diff)
downloadSCons-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.py71
-rw-r--r--src/engine/SCons/Node/FSTests.py89
-rw-r--r--src/engine/SCons/Node/NodeTests.py363
-rw-r--r--src/engine/SCons/Node/__init__.py130
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: