bundle2: allow pulling changegroups using bundle2
authorPierre-Yves David <pierre-yves.david@fb.com>
Tue, 01 Apr 2014 23:41:32 -0700
changeset 20955 12f161f08d74
parent 20954 dba91f8060eb
child 20956 dbf0fa39a5b8
bundle2: allow pulling changegroups using bundle2 This changeset refactors the pull code to use a bundle2 when available. We keep bundle2 disabled by default. The current code is not ready for prime time. Ultimately we'll want to unify the API of `bunde10` and `bundle20` to have less different code. But for now, testing the bundle2 exchange flow is an higher priority.
mercurial/exchange.py
mercurial/localrepo.py
tests/test-bundle2.t
--- a/mercurial/exchange.py	Fri Apr 04 01:51:54 2014 -0700
+++ b/mercurial/exchange.py	Tue Apr 01 23:41:32 2014 -0700
@@ -7,9 +7,10 @@
 
 from i18n import _
 from node import hex, nullid
+import cStringIO
 import errno
 import util, scmutil, changegroup, base85
-import discovery, phases, obsolete, bookmarks
+import discovery, phases, obsolete, bookmarks, bundle2
 
 
 class pushoperation(object):
@@ -455,6 +456,8 @@
     lock = pullop.repo.lock()
     try:
         _pulldiscovery(pullop)
+        if pullop.remote.capable('bundle2'):
+            _pullbundle2(pullop)
         if 'changegroup' in pullop.todosteps:
             _pullchangeset(pullop)
         if 'phases' in pullop.todosteps:
@@ -479,6 +482,31 @@
                                        force=pullop.force)
     pullop.common, pullop.fetch, pullop.rheads = tmp
 
+def _pullbundle2(pullop):
+    """pull data using bundle2
+
+    For now, the only supported data are changegroup."""
+    kwargs = {'bundlecaps': set(['HG20'])}
+    # pulling changegroup
+    pullop.todosteps.remove('changegroup')
+    if not pullop.fetch:
+            pullop.repo.ui.status(_("no changes found\n"))
+            pullop.cgresult = 0
+    else:
+        kwargs['common'] = pullop.common
+        kwargs['heads'] = pullop.heads or pullop.rheads
+        if pullop.heads is None and list(pullop.common) == [nullid]:
+            pullop.repo.ui.status(_("requesting all changes\n"))
+    if kwargs.keys() == ['format']:
+        return # nothing to pull
+    bundle = pullop.remote.getbundle('pull', **kwargs)
+    try:
+        op = bundle2.processbundle(pullop.repo, bundle, pullop.gettransaction)
+    except KeyError, exc:
+        raise util.Abort('missing support for %s' % exc)
+    assert len(op.records['changegroup']) == 1
+    pullop.cgresult = op.records['changegroup'][0]['return']
+
 def _pullchangeset(pullop):
     """pull changeset from unbundle into the local repo"""
     # We delay the open of the transaction as late as possible so we
--- a/mercurial/localrepo.py	Fri Apr 04 01:51:54 2014 -0700
+++ b/mercurial/localrepo.py	Tue Apr 01 23:41:32 2014 -0700
@@ -62,7 +62,8 @@
         return orig(repo.unfiltered(), *args, **kwargs)
     return wrapper
 
-moderncaps = set(('lookup', 'branchmap', 'pushkey', 'known', 'getbundle'))
+moderncaps = set(('lookup', 'branchmap', 'pushkey', 'known', 'getbundle',
+                  'bundle2'))
 legacycaps = moderncaps.union(set(['changegroupsubset']))
 
 class localpeer(peer.peerrepository):
@@ -276,6 +277,11 @@
         pass
 
     def _restrictcapabilities(self, caps):
+        # bundle2 is not ready for prime time, drop it unless explicitly
+        # required by the tests (or some brave tester)
+        if not self.ui.configbool('server', 'bundle2', False):
+            caps = set(caps)
+            caps.remove('bundle2')
         return caps
 
     def _applyrequirements(self, requirements):
--- a/tests/test-bundle2.t	Fri Apr 04 01:51:54 2014 -0700
+++ b/tests/test-bundle2.t	Tue Apr 01 23:41:32 2014 -0700
@@ -142,6 +142,8 @@
   $ cat >> $HGRCPATH << EOF
   > [extensions]
   > bundle2=$TESTTMP/bundle2.py
+  > [server]
+  > bundle2=True
   > EOF
 
 The extension requires a repo (currently unused)
@@ -560,3 +562,41 @@
   added 0 changesets with 0 changes to 3 files
   0 unread bytes
   addchangegroup return: 1
+
+Real world exchange
+=====================
+
+
+clone --pull
+
+  $ cd ..
+  $ hg clone main other --pull --rev 9520eea781bc
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg -R other log -G
+  @  changeset:   1:9520eea781bc
+  |  tag:         tip
+  |  user:        Nicolas Dumazet <nicdumz.commits@gmail.com>
+  |  date:        Sat Apr 30 15:24:48 2011 +0200
+  |  summary:     E
+  |
+  o  changeset:   0:cd010b8cd998
+     user:        Nicolas Dumazet <nicdumz.commits@gmail.com>
+     date:        Sat Apr 30 15:24:48 2011 +0200
+     summary:     A
+  
+
+pull
+
+  $ hg -R other pull
+  pulling from $TESTTMP/main (glob)
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 7 changesets with 6 changes to 6 files (+3 heads)
+  (run 'hg heads' to see heads, 'hg merge' to merge)