[PATCH 4 of 4] bundle2: allow pulling changegroup using bundle2

pierre-yves.david at ens-lyon.org pierre-yves.david at ens-lyon.org
Fri Apr 4 17:29:41 CDT 2014


# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at fb.com>
# Date 1396420892 25200
#      Tue Apr 01 23:41:32 2014 -0700
# Node ID 2c63384c28de4086080165b8f11da11b8fb5d476
# Parent  7d8624d40967bb222986f5dbad9ebc2e11464fa4
bundle2: allow pulling changegroup using bundle2

This changeset refactor the pull code to use a bundle2 when available. We keep
bundle2 disable 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.

diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -5,13 +5,14 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
 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):
     """A object that represent a single push operation
 
@@ -453,10 +454,12 @@ def pull(repo, remote, heads=None, force
             raise util.Abort(msg)
 
     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:
             _pullphase(pullop)
         if 'obsmarkers' in pullop.todosteps:
@@ -477,10 +480,35 @@ def _pulldiscovery(pullop):
                                        pullop.remote,
                                        heads=pullop.heads,
                                        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
     # don't open transaction for nothing or you break future useful
     # rollback call
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -60,11 +60,12 @@ def unfilteredmethod(orig):
     """decorate method that always need to be run on unfiltered version"""
     def wrapper(repo, *args, **kwargs):
         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):
     '''peer for a local repo; reflects only the most recent API'''
 
@@ -274,10 +275,15 @@ class localrepository(object):
 
     def close(self):
         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):
         self.requirements = requirements
         self.sopener.options = dict((r, 1) for r in requirements
diff --git a/tests/test-bundle2.t b/tests/test-bundle2.t
--- a/tests/test-bundle2.t
+++ b/tests/test-bundle2.t
@@ -140,10 +140,12 @@ Create an extension to test bundle2 API
   >         ui.write('    payload: %i bytes\n' % len(p.data))
   > EOF
   $ cat >> $HGRCPATH << EOF
   > [extensions]
   > bundle2=$TESTTMP/bundle2.py
+  > [server]
+  > bundle2=True
   > EOF
 
 The extension requires a repo (currently unused)
 
   $ hg init main
@@ -558,5 +560,43 @@ Support for changegroup
   adding manifests
   adding file changes
   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 at gmail.com>
+  |  date:        Sat Apr 30 15:24:48 2011 +0200
+  |  summary:     E
+  |
+  o  changeset:   0:cd010b8cd998
+     user:        Nicolas Dumazet <nicdumz.commits at 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)


More information about the Mercurial-devel mailing list