Refactorings towards a RelativeTopDir() function.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 29 Jul 2004 21:25:15 +0000 (21:25 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 29 Jul 2004 21:25:15 +0000 (21:25 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@1011 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/engine/SCons/Node/FS.py
src/engine/SCons/Node/FSTests.py
src/engine/SCons/SConf.py

index 1cb77792b2398fea5d34bbd901f100be1c9a922c..31d894617aae4074af6a07a635a129a076c71c7d 100644 (file)
@@ -286,8 +286,6 @@ class ParentOfRoot:
     def __init__(self):
         self.abspath = ''
         self.path = ''
-        self.abspath_ = ''
-        self.path_ = ''
         self.name=''
         self.duplicate=0
         self.srcdir=None
@@ -305,12 +303,15 @@ class ParentOfRoot:
     def get_dir(self):
         return None
 
-    def recurse_get_path(self, dir, path_elems):
-        return path_elems
-
     def src_builder(self):
         return _null
 
+    def entry_abspath(self, name):
+        return name
+
+    def entry_path(self, name):
+        return name
+
 # Cygwin's os.path.normcase pretends it's on a case-sensitive filesystem.
 _is_cygwin = sys.platform == "cygwin"
 if os.path.normcase("TeSt") == os.path.normpath("TeSt") and not _is_cygwin:
@@ -439,18 +440,16 @@ class Base(SCons.Node.Node):
 
         self.name = name
         self.fs = fs
-        self.relpath = {}
+        self.relpath = {self : '.'}
 
         assert directory, "A directory must be provided"
 
-        self.abspath = directory.abspath_ + name
+        self.abspath = directory.entry_abspath(name)
         if directory.path == '.':
             self.path = name
         else:
-            self.path = directory.path_ + name
+            self.path = directory.entry_path(name)
 
-        self.path_ = self.path
-        self.abspath_ = self.abspath
         self.dir = directory
         self.cwd = None # will hold the SConscript directory for target nodes
         self.duplicate = directory.duplicate
@@ -473,7 +472,7 @@ class Base(SCons.Node.Node):
             delattr(self, '_str_val')
         except AttributeError:
             pass
-        self.relpath = {}
+        self.relpath = {self : '.'}
 
     def get_dir(self):
         return self.dir
@@ -543,14 +542,6 @@ class Base(SCons.Node.Node):
             self._srcnode = self
             return self._srcnode
 
-    def recurse_get_path(self, dir, path_elems):
-        """Recursively build a path relative to a supplied directory
-        node."""
-        if self != dir:
-            path_elems.append(self.name)
-            path_elems = self.dir.recurse_get_path(dir, path_elems)
-        return path_elems
-
     def get_path(self, dir=None):
         """Return path relative to the current working directory of the
         Node.FS.Base object that owns us."""
@@ -559,13 +550,13 @@ class Base(SCons.Node.Node):
         try:
             return self.relpath[dir]
         except KeyError:
-            if self == dir:
-                # Special case, return "." as the path
-                ret = '.'
-            else:
-                path_elems = self.recurse_get_path(dir, [])
-                path_elems.reverse()
-                ret = string.join(path_elems, os.sep)
+            path_elems = []
+            d = self
+            while d != dir and not isinstance(d, ParentOfRoot):
+                path_elems.append(d.name)
+                d = d.dir
+            path_elems.reverse()
+            ret = string.join(path_elems, os.sep)
             self.relpath[dir] = ret
             return ret
             
@@ -783,7 +774,6 @@ class FS(LocalFS):
         if not self.Top:
             self.Top = self.__doLookup(Dir, os.path.normpath(self.pathTop))
             self.Top.path = '.'
-            self.Top.path_ = '.' + os.sep
             self._cwd = self.Top
         
     def getcwd(self):
@@ -832,11 +822,8 @@ class FS(LocalFS):
             except KeyError:
                 if not create:
                     raise SCons.Errors.UserError
-                dir = Dir(drive, ParentOfRoot(), self)
-                dir.path = dir.path + os.sep
-                dir.abspath = dir.abspath + os.sep
-                self.Root[drive] = dir
-                directory = dir
+                directory = RootDir(drive, ParentOfRoot(), self)
+                self.Root[drive] = directory
             path_comp = path_comp[1:]
         else:
             path_comp = [ path_first, ] + path_comp[1:]
@@ -856,7 +843,7 @@ class FS(LocalFS):
 
                 # look at the actual filesystem and make sure there isn't
                 # a file already there
-                path = directory.path_ + path_name
+                path = directory.entry_path(path_name)
                 if self.isfile(path):
                     raise TypeError, \
                           "File %s found where directory expected." % path
@@ -874,7 +861,7 @@ class FS(LocalFS):
 
             # make sure we don't create File nodes when there is actually
             # a directory at that path on the disk, and vice versa
-            path = directory.path_ + path_comp[-1]
+            path = directory.entry_path(path_comp[-1])
             if fsclass == File:
                 if self.isdir(path):
                     raise TypeError, \
@@ -1142,8 +1129,6 @@ class Dir(Base):
         system tree.  Specify that directories (this Node) don't use
         signatures for calculating whether they're current."""
 
-        self.path_ = self.path + os.sep
-        self.abspath_ = self.abspath + os.sep
         self.repositories = []
         self.srcdir = None
 
@@ -1348,6 +1333,33 @@ class Dir(Base):
                 stamp = kid.get_timestamp()
         return stamp
 
+    def entry_abspath(self, name):
+        return self.abspath + os.sep + name
+
+    def entry_path(self, name):
+        return self.path + os.sep + name
+
+class RootDir(Dir):
+    """A class for the root directory of a file system.
+
+    This is the same as a Dir class, except that the path separator
+    ('/' or '\\') is actually part of the name, so we don't need to
+    add a separator when creating the path names of entries within
+    this directory.
+    """
+    def __init__(self, name, directory, fs):
+        if __debug__: logInstanceCreation(self, 'Node.FS.RootDir')
+        Base.__init__(self, name, directory, fs)
+        self.path = self.path + os.sep
+        self.abspath = self.abspath + os.sep
+        self._morph()
+
+    def entry_abspath(self, name):
+        return self.abspath + name
+
+    def entry_path(self, name):
+        return self.path + name
+
 class BuildInfo:
     bsig = None
     def __cmp__(self, other):
index 4a868b90e1b936a4b217f4ad82dffec5aeea2213..c5d064d44134480546df07e8e827553075abf72d 100644 (file)
@@ -651,21 +651,12 @@ class FSTestCase(unittest.TestCase):
                 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.get_abspath() == abspath, \
                        "dir.abspath %s != expected absolute path %s" % \
                        (dir.get_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/bar',     'foo/bar/',    sub_dir_foo_bar,   'foo/')
@@ -733,19 +724,13 @@ class FSTestCase(unittest.TestCase):
                             os.path.join('ddd', 'f1'),
                             os.path.join('ddd', 'f2'),
                             os.path.join('ddd', 'f3')], kids
-            kids = map(lambda x: x.path_, dir.children(None))
-            kids.sort()
-            assert kids == [os.path.join('ddd', 'd1', ''),
-                            os.path.join('ddd', 'f1'),
-                            os.path.join('ddd', 'f2'),
-                            os.path.join('ddd', 'f3')], kids
 
         # Test for a bug in 0.04 that did not like looking up
         # dirs with a trailing slash on Win32.
         d=fs.Dir('./')
-        assert d.path_ == '.' + os.sep, d.abspath_
+        assert d.path == '.', d.abspath
         d=fs.Dir('foo/')
-        assert d.path_ == 'foo' + os.sep, d.path_
+        assert d.path == 'foo', d.abspath
 
         # Test for sub-classing of node building.
         global built_it
@@ -773,56 +758,47 @@ class FSTestCase(unittest.TestCase):
         e1 = fs.Entry("d1")
         assert e1.__class__.__name__ == 'Dir'
         match(e1.path, "d1")
-        match(e1.path_, "d1/")
         match(e1.dir.path, ".")
 
         e2 = fs.Entry("d1/f1")
         assert e2.__class__.__name__ == 'File'
         match(e2.path, "d1/f1")
-        match(e2.path_, "d1/f1")
         match(e2.dir.path, "d1")
 
         e3 = fs.Entry("e3")
         assert e3.__class__.__name__ == 'Entry'
         match(e3.path, "e3")
-        match(e3.path_, "e3")
         match(e3.dir.path, ".")
 
         e4 = fs.Entry("d1/e4")
         assert e4.__class__.__name__ == 'Entry'
         match(e4.path, "d1/e4")
-        match(e4.path_, "d1/e4")
         match(e4.dir.path, "d1")
 
         e5 = fs.Entry("e3/e5")
         assert e3.__class__.__name__ == 'Dir'
         match(e3.path, "e3")
-        match(e3.path_, "e3/")
         match(e3.dir.path, ".")
         assert e5.__class__.__name__ == 'Entry'
         match(e5.path, "e3/e5")
-        match(e5.path_, "e3/e5")
         match(e5.dir.path, "e3")
 
         e6 = fs.Dir("d1/e4")
         assert e6 is e4
         assert e4.__class__.__name__ == 'Dir'
         match(e4.path, "d1/e4")
-        match(e4.path_, "d1/e4/")
         match(e4.dir.path, "d1")
 
         e7 = fs.File("e3/e5")
         assert e7 is e5
         assert e5.__class__.__name__ == 'File'
         match(e5.path, "e3/e5")
-        match(e5.path_, "e3/e5")
         match(e5.dir.path, "e3")
 
         fs.chdir(fs.Dir('subdir'))
         f11 = fs.File("f11")
         match(f11.path, "subdir/f11")
         d12 = fs.Dir("d12")
-        match(d12.path_, "subdir/d12/")
         e13 = fs.Entry("subdir/e13")
         match(e13.path, "subdir/subdir/e13")
         fs.chdir(fs.Dir('..'))
@@ -834,13 +810,13 @@ class FSTestCase(unittest.TestCase):
         f1.target_scanner = Scanner(xyz)
 
         f1.scan()
-        assert f1.implicit[0].path_ == "xyz"
+        assert f1.implicit[0].path == "xyz"
         f1.implicit = []
         f1.scan()
         assert f1.implicit == []
         f1.implicit = None
         f1.scan()
-        assert f1.implicit[0].path_ == "xyz"
+        assert f1.implicit[0].path == "xyz"
 
         # Test underlying scanning functionality in get_found_includes()
         env = Environment()
index 0cda8c1e86644f5234e7dabe0a453965ea44f436..8087136744f7fc0378f9aca458ed5d1368b346f2 100644 (file)
@@ -61,13 +61,13 @@ SCons.Warnings.enableWarningClass( SConfWarning )
 
 # action to create the source
 def _createSource( target, source, env ):
-    fd = open(target[0].get_path(), "w")
+    fd = open(str(target[0]), "w")
     fd.write(env['SCONF_TEXT'])
     fd.close()
 
 def _stringSource( target, source, env ):
     import string
-    return (target[0].get_path() + ' <- \n  |' +
+    return (str(target[0]) + ' <- \n  |' +
             string.replace( env['SCONF_TEXT'], "\n", "\n  |" ) )
 
 BooleanTypes = [types.IntType]
@@ -332,8 +332,9 @@ class SConf:
         ok = self.TryLink(text, extension)
         if( ok ):
             prog = self.lastTarget
-            output = SConfFS.File(prog.get_path()+'.out')
-            node = self.env.Command(output, prog, [ [ prog.get_path(), ">", "${TARGET}"] ])
+            pname = str(prog)
+            output = SConfFS.File(pname+'.out')
+            node = self.env.Command(output, prog, [ [ pname, ">", "${TARGET}"] ])
             ok = self.BuildNodes([node])
             if ok:
                 outputStr = output.get_contents()
@@ -377,21 +378,22 @@ class SConf:
             if node.get_state() != SCons.Node.up_to_date:
                 # if any of the sources has changed, we cannot use our cache
                 needs_rebuild = 1
-        if not self.cache.has_key( target[0].get_path() ):
+        tname = str(target[0])
+        if not self.cache.has_key( tname ):
             # We have no recorded error, so we try to build the target
             needs_rebuild = 1
         else:
-            lastBuildSig = self.cache[target[0].get_path()]['builder']
+            lastBuildSig = self.cache[tname]['builder']
             if lastBuildSig != buildSig:
                 needs_rebuild = 1
         if not needs_rebuild:
             # When we are here, we can savely pass the recorded error
             print ('(cached): Building "%s" failed in a previous run.' %
-                   target[0].get_path())
+                   target[0])
             return 1
         else:
             # Otherwise, we try to record an error
-            self.cache[target[0].get_path()] = {
+            self.cache[tname] = {
                'builder' :  buildSig
             }
 
@@ -399,7 +401,7 @@ class SConf:
         # Action after target is successfully built
         #
         # No error during build -> remove the recorded error
-        del self.cache[target[0].get_path()]
+        del self.cache[str(target[0])]
 
     def _stringCache(self, target, source, env):
         return None
@@ -407,7 +409,7 @@ class SConf:
     def _loadCache(self):
         # try to load build-error cache
         try:
-            cacheDesc = cPickle.load(open(self.confdir.File(".cache").get_path()))
+            cacheDesc = cPickle.load(open(str(self.confdir.File(".cache"))))
             if cacheDesc['scons_version'] != SCons.__version__:
                 raise Exception, "version mismatch"
             self.cache = cacheDesc['data']
@@ -423,14 +425,14 @@ class SConf:
         try:
             cacheDesc = {'scons_version' : SCons.__version__,
                          'data'          : self.cache }
-            cPickle.dump(cacheDesc, open(self.confdir.File(".cache").get_path(),"w"))
+            cPickle.dump(cacheDesc, open(str(self.confdir.File(".cache")),"w"))
         except Exception, e:
             # this is most likely not only an IO error, but an error
             # inside SConf ...
             SCons.Warnings.warn( SConfWarning, "Couldn't dump SConf cache" )
 
     def _createDir( self, node ):
-        dirName = node.get_path()
+        dirName = str(node)
         if dryrun:
             if not os.path.isdir( dirName ):
                 raise SCons.Errors.ConfigureDryRunError(dirName)
@@ -459,7 +461,7 @@ class SConf:
                 log_mode = "w"
             else:
                 log_mode = "a"
-            self.logstream = open(self.logfile.get_path(), log_mode)
+            self.logstream = open(str(self.logfile), log_mode)
             # logfile may stay in a build directory, so we tell
             # the build system not to override it with a eventually
             # existing file with the same name in the source directory
@@ -468,7 +470,7 @@ class SConf:
             tb = traceback.extract_stack()[-3]
             
             self.logstream.write( '\nfile %s,line %d:\n\tConfigure( confdir = %s )\n\n' %
-                                  (tb[0], tb[1], self.confdir.get_path()) )
+                                  (tb[0], tb[1], str(self.confdir)) )
         else: 
             self.logstream = None
         # we use a special builder to create source files from TEXT