[PATCH 2 of 3] Add a new function, fspath
Paul Moore
p.f.moore at gmail.com
Fri Jun 6 18:24:05 UTC 2008
# HG changeset patch
# User Paul Moore <p.f.moore at gmail.com>
# Date 1212776603 -3600
# Node ID 3141723474c64c35a03540ada08137bfe26b43c9
# Parent dd5c4c84244629ae08a1870dd11033a29cc5b3b5
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 relative to the root, but retains
the path separators used in the input path. (This is not strictly necessary,
but retaining the path separators minimises misleading test suite failures).
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,53 @@
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).
+ '''
+ # If name is absolute, make it relative
+ if name.lower().startswith(root.lower()):
+ l = len(root)
+ if name[l] == os.sep or name[l] == os.altsep:
+ l = l + 1
+ name = name[l:]
+
+ if not os.path.exists(os.path.join(root, name)):
+ return None
+
+ seps = os.sep
+ if os.altsep:
+ seps = seps + os.altsep
+ # Protect backslashes. This gets silly very quickly.
+ seps.replace('\\','\\\\')
+ pattern = re.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
+ dir = os.path.normcase(os.path.normpath(root))
+ result = []
+ for part, sep in pattern.findall(name):
+ if sep:
+ result.append(sep)
+ continue
+
+ if dir not in _fspathcache:
+ _fspathcache[dir] = os.listdir(dir)
+ contents = _fspathcache[dir]
+
+ lpart = part.lower()
+ for n in contents:
+ if n.lower() == lpart:
+ result.append(n)
+ break
+ else:
+ # Cannot happen, as the file exists!
+ result.append(part)
+ dir = os.path.join(dir, lpart)
+
+ return ''.join(result)
def checkexec(path):
"""
More information about the Mercurial-devel
mailing list