[PATCH 2 of 3] Add a new function, fspath

Paul Moore p.f.moore at gmail.com
Tue Jun 3 11:55:33 CDT 2008


# HG changeset patch
# User "Paul Moore <p.f.moore at gmail.com>"
# Date 1211406485 -3600
# Node ID 025ba311a38a094fac501ccf81c5aaa62e895466
# Parent  84939eb9dcca1152dc98cb2d58259c922b57177f
Add a new function, fspath

The function, given a relative filename and a root, returns the filename
modified to use the case actually stored in the filesystem (or None if the
file does not exist). The returned name is normalised to be relative to the
root, and to use os.sep as the path separator.

A win32-specific implementation (using win32api.FindFiles) is possible, but it
has not been implemented as testing seems to demonstrate that the
win32-specific code is not significantly faster (thanks to the caching of
results in the generic code).

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -858,6 +858,45 @@
         return True
     except:
         return True
+
+_fspathcache = {}
+def fspath(name, root):
+    '''Get name in the case stored in the filesystem
+
+    The name is either relative to root, or it is an absolute path starting
+    with root. Note that this function is unnecessary, and should not be
+    called, for case-sensitive filesystems (simply because it's expensive).
+    '''
+    name = os.path.normcase(os.path.normpath(name))
+    root = os.path.normcase(os.path.normpath(root))
+
+    # If name is absolute, make it relative
+    if name.startswith(root):
+        l = len(root)
+        if name[l] == os.sep:
+            l = l + 1
+        name = name[l:]
+
+    if not os.path.exists(os.path.join(root, name)):
+        return None
+
+    dir = root
+    result = []
+    for part in splitpath(name):
+        if dir not in _fspathcache:
+            _fspathcache[dir] = os.listdir(dir)
+        contents = _fspathcache[dir]
+
+        for n in contents:
+            if os.path.normcase(n) == part:
+                result.append(n)
+                break
+        else:
+            # Cannot happen, as the file exists!
+            result.append(part)
+        dir = os.path.join(dir, part)
+
+    return os.path.join(*result)
 
 def checkexec(path):
     """


More information about the Mercurial-devel mailing list