[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