fix issue 322.
do not allow to add files that shadow files or directories already in dirstate.
--- a/mercurial/dirstate.py Fri Aug 18 15:53:14 2006 -0700
+++ b/mercurial/dirstate.py Fri Aug 18 21:03:29 2006 -0700
@@ -10,7 +10,7 @@
from node import *
from i18n import gettext as _
from demandload import *
-demandload(globals(), "struct os time bisect stat util re errno")
+demandload(globals(), "struct os time bisect stat strutil util re errno")
class dirstate(object):
format = ">cllll"
@@ -22,6 +22,7 @@
self.ui = ui
self.map = None
self.pl = None
+ self.dirs = None
self.copies = {}
self.ignorefunc = None
self.blockignore = False
@@ -197,6 +198,38 @@
def copied(self, file):
return self.copies.get(file, None)
+ def initdirs(self):
+ if self.dirs is None:
+ self.dirs = {}
+ for f in self.map:
+ self.updatedirs(f, 1)
+
+ def updatedirs(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
+
+ def checkshadows(self, files):
+ def prefixes(f):
+ for c in strutil.rfindall(f, '/'):
+ yield f[:c]
+ self.lazyread()
+ self.initdirs()
+ seendirs = {}
+ for f in files:
+ if self.dirs.get(f):
+ raise util.Abort(_('directory named %r already in dirstate') %
+ f)
+ for d in prefixes(f):
+ if d in seendirs:
+ break
+ if d in self.map:
+ raise util.Abort(_('file named %r already in dirstate') %
+ d)
+ seendirs[d] = True
+
def update(self, files, state, **kw):
''' current states:
n normal
@@ -207,10 +240,16 @@
if not files: return
self.lazyread()
self.markdirty()
+ if state == "a":
+ self.initdirs()
+ self.checkshadows(files)
for f in files:
if state == "r":
self.map[f] = ('r', 0, 0, 0)
+ self.updatedirs(f, -1)
else:
+ if state == "a":
+ self.updatedirs(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)
@@ -222,9 +261,11 @@
if not files: return
self.lazyread()
self.markdirty()
+ self.initdirs()
for f in files:
try:
del self.map[f]
+ self.updatedirs(f, -1)
except KeyError:
self.ui.warn(_("not in dirstate: %s!\n") % f)
pass
@@ -232,6 +273,7 @@
def clear(self):
self.map = {}
self.copies = {}
+ self.dirs = None
self.markdirty()
def rebuild(self, parent, files):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/strutil.py Fri Aug 18 21:03:29 2006 -0700
@@ -0,0 +1,34 @@
+# strutil.py - string utilities for Mercurial
+#
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+def findall(haystack, needle, start=0, end=None):
+ if end is None:
+ end = len(haystack)
+ if end < 0:
+ end += len(haystack)
+ if start < 0:
+ start += len(haystack)
+ while start < end:
+ c = haystack.find(needle, start, end)
+ if c == -1:
+ break
+ yield c
+ start = c + 1
+
+def rfindall(haystack, needle, start=0, end=None):
+ if end is None:
+ end = len(haystack)
+ if end < 0:
+ end += len(haystack)
+ if start < 0:
+ start += len(haystack)
+ while end >= 0:
+ c = haystack.rfind(needle, start, end)
+ if c == -1:
+ break
+ yield c
+ end = c - 1
--- a/mercurial/util.py Fri Aug 18 15:53:14 2006 -0700
+++ b/mercurial/util.py Fri Aug 18 21:03:29 2006 -0700
@@ -995,4 +995,3 @@
if path.startswith('//'):
path = path[2:]
return path
-
--- a/tests/test-issue322 Fri Aug 18 15:53:14 2006 -0700
+++ b/tests/test-issue322 Fri Aug 18 21:03:29 2006 -0700
@@ -14,15 +14,7 @@
echo % should fail - would corrupt dirstate
hg add a/a
-echo % should fail - if add succeeded, would corrupt manifest
-hg commit -mb
-
-echo % should fail if commit succeeded - manifest is corrupt
-hg verify
-
cd ..
-echo % should succeed, but manifest is corrupt
-hg --debug --traceback clone a b
echo % directory replaced with file
@@ -38,8 +30,20 @@
echo % should fail - would corrupt dirstate
hg add a
-echo % should fail - if add succeeded, would corrupt manifest
-hg commit -mb a
+cd ..
+
+echo % directory replaced with file
-echo % should fail if commit succeeded - manifest is corrupt
-hg verify
+hg init d
+cd d
+mkdir b
+mkdir b/c
+echo a > b/c/d
+hg commit -Ama
+rm -rf b
+echo a > b
+
+echo % should fail - would corrupt dirstate
+hg add b
+
+exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-issue322.out Fri Aug 18 21:03:29 2006 -0700
@@ -0,0 +1,12 @@
+% file replaced with directory
+adding a
+% should fail - would corrupt dirstate
+abort: file named 'a' already in dirstate
+% directory replaced with file
+adding a/a
+% should fail - would corrupt dirstate
+abort: directory named 'a' already in dirstate
+% directory replaced with file
+adding b/c/d
+% should fail - would corrupt dirstate
+abort: directory named 'b' already in dirstate