Patchwork [4,of,5] scmutil: check collision between tracked files and directory part of added one

login
register
mail settings
Submitter Katsunori FUJIWARA
Date Nov. 11, 2013, 3:15 p.m.
Message ID <f3dbb1f34b4fa0ee743c.1384182959@juju>
Download mbox | patch
Permalink /patch/2903/
State Superseded
Headers show

Comments

Katsunori FUJIWARA - Nov. 11, 2013, 3:15 p.m.
# HG changeset patch
# User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
# Date 1384182518 -32400
#      Tue Nov 12 00:08:38 2013 +0900
# Node ID f3dbb1f34b4fa0ee743c7a43a95e3c4c92ad3099
# Parent  69fed456e3a20657acad10eae294951fc64d04fa
scmutil: check collision between tracked files and directory part of added one

Before this patch, "hg add" doesn't show any warning messages, when
directory part of newly added file causes case-folding collision
against already tracked ones.

Such adding causes failure of "hg update" on icasefs system.

This patch checks case-folding collision between already tracked files
and directory part of newly added one.

This patch tests collision detection by multiple path patterns
corresponded to detections in the first, the middle and the last of
"while dparts" loop.

In fact, "dl in self._loweredfiles" is enough for collision check
itself, because it means case-folding collision between file and
directory.

But adding file in NOT "dirstate[d] in 'r?'" case should be aborted in
"dirstate._addpath()" (see also issues #660 and #332).

For collision detection between files, only "dirstate[f] in '?'" (= "f
not in dirstate") case is treated as collision, because reusing name
of already removed file is treated as reverting of it.

But for collision detection between directories, "dirstate[d] in 'r'"
case should be also treated as collision: it means that there is at
least one colliding file already tracked (or newly added), because
"self._loweredfiles" doesn't contain removed files.

Patch

diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -97,6 +97,7 @@ 
         self._newfiles = set()
 
         self._lowereddirs = dirs(self._loweredfiles)
+        self._newdirs = dirs([])
 
     def __call__(self, f):
         if f in self._newfiles:
@@ -108,9 +109,28 @@ 
             if self._abort:
                 raise util.Abort(msg)
             self._ui.warn(_("warning: %s\n") % msg)
+        else:
+            dirstate = self._dirstate
+            dparts = f.split('/')
+            dparts.pop()
+            dlparts = fl.split('/')
+            while dparts:
+                dlparts.pop()
+                d = '/'.join(dparts)
+                if d in self._newdirs:
+                    break
+                dl = '/'.join(dlparts)
+                if dl in self._loweredfiles and dirstate[d] in 'r?':
+                    msg = _('possible case-folding collision for %s') % f
+                    if self._abort:
+                        raise util.Abort(msg)
+                    self._ui.warn(_("warning: %s\n") % msg)
+                    break
+                dparts.pop()
         self._loweredfiles.add(fl)
         self._newfiles.add(f)
         self._lowereddirs.addpath(fl)
+        self._newdirs.addpath(f)
 
 class pathauditor(object):
     '''ensure that a filesystem path contains no banned components.
diff --git a/tests/test-casecollision.t b/tests/test-casecollision.t
--- a/tests/test-casecollision.t
+++ b/tests/test-casecollision.t
@@ -71,12 +71,28 @@ 
   $ touch I/I2/x
   $ hg add I/I2/x
 
+  $ mkdir -p J/J/j1 J/j2/J j3/J/J
+  $ touch J/J/J1 J/J2 J3 J/J/j1/y J/j2/J/y j3/J/J/y
+  $ hg add J/J/J1 J/J2 J3 J/J/j1/y J/j2/J/y j3/J/J/y
+  warning: possible case-folding collision for J/J/j1/y
+  warning: possible case-folding collision for J/j2/J/y
+  warning: possible case-folding collision for j3/J/J/y
+  $ touch J/J4 J/j4
+  $ hg add J/J4 J/j4
+  warning: possible case-folding collision for J/j4
+
   $ hg commit -m '#0'
 
   $ hg remove I/I2/x
   $ touch I/i2
   $ hg add I/i2
 
+  $ hg remove J/j4
+  $ mkdir J/j4
+  $ touch J/j4/y
+  $ hg add J/j4/y
+  warning: possible case-folding collision for J/j4/y
+
 case changing rename must not warn or abort
 
   $ echo c > c