[PATCH 1 of 8] Add a new function, fspath

Paul Moore p.f.moore at gmail.com
Wed Apr 30 12:37:23 CDT 2008


# HG changeset patch
# User "Paul Moore <p.f.moore at gmail.com>"
# Date 1209573914 -3600
# Node ID 4c332d2df388086257be74380d53701631fd3a2e
# Parent  7758fc67c39fd22b1025faa02a69b49acfdb557c
Add a new function, fspath

The function, given a filename and an (optional) root, returns the filename
modified to use the case actually stored in the filesystem (if the file does
not exist, return a default value).

A generic implementation is provided in util.py, with a faster win32-specific
implementation (using win32api.FindFiles) in util_win32.py.

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -868,6 +868,45 @@
         return True
     except:
         return True
+
+def fspath(name, root='', default=None):
+    '''Get name in the case stored in the filesystem
+
+    The filename 'name' is relative to the path 'root' (if given).
+    If the file does not exist, return default (or name unchanged if default
+    is not given). Otherwise, return the version of name with case as stored
+    in the filesystem.
+    '''
+    if not os.path.exists(os.path.join(root, name)):
+        if default is None:
+            return name
+        return default
+    parts = []
+    while name:
+        dir, leaf = os.path.split(name)
+
+        # Scan os.listdir for a name that matches leaf except for case
+        leaf_l = leaf.lower()
+        for n in os.listdir(os.path.join(root, dir)):
+            if n.lower() == leaf_l:
+                parts.append(n)
+                break
+        else:
+            # This should never happen, as the file exists so it should
+            # show up in os.listdir (even hidden files on Windows do).
+            # But just in case, append the leafname unchanged if it happens.
+            parts.append(leaf)
+
+        # Get the actual separator used in 'name', as we want to match
+        # whichever of os.sep or os.altsep was used.
+        if dir:
+            sep = name[len(dir)]
+            parts.append(sep)
+
+        name = dir
+
+    parts.reverse()
+    return ''.join(parts)
 
 def checkexec(path):
     """
diff --git a/mercurial/util_win32.py b/mercurial/util_win32.py
--- a/mercurial/util_win32.py
+++ b/mercurial/util_win32.py
@@ -369,3 +369,50 @@
     def handler(event):
         win32process.ExitProcess(1)
     win32api.SetConsoleCtrlHandler(handler)
+
+def fspath(name, root='', default=None):
+    '''Get name in the case stored in the filesystem
+
+    The filename 'name' is relative to the path 'root' (if given).
+    If the file does not exist, return default (or name unchanged if default
+    is not given). Otherwise, return the version of name with case as stored
+    in the filesystem.
+    '''
+    if not os.path.exists(os.path.join(root, name)):
+        if default is None:
+            return name
+        return default
+    parts = []
+    while name:
+        dir, leaf = os.path.split(name)
+
+        fullpath = os.path.join(root, name)
+        osleaf = None
+        if os.path.isdir(fullpath):
+            # win32api.FindFiles does the wrong thing on directories :-(
+            # So fall back to a slower os.listdir scan.
+            filelist = os.listdir(os.path.dirname(fullpath))
+            leaf_l = leaf.lower()
+            for f in filelist:
+                if f.lower() == leaf_l:
+                    osleaf = f
+                    break
+        else:
+            filelist = win32api.FindFiles(fullpath)
+            if len(filelist) == 1:
+                osleaf = filelist[0][8]
+        if osleaf is not None:
+            parts.append(osleaf)
+        else:
+            parts.append(leaf)
+
+        # Get the actual separator used in 'name', as we want to match
+        # whichever of os.sep or os.altsep was used.
+        if dir:
+            sep = name[len(dir)]
+            parts.append(sep)
+
+        name = dir
+
+    parts.reverse()
+    return ''.join(parts)


More information about the Mercurial-devel mailing list