convert: follow svn tags history (
issue953)
--- a/hgext/convert/subversion.py Sat Mar 29 17:15:43 2008 +0100
+++ b/hgext/convert/subversion.py Sat Mar 29 17:15:45 2008 +0100
@@ -369,18 +369,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-svn-tags Sat Mar 29 17:15:43 2008 +0100
+++ b/tests/test-convert-svn-tags Sat Mar 29 17:15:45 2008 +0100
@@ -27,6 +27,7 @@
mkdir trunk
mkdir branches
mkdir tags
+mkdir unrelated
cd ..
svnurl=file://$svnpath/svn-repo/projA
@@ -42,12 +43,23 @@
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 ci -m "tagging 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
--- a/tests/test-convert-svn-tags.out Sat Mar 29 17:15:43 2008 +0100
+++ b/tests/test-convert-svn-tags.out Sat Mar 29 17:15:45 2008 +0100
@@ -1,11 +1,13 @@
% 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.
@@ -19,15 +21,30 @@
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 4.
+At revision 5.
A tags/trunk.v1
+A tags/trunk.badtag
+Adding tags/trunk.badtag
Adding tags/trunk.v1
-Committed revision 5.
+Committed revision 6.
Sending trunk/a
Transmitting file data .
-Committed revision 6.
+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...
@@ -43,7 +60,7 @@
|
o 4 changea3 tags:
|
-o 3 changea2 tags: trunk.v1
+o 3 changea2 tags: trunk.v1 trunk.goodtag
|
o 2 changea tags:
|
@@ -53,3 +70,4 @@
tip
trunk.v1
+trunk.goodtag