summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons/Node
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2003-03-22 08:31:26 (GMT)
committerSteven Knight <knight@baldmt.com>2003-03-22 08:31:26 (GMT)
commit3be8585d1be52d25020b93d99c333d9c9d577b51 (patch)
tree1841b7b005e680ba16d9a897e759774390a1583c /src/engine/SCons/Node
parent5ea9b7416ae70c3a4678bcf337bebd41b944cf86 (diff)
downloadSCons-3be8585d1be52d25020b93d99c333d9c9d577b51.zip
SCons-3be8585d1be52d25020b93d99c333d9c9d577b51.tar.gz
SCons-3be8585d1be52d25020b93d99c333d9c9d577b51.tar.bz2
Make RCS/SCCS/BitKeeper support more transparent.
Diffstat (limited to 'src/engine/SCons/Node')
-rw-r--r--src/engine/SCons/Node/FS.py120
-rw-r--r--src/engine/SCons/Node/FSTests.py65
-rw-r--r--src/engine/SCons/Node/NodeTests.py21
-rw-r--r--src/engine/SCons/Node/__init__.py5
4 files changed, 143 insertions, 68 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index e5182cd..89566b2 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -154,6 +154,32 @@ def CachePushFunc(target, source, env):
CachePush = SCons.Action.Action(CachePushFunc, None)
+class _Null:
+ pass
+
+_null = _Null()
+
+DefaultSCCSBuilder = None
+DefaultRCSBuilder = None
+
+def get_DefaultSCCSBuilder():
+ global DefaultSCCSBuilder
+ if DefaultSCCSBuilder is None:
+ import SCons.Builder
+ import SCons.Defaults
+ DefaultSCCSBuilder = SCons.Builder.Builder(action = '$SCCSCOM',
+ env = SCons.Defaults._default_env)
+ return DefaultSCCSBuilder
+
+def get_DefaultRCSBuilder():
+ global DefaultRCSBuilder
+ if DefaultRCSBuilder is None:
+ import SCons.Builder
+ import SCons.Defaults
+ DefaultRCSBuilder = SCons.Builder.Builder(action = '$RCSCOM',
+ env = SCons.Defaults._default_env)
+ return DefaultRCSBuilder
+
#
class ParentOfRoot:
"""
@@ -188,7 +214,7 @@ class ParentOfRoot:
return path_elems
def src_builder(self):
- return None
+ return _null
if os.path.normcase("TeSt") == os.path.normpath("TeSt"):
def _my_normcase(x):
@@ -265,7 +291,7 @@ class Entry(SCons.Node.Node):
try:
return self._exists
except AttributeError:
- self._exists = os.path.exists(self.abspath)
+ self._exists = _existsp(self.abspath)
return self._exists
def rexists(self):
@@ -382,7 +408,7 @@ class FS:
self.pathTop = path
self.Root = {}
self.Top = None
- self.SConstruct = None
+ self.SConstruct_dir = None
self.CachePath = None
self.cache_force = None
self.cache_show = None
@@ -391,8 +417,8 @@ class FS:
assert not self.Top, "You can only set the top-level path on an FS object that has not had its File, Dir, or Entry methods called yet."
self.pathTop = path
- def set_SConstruct(self, path):
- self.SConstruct = self.File(path)
+ def set_SConstruct_dir(self, dir):
+ self.SConstruct_dir = dir
def __setTopLevelDir(self):
if not self.Top:
@@ -636,7 +662,6 @@ class FS:
# Go up one directory
d = d.get_dir()
return None
-
def Rsearchall(self, pathlist, must_exist=1, clazz=_classEntry, cwd=None):
"""Search for a list of somethings in the Repository list."""
@@ -661,16 +686,20 @@ class FS:
d = n.get_dir()
name = n.name
- # Search repositories of all directories that this file is under.
+ # Search repositories of all directories that this file
+ # is under.
while d:
for rep in d.getRepositories():
try:
rnode = self.__doLookup(clazz, name, rep)
- # Only find the node if it exists (or must_exist is zero)
- # and it is not a derived file. If for some reason, we
- # are explicitly building a file IN a Repository, we don't
- # want it to show up in the build tree. This is usually the
- # case with BuildDir(). We only want to find pre-existing files.
+ # Only find the node if it exists (or
+ # must_exist is zero) and it is not a
+ # derived file. If for some reason, we
+ # are explicitly building a file IN a
+ # Repository, we don't want it to show up in
+ # the build tree. This is usually the case
+ # with BuildDir(). We only want to find
+ # pre-existing files.
if (not must_exist or rnode.exists()) and \
(not rnode.has_builder() or isinstance(rnode, Dir)):
ret.append(rnode)
@@ -851,6 +880,17 @@ class Dir(Entry):
else:
return 0
+ def rdir(self):
+ try:
+ return self._rdir
+ except AttributeError:
+ self._rdir = self
+ if not self.exists():
+ n = self.fs.Rsearch(self.path, clazz=Dir, cwd=self.fs.Top)
+ if n:
+ self._rdir = n
+ return self._rdir
+
def sconsign(self):
"""Return the .sconsign file info for this directory,
creating it first if necessary."""
@@ -1039,9 +1079,10 @@ class File(Entry):
so only do thread safe stuff here. Do thread unsafe stuff in
built().
"""
- if not self.has_builder():
+ b = self.has_builder()
+ if not b and not self.has_src_builder():
return
- if self.fs.CachePath:
+ if b and self.fs.CachePath:
if self.fs.cache_show:
if CacheRetrieveSilent(self, None, None) == 0:
def do_print(action, targets, sources, env, self=self):
@@ -1074,27 +1115,56 @@ 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, fetch = 1):
- """Return whether this Node has a builder or not.
+ def has_src_builder(self):
+ """Return whether this Node has a source builder or not.
+
+ If this Node doesn't have an explicit source code builder, this
+ is where we figure out, on the fly, if there's a transparent
+ source code builder for it.
- 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.
+ Note that if we found a source builder, we also set the
+ self.builder attribute, so that all of the methods that actually
+ *build* this file don't have to do anything different.
"""
try:
- b = self.builder
+ scb = self.sbuilder
except AttributeError:
- if fetch and not os.path.exists(self.path):
- b = self.src_builder()
+ if self.rexists():
+ scb = None
else:
- b = None
- self.builder = b
- return not b is None
+ scb = self.dir.src_builder()
+ if scb is _null:
+ scb = None
+ dir = self.dir.path
+ sccspath = os.path.join('SCCS', 's.' + self.name)
+ if dir != '.':
+ sccspath = os.path.join(dir, sccspath)
+ if os.path.exists(sccspath):
+ scb = get_DefaultSCCSBuilder()
+ else:
+ rcspath = os.path.join('RCS', self.name + ',v')
+ if dir != '.':
+ rcspath = os.path.join(dir, rcspath)
+ if os.path.exists(rcspath):
+ scb = get_DefaultRCSBuilder()
+ self.builder = scb
+ self.sbuilder = scb
+ return not scb is None
+
+ def is_derived(self):
+ """Return whether this file is a derived file or not.
+
+ This overrides the base class method to account for the fact
+ that a file may be derived transparently from a source code
+ builder.
+ """
+ return self.has_builder() or self.side_effect or self.has_src_builder()
def prepare(self):
"""Prepare for this file to be created."""
def missing(node):
- return not node.has_builder() and not node.linked and not node.rexists()
+ return not node.has_builder() and not node.linked and not node.rexists() and not node.has_src_builder()
missing_sources = filter(missing, self.children())
if missing_sources:
desc = "No Builder for target `%s', needed by `%s'." % (missing_sources[0], self)
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 294a4bb..d460c1e 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -1182,47 +1182,46 @@ class StringDirTestCase(unittest.TestCase):
assert str(f) == os.path.join('sub', 'file')
assert not f.exists()
-class has_builderTestCase(unittest.TestCase):
+class has_src_builderTestCase(unittest.TestCase):
def runTest(self):
- """Test the has_builder() method"""
+ """Test the has_src_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)
- f4 = fs.File('f4', d)
- f5 = fs.File('f5', d)
- f6 = fs.File('f6', d)
- f7 = fs.File('f7', d)
-
- h = f1.has_builder()
+ test.subdir('sub1')
+ test.subdir('sub2', ['sub2', 'SCCS'], ['sub2', 'RCS'])
+
+ sub1 = fs.Dir('sub1', '.')
+ f1 = fs.File('f1', sub1)
+ f2 = fs.File('f2', sub1)
+ f3 = fs.File('f3', sub1)
+ sub2 = fs.Dir('sub2', '.')
+ f4 = fs.File('f4', sub2)
+ f5 = fs.File('f5', sub2)
+ f6 = fs.File('f6', sub2)
+
+ h = f1.has_src_builder()
assert not h, h
b1 = Builder(fs.File)
- d.set_src_builder(b1)
+ sub1.set_src_builder(b1)
- test.write(['sub', 'f2'], "sub/f2\n")
- h = f1.has_builder() # cached from previous has_builder() call
+ test.write(['sub1', 'f2'], "sub1/f2\n")
+ h = f1.has_src_builder() # cached from previous call
assert not h, h
- h = f2.has_builder()
+ h = f2.has_src_builder()
assert not h, h
- h = f3.has_builder()
+ h = f3.has_src_builder()
assert h, h
assert f3.builder is b1, f3.builder
- test.write(['sub', 'f4'], "sub/f4\n")
- test.write(['sub', 'f6'], "sub/f6\n")
- h = f4.has_builder(fetch = 0)
+ test.write(['sub2', 'SCCS', 's.f5'], "sub2/SCCS/s.f5\n")
+ test.write(['sub2', 'RCS', 'f6,v'], "sub2/RCS/f6,v\n")
+ h = f4.has_src_builder()
assert not h, h
- h = f5.has_builder(fetch = 0)
- assert not h, h
- h = f6.has_builder(fetch = 1)
- assert not h, h
- h = f7.has_builder(fetch = 1)
+ h = f5.has_src_builder()
+ assert h, h
+ h = f6.has_src_builder()
assert h, h
class prepareTestCase(unittest.TestCase):
@@ -1267,13 +1266,13 @@ class get_actionsTestCase(unittest.TestCase):
a = dir.get_actions()
assert a == [], a
-class SConstructTestCase(unittest.TestCase):
+class SConstruct_dirTestCase(unittest.TestCase):
def runTest(self):
- """Test setting the SConstruct file"""
+ """Test setting the SConstruct directory"""
fs = SCons.Node.FS.FS()
- fs.set_SConstruct('xxx')
- assert fs.SConstruct.path == 'xxx'
+ fs.set_SConstruct_dir(fs.Dir('xxx'))
+ assert fs.SConstruct_dir.path == 'xxx'
class CacheDirTestCase(unittest.TestCase):
def runTest(self):
@@ -1437,10 +1436,10 @@ if __name__ == "__main__":
suite.addTest(RepositoryTestCase())
suite.addTest(find_fileTestCase())
suite.addTest(StringDirTestCase())
- suite.addTest(has_builderTestCase())
+ suite.addTest(has_src_builderTestCase())
suite.addTest(prepareTestCase())
suite.addTest(get_actionsTestCase())
- suite.addTest(SConstructTestCase())
+ suite.addTest(SConstruct_dirTestCase())
suite.addTest(CacheDirTestCase())
if not unittest.TextTestRunner().run(suite).wasSuccessful():
sys.exit(1)
diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py
index a9fa361..91b35d0 100644
--- a/src/engine/SCons/Node/NodeTests.py
+++ b/src/engine/SCons/Node/NodeTests.py
@@ -259,20 +259,23 @@ class NodeTestCase(unittest.TestCase):
"""Test the has_builder() method
"""
n1 = SCons.Node.Node()
+ assert n1.has_builder() == 0
+ n1.builder_set(Builder())
+ assert n1.has_builder() == 1
+
+ def test_is_derived(self):
+ """Test the is_derived() method
+ """
+ n1 = SCons.Node.Node()
n2 = SCons.Node.Node()
n3 = SCons.Node.Node()
- assert n1.has_builder() == 0
- assert n2.has_builder(fetch = 0) == 0
- assert n3.has_builder(fetch = 1) == 0
-
- n1.builder_set(Builder())
n2.builder_set(Builder())
- n3.builder_set(Builder())
+ n3.side_effect = 1
- assert n1.has_builder() == 1
- assert n2.has_builder(fetch = 0) == 1
- assert n3.has_builder(fetch = 1) == 1
+ assert n1.is_derived() == 0
+ assert n2.is_derived() == 1
+ assert n3.is_derived() == 1
def test_builder_sig_adapter(self):
"""Test the node's adapter for builder signatures
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 0a64586..326aee3 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -208,7 +208,7 @@ class Node:
def builder_set(self, builder):
self.builder = builder
- def has_builder(self, fetch = 1):
+ def has_builder(self):
"""Return whether this Node has a builder or not.
In Boolean tests, this turns out to be a *lot* more efficient
@@ -228,6 +228,9 @@ class Node:
b = self.builder
return not b is None
+ def is_derived(self):
+ return self.has_builder() or self.side_effect
+
def builder_sig_adapter(self):
"""Create an adapter for calculating a builder's signature.