Eliminate multiple calls to os.stat() to fetch file info.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Fri, 13 May 2005 01:44:10 +0000 (01:44 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Fri, 13 May 2005 01:44:10 +0000 (01:44 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@1294 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/engine/SCons/Node/FS.py
src/engine/SCons/Node/FSTests.py
src/engine/SCons/Script/Main.py
src/engine/SCons/Script/SConscript.py
src/engine/SCons/Tool/zip.py

index 9d7086ce661c9fff508833409e2334ec8b3ca2a7..f2234f76cccc88dba9015e152b228c84a37f87da 100644 (file)
@@ -175,9 +175,8 @@ Unlink = SCons.Action.Action(UnlinkFunc, None)
 
 def MkdirFunc(target, source, env):
     t = target[0]
-    p = t.abspath
-    if not t.fs.exists(p):
-        t.fs.mkdir(p)
+    if not t.exists():
+        t.fs.mkdir(t.abspath)
     return 0
 
 Mkdir = SCons.Action.Action(MkdirFunc, None, presub=None)
@@ -469,14 +468,39 @@ class Base(SCons.Node.Node):
 
     rstr = __str__
 
+    def stat(self):
+        "__cacheable__"
+        try: return self.fs.stat(self.abspath)
+        except os.error: return None
+
     def exists(self):
         "__cacheable__"
-        return self.fs.exists(self.abspath)
+        return not self.stat() is None
 
     def rexists(self):
         "__cacheable__"
         return self.rfile().exists()
 
+    def getmtime(self):
+        return self.stat()[stat.ST_MTIME]
+
+    def isdir(self):
+        st = self.stat()
+        return not st is None and stat.S_ISDIR(st[stat.ST_MODE])
+
+    def isfile(self):
+        st = self.stat()
+        return not st is None and stat.S_ISREG(st[stat.ST_MODE])
+
+    if hasattr(os, 'symlink'):
+        def islink(self):
+            try: st = self.fs.lstat(self.abspath)
+            except os.error: return 0
+            return stat.S_ISLNK(st[stat.ST_MODE])
+    else:
+        def islink(self):
+            return 0                    # no symlinks
+
     def is_under(self, dir):
         if self is dir:
             return 1
@@ -563,7 +587,7 @@ class Entry(Base):
     class."""
 
     def disambiguate(self):
-        if self.fs.isdir(self.abspath):
+        if self.isdir():
             self.__class__ = Dir
             self._morph()
         else:
@@ -594,15 +618,15 @@ class Entry(Base):
         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 self.fs.isfile(self.abspath):
+        if self.isfile():
             self.__class__ = File
             self._morph()
             return self.get_contents()
-        if self.fs.isdir(self.abspath):
+        if self.isdir():
             self.__class__ = Dir
             self._morph()
             return self.get_contents()
-        if self.fs.islink(self.abspath):
+        if self.islink():
             return ''             # avoid errors for dangling symlinks
         raise AttributeError
 
@@ -667,6 +691,8 @@ class LocalFS:
         return os.path.isfile(path)
     def link(self, src, dst):
         return os.link(src, dst)
+    def lstat(self, path):
+        return os.lstat(path)
     def listdir(self, path):
         return os.listdir(path)
     def makedirs(self, path):
@@ -687,12 +713,9 @@ class LocalFS:
     if hasattr(os, 'symlink'):
         def islink(self, path):
             return os.path.islink(path)
-        def exists_or_islink(self, path):
-            return os.path.exists(path) or os.path.islink(path)
     else:
         def islink(self, path):
             return 0                    # no symlinks
-        exists_or_islink = exists
 
 if not SCons.Memoize.has_metaclass:
     _FSBase = LocalFS
@@ -1491,7 +1514,7 @@ class File(Base):
 
     def get_timestamp(self):
         if self.rexists():
-            return self.fs.getmtime(self.rfile().abspath)
+            return self.rfile().getmtime()
         else:
             return 0
 
@@ -1593,13 +1616,13 @@ class File(Base):
         # Push this file out to cache before the superclass Node.built()
         # method has a chance to clear the build signature, which it
         # will do if this file has a source scanner.
-        if self.fs.CachePath and self.fs.exists(self.path):
+        if self.fs.CachePath and self.exists():
             CachePush(self, [], None)
         self.fs.clear_cache()
         SCons.Node.Node.built(self)
 
     def visited(self):
-        if self.fs.CachePath and self.fs.cache_force and self.fs.exists(self.path):
+        if self.fs.CachePath and self.fs.cache_force and self.exists():
             CachePush(self, None, None)
 
     def has_src_builder(self):
@@ -1664,7 +1687,7 @@ class File(Base):
 
     def remove(self):
         """Remove this file."""
-        if self.fs.exists_or_islink(self.path):
+        if self.exists() or self.islink():
             self.fs.unlink(self.path)
             return 1
         return None
index 935f0a21bbe67aaeb8da20f8837616c85174a124..862618565d0d85b5ef3c6fcc791c5372b96aad22 100644 (file)
@@ -605,6 +605,83 @@ class BuildDirTestCase(unittest.TestCase):
 
         self.failIf(errors)
 
+class BaseTestCase(_tempdirTestCase):
+    def test_stat(self):
+        """Test the Base.stat() method"""
+        test = self.test
+        test.write("e1", "e1\n")
+        fs = SCons.Node.FS.FS()
+
+        e1 = fs.Entry('e1')
+        s = e1.stat()
+        assert not s is None, s
+
+        e2 = fs.Entry('e2')
+        s = e2.stat()
+        assert s is None, s
+
+    def test_getmtime(self):
+        """Test the Base.getmtime() method"""
+        test = self.test
+        test.write("file", "file\n")
+        fs = SCons.Node.FS.FS()
+
+        file = fs.Entry('file')
+        assert file.getmtime()
+
+    def test_isdir(self):
+        """Test the Base.isdir() method"""
+        test = self.test
+        test.subdir('dir')
+        test.write("file", "file\n")
+        fs = SCons.Node.FS.FS()
+
+        dir = fs.Entry('dir')
+        assert dir.isdir()
+
+        file = fs.Entry('file')
+        assert not file.isdir()
+
+        nonexistent = fs.Entry('nonexistent')
+        assert not nonexistent.isdir()
+
+    def test_isfile(self):
+        """Test the Base.isfile() method"""
+        test = self.test
+        test.subdir('dir')
+        test.write("file", "file\n")
+        fs = SCons.Node.FS.FS()
+
+        dir = fs.Entry('dir')
+        assert not dir.isfile()
+
+        file = fs.Entry('file')
+        assert file.isfile()
+
+        nonexistent = fs.Entry('nonexistent')
+        assert not nonexistent.isfile()
+
+    if hasattr(os, 'symlink'):
+        def test_islink(self):
+            """Test the Base.islink() method"""
+            test = self.test
+            test.subdir('dir')
+            test.write("file", "file\n")
+            test.symlink("symlink", "symlink")
+            fs = SCons.Node.FS.FS()
+
+            dir = fs.Entry('dir')
+            assert not dir.islink()
+
+            file = fs.Entry('file')
+            assert not file.islink()
+
+            symlink = fs.Entry('symlink')
+            assert symlink.islink()
+
+            nonexistent = fs.Entry('nonexistent')
+            assert not nonexistent.islink()
+
 class FSTestCase(_tempdirTestCase):
     def test_runTest(self):
         """Test FS (file system) Node operations
@@ -2625,6 +2702,7 @@ if __name__ == "__main__":
     suite.addTest(SpecialAttrTestCase())
     suite.addTest(SaveStringsTestCase())
     tclasses = [
+        BaseTestCase,
         FSTestCase,
         DirTestCase,
         RepositoryTestCase,
index fd2a9143c4fdf0caa84e8acba46a45c869c9444e..7dcb9877973ae604c622e1887b174fea91b5e2e0 100644 (file)
@@ -191,16 +191,17 @@ class BuildTask(SCons.Taskmaster.Task):
 class CleanTask(SCons.Taskmaster.Task):
     """An SCons clean task."""
     def show(self):
-        if (self.targets[0].has_builder() or self.targets[0].side_effect) \
-           and not os.path.isdir(str(self.targets[0])):
-            display("Removed " + str(self.targets[0]))
-        if SCons.Environment.CleanTargets.has_key(self.targets[0]):
-            files = SCons.Environment.CleanTargets[self.targets[0]]
+        target = self.targets[0]
+        if (target.has_builder() or target.side_effect) and not target.isdir():
+            display("Removed " + str(target))
+        if SCons.Environment.CleanTargets.has_key(target):
+            files = SCons.Environment.CleanTargets[target]
             for f in files:
                 SCons.Util.fs_delete(str(f), 0)
 
     def remove(self):
-        if self.targets[0].has_builder() or self.targets[0].side_effect:
+        target = self.targets[0]
+        if target.has_builder() or target.side_effect:
             for t in self.targets:
                 try:
                     removed = t.remove()
@@ -209,8 +210,8 @@ class CleanTask(SCons.Taskmaster.Task):
                 else:
                     if removed:
                         display("Removed " + str(t))
-        if SCons.Environment.CleanTargets.has_key(self.targets[0]):
-            files = SCons.Environment.CleanTargets[self.targets[0]]
+        if SCons.Environment.CleanTargets.has_key(target):
+            files = SCons.Environment.CleanTargets[target]
             for f in files:
                 SCons.Util.fs_delete(str(f))
 
index 7ca99939a41b063a5748032876f4394489a7bc48..af9d492ee937fb4862004d3f6c84ec24cfaa3b07 100644 (file)
@@ -184,9 +184,8 @@ def _SConscript(fs, *files, **kw):
                     # during the actual build phase.
                     f.build()
                     f.builder_set(None)
-                    s = str(f)
-                    if os.path.exists(s):
-                        _file_ = open(s, "r")
+                    if f.exists():
+                        _file_ = open(str(f), "r")
                 if _file_:
                     # Chdir to the SConscript directory.  Use a path
                     # name relative to the SConstruct file so that if
index fe9ce32bf32fbc5f1c0e3710d309b936961b9e74..f0d4ed0bd70703ff76ec5613a49af460c8a29bf7 100644 (file)
@@ -56,7 +56,7 @@ if internal_zip:
         compression = env.get('ZIPCOMPRESSION', 0)
         zf = zipfile.ZipFile(str(target[0]), 'w', compression)
         for s in source:
-            if os.path.isdir(str(s)):
+            if s.isdir():
                 os.path.walk(str(s), visit, zf)
             else:
                 zf.write(str(s))