summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons/Node
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2003-02-18 08:04:29 (GMT)
committerSteven Knight <knight@baldmt.com>2003-02-18 08:04:29 (GMT)
commit5aaf9d3bad67e5ac33a342478e4449e4c71f039c (patch)
tree9b62b6fab5539b7ef535182b0fe29b05acd4baff /src/engine/SCons/Node
parentbdbeeed7d1492c270c24d809237eb5f724c7cbf5 (diff)
downloadSCons-5aaf9d3bad67e5ac33a342478e4449e4c71f039c.zip
SCons-5aaf9d3bad67e5ac33a342478e4449e4c71f039c.tar.gz
SCons-5aaf9d3bad67e5ac33a342478e4449e4c71f039c.tar.bz2
Add support for fetching files from rcs.
Diffstat (limited to 'src/engine/SCons/Node')
-rw-r--r--src/engine/SCons/Node/FS.py37
-rw-r--r--src/engine/SCons/Node/FSTests.py29
-rw-r--r--src/engine/SCons/Node/NodeTests.py19
-rw-r--r--src/engine/SCons/Node/__init__.py43
4 files changed, 121 insertions, 7 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index 651d280..5a8687e 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -168,6 +168,9 @@ class ParentOfRoot:
def get_dir(self):
return None
+ def src_builder(self):
+ return None
+
if os.path.normcase("TeSt") == os.path.normpath("TeSt"):
def _my_normcase(x):
return x
@@ -294,6 +297,24 @@ class Entry(SCons.Node.Node):
self._srcnode = self
return self._srcnode
+ def set_src_builder(self, builder):
+ """Set the source code builder for this node."""
+ self.sbuilder = builder
+
+ def src_builder(self):
+ """Fetch the source code builder for this node.
+
+ If there isn't one, we cache the source code builder specified
+ for the directory (which in turn will cache the value from its
+ parent directory, and so on up to the file system root).
+ """
+ try:
+ scb = self.sbuilder
+ except AttributeError:
+ scb = self.dir.src_builder()
+ self.sbuilder = scb
+ return scb
+
# This is for later so we can differentiate between Entry the class and Entry
# the method of the FS class.
_classEntry = Entry
@@ -995,6 +1016,22 @@ class File(Entry):
if self.fs.CachePath and self.fs.cache_force and os.path.exists(self.path):
CachePush(self, None, None)
+ def has_builder(self):
+ """Return whether this Node has a builder or not.
+
+ If this Node doesn't have an explicit builder, this is where we
+ figure out, on the fly, if there's a source code builder for it.
+ """
+ try:
+ b = self.builder
+ except AttributeError:
+ if not os.path.exists(self.path):
+ b = self.src_builder()
+ else:
+ b = None
+ self.builder = b
+ return not b is None
+
def prepare(self):
"""Prepare for this file to be created."""
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index fa32c25..f1160c1 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -1168,6 +1168,34 @@ class StringDirTestCase(unittest.TestCase):
assert str(f) == os.path.join('sub', 'file')
assert not f.exists()
+class has_builderTestCase(unittest.TestCase):
+ def runTest(self):
+ """Test the has_builder() method"""
+ test = TestCmd(workdir = '')
+ fs = SCons.Node.FS.FS(test.workpath(''))
+ os.chdir(test.workpath(''))
+ test.subdir('sub')
+
+ d = fs.Dir('sub', '.')
+ f1 = fs.File('f1', d)
+ f2 = fs.File('f2', d)
+ f3 = fs.File('f3', d)
+
+ h = f1.has_builder()
+ assert not h, h
+
+ b1 = Builder(fs.File)
+ d.set_src_builder(b1)
+
+ test.write(['sub', 'f2'], "sub/f2\n")
+ h = f1.has_builder() # cached from previous has_builder() call
+ assert not h, h
+ h = f2.has_builder()
+ assert not h, h
+ h = f3.has_builder()
+ assert h, h
+ assert f3.builder is b1, f3.builder
+
class prepareTestCase(unittest.TestCase):
def runTest(self):
"""Test the prepare() method"""
@@ -1328,6 +1356,7 @@ if __name__ == "__main__":
suite.addTest(RepositoryTestCase())
suite.addTest(find_fileTestCase())
suite.addTest(StringDirTestCase())
+ suite.addTest(has_builderTestCase())
suite.addTest(prepareTestCase())
suite.addTest(get_actionsTestCase())
suite.addTest(CacheDirTestCase())
diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py
index 86dcc56..b47106d 100644
--- a/src/engine/SCons/Node/NodeTests.py
+++ b/src/engine/SCons/Node/NodeTests.py
@@ -110,7 +110,7 @@ class ExceptBuilder2:
class Environment:
def Dictionary(self, *args):
return {}
- def Override(selv, overrides):
+ def Override(self, overrides):
return overrides
class Scanner:
@@ -166,7 +166,7 @@ class NodeTestCase(unittest.TestCase):
node.overrides = { "foo" : 1, "bar" : 2 }
node.build()
assert built_it
- assert built_target[0] == node, build_target[0]
+ assert built_target[0] == node, built_target[0]
assert built_source == ["rrr", "sss"], built_source
assert built_args["foo"] == 1, built_args
assert built_args["bar"] == 2, built_args
@@ -186,6 +186,21 @@ class NodeTestCase(unittest.TestCase):
# [Charles C. 1/7/2002] Uhhh, why are there no asserts here?
built_it = None
+ jjj = MyNode("jjj")
+ b = Builder()
+ jjj.builder_set(b)
+ # NOTE: No env_set()! We should pull the environment from the builder.
+ b.env = Environment()
+ b.overrides = { "on" : 3, "off" : 4 }
+ e.builder = b
+ jjj.build()
+ assert built_it
+ assert built_target[0] == jjj, built_target[0]
+ assert built_source == [], built_source
+ assert built_args["on"] == 3, built_args
+ assert built_args["off"] == 4, built_args
+
+ built_it = None
built_order = 0
node = MyNode("xxx")
node.builder_set(Builder())
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 600c478..27ff4db 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -89,15 +89,21 @@ class Node:
pass
def __init__(self):
+ # Note that we no longer explicitly initialize a self.builder
+ # attribute to None here. That's because the self.builder
+ # attribute may be created on-the-fly later by a subclass (the
+ # canonical example being a builder to fetch a file from a
+ # source code system like CVS or Subversion).
+
self.sources = [] # source files used to build node
self.depends = [] # explicit dependencies (from Depends)
self.implicit = None # implicit (scanned) dependencies (None means not scanned yet)
self.ignore = [] # dependencies to ignore
self.parents = {}
self.wkids = None # Kids yet to walk, when it's an array
- self.builder = None
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.precious = None
@@ -116,12 +122,32 @@ class Node:
Annotate(self)
def generate_build_env(self):
- return self.env.Override(self.overrides)
+ """Generate the appropriate Environment to build this node."""
+ if self.env is None:
+ # The node itself doesn't have an associated Environment
+ # (which kind of implies it's a source code file, but who
+ # knows...). Regardless of why, use the environment (if
+ # any) associated with the Builder itself.
+ env = self.builder.env
+ overrides = self.builder.overrides
+ else:
+ # The normal case: use the Environment used to specify how
+ # this Node is to be built.
+ env = self.env
+ overrides = self.overrides
+ return env.Override(overrides)
def _for_each_action(self, func):
+ """Call a function for each action required to build a node.
+
+ The purpose here is to have one place for the logic that
+ collects and executes all of the actions for a node's builder,
+ even though multiple sections of code elsewhere need this logic
+ to do different things."""
if not self.has_builder():
- return None
- action_list = self.pre_actions + self.builder.get_actions() + \
+ return
+ action_list = self.pre_actions + \
+ self.builder.get_actions() + \
self.post_actions
if not action_list:
return
@@ -193,7 +219,14 @@ class Node:
class(es), generating a bazillion extra calls and slowing
things down immensely.
"""
- return not self.builder is None
+ try:
+ b = self.builder
+ except AttributeError:
+ # There was no explicit builder for this Node, so initialize
+ # the self.builder attribute to None now.
+ self.builder = None
+ b = self.builder
+ return not b is None
def builder_sig_adapter(self):
"""Create an adapter for calculating a builder's signature.