changeset 11129:ee8ea6356733

Merge with crew-stable
author Patrick Mezard <pmezard@gmail.com>
date Sun, 09 May 2010 19:25:35 +0200
parents 0bedcbcb3ae2 (current diff) a9b427b5821e (diff)
children e81966e88e80
files
diffstat 7 files changed, 502 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/convert/subversion.py	Fri May 07 23:31:49 2010 +0200
+++ b/hgext/convert/subversion.py	Sun May 09 19:25:35 2010 +0200
@@ -386,7 +386,7 @@
         self.modecache = {}
         (paths, parents) = self.paths[rev]
         if parents:
-            files, copies = self.expandpaths(rev, paths, parents)
+            files, self.removed, copies = self.expandpaths(rev, paths, parents)
         else:
             # Perform a full checkout on roots
             uuid, module, revnum = self.revsplit(rev)
@@ -395,6 +395,7 @@
             files = [n for n, e in entries.iteritems()
                      if e.kind == svn.core.svn_node_file]
             copies = {}
+            self.removed = set()
 
         files.sort()
         files = zip(files, [rev] * len(files))
@@ -610,7 +611,7 @@
         return prevmodule
 
     def expandpaths(self, rev, paths, parents):
-        entries = []
+        changed, removed = set(), set()
         # Map of entrypath, revision for finding source of deleted
         # revisions.
         copyfrom = {}
@@ -626,7 +627,7 @@
 
             kind = self._checkpath(entrypath, revnum)
             if kind == svn.core.svn_node_file:
-                entries.append(self.recode(entrypath))
+                changed.add(self.recode(entrypath))
                 if not ent.copyfrom_path or not parents:
                     continue
                 # Copy sources not in parent revisions cannot be
@@ -644,41 +645,34 @@
                 self.ui.debug("gone from %s\n" % ent.copyfrom_rev)
                 pmodule, prevnum = self.revsplit(parents[0])[1:]
                 parentpath = pmodule + "/" + entrypath
-                self.ui.debug("entry %s\n" % parentpath)
-
-                # We can avoid the reparent calls if the module has
-                # not changed but it probably does not worth the pain.
-                prevmodule = self.reparent('')
-                fromkind = svn.ra.check_path(self.ra, parentpath.strip('/'),
-                                             prevnum)
-                self.reparent(prevmodule)
+                fromkind = self._checkpath(entrypath, prevnum, pmodule)
 
                 if fromkind == svn.core.svn_node_file:
-                    entries.append(self.recode(entrypath))
+                    removed.add(self.recode(entrypath))
                 elif fromkind == svn.core.svn_node_dir:
-                    if ent.action == 'C':
-                        children = self._find_children(path, prevnum)
-                    else:
-                        oroot = parentpath.strip('/')
-                        nroot = path.strip('/')
-                        children = self._find_children(oroot, prevnum)
-                        children = [s.replace(oroot, nroot) for s in children]
-
+                    oroot = parentpath.strip('/')
+                    nroot = path.strip('/')
+                    children = self._find_children(oroot, prevnum)
+                    children = [s.replace(oroot, nroot) for s in children]
                     for child in children:
                         childpath = self.getrelpath("/" + child, pmodule)
-                        if not childpath:
-                            continue
-                        if childpath in copies:
-                            del copies[childpath]
-                        entries.append(childpath)
+                        if childpath:
+                            removed.add(self.recode(childpath))
                 else:
                     self.ui.debug('unknown path in revision %d: %s\n' % \
                                   (revnum, path))
-            elif kind == svn.core.svn_node_dir:
-                # If the directory just had a prop change,
-                # then we shouldn't need to look for its children.
+            elif kind == svn.core.svn_node_dir:                
                 if ent.action == 'M':
+                    # If the directory just had a prop change,
+                    # then we shouldn't need to look for its children.
                     continue
+                elif ent.action == 'R' and parents:
+                    # If a directory is replacing a file, mark the previous
+                    # file as deleted
+                    pmodule, prevnum = self.revsplit(parents[0])[1:]
+                    pkind = self._checkpath(entrypath, prevnum, pmodule)
+                    if pkind == svn.core.svn_node_file:
+                        removed.add(self.recode(entrypath))
 
                 children = sorted(self._find_children(path, revnum))
                 for child in children:
@@ -691,7 +685,7 @@
                         # Need to filter out directories here...
                         kind = self._checkpath(entrypath, revnum)
                         if kind != svn.core.svn_node_dir:
-                            entries.append(self.recode(entrypath))
+                            changed.add(self.recode(entrypath))
 
                 # Handle directory copies
                 if not ent.copyfrom_path or not parents:
@@ -717,7 +711,8 @@
                     copytopath = self.getrelpath(copytopath)
                     copies[self.recode(copytopath)] = self.recode(entrypath)
 
-        return (list(set(entries)), copies)
+        changed.update(removed)
+        return (list(changed), removed, copies)
 
     def _fetch_revisions(self, from_revnum, to_revnum):
         if from_revnum < to_revnum:
@@ -846,6 +841,8 @@
 
     def _getfile(self, file, rev):
         # TODO: ra.get_file transmits the whole file instead of diffs.
+        if file in self.removed:
+            raise IOError()
         mode = ''
         try:
             new_module, revnum = self.revsplit(rev)[1:]
@@ -901,11 +898,18 @@
         self.ui.debug('%r is not under %r, ignoring\n' % (path, module))
         return None
 
-    def _checkpath(self, path, revnum):
-        # ra.check_path does not like leading slashes very much, it leads
-        # to PROPFIND subversion errors
-        return svn.ra.check_path(self.ra, path.strip('/'), revnum)
-
+    def _checkpath(self, path, revnum, module=None):
+        if module is not None:
+            prevmodule = self.reparent('')
+            path = module + '/' + path
+        try:
+            # ra.check_path does not like leading slashes very much, it leads
+            # to PROPFIND subversion errors
+            return svn.ra.check_path(self.ra, path.strip('/'), revnum)
+        finally:
+            if module is not None:
+                self.reparent(prevmodule)
+    
     def _getlog(self, paths, start, end, limit=0, discover_changed_paths=True,
                 strict_node_history=False):
         # Normalize path names, svn >= 1.5 only wants paths relative to
--- a/tests/svn/move.svndump	Fri May 07 23:31:49 2010 +0200
+++ b/tests/svn/move.svndump	Sun May 09 19:25:35 2010 +0200
@@ -1,6 +1,6 @@
 SVN-fs-dump-format-version: 2
 
-UUID: 9de99ecc-876b-46e5-bc59-bff9b2b58b1e
+UUID: 7d15f7c2-5863-4c16-aa2a-3418b1721d3a
 
 Revision-number: 0
 Prop-content-length: 56
@@ -9,7 +9,7 @@
 K 8
 svn:date
 V 27
-2009-06-21T14:32:26.678698Z
+2010-05-09T13:02:37.336239Z
 PROPS-END
 
 Revision-number: 1
@@ -27,7 +27,7 @@
 K 8
 svn:date
 V 27
-2009-06-21T14:32:27.278689Z
+2010-05-09T13:02:37.372834Z
 PROPS-END
 
 Node-path: trunk
@@ -124,7 +124,7 @@
 K 8
 svn:date
 V 27
-2009-06-21T14:32:28.312955Z
+2010-05-09T13:02:38.049068Z
 PROPS-END
 
 Node-path: trunk/a
@@ -166,7 +166,7 @@
 K 8
 svn:date
 V 27
-2009-06-21T14:32:29.183467Z
+2010-05-09T13:02:39.044479Z
 PROPS-END
 
 Node-path: subproject
@@ -195,7 +195,7 @@
 K 8
 svn:date
 V 27
-2009-06-21T14:32:30.300975Z
+2010-05-09T13:02:40.057804Z
 PROPS-END
 
 Node-path: subproject/trunk
@@ -222,7 +222,7 @@
 K 8
 svn:date
 V 27
-2009-06-21T14:32:31.354398Z
+2010-05-09T13:02:41.058871Z
 PROPS-END
 
 Node-path: subproject/branches
@@ -249,7 +249,7 @@
 K 8
 svn:date
 V 27
-2009-06-21T14:32:32.121901Z
+2010-05-09T13:02:42.046689Z
 PROPS-END
 
 Node-path: subproject/trunk/d1
@@ -278,7 +278,7 @@
 K 8
 svn:date
 V 27
-2009-06-21T14:32:32.317815Z
+2010-05-09T13:02:42.071413Z
 PROPS-END
 
 Node-path: subproject/trunk/d2
@@ -307,7 +307,7 @@
 K 8
 svn:date
 V 27
-2009-06-21T14:32:33.418320Z
+2010-05-09T13:02:43.062018Z
 PROPS-END
 
 Node-path: subproject/trunk/d1/b
@@ -341,7 +341,7 @@
 K 8
 svn:date
 V 27
-2009-06-21T14:32:34.126542Z
+2010-05-09T13:02:44.047997Z
 PROPS-END
 
 Node-path: subproject/branches/d1
@@ -370,7 +370,7 @@
 K 8
 svn:date
 V 27
-2009-06-21T14:32:34.436015Z
+2010-05-09T13:02:44.086619Z
 PROPS-END
 
 Node-path: subproject/trunk/d
@@ -397,7 +397,7 @@
 K 8
 svn:date
 V 27
-2009-06-21T14:32:34.803189Z
+2010-05-09T13:02:44.111550Z
 PROPS-END
 
 Node-path: subproject/trunk/d2
@@ -422,7 +422,7 @@
 K 8
 svn:date
 V 27
-2009-06-21T14:32:36.531735Z
+2010-05-09T13:02:45.067982Z
 PROPS-END
 
 Node-path: subproject/trunk/d3
@@ -484,7 +484,7 @@
 K 8
 svn:date
 V 27
-2009-06-21T14:32:38.281829Z
+2010-05-09T13:02:47.061259Z
 PROPS-END
 
 Node-path: subproject/trunk/d3/d31
@@ -498,3 +498,72 @@
 Node-copyfrom-path: subproject/trunk/d3
 
 
+Revision-number: 14
+Prop-content-length: 110
+Content-length: 110
+
+K 7
+svn:log
+V 9
+add d4old
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:49.063363Z
+PROPS-END
+
+Node-path: subproject/trunk/d4old
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: subproject/trunk/d4old/g
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: f5302386464f953ed581edac03556e55
+Text-content-sha1: a5938ace3f424be1a26904781cdb06d55b614e6b
+Content-length: 12
+
+PROPS-END
+g
+
+
+Revision-number: 15
+Prop-content-length: 125
+Content-length: 125
+
+K 7
+svn:log
+V 23
+rename d4old into d4new
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T13:02:51.047304Z
+PROPS-END
+
+Node-path: subproject/trunk/d4new
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 14
+Node-copyfrom-path: subproject/trunk/d4old
+
+
+Node-path: subproject/trunk/d4old
+Node-action: delete
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/svn/replace.svndump	Sun May 09 19:25:35 2010 +0200
@@ -0,0 +1,241 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 4a895937-439c-4e56-b7b0-fa1c8acc0c20
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2010-05-09T14:57:31.007802Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 108
+Content-length: 108
+
+K 7
+svn:log
+V 7
+initial
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T14:57:32.094732Z
+PROPS-END
+
+Node-path: branches
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Node-path: trunk/d
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/d/b
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 3b5d5c3712955042212316173ccf37be
+Text-content-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b
+Content-length: 12
+
+PROPS-END
+b
+
+
+Node-path: trunk/dlink
+Node-kind: file
+Node-action: add
+Prop-content-length: 33
+Text-content-length: 6
+Text-content-md5: cca56829f18345718a4980bb02b6d8c3
+Text-content-sha1: 7c54cc5d472b78c94a04382df34b0f4f0f4f2d49
+Content-length: 39
+
+K 11
+svn:special
+V 1
+*
+PROPS-END
+link d
+
+Node-path: trunk/dlink2
+Node-kind: file
+Node-action: add
+Prop-content-length: 33
+Text-content-length: 6
+Text-content-md5: cca56829f18345718a4980bb02b6d8c3
+Text-content-sha1: 7c54cc5d472b78c94a04382df34b0f4f0f4f2d49
+Content-length: 39
+
+K 11
+svn:special
+V 1
+*
+PROPS-END
+link d
+
+Node-path: trunk/dlink3
+Node-kind: file
+Node-action: add
+Prop-content-length: 33
+Text-content-length: 6
+Text-content-md5: cca56829f18345718a4980bb02b6d8c3
+Text-content-sha1: 7c54cc5d472b78c94a04382df34b0f4f0f4f2d49
+Content-length: 39
+
+K 11
+svn:special
+V 1
+*
+PROPS-END
+link d
+
+Revision-number: 2
+Prop-content-length: 117
+Content-length: 117
+
+K 7
+svn:log
+V 15
+clobber symlink
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2010-05-09T14:57:33.071117Z
+PROPS-END
+
+Node-path: trunk/dlink3
+Node-kind: file
+Node-action: change
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: e29311f6f1bf1af907f9ef9f44b8328b
+Text-content-sha1: e983f374794de9c64e3d1c1de1d490c0756eeeff
+Content-length: 12
+
+PROPS-END
+d
+
+
+Revision-number: 3
+Prop-content-length: 106
+Content-length: 106
+
+K 7
+svn:log
+V 8
+clobber1
+K 10
+svn:author
+V 4
+evil
+K 8
+svn:date
+V 27
+2010-05-09T14:57:35.268057Z
+PROPS-END
+
+Node-path: trunk/a
+Node-kind: dir
+Node-action: delete
+
+Node-path: trunk/a
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk/d
+
+
+
+
+Node-path: trunk/dlink
+Node-kind: dir
+Node-action: delete
+
+Node-path: trunk/dlink
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk/d
+
+
+
+
+Revision-number: 4
+Prop-content-length: 106
+Content-length: 106
+
+K 7
+svn:log
+V 8
+clobber2
+K 10
+svn:author
+V 4
+evil
+K 8
+svn:date
+V 27
+2010-05-09T14:57:35.521816Z
+PROPS-END
+
+Node-path: trunk/dlink3
+Node-kind: file
+Node-action: delete
+
+Node-path: trunk/dlink3
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 3
+Node-copyfrom-path: trunk/dlink2
+Text-copy-source-md5: cca56829f18345718a4980bb02b6d8c3
+Text-copy-source-sha1: 7c54cc5d472b78c94a04382df34b0f4f0f4f2d49
+
+
+
+
--- a/tests/svn/svndump-move.sh	Fri May 07 23:31:49 2010 +0200
+++ b/tests/svn/svndump-move.sh	Sun May 09 19:25:35 2010 +0200
@@ -68,6 +68,16 @@
 svn copy subproject/trunk/d3 subproject/trunk/d4
 svn rm subproject/trunk/d3/d31
 svn ci -m "copy dir and remove subdir"
+
+# Test directory moves
+svn up
+mkdir -p subproject/trunk/d4old
+echo g > subproject/trunk/d4old/g
+svn add subproject/trunk/d4old
+svn ci -m "add d4old"
+svn mv subproject/trunk/d4old subproject/trunk/d4new
+svn ci -m "rename d4old into d4new"
+
 cd ..
 
 svnadmin dump svn-repo > ../move.svndump
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/svn/svndump-replace.sh	Sun May 09 19:25:35 2010 +0200
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+RSVN="`pwd`/rsvn.py"
+export PATH=/bin:/usr/bin
+mkdir temp
+cd temp
+
+svnadmin create repo
+svn co file://`pwd`/repo wc
+
+cd wc
+mkdir trunk branches
+cd trunk
+echo a > a
+mkdir d
+echo b > d/b
+ln -s d dlink
+ln -s d dlink2
+ln -s d dlink3
+cd ..
+svn add *
+svn ci -m 'initial'
+# Clobber symlink with file with similar content
+cd trunk
+ls -Alh
+readlink dlink3 > dlink3tmp
+rm dlink3
+mv dlink3tmp dlink3
+svn propdel svn:special dlink3
+svn ci -m 'clobber symlink'
+cd ..
+svn up
+
+# Clobber files and symlink with directories
+cd ..
+cat > clobber.rsvn <<EOF
+rdelete trunk/a
+rdelete trunk/dlink
+rcopy trunk/d trunk/a
+rcopy trunk/d trunk/dlink
+EOF
+
+python $RSVN --message=clobber1 --username=evil `pwd`/repo < clobber.rsvn
+
+# Clobber non-symlink with symlink with same content (kudos openwrt)
+cat > clobber.rsvn <<EOF
+rdelete trunk/dlink3
+rcopy trunk/dlink2 trunk/dlink3
+EOF
+
+python $RSVN --message=clobber2 --username=evil `pwd`/repo < clobber.rsvn
+
+svn log -v file://`pwd`/repo
+
+svnadmin dump repo > ../replace.svndump
--- a/tests/test-convert-svn-move	Fri May 07 23:31:49 2010 +0200
+++ b/tests/test-convert-svn-move	Sun May 09 19:25:35 2010 +0200
@@ -28,5 +28,26 @@
 
 cd A-hg
 hg glog --template '{rev} {desc|firstline} files: {files}\n'
+echo '% check move copy records'
+hg st --rev 12:13 --copies
+echo '% check branches'
 hg branches | sed 's/:.*/:/'
 cd ..
+
+mkdir test-replace
+cd test-replace
+svnadmin create svn-repo
+cat "$TESTDIR/svn/replace.svndump" | svnadmin load svn-repo > /dev/null
+
+echo '% convert files being replaced by directories'
+hg convert svn-repo hg-repo
+cd hg-repo
+echo '% manifest before'
+hg -v manifest -r 1
+echo '% manifest after clobber1'
+hg -v manifest -r 2
+echo '% manifest after clobber2'
+hg -v manifest -r 3
+echo '% try updating'
+hg up -qC default
+cd ..
--- a/tests/test-convert-svn-move.out	Fri May 07 23:31:49 2010 +0200
+++ b/tests/test-convert-svn-move.out	Sun May 09 19:25:35 2010 +0200
@@ -3,18 +3,24 @@
 scanning source...
 sorting...
 converting...
-11 createtrunk
-10 moved1
-9 moved1
-8 moved2
-7 changeb and rm d2
-6 changeb and rm d2
-5 moved1again
-4 moved1again
-3 copyfilefrompast
-2 copydirfrompast
-1 add d3
-0 copy dir and remove subdir
+13 createtrunk
+12 moved1
+11 moved1
+10 moved2
+9 changeb and rm d2
+8 changeb and rm d2
+7 moved1again
+6 moved1again
+5 copyfilefrompast
+4 copydirfrompast
+3 add d3
+2 copy dir and remove subdir
+1 add d4old
+0 rename d4old into d4new
+o  13 rename d4old into d4new files: d4new/g d4old/g
+|
+o  12 add d4old files: d4old/g
+|
 o  11 copy dir and remove subdir files: d3/d31/e d4/d31/e d4/f
 |
 o  10 add d3 files: d3/d31/e d3/f
@@ -39,5 +45,38 @@
 |
 o  0 createtrunk files:
 
-default                       11:
+% check move copy records
+A d4new/g
+  d4old/g
+R d4old/g
+% check branches
+default                       13:
 d1                             6:
+% convert files being replaced by directories
+initializing destination hg-repo repository
+scanning source...
+sorting...
+converting...
+3 initial
+2 clobber symlink
+1 clobber1
+0 clobber2
+% manifest before
+644   a
+644   d/b
+644 @ dlink
+644 @ dlink2
+644   dlink3
+% manifest after clobber1
+644   a/b
+644   d/b
+644   dlink/b
+644 @ dlink2
+644   dlink3
+% manifest after clobber2
+644   a/b
+644   d/b
+644   dlink/b
+644 @ dlink2
+644 @ dlink3
+% try updating