narrow: the first version of narrow_widen wireprotocol command
This patch introduces a wireprotocol command narrow_widen() which will be used
to widen a narrow copy using `hg tracked` command provided by narrow extension.
The wireprotocol command takes the old and new includes and excludes, common
heads, changegroup version, known revs, and a boolean ellipses and generates a
bundle2 of the required data and send it. The clients receives the bundle2
and applies that.
A bundle2 instead of changegroup because in future we might want to add more
things to send while widening. Thanks for martinvonz for the suggestion.
I am not sure whether we need changegroup version as an argument to the command
as I *think* narrow needs changegroup3 already.
The tests shows that we don't exchange phase data now while widening which is
nice. Also we don't check for pushkeys, rbc-cache, bookmarks etc.
This does not support ellipses cases for now but will be supported in future
patches. Since we send bundle2, it won't be hard to plug the ellipses logic in
here.
The existing code for widening a non-ellipses case is also dropped in this
patch.
Differential Revision: https://phab.mercurial-scm.org/D4813
--- a/hgext/narrow/narrowbundle2.py Fri Oct 05 21:43:57 2018 +0900
+++ b/hgext/narrow/narrowbundle2.py Fri Sep 28 23:42:31 2018 +0300
@@ -21,7 +21,6 @@
error,
exchange,
extensions,
- match as matchmod,
narrowspec,
repair,
repository,
@@ -57,7 +56,7 @@
repo is the localrepository instance
diffmatcher is a differencemacther of '(newincludes, newexcludes) -
(oldincludes, oldexcludes)'
- common is set of common revs between server and client
+ common is set of common heads between server and client
known is a set of revs known on the client side (used in ellipses)
cgversion is the changegroup version to send
ellipses is boolean value telling whether to send ellipses data or not
@@ -84,41 +83,6 @@
return None
-def getbundlechangegrouppart_widen(bundler, repo, source, bundlecaps=None,
- b2caps=None, heads=None, common=None,
- **kwargs):
- """Handling changegroup changegroup generation on the server when user
- is widening their narrowspec"""
-
- cgversions = b2caps.get('changegroup')
- if cgversions: # 3.1 and 3.2 ship with an empty value
- cgversions = [v for v in cgversions
- if v in changegroup.supportedoutgoingversions(repo)]
- if not cgversions:
- raise ValueError(_('no common changegroup version'))
- version = max(cgversions)
- else:
- raise ValueError(_("server does not advertise changegroup version,"
- " can't negotiate support for ellipsis nodes"))
-
- include = sorted(filter(bool, kwargs.get(r'includepats', [])))
- exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
- newmatch = narrowspec.match(repo.root, include=include, exclude=exclude)
- oldinclude = sorted(filter(bool, kwargs.get(r'oldincludepats', [])))
- oldexclude = sorted(filter(bool, kwargs.get(r'oldexcludepats', [])))
- oldmatch = narrowspec.match(repo.root, include=oldinclude,
- exclude=oldexclude)
- diffmatch = matchmod.differencematcher(newmatch, oldmatch)
- common = set(common or [nullid])
-
- if (oldinclude != include or oldexclude != exclude):
- cgdata = widen_bundle(repo, diffmatch, common, [], version, False)
- if cgdata is not None:
- part = bundler.newpart('changegroup', data=cgdata)
- part.addparam('version', version)
- if 'treemanifest' in repo.requirements:
- part.addparam('treemanifest', '1')
-
# Serve a changegroup for a client with a narrow clone.
def getbundlechangegrouppart_narrow(bundler, repo, source,
bundlecaps=None, b2caps=None, heads=None,
@@ -326,7 +290,6 @@
getbundleargs = wireprototypes.GETBUNDLE_ARGUMENTS
getbundleargs['narrow'] = 'boolean'
- getbundleargs['widen'] = 'boolean'
getbundleargs['depth'] = 'plain'
getbundleargs['oldincludepats'] = 'csv'
getbundleargs['oldexcludepats'] = 'csv'
@@ -344,8 +307,6 @@
if (kwargs.get(r'narrow', False) and
repo.ui.configbool('experimental', 'narrowservebrokenellipses')):
getbundlechangegrouppart_narrow(*args, **kwargs)
- elif kwargs.get(r'widen', False) and kwargs.get(r'narrow', False):
- getbundlechangegrouppart_widen(*args, **kwargs)
else:
origcgfn(*args, **kwargs)
exchange.getbundle2partsmapping['changegroup'] = wrappedcgfn
--- a/hgext/narrow/narrowcommands.py Fri Oct 05 21:43:57 2018 +0900
+++ b/hgext/narrow/narrowcommands.py Fri Sep 28 23:42:31 2018 +0300
@@ -11,6 +11,7 @@
from mercurial.i18n import _
from mercurial import (
+ bundle2,
cmdutil,
commands,
discovery,
@@ -265,7 +266,6 @@
# The old{in,ex}cludepats have already been set by orig()
kwargs['includepats'] = newincludes
kwargs['excludepats'] = newexcludes
- kwargs['widen'] = True
wrappedextraprepare = extensions.wrappedfunction(exchange,
'_pullbundle2extraprepare', pullbundle2extraprepare_widen)
@@ -290,9 +290,23 @@
with ds.parentchange():
ds.setparents(p1, p2)
else:
- with wrappedextraprepare,\
+ with remote.commandexecutor() as e:
+ bundle = e.callcommand('narrow_widen', {
+ 'oldincludes': oldincludes,
+ 'oldexcludes': oldexcludes,
+ 'newincludes': newincludes,
+ 'newexcludes': newexcludes,
+ 'cgversion': '03',
+ 'commonheads': common,
+ 'known': [],
+ 'ellipses': False,
+ }).result()
+
+ with repo.transaction('widening') as tr,\
repo.ui.configoverride(overrides, 'widen'):
- exchange.pull(repo, remote, heads=common)
+ tgetter = lambda: tr
+ bundle2.processbundle(repo, bundle,
+ transactiongetter=tgetter)
repo.setnewnarrowpats()
actions = {k: [] for k in 'a am f g cd dc r dm dg m e k p pr'.split()}
--- a/hgext/narrow/narrowwirepeer.py Fri Oct 05 21:43:57 2018 +0900
+++ b/hgext/narrow/narrowwirepeer.py Fri Sep 28 23:42:31 2018 +0300
@@ -8,14 +8,24 @@
from __future__ import absolute_import
from mercurial import (
+ bundle2,
+ error,
extensions,
hg,
+ match as matchmod,
+ narrowspec,
+ pycompat,
wireprotoserver,
+ wireprototypes,
+ wireprotov1peer,
wireprotov1server,
)
+from . import narrowbundle2
+
def uisetup():
extensions.wrapfunction(wireprotov1server, '_capabilities', addnarrowcap)
+ wireprotov1peer.wirepeer.narrow_widen = peernarrowwiden
def addnarrowcap(orig, repo, proto):
"""add the narrow capability to the server"""
@@ -37,3 +47,78 @@
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
+ """
+
+ bundler = bundle2.bundle20(repo.ui)
+ 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 = None
+ if known:
+ known = wireprototypes.decodelist(known)
+ if ellipses == '0':
+ ellipses = False
+ else:
+ ellipses = bool(ellipses)
+ cgversion = cgversion
+ newmatch = narrowspec.match(repo.root, include=newincludes,
+ exclude=newexcludes)
+ oldmatch = narrowspec.match(repo.root, include=oldincludes,
+ exclude=oldexcludes)
+ diffmatch = matchmod.differencematcher(newmatch, oldmatch)
+
+ # get changegroup data
+ cg = narrowbundle2.widen_bundle(repo, diffmatch, common, known,
+ cgversion, ellipses)
+ if cg is not None:
+ part = bundler.newpart('changegroup', data=cg)
+ part.addparam('version', cgversion)
+ if 'treemanifest' in repo.requirements:
+ part.addparam('treemanifest', '1')
+ except error.Abort as exc:
+ 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))
+
+ chunks = bundler.getchunks()
+ return wireprototypes.streamres(gen=chunks)
+
+def peernarrowwiden(remote, **kwargs):
+ for ch in ('oldincludes', 'newincludes', 'oldexcludes', 'newexcludes',
+ 'commonheads', 'known'):
+ kwargs[ch] = wireprototypes.encodelist(kwargs[ch])
+
+ kwargs['ellipses'] = '%i' % bool(kwargs['ellipses'])
+ f = remote._callcompressable('narrow_widen', **kwargs)
+ return bundle2.getunbundler(remote.ui, f)
--- a/tests/test-narrow-widen-no-ellipsis.t Fri Oct 05 21:43:57 2018 +0900
+++ b/tests/test-narrow-widen-no-ellipsis.t Fri Sep 28 23:42:31 2018 +0300
@@ -104,8 +104,7 @@
sending batch command
searching for changes
all local heads known remotely
- no changes found
- sending getbundle command
+ sending narrow_widen command
bundle2-input-bundle: with-transaction
bundle2-input-part: "changegroup" (params: * mandatory) supported (glob)
adding changesets
@@ -115,12 +114,7 @@
adding widest/f revisions (tree !)
added 0 changesets with 1 changes to 1 files
bundle2-input-part: total payload size * (glob)
- bundle2-input-part: "listkeys" (params: 1 mandatory) supported
- bundle2-input-part: "phase-heads" supported
- bundle2-input-part: total payload size 24
- bundle2-input-bundle: 2 parts total
- checking for updated bookmarks
- 3 local changesets published
+ bundle2-input-bundle: 0 parts total
widest/f: add from widened narrow clone -> g
getting widest/f
$ hg tracked
@@ -143,6 +137,7 @@
adding file changes
added 5 changesets with 4 changes to 2 files
new changesets *:* (glob)
+ 3 local changesets published
(run 'hg update' to get a working copy)
$ hg update -r 'desc("add wider")'
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -179,12 +174,10 @@
$ hg tracked --addinclude wider
comparing with ssh://user@dummy/master
searching for changes
- no changes found
adding changesets
adding manifests
adding file changes
added 0 changesets with 1 changes to 1 files
- 5 local changesets published
$ hg tracked
I path:inside
I path:wider
@@ -284,12 +277,10 @@
$ hg tracked --addinclude d1
comparing with ssh://user@dummy/upstream
searching for changes
- no changes found
adding changesets
adding manifests
adding file changes
added 0 changesets with 1 changes to 1 files
- 11 local changesets published
$ hg tracked
I path:d0
I path:d1
@@ -376,12 +367,10 @@
$ hg --config hooks.pretxnchangegroup.bad=false tracked --addinclude d1
comparing with ssh://user@dummy/upstream
searching for changes
- no changes found
adding changesets
adding manifests
adding file changes
added 0 changesets with 1 changes to 1 files
- 11 local changesets published
$ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
11: local
10: add d10/f