diff options
Diffstat (limited to 'src/engine/SCons/Node')
-rw-r--r-- | src/engine/SCons/Node/FS.py | 148 | ||||
-rw-r--r-- | src/engine/SCons/Node/FSTests.py | 6 | ||||
-rw-r--r-- | src/engine/SCons/Node/NodeTests.py | 6 | ||||
-rw-r--r-- | src/engine/SCons/Node/__init__.py | 17 |
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 |