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.py148
-rw-r--r--src/engine/SCons/Node/FSTests.py6
-rw-r--r--src/engine/SCons/Node/NodeTests.py6
-rw-r--r--src/engine/SCons/Node/__init__.py17
4 files changed, 103 insertions, 74 deletions
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index e64aacc..884736e 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -190,7 +190,7 @@ class ParentOfRoot:
This class is an instance of the Null object pattern.
"""
def __init__(self):
- self.abspath_str = ''
+ self.abspath = ''
self.path = ''
self.abspath_ = ''
self.path_ = ''
@@ -224,6 +224,61 @@ else:
def _my_normcase(x):
return string.upper(x)
+class EntryProxy(SCons.Util.Proxy):
+ def __init__(self, entry):
+ SCons.Util.Proxy.__init__(self, entry)
+ self.abspath = SCons.Util.SpecialAttrWrapper(entry.abspath,
+ entry.name + "_abspath")
+ filebase, suffix = os.path.splitext(entry.name)
+ self.filebase = SCons.Util.SpecialAttrWrapper(filebase,
+ entry.name + "_filebase")
+ self.suffix = SCons.Util.SpecialAttrWrapper(suffix,
+ entry.name + "_suffix")
+ self.file = SCons.Util.SpecialAttrWrapper(entry.name,
+ entry.name + "_file")
+
+ def __get_base_path(self):
+ """Return the file's directory and file name, with the
+ suffix stripped."""
+ return SCons.Util.SpecialAttrWrapper(os.path.splitext(self.get().get_path())[0],
+ self.get().name + "_base")
+
+ def __get_posix_path(self):
+ """Return the path with / as the path separator, regardless
+ of platform."""
+ if os.sep == '/':
+ return self
+ else:
+ return SCons.Util.SpecialAttrWrapper(string.replace(self.get().get_path(),
+ os.sep, '/'),
+ self.get().name + "_posix")
+
+ def __get_srcnode(self):
+ return EntryProxy(self.get().srcnode())
+
+ def __get_srcdir(self):
+ """Returns the directory containing the source node linked to this
+ node via BuildDir(), or the directory of this node if not linked."""
+ return EntryProxy(self.get().srcnode().dir)
+
+ def __get_dir(self):
+ return EntryProxy(self.get().dir)
+
+ dictSpecialAttrs = { "base" : __get_base_path,
+ "posix" : __get_posix_path,
+ "srcpath" : __get_srcnode,
+ "srcdir" : __get_srcdir,
+ "dir" : __get_dir }
+
+ def __getattr__(self, name):
+ # This is how we implement the "special" attributes
+ # such as base, posix, srcdir, etc.
+ try:
+ return self.dictSpecialAttrs[name](self)
+ except KeyError:
+ return SCons.Util.Proxy.__getattr__(self, name)
+
+
class Entry(SCons.Node.Node):
"""A generic class for file system entries. This class is for
when we don't know yet whether the entry being looked up is a file
@@ -251,14 +306,14 @@ class Entry(SCons.Node.Node):
assert directory, "A directory must be provided"
- self.abspath_str = directory.abspath_ + name
+ self.abspath = directory.abspath_ + name
if directory.path == '.':
self.path = name
else:
self.path = directory.path_ + name
self.path_ = self.path
- self.abspath_ = self.abspath_str
+ self.abspath_ = self.abspath
self.dir = directory
self.cwd = None # will hold the SConscript directory for target nodes
self.duplicate = directory.duplicate
@@ -293,11 +348,11 @@ class Entry(SCons.Node.Node):
Since this should return the real contents from the file
system, we check to see into what sort of subclass we should
morph this Entry."""
- if os.path.isfile(self.abspath_str):
+ if os.path.isfile(self.abspath):
self.__class__ = File
self._morph()
return File.get_contents(self)
- if os.path.isdir(self.abspath_str):
+ if os.path.isdir(self.abspath):
self.__class__ = Dir
self._morph()
return Dir.get_contents(self)
@@ -307,7 +362,7 @@ class Entry(SCons.Node.Node):
try:
return self._exists
except AttributeError:
- self._exists = _existsp(self.abspath_str)
+ self._exists = _existsp(self.abspath)
return self._exists
def rexists(self):
@@ -403,64 +458,9 @@ class Entry(SCons.Node.Node):
self.sbuilder = scb
return scb
- def get_base_path(self):
- """Return the file's directory and file name, with the
- suffix stripped."""
- return os.path.splitext(self.get_path())[0]
-
- def get_suffix(self):
- """Return the file's suffix."""
- return os.path.splitext(self.get_path())[1]
-
- def get_file_name(self):
- """Return the file's name without the path."""
- return self.name
-
- def get_file_base(self):
- """Return the file name with path and suffix stripped."""
- return os.path.splitext(self.name)[0]
-
- def get_posix_path(self):
- """Return the path with / as the path separator, regardless
- of platform."""
- if os.sep == '/':
- return str(self)
- else:
- return string.replace(self.get_path(), os.sep, '/')
-
def get_abspath(self):
"""Get the absolute path of the file."""
- return self.abspath_str
-
- def get_srcdir(self):
- """Returns the directory containing the source node linked to this
- node via BuildDir(), or the directory of this node if not linked."""
- return self.srcnode().dir
-
- dictSpecialAttrs = { "file" : get_file_name,
- "base" : get_base_path,
- "filebase" : get_file_base,
- "suffix" : get_suffix,
- "posix" : get_posix_path,
- "abspath" : get_abspath,
- "srcpath" : srcnode,
- "srcdir" : get_srcdir }
-
- def __getattr__(self, name):
- # This is how we implement the "special" attributes
- # such as base, suffix, basepath, etc.
- #
- # Note that we enclose values in a SCons.Util.Literal instance,
- # so they will retain special characters during Environment variable
- # substitution.
- try:
- attr = self.dictSpecialAttrs[name](self)
- except KeyError:
- raise AttributeError, '%s has no attribute: %s' % (self.__class__, name)
- if SCons.Util.is_String(attr):
- return SCons.Util.SpecialAttrWrapper(attr, self.name +
- "_%s" % name)
- return attr
+ return self.abspath
def for_signature(self):
# Return just our name. Even an absolute path would not work,
@@ -468,6 +468,14 @@ class Entry(SCons.Node.Node):
# paths.
return self.name
+ def get_subst_proxy(self):
+ try:
+ return self._proxy
+ except AttributeError:
+ ret = EntryProxy(self)
+ self._proxy = ret
+ return ret
+
# This is for later so we can differentiate between Entry the class and Entry
# the method of the FS class.
_classEntry = Entry
@@ -556,7 +564,7 @@ class FS:
raise SCons.Errors.UserError
dir = Dir(drive, ParentOfRoot(), self)
dir.path = dir.path + os.sep
- dir.abspath_str = dir.abspath_str + os.sep
+ dir.abspath = dir.abspath + os.sep
self.Root[drive] = dir
directory = dir
path_comp = path_comp[1:]
@@ -642,7 +650,7 @@ class FS:
if not dir is None:
self._cwd = dir
if change_os_dir:
- os.chdir(dir.abspath_str)
+ os.chdir(dir.abspath)
except:
self._cwd = curr
raise
@@ -850,7 +858,7 @@ class Dir(Entry):
node) don't use signatures for currency calculation."""
self.path_ = self.path + os.sep
- self.abspath_ = self.abspath_str + os.sep
+ self.abspath_ = self.abspath + os.sep
self.repositories = []
self.srcdir = None
@@ -951,9 +959,9 @@ class Dir(Entry):
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_str < two.abspath_str:
+ if one.abspath < two.abspath:
return -1
- if one.abspath_str > two.abspath_str:
+ if one.abspath > two.abspath:
return 1
return 0
kids.sort(c)
@@ -1085,11 +1093,11 @@ class File(Entry):
def get_contents(self):
if not self.rexists():
return ''
- return open(self.rfile().abspath_str, "rb").read()
+ return open(self.rfile().abspath, "rb").read()
def get_timestamp(self):
if self.rexists():
- return os.path.getmtime(self.rfile().abspath_str)
+ return os.path.getmtime(self.rfile().abspath)
else:
return 0
@@ -1328,7 +1336,7 @@ class File(Entry):
# Duplicate from source path if we are set up to do this.
if self.duplicate and not self.has_builder() and not self.linked:
src=self.srcnode().rfile()
- if src.exists() and src.abspath_str != self.abspath_str:
+ if src.exists() and src.abspath != self.abspath:
self._createDir()
try:
Unlink(self, None, None)
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 209e80d..1f58264 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -1524,7 +1524,7 @@ class SpecialAttrTestCase(unittest.TestCase):
test=TestCmd(workdir='')
fs = SCons.Node.FS.FS(test.workpath(''))
- f=fs.Entry('foo/bar/baz.blat')
+ f=fs.Entry('foo/bar/baz.blat').get_subst_proxy()
assert str(f.dir) == os.path.normpath('foo/bar'), str(f.dir)
assert f.dir.is_literal()
assert f.dir.for_signature() == 'bar', f.dir.for_signature()
@@ -1564,11 +1564,11 @@ class SpecialAttrTestCase(unittest.TestCase):
assert str(f.srcpath) == os.path.normpath('baz/bar/baz.blat'), str(f.srcpath)
assert f.srcpath.is_literal()
- assert isinstance(f.srcpath, SCons.Node.FS.Entry)
+ assert isinstance(f.srcpath.get(), SCons.Node.FS.Entry)
assert str(f.srcdir) == os.path.normpath('baz/bar'), str(f.srcdir)
assert f.srcdir.is_literal()
- assert isinstance(f.srcdir, SCons.Node.FS.Dir)
+ assert isinstance(f.srcdir.get(), SCons.Node.FS.Dir)
# And now, combinations!!!
assert str(f.srcpath.base) == os.path.normpath('baz/bar/baz'), str(f.srcpath.base)
diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py
index b188f81..2cf6d4b 100644
--- a/src/engine/SCons/Node/NodeTests.py
+++ b/src/engine/SCons/Node/NodeTests.py
@@ -949,6 +949,12 @@ class NodeTestCase(unittest.TestCase):
assert n.found_includes == {}, n.found_includes
assert n.implicit is None, n.implicit
+ def test_get_subst_proxy(self):
+ """Test the get_subst_proxy method."""
+ n = MyNode("test")
+
+ assert n.get_subst_proxy() == n, n.get_subst_proxy()
+
if __name__ == "__main__":
suite = unittest.makeSuite(NodeTestCase, 'test_')
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 883d757..5231f90 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -628,7 +628,7 @@ class Node:
generator is being called to generate a signature for the
command line, which determines if we should rebuild or not.
- Such command generators should use this method in preference
+ Such command generators shoud use this method in preference
to str(Node) when converting a Node to a string, passing
in the for_signature parameter, such that we will call
Node.for_signature() or str(Node) properly, depending on whether
@@ -638,6 +638,21 @@ class Node:
return self.for_signature()
return str(self)
+ def get_subst_proxy(self):
+ """
+ This method is expected to return an object that will function
+ exactly like this Node, except that it implements any additional
+ special features that we would like to be in effect for
+ Environment variable substitution. The principle use is that
+ some Nodes would like to implement a __getattr__() method,
+ but putting that in the Node type itself has a tendency to kill
+ performance. We instead put it in a proxy and return it from
+ this method. It is legal for this method to return self
+ if no new functionality is needed for Environment substitution.
+ """
+ return self
+
+
def get_children(node, parent): return node.children()
def ignore_cycle(node, stack): pass
def do_nothing(node, parent): pass