summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons/Node
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2001-10-25 13:11:10 (GMT)
committerSteven Knight <knight@baldmt.com>2001-10-25 13:11:10 (GMT)
commit123be6df3fe113bad181c0c93aab4ee58b26e91f (patch)
treeac0b0ab9c7630768dc6411a2e8887ae3efc6dd3f /src/engine/SCons/Node
parent6a98a941a75eab2e4c22fa3e19cb973046f613b6 (diff)
downloadSCons-123be6df3fe113bad181c0c93aab4ee58b26e91f.zip
SCons-123be6df3fe113bad181c0c93aab4ee58b26e91f.tar.gz
SCons-123be6df3fe113bad181c0c93aab4ee58b26e91f.tar.bz2
Support building (sub)directories.
Diffstat (limited to 'src/engine/SCons/Node')
-rw-r--r--src/engine/SCons/Node/FS.py79
-rw-r--r--src/engine/SCons/Node/FSTests.py88
-rw-r--r--src/engine/SCons/Node/NodeTests.py6
-rw-r--r--src/engine/SCons/Node/__init__.py16
4 files changed, 157 insertions, 32 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index e44da22..cfb4142 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -35,7 +35,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os
import os.path
-from SCons.Node import Node
+import SCons.Node
from UserDict import UserDict
import sys
@@ -119,6 +119,7 @@ class FS:
self.Root = PathDict()
self.Top = self.__doLookup(Dir, path)
self.Top.path = '.'
+ self.Top.path_ = './'
def __doLookup(self, fsclass, name, directory=None):
"""This method differs from the File and Dir factory methods in
@@ -228,7 +229,7 @@ class FS:
-class Entry(Node):
+class Entry(SCons.Node.Node):
"""A generic class for file system entries. This class if for
when we don't know yet whether the entry being looked up is a file
or a directory. Instances of this class can morph into either
@@ -241,8 +242,9 @@ class Entry(Node):
our relative and absolute paths, identify our parent
directory, and indicate that this node should use
signatures."""
- Node.__init__(self)
+ SCons.Node.Node.__init__(self)
+ self.name = name
if directory:
self.abspath = os.path.join(directory.abspath, name)
if str(directory.path) == '.':
@@ -251,13 +253,18 @@ class Entry(Node):
self.path = os.path.join(directory.path, name)
else:
self.abspath = self.path = name
- self.parent = directory
+ self.path_ = self.path
+ self.abspath_ = self.abspath
+ self.dir = directory
self.use_signature = 1
def __str__(self):
"""A FS node's string representation is its path name."""
return self.path
+ def set_signature(self, sig):
+ SCons.Node.Node.set_signature(self, sig)
+
def exists(self):
return os.path.exists(self.path)
@@ -299,17 +306,18 @@ class Dir(Entry):
into the file system tree. Specify that directories (this
node) don't use signatures for currency calculation."""
- self.path = os.path.join(self.path, '')
- self.abspath = os.path.join(self.abspath, '')
+ self.path_ = os.path.join(self.path, '')
+ self.abspath_ = os.path.join(self.abspath, '')
self.entries = PathDict()
self.entries['.'] = self
- if hasattr(self, 'parent'):
- self.entries['..'] = self.parent
- delattr(self, 'parent')
+ if hasattr(self, 'dir'):
+ self.entries['..'] = self.dir
else:
self.entries['..'] = None
self.use_signature = None
+ self.builder = 1
+ self._sconsign = None
def up(self):
return self.entries['..']
@@ -321,15 +329,42 @@ class Dir(Entry):
return self.entries['..'].root()
def children(self):
- return map(lambda x, s=self: s.entries[x],
+ #XXX --random: randomize "dependencies?"
+ kids = map(lambda x, s=self: s.entries[x],
filter(lambda k: k != '.' and k != '..',
self.entries.keys()))
+ kids.sort()
+ return kids
+
+ def build(self):
+ """A null "builder" for directories."""
+ pass
+
+ def set_signature(self, sig):
+ """A directory has no signature."""
+ pass
def current(self):
- """Always return that a directory node is out-of-date so
- that it will always be "built" by trying to build all of
- its directory entries."""
- return 0
+ """If all of our children were up-to-date, then this
+ directory was up-to-date, too."""
+ state = 0
+ for kid in self.children():
+ s = kid.get_state()
+ if s and (not state or s > state):
+ state = s
+ import SCons.Node
+ if state == SCons.Node.up_to_date:
+ return 1
+ else:
+ return 0
+
+ def sconsign(self):
+ if not self._sconsign:
+ #XXX Rework this to get rid of the hard-coding
+ import SCons.Sig
+ import SCons.Sig.MD5
+ self._sconsign = SCons.Sig.SConsignFile(self.path, SCons.Sig.MD5)
+ return self._sconsign
# XXX TODO?
@@ -362,13 +397,25 @@ class File(Entry):
pass
def root(self):
- return self.parent.root()
+ return self.dir.root()
def get_contents(self):
return open(self.path, "r").read()
def get_timestamp(self):
- return os.path.getmtime(self.path)
+ if self.exists():
+ return os.path.getmtime(self.path)
+ else:
+ return 0
+
+ def set_signature(self, sig):
+ Entry.set_signature(self, sig)
+ #XXX Rework this to get rid of the hard-coding
+ import SCons.Sig.MD5
+ self.dir.sconsign().set(self.name, self.get_timestamp(), sig, SCons.Sig.MD5)
+
+ def get_oldentry(self):
+ return self.dir.sconsign().get(self.name)
default_fs = FS()
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 044f83f..8b1ee5a 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -84,36 +84,60 @@ class FSTestCase(unittest.TestCase):
for sep in seps:
- def Dir_test(lpath, path, abspath, up_path, fileSys=fs, s=sep):
+ def Dir_test(lpath, path_, abspath_, up_path_, fileSys=fs, s=sep):
dir = fileSys.Dir(string.replace(lpath, '/', s))
+ def strip_slash(p):
+ if p[-1] == '/' and len(p) > 1:
+ p = p[:-1]
+ return p
+ path = strip_slash(path_)
+ abspath = strip_slash(abspath_)
+ up_path = strip_slash(up_path_)
+ name = string.split(abspath, '/')[-1]
+
if os.sep != '/':
path = string.replace(path, '/', os.sep)
+ path_ = string.replace(path_, '/', os.sep)
abspath = string.replace(abspath, '/', os.sep)
+ abspath_ = string.replace(abspath_, '/', os.sep)
up_path = string.replace(up_path, '/', os.sep)
+ up_path_ = string.replace(up_path_, '/', os.sep)
+ assert dir.name == name, \
+ "dir.name %s != expected name %s" % \
+ (dir.name, name)
assert dir.path == path, \
"dir.path %s != expected path %s" % \
(dir.path, path)
assert str(dir) == path, \
"str(dir) %s != expected path %s" % \
(str(dir), path)
+ assert dir.path_ == path_, \
+ "dir.path_ %s != expected path_ %s" % \
+ (dir.path_, path_)
assert dir.abspath == abspath, \
"dir.abspath %s != expected absolute path %s" % \
(dir.abspath, abspath)
+ assert dir.abspath_ == abspath_, \
+ "dir.abspath_ %s != expected absolute path_ %s" % \
+ (dir.abspath_, abspath_)
assert dir.up().path == up_path, \
"dir.up().path %s != expected parent path %s" % \
(dir.up().path, up_path)
+ assert dir.up().path_ == up_path_, \
+ "dir.up().path_ %s != expected parent path_ %s" % \
+ (dir.up().path_, up_path_)
- Dir_test('foo', 'foo/', sub_dir_foo, '.')
+ Dir_test('foo', 'foo/', sub_dir_foo, './')
Dir_test('foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
Dir_test('/foo', '/foo/', '/foo/', '/')
Dir_test('/foo/bar', '/foo/bar/', '/foo/bar/', '/foo/')
Dir_test('..', sub, sub, wp)
- Dir_test('foo/..', '.', sub_dir, sub)
+ Dir_test('foo/..', './', sub_dir, sub)
Dir_test('../foo', sub_foo, sub_foo, sub)
- Dir_test('.', '.', sub_dir, sub)
- Dir_test('./.', '.', sub_dir, sub)
+ Dir_test('.', './', sub_dir, sub)
+ Dir_test('./.', './', sub_dir, sub)
Dir_test('foo/./bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
try:
@@ -136,7 +160,7 @@ class FSTestCase(unittest.TestCase):
f2 = fs.File('d1')
except TypeError, x:
assert str(x) == ("Tried to lookup Dir '%s' as a File." %
- os.path.join('d1', '')), x
+ 'd1'), x
except:
raise
@@ -150,10 +174,16 @@ class FSTestCase(unittest.TestCase):
fs.Dir(string.join(['ddd', 'd1', 'f5'], sep))
kids = map(lambda x: x.path, dir.children())
kids.sort()
- assert kids == [os.path.join('ddd', 'd1', ''),
+ 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.sort()
+ assert kids == [os.path.join('ddd', 'd1', ''),
+ os.path.join('ddd', 'f1'),
+ os.path.join('ddd', 'f2'),
+ os.path.join('ddd', 'f3')]
# Test for sub-classing of node building.
global built_it
@@ -164,7 +194,7 @@ class FSTestCase(unittest.TestCase):
d1.builder_set(Builder())
d1.env_set(Environment())
d1.build()
- assert built_it
+ assert not built_it
assert d1.get_parents() == []
@@ -178,35 +208,71 @@ class FSTestCase(unittest.TestCase):
e1 = fs.Entry("d1")
assert e1.__class__.__name__ == 'Dir'
- assert e1.path == "d1/", e1.path
+ assert e1.path == "d1", e1.path
+ assert e1.path_ == "d1/", e1.path_
+ assert e1.dir.path == ".", e1.dir.path
e2 = fs.Entry("d1/f1")
assert e2.__class__.__name__ == 'File'
assert e2.path == "d1/f1", e2.path
+ assert e2.path_ == "d1/f1", e2.path_
+ assert e2.dir.path == "d1", e2.dir.path
e3 = fs.Entry("e3")
assert e3.__class__.__name__ == 'Entry'
assert e3.path == "e3", e3.path
+ assert e3.path_ == "e3", e3.path_
+ assert e3.dir.path == ".", e3.dir.path
e4 = fs.Entry("d1/e4")
assert e4.__class__.__name__ == 'Entry'
assert e4.path == "d1/e4", e4.path
+ assert e4.path_ == "d1/e4", e4.path_
+ assert e4.dir.path == "d1", e4.dir.path
e5 = fs.Entry("e3/e5")
assert e3.__class__.__name__ == 'Dir'
- assert e3.path == "e3/", e3.path
+ assert e3.path == "e3", e3.path
+ assert e3.path_ == "e3/", e3.path_
+ assert e3.dir.path == ".", e3.dir.path
assert e5.__class__.__name__ == 'Entry'
assert e5.path == "e3/e5", e5.path
+ assert e5.path_ == "e3/e5", e5.path_
+ assert e5.dir.path == "e3", e5.dir.path
e6 = fs.Dir("d1/e4")
assert e6 is e4
assert e4.__class__.__name__ == 'Dir'
- assert e4.path == "d1/e4/", e4.path
+ assert e4.path == "d1/e4", e4.path
+ assert e4.path_ == "d1/e4/", e4.path_
+ assert e4.dir.path == "d1", e4.dir.path
e7 = fs.File("e3/e5")
assert e7 is e5
assert e5.__class__.__name__ == 'File'
assert e5.path == "e3/e5", e5.path
+ assert e5.path_ == "e3/e5", e5.path_
+ assert e5.dir.path == "e3", e5.dir.path
+
+ #XXX test set_signature()
+
+ #XXX test exists()
+
+ #XXX test current() for directories
+
+ #XXX test sconsign() for directories
+
+ #XXX test set_signature() for directories
+
+ #XXX test build() for directories
+
+ #XXX test root()
+
+ #XXX test get_contents()
+
+ #XXX test get_timestamp()
+
+ #XXX test get_oldentry()
diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py
index b8015c2..cf7e59b 100644
--- a/src/engine/SCons/Node/NodeTests.py
+++ b/src/engine/SCons/Node/NodeTests.py
@@ -90,6 +90,8 @@ class NodeTestCase(unittest.TestCase):
assert node.builder == b
def test_current(self):
+ """Test the default current() method
+ """
node = SCons.Node.Node()
assert node.current() is None
@@ -226,6 +228,10 @@ class NodeTestCase(unittest.TestCase):
assert node.get_state() == None
node.set_state(SCons.Node.executing)
assert node.get_state() == SCons.Node.executing
+ assert SCons.Node.pending < SCons.Node.executing
+ assert SCons.Node.executing < SCons.Node.up_to_date
+ assert SCons.Node.up_to_date < SCons.Node.executed
+ assert SCons.Node.executed < SCons.Node.failed
def test_walker(self):
"""Test walking a Node tree.
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index b7bdecf..2995576 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -36,12 +36,18 @@ import string
import types
import copy
-# Node states:
-executing = 1
-executed = 2
+# Node states
+#
+# These are in "priority" order, so that the maximum value for any
+# child/dependency of a node represents the state of that node if
+# it has no builder of its own. The canonical example is a file
+# system directory, which is only up to date if all of its children
+# were up to date.
+pending = 1
+executing = 2
up_to_date = 3
-failed = 4
-pending = 5
+executed = 4
+failed = 5
class Node:
"""The base Node class, for entities that we know how to