# HG changeset patch # User Bryan O'Sullivan # Date 1194297624 28800 # Node ID 2dd399d8a992080b22a2b2b407835347205298f7 # Parent bb417470d62a968b5722387f52dc904fa70bb30e# Parent bf2bb53e5d2b94a0c0c02a19e13dc9e52dc44349 Merge with -stable diff -r bb417470d62a -r 2dd399d8a992 hgext/convert/__init__.py --- a/hgext/convert/__init__.py Mon Nov 05 08:41:22 2007 +0100 +++ b/hgext/convert/__init__.py Mon Nov 05 13:20:24 2007 -0800 @@ -344,7 +344,7 @@ The 'include' directive causes a file, or all files under a directory, to be included in the destination repository, and the - exclussion of all other files and dirs not explicitely included. + exclusion of all other files and dirs not explicitely included. The 'exclude' directive causes files or directories to be omitted. The 'rename' directive renames a file or directory. To rename from a subdirectory into the root of the repository, use '.' as the path to diff -r bb417470d62a -r 2dd399d8a992 mercurial/cmdutil.py --- a/mercurial/cmdutil.py Mon Nov 05 08:41:22 2007 +0100 +++ b/mercurial/cmdutil.py Mon Nov 05 13:20:24 2007 -0800 @@ -266,14 +266,15 @@ mapping[abs] = rel, exact if repo.ui.verbose or not exact: repo.ui.status(_('adding %s\n') % ((pats and rel) or abs)) - if repo.dirstate[abs] != 'r' and not util.lexists(target): + if repo.dirstate[abs] != 'r' and (not util.lexists(target) + or (os.path.isdir(target) and not os.path.islink(target))): remove.append(abs) mapping[abs] = rel, exact if repo.ui.verbose or not exact: repo.ui.status(_('removing %s\n') % ((pats and rel) or abs)) if not dry_run: + repo.remove(remove) repo.add(add) - repo.remove(remove) if similarity > 0: for old, new, score in findrenames(repo, add, remove, similarity): oldrel, oldexact = mapping[old] diff -r bb417470d62a -r 2dd399d8a992 mercurial/dirstate.py --- a/mercurial/dirstate.py Mon Nov 05 08:41:22 2007 +0100 +++ b/mercurial/dirstate.py Mon Nov 05 13:20:24 2007 -0800 @@ -50,7 +50,8 @@ elif name == '_dirs': self._dirs = {} for f in self._map: - self._incpath(f) + if self[f] != 'r': + self._incpath(f) return self._dirs elif name == '_ignore': files = [self._join('.hgignore')] @@ -205,14 +206,25 @@ d = f[:c] if d in self._dirs: break - if d in self._map: + if d in self._map and self[d] != 'r': raise util.Abort(_('file %r in dirstate clashes with %r') % (d, f)) self._incpath(f) + def _changepath(self, f, newstate): + # handle upcoming path changes + oldstate = self[f] + if oldstate not in "?r" and newstate in "?r": + self._decpath(f) + return + if oldstate in "?r" and newstate not in "?r": + self._incpathcheck(f) + return + def normal(self, f): 'mark a file normal and clean' self._dirty = True + self._changepath(f, 'n') s = os.lstat(self._join(f)) self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime, 0) if self._copymap.has_key(f): @@ -221,6 +233,7 @@ def normallookup(self, f): 'mark a file normal, but possibly dirty' self._dirty = True + self._changepath(f, 'n') self._map[f] = ('n', 0, -1, -1, 0) if f in self._copymap: del self._copymap[f] @@ -228,6 +241,7 @@ def normaldirty(self, f): 'mark a file normal, but dirty' self._dirty = True + self._changepath(f, 'n') self._map[f] = ('n', 0, -2, -1, 0) if f in self._copymap: del self._copymap[f] @@ -235,7 +249,7 @@ def add(self, f): 'mark a file added' self._dirty = True - self._incpathcheck(f) + self._changepath(f, 'a') self._map[f] = ('a', 0, -1, -1, 0) if f in self._copymap: del self._copymap[f] @@ -243,8 +257,8 @@ def remove(self, f): 'mark a file removed' self._dirty = True + self._changepath(f, 'r') self._map[f] = ('r', 0, 0, 0, 0) - self._decpath(f) if f in self._copymap: del self._copymap[f] @@ -252,6 +266,7 @@ 'mark a file merged' self._dirty = True s = os.lstat(self._join(f)) + self._changepath(f, 'm') self._map[f] = ('m', s.st_mode, s.st_size, s.st_mtime, 0) if f in self._copymap: del self._copymap[f] @@ -260,13 +275,15 @@ 'forget a file' self._dirty = True try: + self._changepath(f, '?') del self._map[f] - self._decpath(f) except KeyError: self._ui.warn(_("not in dirstate: %s!\n") % f) def clear(self): self._map = {} + if "_dirs" in self.__dict__: + delattr(self, "_dirs"); self._copymap = {} self._pl = [nullid, nullid] self._dirty = True @@ -522,7 +539,7 @@ try: st = lstat(_join(fn)) except OSError, inst: - if inst.errno != errno.ENOENT: + if inst.errno not in (errno.ENOENT, errno.ENOTDIR): raise st = None # We need to re-check that it is a valid file diff -r bb417470d62a -r 2dd399d8a992 mercurial/merge.py --- a/mercurial/merge.py Mon Nov 05 08:41:22 2007 +0100 +++ b/mercurial/merge.py Mon Nov 05 13:20:24 2007 -0800 @@ -401,7 +401,10 @@ act("update permissions", "e", f, m2.flags(f)) # contents same, check mode bits elif m1.flags(f) != m2.flags(f): - if overwrite or fmerge(f) != m1.flags(f): + # are we clobbering? + # is remote's version newer? + # or are we going back? + if overwrite or fmerge(f) != m1.flags(f) or backwards: act("update permissions", "e", f, m2.flags(f)) elif f in copied: continue diff -r bb417470d62a -r 2dd399d8a992 mercurial/util.py --- a/mercurial/util.py Mon Nov 05 08:41:22 2007 +0100 +++ b/mercurial/util.py Mon Nov 05 13:20:24 2007 -0800 @@ -720,7 +720,7 @@ except OSError, err: # EINVAL can be raised as invalid path syntax under win32. # They must be ignored for patterns can be checked too. - if err.errno not in (errno.ENOENT, errno.EINVAL): + if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL): raise else: if stat.S_ISLNK(st.st_mode): diff -r bb417470d62a -r 2dd399d8a992 tests/test-convert.out --- a/tests/test-convert.out Mon Nov 05 08:41:22 2007 +0100 +++ b/tests/test-convert.out Mon Nov 05 13:20:24 2007 -0800 @@ -3,6 +3,7 @@ Convert a foreign SCM repository to a Mercurial one. Accepted source formats: + - Mercurial - CVS - Darcs - git @@ -19,8 +20,8 @@ basename of the source with '-hg' appended. If the destination repository doesn't exist, it will be created. - If isn't given, it will be put in a default location - (/.hg/shamap by default). The is a simple text + If isn't given, it will be put in a default location + (/.hg/shamap by default). The is a simple text file that maps each source commit ID to the destination ID for that revision, like so: @@ -46,11 +47,12 @@ rename from/file to/file The 'include' directive causes a file, or all files under a - directory, to be included in the destination repository. The - 'exclude' directive causes files or directories to be omitted. - The 'rename' directive renames a file or directory. To rename - from a subdirectory into the root of the repository, use '.' as - the path to rename to. + directory, to be included in the destination repository, and the + exclusion of all other files and dirs not explicitely included. + The 'exclude' directive causes files or directories to be omitted. + The 'rename' directive renames a file or directory. To rename from a + subdirectory into the root of the repository, use '.' as the path to + rename to. options: diff -r bb417470d62a -r 2dd399d8a992 tests/test-issue660 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-issue660 Mon Nov 05 13:20:24 2007 -0800 @@ -0,0 +1,89 @@ +#!/bin/sh +# http://www.selenic.com/mercurial/bts/issue660 + + +hg init a +cd a +echo a > a +mkdir b +echo b > b/b +hg commit -A -m "a is file, b is dir" + +echo % file replaced with directory + +rm a +mkdir a +echo a > a/a + +echo % should fail - would corrupt dirstate +hg add a/a + +echo % removing shadow +hg rm --after a + +echo % should succeed - shadow removed +hg add a/a + +echo % directory replaced with file + +rm -r b +echo b > b + +echo % should fail - would corrupt dirstate +hg add b + +echo % removing shadow +hg rm --after b/b + +echo % should succeed - shadow removed +hg add b + +echo % look what we got +hg st + +echo % revert reintroducing shadow - should fail +rm -r a b +hg revert b/b + +echo % revert all - should succeed +hg revert --all +hg st + +echo % addremove + +rm -r a b +mkdir a +echo a > a/a +echo b > b + +hg addremove +hg st + +echo % commit +hg ci -A -m "a is dir, b is file" +hg st --all + +echo % long directory replaced with file + +mkdir d +mkdir d/d +echo d > d/d/d +hg commit -A -m "d is long directory" +rm -r d +echo d > d + +echo % should fail - would corrupt dirstate +hg add d + +echo % removing shadow +hg rm --after d/d/d + +echo % should succeed - shadow removed +hg add d + +#echo % update should work +# +#hg up -r 0 +#hg up -r 1 + +exit 0 diff -r bb417470d62a -r 2dd399d8a992 tests/test-issue660.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-issue660.out Mon Nov 05 13:20:24 2007 -0800 @@ -0,0 +1,42 @@ +adding a +adding b/b +% file replaced with directory +% should fail - would corrupt dirstate +abort: file 'a' in dirstate clashes with 'a/a' +% removing shadow +% should succeed - shadow removed +% directory replaced with file +% should fail - would corrupt dirstate +abort: directory 'b' already in dirstate +% removing shadow +% should succeed - shadow removed +% look what we got +A a/a +A b +R a +R b/b +% revert reintroducing shadow - should fail +abort: file 'b' in dirstate clashes with 'b/b' +% revert all - should succeed +undeleting a +forgetting a/a +forgetting b +undeleting b/b +% addremove +removing a +adding a/a +adding b +removing b/b +A a/a +A b +R a +R b/b +% commit +C a/a +C b +% long directory replaced with file +adding d/d/d +% should fail - would corrupt dirstate +abort: directory 'd' already in dirstate +% removing shadow +% should succeed - shadow removed