changeset 5508:2dd399d8a992

Merge with -stable
author Bryan O'Sullivan <bos@serpentine.com>
date Mon, 05 Nov 2007 13:20:24 -0800
parents bb417470d62a (current diff) bf2bb53e5d2b (diff)
children 305b035c5fda 11d7908a3ea8
files
diffstat 8 files changed, 172 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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]
--- 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
--- 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
--- 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):
--- 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 <revmapfile> isn't given, it will be put in a default location
-    (<dest>/.hg/shamap by default).  The <revmapfile> is a simple text
+    If <MAPFILE> isn't given, it will be put in a default location
+    (<dest>/.hg/shamap by default).  The <MAPFILE> is a simple text
     file that maps each source commit ID to the destination ID for
     that revision, like so:
     <source ID> <destination ID>
@@ -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:
 
--- /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
--- /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