--- a/hgext/convert/subversion.py Sat Mar 29 21:15:34 2008 +0100
+++ b/hgext/convert/subversion.py Sat Mar 29 21:15:54 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 Sat Mar 29 21:15:34 2008 +0100
+++ b/tests/test-convert-mtn Sat Mar 29 21:15:54 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 Sat Mar 29 21:15:34 2008 +0100
+++ b/tests/test-convert-mtn.out Sat Mar 29 21:15:54 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 Sat Mar 29 21:15:34 2008 +0100
+++ b/tests/test-convert-svn-source Sat Mar 29 21:15:54 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 Sat Mar 29 21:15:34 2008 +0100
+++ b/tests/test-convert-svn-source.out Sat Mar 29 21:15:54 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 21:15:54 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 21:15:54 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