diff --git a/hgext/convert/__init__.py b/hgext/convert/__init__.py --- a/hgext/convert/__init__.py +++ b/hgext/convert/__init__.py @@ -227,6 +227,7 @@ class converter(object): self.dest.copyfile(copyf, f) newnode = self.dest.putcommit(filenames, parents, commit) + self.source.converted(rev, newnode) self.map[rev] = newnode def convert(self): diff --git a/hgext/convert/common.py b/hgext/convert/common.py --- a/hgext/convert/common.py +++ b/hgext/convert/common.py @@ -115,6 +115,11 @@ class converter_source(object): """ raise NotImplementedError() + def converted(self, rev, sinkrev): + '''Notify the source that a revision has been converted.''' + pass + + class converter_sink(object): """Conversion sink (target) interface""" diff --git a/hgext/convert/hg.py b/hgext/convert/hg.py --- a/hgext/convert/hg.py +++ b/hgext/convert/hg.py @@ -24,8 +24,6 @@ class mercurial_sink(converter_sink): if os.path.isdir(path) and len(os.listdir(path)) > 0: try: self.repo = hg.repository(self.ui, path) - ui.status(_('destination %s is a Mercurial repository\n') % - path) except hg.RepoError, err: ui.print_exc() raise NoRepo(err.args[0]) @@ -195,6 +193,7 @@ class mercurial_source(converter_source) self.lastrev = None self.lastctx = None self._changescache = None + self.convertfp = None def changectx(self, rev): if self.lastrev != rev: @@ -258,3 +257,9 @@ class mercurial_source(converter_source) return changes[0] + changes[1] + changes[2] + def converted(self, rev, destrev): + if self.convertfp is None: + self.convertfp = open(os.path.join(self.path, '.hg', 'shamap'), + 'a') + self.convertfp.write('%s %s\n' % (destrev, rev)) + self.convertfp.flush() diff --git a/hgext/convert/subversion.py b/hgext/convert/subversion.py --- a/hgext/convert/subversion.py +++ b/hgext/convert/subversion.py @@ -154,6 +154,12 @@ class svn_source(converter_source): self.head = self.revid(self.last_changed) self._changescache = None + if os.path.exists(os.path.join(url, '.svn/entries')): + self.wc = url + else: + self.wc = None + self.convertfp = None + def setrevmap(self, revmap): lastrevs = {} for revid in revmap.iterkeys(): @@ -298,6 +304,15 @@ class svn_source(converter_source): self.ui.note('no tags found at revision %d\n' % start) return tags + def converted(self, rev, destrev): + if not self.wc: + return + if self.convertfp is None: + self.convertfp = open(os.path.join(self.wc, '.svn', 'hg-shamap'), + 'a') + self.convertfp.write('%s %d\n' % (destrev, self.revnum(rev))) + self.convertfp.flush() + # -- helper functions -- def revid(self, revnum, module=None): @@ -749,6 +764,9 @@ class svn_sink(converter_sink, commandli fp.close() util.set_exec(hook, True) + xport = transport.SvnRaTransport(url=geturl(path)) + self.uuid = svn.ra.get_uuid(xport.ra) + def wjoin(self, *names): return os.path.join(self.wc, *names) @@ -837,10 +855,13 @@ class svn_sink(converter_sink, commandli def addchild(self, parent, child): self.childmap[parent] = child + def revid(self, rev): + return u"svn:%s@%s" % (self.uuid, rev) + def putcommit(self, files, parents, commit): for parent in parents: try: - return self.childmap[parent] + return self.revid(self.childmap[parent]) except KeyError: pass entries = set(self.delete) @@ -873,7 +894,7 @@ class svn_sink(converter_sink, commandli revprop=True, revision=rev) for parent in parents: self.addchild(parent, rev) - return rev + return self.revid(rev) finally: os.unlink(messagefile) diff --git a/tests/test-convert-hg-svn b/tests/test-convert-hg-svn new file mode 100755 --- /dev/null +++ b/tests/test-convert-hg-svn @@ -0,0 +1,66 @@ +#!/bin/sh + +"$TESTDIR/hghave" svn svn-bindings || exit 80 + +fix_path() +{ + tr '\\' / +} + +echo "[extensions]" >> $HGRCPATH +echo "convert = " >> $HGRCPATH + +svnpath=`pwd`/svn-repo +svnadmin create $svnpath + +cat > $svnpath/hooks/pre-revprop-change <<'EOF' +#!/bin/sh + +REPOS="$1" +REV="$2" +USER="$3" +PROPNAME="$4" +ACTION="$5" + +if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ]; then exit 0; fi +if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-branch" ]; then exit 0; fi +if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-rev" ]; then exit 0; fi + +echo "Changing prohibited revision property" >&2 +exit 1 +EOF +chmod +x $svnpath/hooks/pre-revprop-change + +svnurl=file://$svnpath +svn co $svnurl $svnpath-wc + +cd $svnpath-wc +echo a > a +svn add a +svn ci -m'added a' a + +cd .. + +echo % initial roundtrip +hg convert -s svn -d hg $svnpath-wc $svnpath-hg | grep -v initializing +hg convert -s hg -d svn $svnpath-hg $svnpath-wc + +echo % second roundtrip should do nothing +hg convert -s svn -d hg $svnpath-wc $svnpath-hg +hg convert -s hg -d svn $svnpath-hg $svnpath-wc + +echo % new hg rev + +hg clone $svnpath-hg $svnpath-work +echo b > $svnpath-work/b +hg --cwd $svnpath-work add b +hg --cwd $svnpath-work ci -mb + +echo % echo hg to svn +hg --cwd $svnpath-hg pull -q $svnpath-work +hg convert -s hg -d svn $svnpath-hg $svnpath-wc + +echo % svn back to hg should do nothing +hg convert -s svn -d hg $svnpath-wc $svnpath-hg +echo % hg back to svn should do nothing +hg convert -s hg -d svn $svnpath-hg $svnpath-wc diff --git a/tests/test-convert-hg-svn.out b/tests/test-convert-hg-svn.out new file mode 100644 --- /dev/null +++ b/tests/test-convert-hg-svn.out @@ -0,0 +1,35 @@ +Checked out revision 0. +A a +Adding a +Transmitting file data . +Committed revision 1. +% initial roundtrip +scanning source... +sorting... +converting... +0 added a +scanning source... +sorting... +converting... +% second roundtrip should do nothing +scanning source... +sorting... +converting... +scanning source... +sorting... +converting... +% new hg rev +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +% echo hg to svn +scanning source... +sorting... +converting... +0 b +% svn back to hg should do nothing +scanning source... +sorting... +converting... +% hg back to svn should do nothing +scanning source... +sorting... +converting...