diff --git a/hgext/narrow/narrowbundle2.py b/hgext/narrow/narrowbundle2.py --- a/hgext/narrow/narrowbundle2.py +++ b/hgext/narrow/narrowbundle2.py @@ -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 diff --git a/hgext/narrow/narrowcommands.py b/hgext/narrow/narrowcommands.py --- a/hgext/narrow/narrowcommands.py +++ b/hgext/narrow/narrowcommands.py @@ -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()} diff --git a/hgext/narrow/narrowwirepeer.py b/hgext/narrow/narrowwirepeer.py --- a/hgext/narrow/narrowwirepeer.py +++ b/hgext/narrow/narrowwirepeer.py @@ -8,14 +8,22 @@ from __future__ import absolute_import from mercurial import ( + bundle2, extensions, hg, + match as matchmod, + narrowspec, 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 +45,65 @@ return orig(cmd, *args, **kwargs) extensions.wrapfunction(peer, '_calltwowaystream', wrapped) hg.wirepeersetupfuncs.append(wirereposetup) + +@wireprotov1server.wireprotocommand('narrow_widen', '*', permission='pull') +def narrow_widen(repo, proto, args): + """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 + """ + + oldincludes = wireprototypes.decodelist(args.get('oldincludes')) + newincludes = wireprototypes.decodelist(args.get('newincludes')) + oldexcludes = wireprototypes.decodelist(args.get('oldexcludes')) + newexcludes = wireprototypes.decodelist(args.get('newexcludes')) + # validate the patterns + narrowspec.validatepatterns(set(oldincludes)) + narrowspec.validatepatterns(set(newincludes)) + narrowspec.validatepatterns(set(oldexcludes)) + narrowspec.validatepatterns(set(newexcludes)) + + common = wireprototypes.decodelist(args.get('commonheads')) + known = None + if args.get('known'): + known = wireprototypes.decodelist(args.get('known')) + if args.get('ellipses') == '0': + ellipses = False + else: + ellipses = bool(args.get('ellipses')) + cgversion = args.get('cgversion') + newmatch = narrowspec.match(repo.root, include=newincludes, + exclude=newexcludes) + oldmatch = narrowspec.match(repo.root, include=oldincludes, + exclude=oldexcludes) + diffmatch = matchmod.differencematcher(newmatch, oldmatch) + + bundler = bundle2.bundle20(repo.ui) + # 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') + 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) diff --git a/tests/test-narrow-widen-no-ellipsis.t b/tests/test-narrow-widen-no-ellipsis.t --- a/tests/test-narrow-widen-no-ellipsis.t +++ b/tests/test-narrow-widen-no-ellipsis.t @@ -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