changeset 15709:a1f4bd47d18e

icasefs: retry directory scan once for already invalidated cache some hg operation (e.g.: qpush) create new files after first dirstate.walk()-ing, and it invalidates _fspathcache for fspath(). then, fspath() will fail to look up specified name in _fspathcache. this causes case preservation breaking, because parts of already normcase()-ed path are used as result at that time. in this case, file creation and writing out should be done before fspath() invocation, so the second invocation of os.listdir() has not so much impact on runtime performance.
author FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
date Fri, 16 Dec 2011 21:09:40 +0900
parents 309e49491253
children f63e40047372
files mercurial/util.py
diffstat 1 files changed, 19 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/util.py	Thu Sep 29 17:20:04 2011 +0200
+++ b/mercurial/util.py	Fri Dec 16 21:09:40 2011 +0900
@@ -630,6 +630,13 @@
     if not os.path.lexists(os.path.join(root, name)):
         return None
 
+    def find(p, contents):
+        lenp = len(p)
+        for n in contents:
+            if lenp == len(n) and normcase(n) == p:
+                return n
+        return None
+
     seps = os.sep
     if os.altsep:
         seps = seps + os.altsep
@@ -643,18 +650,19 @@
             result.append(sep)
             continue
 
-        if dir not in _fspathcache:
-            _fspathcache[dir] = os.listdir(dir)
-        contents = _fspathcache[dir]
+        contents = _fspathcache.get(dir, None)
+        if contents is None:
+            contents = os.listdir(dir)
+            _fspathcache[dir] = contents
 
-        lenp = len(part)
-        for n in contents:
-            if lenp == len(n) and normcase(n) == part:
-                result.append(n)
-                break
-        else:
-            # Cannot happen, as the file exists!
-            result.append(part)
+        found = find(part, contents)
+        if not found:
+            # retry once for the corner case: add files after dir walking
+            contents = os.listdir(dir)
+            _fspathcache[dir] = contents
+            found = find(part, contents)
+
+        result.append(found or part)
         dir = os.path.join(dir, part)
 
     return ''.join(result)