changeset 6402:d1cf40b596f8

Merge with crew-stable
author Patrick Mezard <pmezard@gmail.com>
date Sat, 29 Mar 2008 17:27:35 +0100
parents 3f0294536b24 (current diff) 635c57cf0de8 (diff)
children f08662abdf3f
files
diffstat 7 files changed, 296 insertions(+), 257 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/convert/subversion.py	Fri Mar 28 19:47:22 2008 +0100
+++ b/hgext/convert/subversion.py	Sat Mar 29 17:27:35 2008 +0100
@@ -95,6 +95,10 @@
     else:
         pickle.dump(None, fp, protocol)
     fp.close()
+    # With large history, cleanup process goes crazy and suddenly
+    # consumes *huge* amount of memory. The output file being closed,
+    # there is no need for clean termination.
+    os._exit(0)
 
 def debugsvnlog(ui, **opts):
     """Fetch SVN log in a subprocess and channel them back to parent to
@@ -259,7 +263,7 @@
         rev = optrev(self.last_changed)
         oldmodule = ''
         trunk = getcfgpath('trunk', rev)
-        tags = getcfgpath('tags', rev)
+        self.tags = getcfgpath('tags', rev)
         branches = getcfgpath('branches', rev)
 
         # If the project has a trunk or branches, we will extract heads
@@ -274,7 +278,8 @@
 
         # First head in the list is the module's head
         self.heads = [self.head]
-        self.tags = '%s/%s' % (oldmodule , (tags or 'tags'))
+        if self.tags is not None:
+            self.tags = '%s/%s' % (oldmodule , (self.tags or 'tags'))
 
         # Check if branches bring a few more heads to the list
         if branches:
@@ -365,18 +370,58 @@
         if self.tags is None:
             return tags
 
-        start = self.revnum(self.head)
+        # svn tags are just a convention, project branches left in a
+        # 'tags' directory. There is no other relationship than
+        # ancestry, which is expensive to discover and makes them hard
+        # to update incrementally.  Worse, past revisions may be
+        # referenced by tags far away in the future, requiring a deep
+        # history traversal on every calculation.  Current code
+        # performs a single backward traversal, tracking moves within
+        # the tags directory (tag renaming) and recording a new tag
+        # everytime a project is copied from outside the tags
+        # directory. It also lists deleted tags, this behaviour may
+        # change in the future.
+        pendings = []
+        tagspath = self.tags
+        start = svn.ra.get_latest_revnum(self.ra)
         try:
-            for entry in get_log(self.url, [self.tags], self.startrev, start):
-                orig_paths, revnum, author, date, message = entry
-                for path in orig_paths:
-                    if not path.startswith(self.tags+'/'):
+            for entry in get_log(self.url, [self.tags], start, self.startrev):
+                origpaths, revnum, author, date, message = entry
+                copies = [(e.copyfrom_path, e.copyfrom_rev, p) for p,e 
+                          in origpaths.iteritems() if e.copyfrom_path]
+                copies.sort()
+                # Apply moves/copies from more specific to general
+                copies.reverse()
+
+                srctagspath = tagspath
+                if copies and copies[-1][2] == tagspath:
+                    # Track tags directory moves
+                    srctagspath = copies.pop()[0]
+
+                for source, sourcerev, dest in copies:
+                    if not dest.startswith(tagspath + '/'):
                         continue
-                    ent = orig_paths[path]
-                    source = ent.copyfrom_path
-                    rev = ent.copyfrom_rev
-                    tag = path.split('/')[-1]
-                    tags[tag] = self.revid(rev, module=source)
+                    for tag in pendings:
+                        if tag[0].startswith(dest):
+                            tagpath = source + tag[0][len(dest):]
+                            tag[:2] = [tagpath, sourcerev]
+                            break
+                    else:
+                        pendings.append([source, sourcerev, dest.split('/')[-1]])
+
+                # Tell tag renamings from tag creations
+                remainings = []
+                for source, sourcerev, tagname in pendings:
+                    if source.startswith(srctagspath):
+                        remainings.append([source, sourcerev, tagname])
+                        continue
+                    # From revision may be fake, get one with changes
+                    tagid = self.latest(source, sourcerev)
+                    if tagid:
+                        tags[tagname] = tagid
+                pendings = remainings
+                tagspath = srctagspath
+
         except SubversionException, (inst, num):
             self.ui.note('no tags found at revision %d\n' % start)
         return tags
--- a/tests/test-convert-mtn	Fri Mar 28 19:47:22 2008 +0100
+++ b/tests/test-convert-mtn	Sat Mar 29 17:27:35 2008 +0100
@@ -58,6 +58,15 @@
 # Test directory move
 mtn mv dir dir2
 mtn ci -m movedir
+# Test directory removal with empty directory
+mkdir dir2/dir
+mkdir dir2/dir/subdir
+echo f > dir2/dir/subdir/f
+mkdir dir2/dir/emptydir
+mtn add -R dir2/dir
+mtn ci -m emptydir
+mtn drop -R dir2/dir
+mtn ci -m dropdirectory
 cd ..
 
 echo % convert incrementally
@@ -75,4 +84,6 @@
 hg manifest
 echo % contents
 cat dir2/a
+test -d dir2/dir && echo 'removed dir2/dir is still there!'
+exit 0
 
--- a/tests/test-convert-mtn.out	Fri Mar 28 19:47:22 2008 +0100
+++ b/tests/test-convert-mtn.out	Sat Mar 29 17:27:35 2008 +0100
@@ -29,15 +29,33 @@
 mtn: renaming dir to dir2 in workspace manifest
 mtn: beginning commit on branch 'com.selenic.test'
 mtn: committed revision 5de5abe7c15eae70cf3acdda23c9c319ea50c1af
+mtn: adding dir2/dir to workspace manifest
+mtn: adding dir2/dir/emptydir to workspace manifest
+mtn: adding dir2/dir/subdir to workspace manifest
+mtn: adding dir2/dir/subdir/f to workspace manifest
+mtn: beginning commit on branch 'com.selenic.test'
+mtn: committed revision 27a423be1e406595cc57f50f42a8790fa0a93d8e
+mtn: dropping dir2/dir/subdir/f from workspace manifest
+mtn: dropping dir2/dir/subdir from workspace manifest
+mtn: dropping dir2/dir/emptydir from workspace manifest
+mtn: dropping dir2/dir from workspace manifest
+mtn: beginning commit on branch 'com.selenic.test'
+mtn: committed revision ba57ba5ac63178529d37fa8a2a1a012fc0e42047
 % convert incrementally
 assuming destination repo.mtn-hg
 scanning source...
 sorting...
 converting...
-1 update2
-0 movedir
+3 update2
+2 movedir
+1 emptydir
+0 dropdirectory
 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
-@  3 "movedir" files: dir/a dir2/a
+@  5 "dropdirectory" files: dir2/dir/subdir/f
+|
+o  4 "emptydir" files: dir2/dir/subdir/f
+|
+o  3 "movedir" files: dir/a dir2/a
 |
 o  2 "update2" files: bin bin2 dir/b e
 |
--- a/tests/test-convert-svn-source	Fri Mar 28 19:47:22 2008 +0100
+++ b/tests/test-convert-svn-source	Sat Mar 29 17:27:35 2008 +0100
@@ -9,15 +9,10 @@
 
 echo "[extensions]" >> $HGRCPATH
 echo "convert = " >> $HGRCPATH
+echo 'hgext.graphlog =' >> $HGRCPATH
 
 svnadmin create svn-repo
 
-echo % initial svn import
-mkdir t
-cd t
-echo a > a
-cd ..
-
 svnpath=`pwd | fix_path`
 # SVN wants all paths to start with a slash. Unfortunately,
 # Windows ones don't. Handle that.
@@ -26,106 +21,6 @@
     svnpath='/'$svnpath
 fi
 
-svnurl=file://$svnpath/svn-repo/trunk/test
-svn import -m init t $svnurl | fix_path
-
-echo % update svn repository
-svn co $svnurl t2 | fix_path
-cd t2
-echo b >> a
-echo b > b
-svn add b
-svn ci -m changea
-cd ..
-
-echo % convert to hg once
-hg convert $svnurl
-
-echo % update svn repository again
-cd t2
-echo c >> a
-echo c >> b
-svn ci -m changeb
-cd ..
-
-echo % test incremental conversion
-hg convert -v $svnurl | sed 's/source:.*/source:/'
-
-echo % test filemap
-echo 'include b' > filemap
-hg convert --filemap filemap $svnurl fmap
-echo '[extensions]' >> $HGRCPATH
-echo 'hgext.graphlog =' >> $HGRCPATH
-hg glog -R fmap --template '#rev# #desc|firstline# files: #files#\n'
-
-echo % test stop revision
-hg convert --rev 1 $svnurl stoprev
-# Check convert_revision extra-records.
-# This is also the only place testing more than one extra field
-# in a revision.
-hg --cwd stoprev tip --debug | grep extra | sed 's/=.*/=/'
-
-########################################
-
-echo "# now tests that it works with trunk/branches/tags layout"
-echo
-echo % initial svn import
-mkdir projA
-cd projA
-mkdir trunk
-mkdir branches
-mkdir tags
-cd ..
-
-svnurl=file://$svnpath/svn-repo/projA
-svn import -m "init projA" projA $svnurl | fix_path
-
-
-echo % update svn repository
-svn co $svnurl/trunk A | fix_path
-cd A
-echo hello > letter.txt
-svn add letter.txt
-svn ci -m hello
-
-echo world >> letter.txt
-svn ci -m world
-
-svn copy -m "tag v0.1" $svnurl/trunk $svnurl/tags/v0.1
-
-echo 'nice day today!' >> letter.txt
-svn ci -m "nice day"
-cd ..
-
-echo % convert to hg once
-hg convert $svnurl A-hg
-
-echo % update svn repository again
-cd A
-echo "see second letter" >> letter.txt
-# Put it in a subdirectory to test duplicate file records
-# from svn source (issue 714)
-mkdir todo
-echo "nice to meet you" > todo/letter2.txt
-svn add todo
-svn ci -m "second letter"
-
-svn copy -m "tag v0.2" $svnurl/trunk $svnurl/tags/v0.2
-
-echo "blah-blah-blah" >> todo/letter2.txt
-svn ci -m "work in progress"
-cd ..
-
-echo % test incremental conversion
-hg convert $svnurl A-hg
-
-cd A-hg
-hg glog --template '#rev# #desc|firstline# files: #files#\n'
-hg tags -q
-cd ..
-
-########################################
-
 echo "# now tests that it works with trunk/tags layout, but no branches yet"
 echo
 echo % initial svn import
@@ -171,6 +66,8 @@
 svn ci -m "work in progress"
 cd ..
 
+########################################
+
 echo % test incremental conversion
 hg convert $svnurl B-hg
 
@@ -178,3 +75,15 @@
 hg glog --template '#rev# #desc|firstline# files: #files#\n'
 hg tags -q
 cd ..
+
+echo % test filemap
+echo 'include letter2.txt' > filemap
+hg convert --filemap filemap $svnurl/trunk fmap
+hg glog -R fmap --template '#rev# #desc|firstline# files: #files#\n'
+
+echo % test stop revision
+hg convert --rev 1 $svnurl/trunk stoprev
+# Check convert_revision extra-records.
+# This is also the only place testing more than one extra field
+# in a revision.
+hg --cwd stoprev tip --debug | grep extra | sed 's/=.*/=/'
--- a/tests/test-convert-svn-source.out	Fri Mar 28 19:47:22 2008 +0100
+++ b/tests/test-convert-svn-source.out	Sat Mar 29 17:27:35 2008 +0100
@@ -1,151 +1,24 @@
-% initial svn import
-Adding         t/a
-
-Committed revision 1.
-% update svn repository
-A    t2/a
-Checked out revision 1.
-A         b
-Sending        a
-Adding         b
-Transmitting file data ..
-Committed revision 2.
-% convert to hg once
-assuming destination test-hg
-initializing destination test-hg repository
-scanning source...
-sorting...
-converting...
-1 init
-0 changea
-% update svn repository again
-Sending        a
-Sending        b
-Transmitting file data ..
-Committed revision 3.
-% test incremental conversion
-assuming destination test-hg
-scanning source...
-fetching revision log for "/trunk/test" from 3 to 2
-sorting...
-converting...
-0 changeb
-source:
-a
-b
-no tags found at revision 3
-% test filemap
-initializing destination fmap repository
-scanning source...
-sorting...
-converting...
-2 init
-1 changea
-0 changeb
-o  1 changeb files: b
-|
-o  0 changea files: b
-
-% test stop revision
-initializing destination stoprev repository
-scanning source...
-sorting...
-converting...
-0 init
-extra:       branch=
-extra:       convert_revision=
-# now tests that it works with trunk/branches/tags layout
-
-% initial svn import
-Adding         projA/trunk
-Adding         projA/branches
-Adding         projA/tags
-
-Committed revision 4.
-% update svn repository
-Checked out revision 4.
-A         letter.txt
-Adding         letter.txt
-Transmitting file data .
-Committed revision 5.
-Sending        letter.txt
-Transmitting file data .
-Committed revision 6.
-
-Committed revision 7.
-Sending        letter.txt
-Transmitting file data .
-Committed revision 8.
-% convert to hg once
-initializing destination A-hg repository
-scanning source...
-sorting...
-converting...
-3 init projA
-2 hello
-1 world
-0 nice day
-updating tags
-% update svn repository again
-A         todo
-A         todo/letter2.txt
-Sending        letter.txt
-Adding         todo
-Adding         todo/letter2.txt
-Transmitting file data ..
-Committed revision 9.
-
-Committed revision 10.
-Sending        todo/letter2.txt
-Transmitting file data .
-Committed revision 11.
-% test incremental conversion
-scanning source...
-sorting...
-converting...
-1 second letter
-0 work in progress
-updating tags
-o  7 update tags files: .hgtags
-|
-o  6 work in progress files: todo/letter2.txt
-|
-o  5 second letter files: letter.txt todo/letter2.txt
-|
-o  4 update tags files: .hgtags
-|
-o  3 nice day files: letter.txt
-|
-o  2 world files: letter.txt
-|
-o  1 hello files: letter.txt
-|
-o  0 init projA files:
-
-tip
-v0.2
-v0.1
 # now tests that it works with trunk/tags layout, but no branches yet
 
 % initial svn import
 Adding         projB/trunk
 Adding         projB/tags
 
-Committed revision 12.
+Committed revision 1.
 % update svn repository
-Checked out revision 12.
+Checked out revision 1.
 A         letter.txt
 Adding         letter.txt
 Transmitting file data .
-Committed revision 13.
+Committed revision 2.
 Sending        letter.txt
 Transmitting file data .
-Committed revision 14.
+Committed revision 3.
 
-Committed revision 15.
+Committed revision 4.
 Sending        letter.txt
 Transmitting file data .
-Committed revision 16.
+Committed revision 5.
 % convert to hg once
 initializing destination B-hg repository
 scanning source...
@@ -161,12 +34,12 @@
 Sending        letter.txt
 Adding         letter2.txt
 Transmitting file data ..
-Committed revision 17.
+Committed revision 6.
 
-Committed revision 18.
+Committed revision 7.
 Sending        letter2.txt
 Transmitting file data .
-Committed revision 19.
+Committed revision 8.
 % test incremental conversion
 scanning source...
 sorting...
@@ -193,3 +66,26 @@
 tip
 v0.2
 v0.1
+% test filemap
+initializing destination fmap repository
+scanning source...
+sorting...
+converting...
+5 init projB
+4 hello
+3 world
+2 nice day
+1 second letter
+0 work in progress
+o  1 work in progress files: letter2.txt
+|
+o  0 second letter files: letter2.txt
+
+% test stop revision
+initializing destination stoprev repository
+scanning source...
+sorting...
+converting...
+0 init projB
+extra:       branch=
+extra:       convert_revision=
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-convert-svn-tags	Sat Mar 29 17:27:35 2008 +0100
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+"$TESTDIR/hghave" svn svn-bindings || exit 80
+
+fix_path()
+{
+    tr '\\' /
+}
+
+echo "[extensions]" >> $HGRCPATH
+echo "convert = " >> $HGRCPATH
+echo "hgext.graphlog =" >> $HGRCPATH
+
+svnadmin create svn-repo
+
+svnpath=`pwd | fix_path`
+# SVN wants all paths to start with a slash. Unfortunately,
+# Windows ones don't. Handle that.
+expr $svnpath : "\/" > /dev/null
+if [ $? -ne 0 ]; then
+    svnpath='/'$svnpath
+fi
+
+echo % initial svn import
+mkdir projA
+cd projA
+mkdir trunk
+mkdir branches
+mkdir tags
+mkdir unrelated
+cd ..
+
+svnurl=file://$svnpath/svn-repo/projA
+svn import -m "init projA" projA $svnurl | fix_path
+
+echo % update svn repository
+svn co $svnurl A | fix_path
+cd A
+echo a > trunk/a
+svn add trunk/a
+svn ci -m adda
+echo a >> trunk/a
+svn ci -m changea
+echo a >> trunk/a
+svn ci -m changea2
+# Add an unrelated commit to test that tags are bound to the
+# correct "from" revision and not a dummy one
+echo a >> unrelated/dummy
+svn add unrelated/dummy
+svn ci -m unrelatedchange
+echo % tag current revision
+svn up
+svn copy trunk tags/trunk.v1
+svn copy trunk tags/trunk.badtag
+svn ci -m "tagging trunk.v1 trunk.badtag"
+echo a >> trunk/a
+svn ci -m changea3
+echo % fix the bad tag
+# trunk.badtag should not show in converted tags
+svn up
+svn mv tags/trunk.badtag tags/trunk.goodtag
+svn ci -m "fix trunk.badtag"
+cd ..
+
+echo % convert
+hg convert --datesort $svnurl A-hg
+
+cd A-hg
+hg glog --template '#rev# #desc|firstline# tags: #tags#\n'
+hg tags -q
+cd ..
+
+echo % convert without tags
+hg convert --datesort --config convert.svn.tags= $svnurl A-notags-hg
+hg -R a-notags-hg tags -q
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-convert-svn-tags.out	Sat Mar 29 17:27:35 2008 +0100
@@ -0,0 +1,84 @@
+% initial svn import
+Adding         projA/trunk
+Adding         projA/unrelated
+Adding         projA/branches
+Adding         projA/tags
+
+Committed revision 1.
+% update svn repository
+A    A/trunk
+A    A/unrelated
+A    A/branches
+A    A/tags
+Checked out revision 1.
+A         trunk/a
+Adding         trunk/a
+Transmitting file data .
+Committed revision 2.
+Sending        trunk/a
+Transmitting file data .
+Committed revision 3.
+Sending        trunk/a
+Transmitting file data .
+Committed revision 4.
+A         unrelated/dummy
+Adding         unrelated/dummy
+Transmitting file data .
+Committed revision 5.
+% tag current revision
+At revision 5.
+A         tags/trunk.v1
+A         tags/trunk.badtag
+Adding         tags/trunk.badtag
+Adding         tags/trunk.v1
+
+Committed revision 6.
+Sending        trunk/a
+Transmitting file data .
+Committed revision 7.
+% fix the bad tag
+At revision 7.
+A         tags/trunk.goodtag
+D         tags/trunk.badtag/a
+D         tags/trunk.badtag
+Deleting       tags/trunk.badtag
+Adding         tags/trunk.goodtag
+
+Committed revision 8.
+% convert
+initializing destination A-hg repository
+scanning source...
+sorting...
+converting...
+4 init projA
+3 adda
+2 changea
+1 changea2
+0 changea3
+updating tags
+o  5 update tags tags: tip
+|
+o  4 changea3 tags:
+|
+o  3 changea2 tags: trunk.v1 trunk.goodtag
+|
+o  2 changea tags:
+|
+o  1 adda tags:
+|
+o  0 init projA tags:
+
+tip
+trunk.v1
+trunk.goodtag
+% convert without tags
+initializing destination A-notags-hg repository
+scanning source...
+sorting...
+converting...
+4 init projA
+3 adda
+2 changea
+1 changea2
+0 changea3
+tip