[PATCH] Check case-folding clashes during addremove

Andrei Vermel andrei.vermel at gmail.com
Tue May 15 18:57:28 UTC 2007


----- Original Message ----- 
From: "Alexis S. L. Carvalho" <alexis at cecm.usp.br>
To: "Andrei Vermel" <andrei.vermel at gmail.com>
Cc: "Matt Mackall" <mpm at selenic.com>; "Mercurial Devel" <mercurial-devel at selenic.com>
Sent: Monday, April 16, 2007 3:08 AM
Subject: Re: [PATCH] Check case-folding clashes during addremove
> Instead of populating the foldmap every time we read the dirstate file,
> it'd be better to do it only when we're going to use it, just like the
> initdirs/checkinterfering calls in dirstate.update below.  (Maybe it
> even makes sense to rename initdirs/updatedirs -> initchecks/updatechecks,
> add the foldmap management to these functions and make checkinterfering
> call check_add_case_clashes)

Yes, this makes sense. Modified patch is below and attached.

Regards,

Andrei


# HG changeset patch
# User Andrei Vermel <avermel at mail.ru>
# Date 1179088540 -14400
# Node ID 7e9678d540dc735fbbdfa90b35ff027b4d201e04
# Parent  ba22e867cb23fb11f83c37705743e050afd66a6a
Check case-folding clashes during addremove

diff -r ba22e867cb23 -r 7e9678d540dc mercurial/dirstate.py
--- a/mercurial/dirstate.py  Mon May 07 21:44:11 2007 +0900
+++ b/mercurial/dirstate.py  Mon May 14 00:35:40 2007 +0400
@@ -24,6 +24,7 @@ class dirstate(object):
         self.fp = None
         self.pl = None
         self.dirs = None
+        self.foldmap = None
         self.copymap = {}
         self.ignorefunc = None
         self._branch = None
@@ -252,25 +253,29 @@ class dirstate(object):
     def copies(self):
         return self.copymap
 
-    def initdirs(self):
+    def initchecks(self):
         if self.dirs is None:
             self.dirs = {}
+            self.foldmap = {}
             for f in self.map:
-                self.updatedirs(f, 1)
-
-    def updatedirs(self, path, delta):
+                self.updatechecks(f, 1)
+
+    def updatechecks(self, path, delta):
         if self.dirs is not None:
             for c in strutil.findall(path, '/'):
                 pc = path[:c]
                 self.dirs.setdefault(pc, 0)
                 self.dirs[pc] += delta
+            fl = path.lower()
+            self.foldmap.setdefault(fl, 0)
+            self.foldmap[fl] += delta
 
     def checkinterfering(self, files):
         def prefixes(f):
             for c in strutil.rfindall(f, '/'):
                 yield f[:c]
         self.lazyread()
-        self.initdirs()
+        self.initchecks()
         seendirs = {}
         for f in files:
             # shadows
@@ -287,6 +292,7 @@ class dirstate(object):
             # disallowed
             if '\r' in f or '\n' in f:
                 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames"))
+        self.check_add_case_clashes(files)
 
     def update(self, files, state, **kw):
         ''' current states:
@@ -299,15 +305,15 @@ class dirstate(object):
         self.lazyread()
         self.markdirty()
         if state == "a":
-            self.initdirs()
+            self.initchecks()
             self.checkinterfering(files)
         for f in files:
             if state == "r":
                 self.map[f] = ('r', 0, 0, 0)
-                self.updatedirs(f, -1)
+                self.updatechecks(f, -1)
             else:
                 if state == "a":
-                    self.updatedirs(f, 1)
+                    self.updatechecks(f, 1)
                 s = os.lstat(self.wjoin(f))
                 st_size = kw.get('st_size', s.st_size)
                 st_mtime = kw.get('st_mtime', s.st_mtime)
@@ -319,11 +325,11 @@ class dirstate(object):
         if not files: return
         self.lazyread()
         self.markdirty()
-        self.initdirs()
+        self.initchecks()
         for f in files:
             try:
                 del self.map[f]
-                self.updatedirs(f, -1)
+                self.updatechecks(f, -1)
             except KeyError:
                 self.ui.warn(_("not in dirstate: %s!\n") % f)
                 pass
@@ -332,6 +338,7 @@ class dirstate(object):
         self.map = {}
         self.copymap = {}
         self.dirs = None
+        self.foldmap = None
         self.markdirty()
 
     def rebuild(self, parent, files):
@@ -588,3 +595,37 @@ class dirstate(object):
 
         return (lookup, modified, added, removed, deleted, unknown, ignored,
                 clean)
+
+    def check_add_case_clashes(self, add_files):
+        self.lazyread()   
+        foldmap = self.foldmap     
+        fold_clash = None
+        for fn in add_files:
+            fold=fn.lower()
+            if fold in foldmap:
+                nmb = foldmap[fold]
+                if nmb == 0:
+                    continue
+                if fn in self.map: # add existing file is valid, 
+                    continue       #  e.g. qrefresh does it
+
+                coll=self.report_case_collisions(fn)
+
+
+    def report_case_collisions(self, file):
+        fold = file.lower()
+        clashes=[]
+        for fn in self.map.iterkeys():
+            fl = fn.lower()
+            if fl == fold and fn != file and self.map[fn][0] != 'r':
+                clashes.append(fn)
+
+        if clashes != []:
+           self.ui.warn(_('\nname case fold clashes found!\n'))
+           self.ui.warn(_('    was %s') % clashes[0])
+           for fn in clashes[1:]:
+               self.ui.warn(_(',\n        %s') % fn)
+           self.ui.warn(_(', now %s\n') % file)
+
+           if not util.checkfolding(self.root):
+               raise util.Abort(_('add aborted due to case folding clashes'))
-------------- next part --------------
A non-text attachment was scrubbed...
Name: name_clashes.diff
Type: application/octet-stream
Size: 4733 bytes
Desc: not available
URL: <http://lists.mercurial-scm.org/pipermail/mercurial-devel/attachments/20070515/8650134d/attachment-0002.obj>


More information about the Mercurial-devel mailing list