summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons/Node
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/SCons/Node')
-rw-r--r--src/engine/SCons/Node/FS.py9
-rw-r--r--src/engine/SCons/Node/FSTests.py8
-rw-r--r--src/engine/SCons/Node/NodeTests.py74
-rw-r--r--src/engine/SCons/Node/__init__.py77
4 files changed, 103 insertions, 65 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index 15434cb..0d158a1 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -488,12 +488,6 @@ class Base(SCons.Node.Node):
self._rexists = self.rfile().exists()
return self._rexists
- def get_parents(self):
- parents = SCons.Node.Node.get_parents(self)
- if self.dir and not isinstance(self.dir, ParentOfRoot):
- parents.append(self.dir)
- return parents
-
def is_under(self, dir):
if self is dir:
return 1
@@ -1117,8 +1111,7 @@ class Dir(Base):
self.abspath_ = self.abspath + os.sep
self.repositories = []
self.srcdir = None
- self.source_scanner = None
-
+
self.entries = {}
self.entries['.'] = self
self.entries['..'] = self.dir
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index fb2e0fa..f69dd4e 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -60,6 +60,8 @@ class Scanner:
return [self.node]
def __hash__(self):
return self.hash
+ def select(self, node):
+ return self
class Environment:
def __init__(self):
@@ -1034,12 +1036,6 @@ class FSTestCase(unittest.TestCase):
skey = fs.Dir('ddd.x').scanner_key()
assert skey is None, skey
- d1 = fs.Dir('dir')
- f1 = fs.File('dir/file')
- assert f1.dir == d1, f1.dir
- parents = f1.get_parents()
- assert parents == [ d1 ], parents
-
test.write("i_am_not_a_directory", "\n")
try:
exc_caught = 0
diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py
index 535c84e..e36d6ce 100644
--- a/src/engine/SCons/Node/NodeTests.py
+++ b/src/engine/SCons/Node/NodeTests.py
@@ -138,6 +138,8 @@ class Scanner:
def __call__(self, node):
self.called = 1
return node.found_includes
+ def select(self, node):
+ return self
class MyNode(SCons.Node.Node):
"""The base Node class contains a number of do-nothing methods that
@@ -543,12 +545,6 @@ class NodeTestCase(unittest.TestCase):
node.add_dependency([three, four, one])
assert node.depends == [zero, one, two, three, four]
- assert zero.get_parents() == [node]
- assert one.get_parents() == [node]
- assert two.get_parents() == [node]
- assert three.get_parents() == [node]
- assert four.get_parents() == [node]
-
try:
node.add_depends([[five, six]])
except:
@@ -556,8 +552,6 @@ class NodeTestCase(unittest.TestCase):
else:
raise "did not catch expected exception"
assert node.depends == [zero, one, two, three, four]
- assert five.get_parents() == []
- assert six.get_parents() == []
def test_add_source(self):
@@ -583,12 +577,6 @@ class NodeTestCase(unittest.TestCase):
node.add_source([three, four, one])
assert node.sources == [zero, one, two, three, four]
- assert zero.get_parents() == [node]
- assert one.get_parents() == [node]
- assert two.get_parents() == [node]
- assert three.get_parents() == [node]
- assert four.get_parents() == [node]
-
try:
node.add_source([[five, six]])
except:
@@ -596,8 +584,6 @@ class NodeTestCase(unittest.TestCase):
else:
raise "did not catch expected exception"
assert node.sources == [zero, one, two, three, four]
- assert five.get_parents() == []
- assert six.get_parents() == []
def test_add_ignore(self):
"""Test adding files whose dependencies should be ignored.
@@ -622,12 +608,6 @@ class NodeTestCase(unittest.TestCase):
node.add_ignore([three, four, one])
assert node.ignore == [zero, one, two, three, four]
- assert zero.get_parents() == [node]
- assert one.get_parents() == [node]
- assert two.get_parents() == [node]
- assert three.get_parents() == [node]
- assert four.get_parents() == [node]
-
try:
node.add_ignore([[five, six]])
except:
@@ -635,8 +615,6 @@ class NodeTestCase(unittest.TestCase):
else:
raise "did not catch expected exception"
assert node.ignore == [zero, one, two, three, four]
- assert five.get_parents() == []
- assert six.get_parents() == []
def test_get_found_includes(self):
"""Test the default get_found_includes() method
@@ -689,6 +667,33 @@ class NodeTestCase(unittest.TestCase):
deps = node.get_implicit_deps(env, s, target)
assert deps == [d, e, f], map(str, deps)
+ def test_get_source_scanner(self):
+ """Test fetching the source scanner for a Node
+ """
+ class Builder:
+ pass
+ target = SCons.Node.Node()
+ source = SCons.Node.Node()
+ s = target.get_source_scanner(source)
+ assert s is None, s
+
+ ts1 = Scanner()
+ ts2 = Scanner()
+ ts3 = Scanner()
+
+ source.backup_source_scanner = ts1
+ s = target.get_source_scanner(source)
+ assert s is ts1, s
+
+ source.builder = Builder()
+ source.builder.source_scanner = ts2
+ s = target.get_source_scanner(source)
+ assert s is ts2, s
+
+ target.source_scanner = ts3
+ s = target.get_source_scanner(source)
+ assert s is ts3, s
+
def test_scan(self):
"""Test Scanner functionality
"""
@@ -947,6 +952,7 @@ class NodeTestCase(unittest.TestCase):
n.includes = 'testincludes'
n.found_include = {'testkey':'testvalue'}
n.implicit = 'testimplicit'
+ n.waiting_parents = ['foo', 'bar']
n.clear()
@@ -955,6 +961,7 @@ class NodeTestCase(unittest.TestCase):
assert n.includes is None, n.includes
assert n.found_includes == {}, n.found_includes
assert n.implicit is None, n.implicit
+ assert n.waiting_parents == [], n.waiting_parents
def test_get_subst_proxy(self):
"""Test the get_subst_proxy method."""
@@ -985,6 +992,25 @@ class NodeTestCase(unittest.TestCase):
n = SCons.Node.Node()
n.postprocess()
+ def test_add_to_waiting_parents(self):
+ """Test the add_to_waiting_parents() method"""
+ n1 = SCons.Node.Node()
+ n2 = SCons.Node.Node()
+ assert n1.waiting_parents == [], n1.waiting_parents
+ n1.add_to_waiting_parents(n2)
+ assert n1.waiting_parents == [n2], n1.waiting_parents
+
+ def test_call_for_all_waiting_parents(self):
+ """Test the call_for_all_waiting_parents() method"""
+ n1 = SCons.Node.Node()
+ n2 = SCons.Node.Node()
+ n1.add_to_waiting_parents(n2)
+ result = []
+ def func(node, result=result):
+ result.append(node)
+ n1.call_for_all_waiting_parents(func)
+ assert result == [n1, n2], result
+
if __name__ == "__main__":
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 2841759..75b3a6d 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -116,10 +116,11 @@ class Node:
self.ignore = [] # dependencies to ignore
self.ignore_dict = {}
self.implicit = None # implicit (scanned) dependencies (None means not scanned yet)
- self.parents = {}
+ self.waiting_parents = []
self.wkids = None # Kids yet to walk, when it's an array
self.target_scanner = None # explicit scanner from this node's Builder
- self.source_scanner = None # source scanner
+ self.source_scanner = None
+ self.backup_source_scanner = None
self.env = None
self.state = None
@@ -208,20 +209,29 @@ class Node:
else:
self.store_info(new_binfo)
- # 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
- for parent in self.get_parents():
- parent.implicit = None
- parent.del_binfo()
+ # Clear our scanned included files.
+ self.found_includes = {}
+ self.includes = None
+
+ # Clear the implicit dependency caches of any Nodes
+ # waiting for this Node to be built.
+ for parent in self.waiting_parents:
+ parent.implicit = None
+ parent.del_binfo()
+ self.waiting_parents = []
# The content just changed, delete any cached info
# so it will get recalculated.
self.del_cinfo()
+ def add_to_waiting_parents(self, node):
+ self.waiting_parents.append(node)
+
+ def call_for_all_waiting_parents(self, func):
+ func(self)
+ for parent in self.waiting_parents:
+ parent.call_for_all_waiting_parents(func)
+
def postprocess(self):
"""Clean up anything we don't need to hang onto after we've
been built."""
@@ -248,6 +258,8 @@ class Node:
self.found_includes = {}
self.implicit = None
+ self.waiting_parents = []
+
def visited(self):
"""Called just after this node has been visited
without requiring a build.."""
@@ -329,6 +341,10 @@ class Node:
if not scanner:
return []
+ # Give the scanner a chance to select a more specific scanner
+ # for this Node.
+ scanner = scanner.select(self)
+
try:
recurse = scanner.recursive
except AttributeError:
@@ -367,6 +383,22 @@ class Node:
self.implicit_factory_cache[path] = n
return n
+ def get_source_scanner(self, node):
+ """Fetch the source scanner for the specified node
+
+ NOTE: "self" is the target being built, "node" is
+ the source file for which we want to fetch the scanner.
+ """
+ if self.source_scanner:
+ return self.source_scanner
+ try:
+ scanner = node.builder.source_scanner
+ if scanner:
+ return scanner
+ except AttributeError:
+ pass
+ return node.backup_source_scanner or None
+
def scan(self):
"""Scan this node's dependents for implicit dependencies."""
# Don't bother scanning non-derived files, because we don't
@@ -405,20 +437,14 @@ class Node:
# self.del_binfo()
for child in self.children(scan=0):
- scanner = child.source_scanner
+ scanner = self.get_source_scanner(child)
if scanner:
- self._add_child(self.implicit,
- self.implicit_dict,
- child.get_implicit_deps(build_env,
- scanner,
- self))
+ deps = child.get_implicit_deps(build_env, scanner, self)
+ self._add_child(self.implicit, self.implicit_dict, deps)
# scan this node itself for implicit dependencies
- self._add_child(self.implicit,
- self.implicit_dict,
- self.get_implicit_deps(build_env,
- self.target_scanner,
- self))
+ deps = self.get_implicit_deps(build_env, self.target_scanner, self)
+ self._add_child(self.implicit, self.implicit_dict, deps)
# XXX See note above re: --implicit-cache.
#if implicit_cache:
@@ -632,7 +658,6 @@ class Node:
collection.append(c)
dict[c] = 1
added = 1
- c.parents[self] = 1
if added:
self._children_reset()
@@ -686,9 +711,6 @@ class Node:
else:
return self.sources + self.depends + self.implicit
- def get_parents(self):
- return self.parents.keys()
-
def set_state(self, state):
self.state = state
@@ -738,7 +760,8 @@ class Node:
if self.is_derived() and self.env:
env = self.get_build_env()
for s in self.sources:
- def f(node, env=env, scanner=s.source_scanner, target=self):
+ scanner = s.get_source_scanner(self)
+ def f(node, env=env, scanner=scanner, target=self):
return node.get_found_includes(env, scanner, target)
return SCons.Util.render_tree(s, f, 1)
else: