Patchwork [7,of,7,STABLE] largefiles: check case-folding collision between normal and large files

login
register
mail settings
Submitter Katsunori FUJIWARA
Date May 6, 2013, 8:35 p.m.
Message ID <d4c42b36c321f42f00d4.1367872507@juju>
Download mbox | patch
Permalink /patch/1571/
State Changes Requested, archived
Headers show

Comments

Katsunori FUJIWARA - May 6, 2013, 8:35 p.m.
# HG changeset patch
# User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
# Date 1367870651 -32400
#      Tue May 07 05:04:11 2013 +0900
# Branch stable
# Node ID d4c42b36c321f42f00d44250ab9760950d11d076
# Parent  f6c324c8d745ac8efe0e2c72a085adab7a61cd36
largefiles: check case-folding collision between normal and large files

Before this patch, case-folding collision is checked only between
regular files and standin files (under ".hglf" directory) of large
files. So, case-folding collision between regular files and large
files may be overlooked.

This patch introduces argument "normpath" into
"merge._checkcollision()" to normalize filenames in the (target or
merged) manifest, and overrides it to pass the function specific for
largefiles extension: converting from standin file to large file
itself.

This patch also changes logic of case-folding collision detection:

  - old: "if nf in foldmap"
  - new: "if nf in foldmap and foldmap[nf] != f"

This ignores collision between regular file and large file in exactly
same name: choosing one of them is done after manifest merging.

Patch

diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py
--- a/hgext/largefiles/overrides.py
+++ b/hgext/largefiles/overrides.py
@@ -337,6 +337,14 @@ 
         return False
     return origfn(repo, wctx, mctx, f)
 
+def overridecheckcollision(orgfn, repo, wmf, actions, prompts, casesensitive,
+                           normpath=None):
+    def normlfname(f):
+        if normpath:
+            f = normpath(f)
+        return lfutil.splitstandin(f) or f
+    return orgfn(repo, wmf, actions, prompts, casesensitive, normlfname)
+
 # The manifest merge handles conflicts on the manifest level. We want
 # to handle changes in largefile-ness of files at this level too.
 #
diff --git a/hgext/largefiles/uisetup.py b/hgext/largefiles/uisetup.py
--- a/hgext/largefiles/uisetup.py
+++ b/hgext/largefiles/uisetup.py
@@ -96,6 +96,8 @@ 
                                    overrides.overridecat)
     entry = extensions.wrapfunction(merge, '_checkunknownfile',
                                     overrides.overridecheckunknownfile)
+    entry = extensions.wrapfunction(merge, '_checkcollision',
+                                    overrides.overridecheckcollision)
     entry = extensions.wrapfunction(merge, 'manifestmerge',
                                     overrides.overridemanifestmerge)
     entry = extensions.wrapfunction(filemerge, 'filemerge',
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -146,7 +146,7 @@ 
 
     return actions
 
-def _checkcollision(repo, wmf, actions, prompts, casesensitive):
+def _checkcollision(repo, wmf, actions, prompts, casesensitive, normpath=None):
     # build provisional merged manifest up
     pmmf = set(wmf)
 
@@ -206,18 +206,23 @@ 
             if nf in dirs:
                 raise util.Abort(_("collision between file %s and "
                                    "other directory") % (f))
-            if nf in foldmap:
+            if nf in foldmap and foldmap[nf] != f:
                 raise util.Abort(_("case-folding collision between %s and %s")
                                  % (f, foldmap[nf]))
             foldmap[nf] = f
 
     # check collision in provisional merged manifest
-    if normcase:
+    if normpath or normcase:
+        if not normpath:
+            normpath = lambda x: x
+        if not normcase:
+            normcase = lambda x: x
         def normiter():
             for f in pmmf:
-                yield normcase(f)
+                yield normcase(normpath(f))
         dirs = scmutil.dirs(normiter())
         for f in sorted(pmmf):
+            f = normpath(f)
             check(f, normcase(f))
     else:
         dirs = scmutil.dirs(pmmf)
diff --git a/tests/test-casecollision-merge.t b/tests/test-casecollision-merge.t
--- a/tests/test-casecollision-merge.t
+++ b/tests/test-casecollision-merge.t
@@ -214,6 +214,45 @@ 
   abort: collision between file x and other directory
   [255]
 
+test case-folding collision detection between normal file and largefile
+
+  $ cat > .hg/hgrc <<EOF
+  > [extensions]
+  > hgext.largefiles=
+  > EOF
+  $ hg update -q -C 0
+  $ echo X > X
+  $ hg add --large X
+  $ hg commit -m '#6'
+  created new head
+
+  $ hg status -A
+  C X
+  C a
+  $ hg manifest -r 3
+  a
+  x
+  $ hg merge 3
+  abort: case-folding collision between x and X
+  [255]
+  $ hg status -A
+  C X
+  C a
+
+  $ hg update -q -C 3
+  $ hg status -A
+  C a
+  C x
+  $ hg manifest -r 6
+  .hglf/X
+  a
+  $ hg merge 6
+  abort: case-folding collision between x and X
+  [255]
+  $ hg status -A
+  C a
+  C x
+
   $ cd ..