convert: use splicemap entries when sorting revisions (issue1748)
When sorting revisions before converting them, we have to edit the revision
graph using splicemap entries. Otherwise, a spliced revision may be converted
before its synthetic parents. Invalid splicemap revisions are now detected
before starting the conversion.
--- a/hgext/convert/common.py Fri Feb 10 22:25:49 2012 +0100
+++ b/hgext/convert/common.py Fri Feb 10 22:34:13 2012 +0100
@@ -245,6 +245,10 @@
"""
pass
+ def hascommit(self, rev):
+ """Return True if the sink contains rev"""
+ raise NotImplementedError()
+
class commandline(object):
def __init__(self, ui, command):
self.ui = ui
--- a/hgext/convert/convcmd.py Fri Feb 10 22:25:49 2012 +0100
+++ b/hgext/convert/convcmd.py Fri Feb 10 22:34:13 2012 +0100
@@ -142,6 +142,29 @@
return parents
+ def mergesplicemap(self, parents, splicemap):
+ """A splicemap redefines child/parent relationships. Check the
+ map contains valid revision identifiers and merge the new
+ links in the source graph.
+ """
+ for c in splicemap:
+ if c not in parents:
+ if not self.dest.hascommit(self.map.get(c, c)):
+ # Could be in source but not converted during this run
+ self.ui.warn(_('splice map revision %s is not being '
+ 'converted, ignoring\n') % c)
+ continue
+ pc = []
+ for p in splicemap[c]:
+ # We do not have to wait for nodes already in dest.
+ if self.dest.hascommit(self.map.get(p, p)):
+ continue
+ # Parent is not in dest and not being converted, not good
+ if p not in parents:
+ raise util.Abort(_('unknown splice map parent: %s') % p)
+ pc.append(p)
+ parents[c] = pc
+
def toposort(self, parents, sortmode):
'''Return an ordering such that every uncommitted changeset is
preceeded by all its uncommitted ancestors.'''
@@ -340,6 +363,7 @@
self.ui.status(_("scanning source...\n"))
heads = self.source.getheads()
parents = self.walktree(heads)
+ self.mergesplicemap(parents, self.splicemap)
self.ui.status(_("sorting...\n"))
t = self.toposort(parents, sortmode)
num = len(t)
--- a/hgext/convert/hg.py Fri Feb 10 22:25:49 2012 +0100
+++ b/hgext/convert/hg.py Fri Feb 10 22:34:13 2012 +0100
@@ -223,6 +223,12 @@
self.repo._bookmarks[bookmark] = bin(updatedbookmark[bookmark])
bookmarks.write(self.repo)
+ def hascommit(self, rev):
+ if not rev in self.repo and self.clonebranches:
+ raise util.Abort(_('revision %s not be found in destination '
+ 'repository (lookups with clonebranches=true '
+ 'are not implemented)') % rev)
+ return rev in self.repo
class mercurial_source(converter_source):
def __init__(self, ui, path, rev=None):
--- a/hgext/convert/subversion.py Fri Feb 10 22:25:49 2012 +0100
+++ b/hgext/convert/subversion.py Fri Feb 10 22:34:13 2012 +0100
@@ -1187,3 +1187,12 @@
def puttags(self, tags):
self.ui.warn(_('writing Subversion tags is not yet implemented\n'))
return None, None
+
+ def hascommit(self, rev):
+ # This is not correct as one can convert to an existing subversion
+ # repository and childmap would not list all revisions. Too bad.
+ if rev in self.childmap:
+ return True
+ raise util.Abort(_('splice map revision %s not found in subversion '
+ 'child map (revision lookups are not implemented')
+ % rev)
--- a/tests/test-convert-splicemap.t Fri Feb 10 22:25:49 2012 +0100
+++ b/tests/test-convert-splicemap.t Fri Feb 10 22:34:13 2012 +0100
@@ -4,7 +4,8 @@
$ echo 'graphlog =' >> $HGRCPATH
$ glog()
> {
- > hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
+ > hg glog --template '{rev}:{node|short} "{desc|firstline}"\
+ > files: {files}\n' "$@"
> }
$ hg init repo1
$ cd repo1
@@ -21,6 +22,14 @@
adding c
$ PARENTID2=`hg id --debug -i`
$ cd ..
+ $ glog -R repo1
+ @ 2:e55c719b85b6 "addc" files: c
+ |
+ o 1:6d4c2037ddc2 "addb" files: a b
+ |
+ o 0:07f494440405 "adda" files: a
+
+
$ hg init repo2
$ cd repo2
$ echo b > a
@@ -36,6 +45,13 @@
$ hg ci -Am adde
adding e
$ cd ..
+ $ glog -R repo2
+ @ 2:a39b65753b0a "adde" files: e
+ |
+ o 1:e4ea00df9189 "changed" files: d
+ |
+ o 0:527cdedf31fb "addaandd" files: a d
+
test invalid splicemap
@@ -49,9 +65,12 @@
splice repo2 on repo1
$ cat > splicemap <<EOF
- > $CHILDID1 $PARENTID1
+ > $CHILDID1 $PARENTID1
> $CHILDID2 $PARENTID2,$CHILDID1
> EOF
+ $ cat splicemap
+ 527cdedf31fbd5ea708aa14eeecf53d4676f38db 6d4c2037ddc2cb2627ac3a244ecce35283268f8e
+ e4ea00df91897da3079a10fab658c1eddba6617b e55c719b85b60e5102fac26110ba626e7cb6b7dc,527cdedf31fbd5ea708aa14eeecf53d4676f38db
$ hg clone repo1 target1
updating to branch default
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -65,15 +84,137 @@
spliced in ['e55c719b85b60e5102fac26110ba626e7cb6b7dc', '527cdedf31fbd5ea708aa14eeecf53d4676f38db'] as parents of e4ea00df91897da3079a10fab658c1eddba6617b
0 adde
$ glog -R target1
- o 5 "adde" files: e
+ o 5:16bc847b02aa "adde" files: e
+ |
+ o 4:e30e4fee3418 "changed" files: d
+ |\
+ | o 3:e673348c3a3c "addaandd" files: a d
+ | |
+ @ | 2:e55c719b85b6 "addc" files: c
+ |/
+ o 1:6d4c2037ddc2 "addb" files: a b
|
- o 4 "changed" files: d
+ o 0:07f494440405 "adda" files: a
+
+
+
+
+Test splicemap and conversion order
+
+ $ hg init ordered
+ $ cd ordered
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ hg branch branch
+ marked working directory as branch branch
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a >> a
+ $ hg ci -Am changea
+ $ echo a >> a
+ $ hg ci -Am changeaagain
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b > b
+ $ hg ci -Am addb
+ adding b
+
+We want 2 to depend on 1 and 3. Since 3 is always converted after 2,
+the bug should be exhibited with all conversion orders.
+
+ $ cat > ../splicemap <<EOF
+ > $(hg id -r 2 -i --debug) $(hg id -r 1 -i --debug),$(hg id -r 3 -i --debug)
+ > EOF
+ $ cd ..
+ $ cat splicemap
+ 7c364e7fa7d70ae525610c016317ed717b519d97 717d54d67e6c31fd75ffef2ff3042bdd98418437,102a90ea7b4a3361e4082ed620918c261189a36a
+
+Test regular conversion
+
+ $ hg convert --splicemap splicemap ordered ordered-hg1
+ initializing destination ordered-hg1 repository
+ scanning source...
+ sorting...
+ converting...
+ 3 adda
+ 2 changea
+ 1 addb
+ 0 changeaagain
+ spliced in ['717d54d67e6c31fd75ffef2ff3042bdd98418437', '102a90ea7b4a3361e4082ed620918c261189a36a'] as parents of 7c364e7fa7d70ae525610c016317ed717b519d97
+ $ glog -R ordered-hg1
+ o 3:4cb04b9afbf2 "changeaagain" files: a
|\
- | o 3 "addaandd" files: a d
+ | o 2:102a90ea7b4a "addb" files: b
| |
- @ | 2 "addc" files: c
+ o | 1:717d54d67e6c "changea" files: a
|/
- o 1 "addb" files: a b
- |
- o 0 "adda" files: a
+ o 0:07f494440405 "adda" files: a
+
+Test conversion with parent revisions already in dest, using source
+and destination identifiers. Test unknown splicemap target.
+
+ $ hg convert -r1 ordered ordered-hg2
+ initializing destination ordered-hg2 repository
+ scanning source...
+ sorting...
+ converting...
+ 1 adda
+ 0 changea
+ $ hg convert -r3 ordered ordered-hg2
+ scanning source...
+ sorting...
+ converting...
+ 0 addb
+ $ cat > splicemap <<EOF
+ > $(hg -R ordered id -r 2 -i --debug) \
+ > $(hg -R ordered-hg2 id -r 1 -i --debug),\
+ > $(hg -R ordered-hg2 id -r 2 -i --debug)
+ > deadbeef102a90ea7b4a3361e4082ed620918c26 deadbeef102a90ea7b4a3361e4082ed620918c27
+ > EOF
+ $ hg convert --splicemap splicemap ordered ordered-hg2
+ scanning source...
+ splice map revision deadbeef102a90ea7b4a3361e4082ed620918c26 is not being converted, ignoring
+ sorting...
+ converting...
+ 0 changeaagain
+ spliced in ['717d54d67e6c31fd75ffef2ff3042bdd98418437', '102a90ea7b4a3361e4082ed620918c261189a36a'] as parents of 7c364e7fa7d70ae525610c016317ed717b519d97
+ $ glog -R ordered-hg2
+ o 3:4cb04b9afbf2 "changeaagain" files: a
+ |\
+ | o 2:102a90ea7b4a "addb" files: b
+ | |
+ o | 1:717d54d67e6c "changea" files: a
+ |/
+ o 0:07f494440405 "adda" files: a
+
+
+Test empty conversion
+
+ $ hg convert --splicemap splicemap ordered ordered-hg2
+ scanning source...
+ splice map revision deadbeef102a90ea7b4a3361e4082ed620918c26 is not being converted, ignoring
+ sorting...
+ converting...
+
+Test clonebranches
+
+ $ hg --config convert.hg.clonebranches=true convert \
+ > --splicemap splicemap ordered ordered-hg3
+ initializing destination ordered-hg3 repository
+ scanning source...
+ abort: revision 717d54d67e6c31fd75ffef2ff3042bdd98418437 not be found in destination repository (lookups with clonebranches=true are not implemented)
+ [255]
+
+Test invalid dependency
+
+ $ cat > splicemap <<EOF
+ > $(hg -R ordered id -r 2 -i --debug) \
+ > deadbeef102a90ea7b4a3361e4082ed620918c26,\
+ > $(hg -R ordered-hg2 id -r 2 -i --debug)
+ > EOF
+ $ hg convert --splicemap splicemap ordered ordered-hg4
+ initializing destination ordered-hg4 repository
+ scanning source...
+ abort: unknown splice map parent: deadbeef102a90ea7b4a3361e4082ed620918c26
+ [255]