narrow: use narrow_widen wireproto command to widen in case of ellipses
Few releases ago, we introduce narrow_widen wireproto command to be used to widen
narrow repositories. Before this patch, that was used in non-ellipses cases
only. In ellipses cases, we still do exchange.pull() which can pull more data
than required.
After this patch, the client will first check whether server supports doing
ellipses widening using wireproto command or not by checking server's wireproto
capability. If the server is upto date and support latest ellipses capability,
we call the wireproto command. Otherwise we fallback to exchange.pull() like
before.
The compat code make sure that things works even if one of the client or server
is old. The initial version of this patch does not had this compat code. It's
added to help Google release things smoothly internally. I plan to drop the
compat code before the upcoming major release.
Due to change to wireproto command, the code looks a bit dirty, next patches
will clean that up.
Differential Revision: https://phab.mercurial-scm.org/D6436
# narrowwirepeer.py - passes narrow spec with unbundle command
#
# Copyright 2017 Google, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
from mercurial import (
bundle2,
error,
extensions,
hg,
narrowspec,
node as nodemod,
pycompat,
wireprototypes,
wireprotov1peer,
wireprotov1server,
)
from . import narrowbundle2
def uisetup():
wireprotov1peer.wirepeer.narrow_widen = peernarrowwiden
def reposetup(repo):
def wirereposetup(ui, peer):
def wrapped(orig, cmd, *args, **kwargs):
if cmd == 'unbundle':
# TODO: don't blindly add include/exclude wireproto
# arguments to unbundle.
include, exclude = repo.narrowpats
kwargs[r"includepats"] = ','.join(include)
kwargs[r"excludepats"] = ','.join(exclude)
return orig(cmd, *args, **kwargs)
extensions.wrapfunction(peer, '_calltwowaystream', wrapped)
hg.wirepeersetupfuncs.append(wirereposetup)
@wireprotov1server.wireprotocommand('narrow_widen', 'oldincludes oldexcludes'
' newincludes newexcludes'
' commonheads cgversion'
' known ellipses',
permission='pull')
def narrow_widen(repo, proto, oldincludes, oldexcludes, newincludes,
newexcludes, commonheads, cgversion, known, ellipses):
"""wireprotocol command to send data when a narrow clone is widen. We will
be sending a changegroup here.
The current set of arguments which are required:
oldincludes: the old includes of the narrow copy
oldexcludes: the old excludes of the narrow copy
newincludes: the new includes of the narrow copy
newexcludes: the new excludes of the narrow copy
commonheads: list of heads which are common between the server and client
cgversion(maybe): the changegroup version to produce
known: list of nodes which are known on the client (used in ellipses cases)
ellipses: whether to send ellipses data or not
"""
preferuncompressed = False
try:
oldincludes = wireprototypes.decodelist(oldincludes)
newincludes = wireprototypes.decodelist(newincludes)
oldexcludes = wireprototypes.decodelist(oldexcludes)
newexcludes = wireprototypes.decodelist(newexcludes)
# validate the patterns
narrowspec.validatepatterns(set(oldincludes))
narrowspec.validatepatterns(set(newincludes))
narrowspec.validatepatterns(set(oldexcludes))
narrowspec.validatepatterns(set(newexcludes))
common = wireprototypes.decodelist(commonheads)
known = wireprototypes.decodelist(known)
known = {nodemod.bin(n) for n in known}
if ellipses == '0':
ellipses = False
else:
ellipses = bool(ellipses)
cgversion = cgversion
if not ellipses:
newmatch = narrowspec.match(repo.root, include=newincludes,
exclude=newexcludes)
oldmatch = narrowspec.match(repo.root, include=oldincludes,
exclude=oldexcludes)
bundler = bundle2.widen_bundle(repo, oldmatch, newmatch, common,
known, cgversion, ellipses)
else:
bundler = bundle2.bundle20(repo.ui)
narrowbundle2.generateellipsesbundle2(bundler, repo, oldincludes,
oldexcludes, newincludes, newexcludes, cgversion, common,
list(common), known, None)
except error.Abort as exc:
bundler = bundle2.bundle20(repo.ui)
manargs = [('message', pycompat.bytestr(exc))]
advargs = []
if exc.hint is not None:
advargs.append(('hint', exc.hint))
bundler.addpart(bundle2.bundlepart('error:abort', manargs, advargs))
preferuncompressed = True
chunks = bundler.getchunks()
return wireprototypes.streamres(gen=chunks,
prefer_uncompressed=preferuncompressed)
def peernarrowwiden(remote, **kwargs):
for ch in (r'oldincludes', r'newincludes', r'oldexcludes', r'newexcludes',
r'commonheads', r'known'):
kwargs[ch] = wireprototypes.encodelist(kwargs[ch])
kwargs[r'ellipses'] = '%i' % bool(kwargs[r'ellipses'])
f = remote._callcompressable('narrow_widen', **kwargs)
return bundle2.getunbundler(remote.ui, f)