convert: use splicemap entries when sorting revisions (issue1748) stable
authorPatrick Mezard <patrick@mezard.eu>
Fri, 10 Feb 2012 22:34:13 +0100
branchstable
changeset 16106 d75aa756149b
parent 16105 ebaa0aa749e2
child 16107 a3dcc59054ca
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.
hgext/convert/common.py
hgext/convert/convcmd.py
hgext/convert/hg.py
hgext/convert/subversion.py
tests/test-convert-splicemap.t
--- 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]