# HG changeset patch # User Raphaël Gomès # Date 1638891862 -3600 # Node ID 04688c51f81f417b6a69548b9413985b0220892a # Parent d6c53b40b078b4aa659b1e18ee237ab8c1041dfe exchangev2: remove it As discussed on the mailing list, this is incomplete and unused with little hope of revival. Differential Revision: https://phab.mercurial-scm.org/D11954 diff -r d6c53b40b078 -r 04688c51f81f mercurial/configitems.py --- a/mercurial/configitems.py Thu Dec 30 13:25:44 2021 +0100 +++ b/mercurial/configitems.py Tue Dec 07 16:44:22 2021 +0100 @@ -1102,16 +1102,6 @@ ) coreconfigitem( b'experimental', - b'httppeer.advertise-v2', - default=False, -) -coreconfigitem( - b'experimental', - b'httppeer.v2-encoder-order', - default=None, -) -coreconfigitem( - b'experimental', b'httppostargs', default=False, ) @@ -1211,11 +1201,6 @@ ) coreconfigitem( b'experimental', - b'sshserver.support-v2', - default=False, -) -coreconfigitem( - b'experimental', b'sparse-read', default=False, ) @@ -1241,26 +1226,6 @@ ) coreconfigitem( b'experimental', - b'sshpeer.advertise-v2', - default=False, -) -coreconfigitem( - b'experimental', - b'web.apiserver', - default=False, -) -coreconfigitem( - b'experimental', - b'web.api.http-v2', - default=False, -) -coreconfigitem( - b'experimental', - b'web.api.debugreflect', - default=False, -) -coreconfigitem( - b'experimental', b'web.full-garbage-collection-rate', default=1, # still forcing a full collection on each request ) diff -r d6c53b40b078 -r 04688c51f81f mercurial/debugcommands.py --- a/mercurial/debugcommands.py Thu Dec 30 13:25:44 2021 +0100 +++ b/mercurial/debugcommands.py Tue Dec 07 16:44:22 2021 +0100 @@ -91,7 +91,6 @@ vfs as vfsmod, wireprotoframing, wireprotoserver, - wireprotov2peer, ) from .interfaces import repository from .utils import ( @@ -4352,8 +4351,8 @@ ``--peer`` can be used to bypass the handshake protocol and construct a peer instance using the specified class type. Valid values are ``raw``, - ``http2``, ``ssh1``, and ``ssh2``. ``raw`` instances only allow sending - raw data payloads and don't support higher-level command actions. + ``ssh1``. ``raw`` instances only allow sending raw data payloads and + don't support higher-level command actions. ``--noreadstderr`` can be used to disable automatic reading from stderr of the peer (for SSH connections only). Disabling automatic reading of @@ -4528,13 +4527,11 @@ if opts[b'peer'] and opts[b'peer'] not in ( b'raw', - b'http2', b'ssh1', - b'ssh2', ): raise error.Abort( _(b'invalid value for --peer'), - hint=_(b'valid values are "raw", "ssh1", and "ssh2"'), + hint=_(b'valid values are "raw" and "ssh1"'), ) if path and opts[b'localssh']: @@ -4602,18 +4599,6 @@ None, autoreadstderr=autoreadstderr, ) - elif opts[b'peer'] == b'ssh2': - ui.write(_(b'creating ssh peer for wire protocol version 2\n')) - peer = sshpeer.sshv2peer( - ui, - url, - proc, - stdin, - stdout, - stderr, - None, - autoreadstderr=autoreadstderr, - ) elif opts[b'peer'] == b'raw': ui.write(_(b'using raw connection to peer\n')) peer = None @@ -4666,34 +4651,7 @@ opener = urlmod.opener(ui, authinfo, **openerargs) - if opts[b'peer'] == b'http2': - ui.write(_(b'creating http peer for wire protocol version 2\n')) - # We go through makepeer() because we need an API descriptor for - # the peer instance to be useful. - maybe_silent = ( - ui.silent() - if opts[b'nologhandshake'] - else util.nullcontextmanager() - ) - with maybe_silent, ui.configoverride( - {(b'experimental', b'httppeer.advertise-v2'): True} - ): - peer = httppeer.makepeer(ui, path, opener=opener) - - if not isinstance(peer, httppeer.httpv2peer): - raise error.Abort( - _( - b'could not instantiate HTTP peer for ' - b'wire protocol version 2' - ), - hint=_( - b'the server may not have the feature ' - b'enabled or is not allowing this ' - b'client version' - ), - ) - - elif opts[b'peer'] == b'raw': + if opts[b'peer'] == b'raw': ui.write(_(b'using raw connection to peer\n')) peer = None elif opts[b'peer']: @@ -4774,17 +4732,10 @@ with peer.commandexecutor() as e: res = e.callcommand(command, args).result() - if isinstance(res, wireprotov2peer.commandresponse): - val = res.objects() - ui.status( - _(b'response: %s\n') - % stringutil.pprint(val, bprefix=True, indent=2) - ) - else: - ui.status( - _(b'response: %s\n') - % stringutil.pprint(res, bprefix=True, indent=2) - ) + ui.status( + _(b'response: %s\n') + % stringutil.pprint(res, bprefix=True, indent=2) + ) elif action == b'batchbegin': if batchedcommands is not None: diff -r d6c53b40b078 -r 04688c51f81f mercurial/exchange.py --- a/mercurial/exchange.py Thu Dec 30 13:25:44 2021 +0100 +++ b/mercurial/exchange.py Tue Dec 07 16:44:22 2021 +0100 @@ -22,7 +22,6 @@ changegroup, discovery, error, - exchangev2, lock as lockmod, logexchange, narrowspec, @@ -1666,21 +1665,17 @@ ): add_confirm_callback(repo, pullop) - # Use the modern wire protocol, if available. - if remote.capable(b'command-changesetdata'): - exchangev2.pull(pullop) - else: - # This should ideally be in _pullbundle2(). However, it needs to run - # before discovery to avoid extra work. - _maybeapplyclonebundle(pullop) - streamclone.maybeperformlegacystreamclone(pullop) - _pulldiscovery(pullop) - if pullop.canusebundle2: - _fullpullbundle2(repo, pullop) - _pullchangeset(pullop) - _pullphase(pullop) - _pullbookmarks(pullop) - _pullobsolete(pullop) + # This should ideally be in _pullbundle2(). However, it needs to run + # before discovery to avoid extra work. + _maybeapplyclonebundle(pullop) + streamclone.maybeperformlegacystreamclone(pullop) + _pulldiscovery(pullop) + if pullop.canusebundle2: + _fullpullbundle2(repo, pullop) + _pullchangeset(pullop) + _pullphase(pullop) + _pullbookmarks(pullop) + _pullobsolete(pullop) # storing remotenames if repo.ui.configbool(b'experimental', b'remotenames'): diff -r d6c53b40b078 -r 04688c51f81f mercurial/exchangev2.py --- a/mercurial/exchangev2.py Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,804 +0,0 @@ -# exchangev2.py - repository exchange for wire protocol version 2 -# -# Copyright 2018 Gregory Szorc -# -# 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 - -import collections -import weakref - -from .i18n import _ -from .node import short -from . import ( - bookmarks, - error, - mdiff, - narrowspec, - phases, - pycompat, - requirements as requirementsmod, - setdiscovery, -) -from .interfaces import repository - - -def pull(pullop): - """Pull using wire protocol version 2.""" - repo = pullop.repo - remote = pullop.remote - - usingrawchangelogandmanifest = _checkuserawstorefiledata(pullop) - - # If this is a clone and it was requested to perform a "stream clone", - # we obtain the raw files data from the remote then fall back to an - # incremental pull. This is somewhat hacky and is not nearly robust enough - # for long-term usage. - if usingrawchangelogandmanifest: - with repo.transaction(b'clone'): - _fetchrawstorefiles(repo, remote) - repo.invalidate(clearfilecache=True) - - tr = pullop.trmanager.transaction() - - # We don't use the repo's narrow matcher here because the patterns passed - # to exchange.pull() could be different. - narrowmatcher = narrowspec.match( - repo.root, - # Empty maps to nevermatcher. So always - # set includes if missing. - pullop.includepats or {b'path:.'}, - pullop.excludepats, - ) - - if pullop.includepats or pullop.excludepats: - pathfilter = {} - if pullop.includepats: - pathfilter[b'include'] = sorted(pullop.includepats) - if pullop.excludepats: - pathfilter[b'exclude'] = sorted(pullop.excludepats) - else: - pathfilter = None - - # Figure out what needs to be fetched. - common, fetch, remoteheads = _pullchangesetdiscovery( - repo, remote, pullop.heads, abortwhenunrelated=pullop.force - ) - - # And fetch the data. - pullheads = pullop.heads or remoteheads - csetres = _fetchchangesets(repo, tr, remote, common, fetch, pullheads) - - # New revisions are written to the changelog. But all other updates - # are deferred. Do those now. - - # Ensure all new changesets are draft by default. If the repo is - # publishing, the phase will be adjusted by the loop below. - if csetres[b'added']: - phases.registernew( - repo, tr, phases.draft, [repo[n].rev() for n in csetres[b'added']] - ) - - # And adjust the phase of all changesets accordingly. - for phasenumber, phase in phases.phasenames.items(): - if phase == b'secret' or not csetres[b'nodesbyphase'][phase]: - continue - - phases.advanceboundary( - repo, - tr, - phasenumber, - csetres[b'nodesbyphase'][phase], - ) - - # Write bookmark updates. - bookmarks.updatefromremote( - repo.ui, - repo, - csetres[b'bookmarks'], - remote.url(), - pullop.gettransaction, - explicit=pullop.explicitbookmarks, - ) - - manres = _fetchmanifests(repo, tr, remote, csetres[b'manifestnodes']) - - # We don't properly support shallow changeset and manifest yet. So we apply - # depth limiting locally. - if pullop.depth: - relevantcsetnodes = set() - clnode = repo.changelog.node - - for rev in repo.revs( - b'ancestors(%ln, %s)', pullheads, pullop.depth - 1 - ): - relevantcsetnodes.add(clnode(rev)) - - csetrelevantfilter = lambda n: n in relevantcsetnodes - - else: - csetrelevantfilter = lambda n: True - - # If obtaining the raw store files, we need to scan the full repo to - # derive all the changesets, manifests, and linkrevs. - if usingrawchangelogandmanifest: - csetsforfiles = [] - mnodesforfiles = [] - manifestlinkrevs = {} - - for rev in repo: - ctx = repo[rev] - node = ctx.node() - - if not csetrelevantfilter(node): - continue - - mnode = ctx.manifestnode() - - csetsforfiles.append(node) - mnodesforfiles.append(mnode) - manifestlinkrevs[mnode] = rev - - else: - csetsforfiles = [n for n in csetres[b'added'] if csetrelevantfilter(n)] - mnodesforfiles = manres[b'added'] - manifestlinkrevs = manres[b'linkrevs'] - - # Find all file nodes referenced by added manifests and fetch those - # revisions. - fnodes = _derivefilesfrommanifests(repo, narrowmatcher, mnodesforfiles) - _fetchfilesfromcsets( - repo, - tr, - remote, - pathfilter, - fnodes, - csetsforfiles, - manifestlinkrevs, - shallow=bool(pullop.depth), - ) - - -def _checkuserawstorefiledata(pullop): - """Check whether we should use rawstorefiledata command to retrieve data.""" - - repo = pullop.repo - remote = pullop.remote - - # Command to obtain raw store data isn't available. - if b'rawstorefiledata' not in remote.apidescriptor[b'commands']: - return False - - # Only honor if user requested stream clone operation. - if not pullop.streamclonerequested: - return False - - # Only works on empty repos. - if len(repo): - return False - - # TODO This is super hacky. There needs to be a storage API for this. We - # also need to check for compatibility with the remote. - if requirementsmod.REVLOGV1_REQUIREMENT not in repo.requirements: - return False - - return True - - -def _fetchrawstorefiles(repo, remote): - with remote.commandexecutor() as e: - objs = e.callcommand( - b'rawstorefiledata', - { - b'files': [b'changelog', b'manifestlog'], - }, - ).result() - - # First object is a summary of files data that follows. - overall = next(objs) - - progress = repo.ui.makeprogress( - _(b'clone'), total=overall[b'totalsize'], unit=_(b'bytes') - ) - with progress: - progress.update(0) - - # Next are pairs of file metadata, data. - while True: - try: - filemeta = next(objs) - except StopIteration: - break - - for k in (b'location', b'path', b'size'): - if k not in filemeta: - raise error.Abort( - _(b'remote file data missing key: %s') % k - ) - - if filemeta[b'location'] == b'store': - vfs = repo.svfs - else: - raise error.Abort( - _(b'invalid location for raw file data: %s') - % filemeta[b'location'] - ) - - bytesremaining = filemeta[b'size'] - - with vfs.open(filemeta[b'path'], b'wb') as fh: - while True: - try: - chunk = next(objs) - except StopIteration: - break - - bytesremaining -= len(chunk) - - if bytesremaining < 0: - raise error.Abort( - _( - b'received invalid number of bytes for file ' - b'data; expected %d, got extra' - ) - % filemeta[b'size'] - ) - - progress.increment(step=len(chunk)) - fh.write(chunk) - - try: - if chunk.islast: - break - except AttributeError: - raise error.Abort( - _( - b'did not receive indefinite length bytestring ' - b'for file data' - ) - ) - - if bytesremaining: - raise error.Abort( - _( - b'received invalid number of bytes for' - b'file data; expected %d got %d' - ) - % ( - filemeta[b'size'], - filemeta[b'size'] - bytesremaining, - ) - ) - - -def _pullchangesetdiscovery(repo, remote, heads, abortwhenunrelated=True): - """Determine which changesets need to be pulled.""" - - if heads: - knownnode = repo.changelog.hasnode - if all(knownnode(head) for head in heads): - return heads, False, heads - - # TODO wire protocol version 2 is capable of more efficient discovery - # than setdiscovery. Consider implementing something better. - common, fetch, remoteheads = setdiscovery.findcommonheads( - repo.ui, repo, remote, abortwhenunrelated=abortwhenunrelated - ) - - common = set(common) - remoteheads = set(remoteheads) - - # If a remote head is filtered locally, put it back in the common set. - # See the comment in exchange._pulldiscoverychangegroup() for more. - - if fetch and remoteheads: - has_node = repo.unfiltered().changelog.index.has_node - - common |= {head for head in remoteheads if has_node(head)} - - if set(remoteheads).issubset(common): - fetch = [] - - common.discard(repo.nullid) - - return common, fetch, remoteheads - - -def _fetchchangesets(repo, tr, remote, common, fetch, remoteheads): - # TODO consider adding a step here where we obtain the DAG shape first - # (or ask the server to slice changesets into chunks for us) so that - # we can perform multiple fetches in batches. This will facilitate - # resuming interrupted clones, higher server-side cache hit rates due - # to smaller segments, etc. - with remote.commandexecutor() as e: - objs = e.callcommand( - b'changesetdata', - { - b'revisions': [ - { - b'type': b'changesetdagrange', - b'roots': sorted(common), - b'heads': sorted(remoteheads), - } - ], - b'fields': {b'bookmarks', b'parents', b'phase', b'revision'}, - }, - ).result() - - # The context manager waits on all response data when exiting. So - # we need to remain in the context manager in order to stream data. - return _processchangesetdata(repo, tr, objs) - - -def _processchangesetdata(repo, tr, objs): - repo.hook(b'prechangegroup', throw=True, **pycompat.strkwargs(tr.hookargs)) - - urepo = repo.unfiltered() - cl = urepo.changelog - - cl.delayupdate(tr) - - # The first emitted object is a header describing the data that - # follows. - meta = next(objs) - - progress = repo.ui.makeprogress( - _(b'changesets'), unit=_(b'chunks'), total=meta.get(b'totalitems') - ) - - manifestnodes = {} - added = [] - - def linkrev(node): - repo.ui.debug(b'add changeset %s\n' % short(node)) - # Linkrev for changelog is always self. - return len(cl) - - def ondupchangeset(cl, rev): - added.append(cl.node(rev)) - - def onchangeset(cl, rev): - progress.increment() - - revision = cl.changelogrevision(rev) - added.append(cl.node(rev)) - - # We need to preserve the mapping of changelog revision to node - # so we can set the linkrev accordingly when manifests are added. - manifestnodes[rev] = revision.manifest - - repo.register_changeset(rev, revision) - - nodesbyphase = {phase: set() for phase in phases.phasenames.values()} - remotebookmarks = {} - - # addgroup() expects a 7-tuple describing revisions. This normalizes - # the wire data to that format. - # - # This loop also aggregates non-revision metadata, such as phase - # data. - def iterrevisions(): - for cset in objs: - node = cset[b'node'] - - if b'phase' in cset: - nodesbyphase[cset[b'phase']].add(node) - - for mark in cset.get(b'bookmarks', []): - remotebookmarks[mark] = node - - # TODO add mechanism for extensions to examine records so they - # can siphon off custom data fields. - - extrafields = {} - - for field, size in cset.get(b'fieldsfollowing', []): - extrafields[field] = next(objs) - - # Some entries might only be metadata only updates. - if b'revision' not in extrafields: - continue - - data = extrafields[b'revision'] - - yield ( - node, - cset[b'parents'][0], - cset[b'parents'][1], - # Linknode is always itself for changesets. - cset[b'node'], - # We always send full revisions. So delta base is not set. - repo.nullid, - mdiff.trivialdiffheader(len(data)) + data, - # Flags not yet supported. - 0, - # Sidedata not yet supported - {}, - ) - - cl.addgroup( - iterrevisions(), - linkrev, - weakref.proxy(tr), - alwayscache=True, - addrevisioncb=onchangeset, - duplicaterevisioncb=ondupchangeset, - ) - - progress.complete() - - return { - b'added': added, - b'nodesbyphase': nodesbyphase, - b'bookmarks': remotebookmarks, - b'manifestnodes': manifestnodes, - } - - -def _fetchmanifests(repo, tr, remote, manifestnodes): - rootmanifest = repo.manifestlog.getstorage(b'') - - # Some manifests can be shared between changesets. Filter out revisions - # we already know about. - fetchnodes = [] - linkrevs = {} - seen = set() - - for clrev, node in sorted(pycompat.iteritems(manifestnodes)): - if node in seen: - continue - - try: - rootmanifest.rev(node) - except error.LookupError: - fetchnodes.append(node) - linkrevs[node] = clrev - - seen.add(node) - - # TODO handle tree manifests - - # addgroup() expects 7-tuple describing revisions. This normalizes - # the wire data to that format. - def iterrevisions(objs, progress): - for manifest in objs: - node = manifest[b'node'] - - extrafields = {} - - for field, size in manifest.get(b'fieldsfollowing', []): - extrafields[field] = next(objs) - - if b'delta' in extrafields: - basenode = manifest[b'deltabasenode'] - delta = extrafields[b'delta'] - elif b'revision' in extrafields: - basenode = repo.nullid - revision = extrafields[b'revision'] - delta = mdiff.trivialdiffheader(len(revision)) + revision - else: - continue - - yield ( - node, - manifest[b'parents'][0], - manifest[b'parents'][1], - # The value passed in is passed to the lookup function passed - # to addgroup(). We already have a map of manifest node to - # changelog revision number. So we just pass in the - # manifest node here and use linkrevs.__getitem__ as the - # resolution function. - node, - basenode, - delta, - # Flags not yet supported. - 0, - # Sidedata not yet supported. - {}, - ) - - progress.increment() - - progress = repo.ui.makeprogress( - _(b'manifests'), unit=_(b'chunks'), total=len(fetchnodes) - ) - - commandmeta = remote.apidescriptor[b'commands'][b'manifestdata'] - batchsize = commandmeta.get(b'recommendedbatchsize', 10000) - # TODO make size configurable on client? - - # We send commands 1 at a time to the remote. This is not the most - # efficient because we incur a round trip at the end of each batch. - # However, the existing frame-based reactor keeps consuming server - # data in the background. And this results in response data buffering - # in memory. This can consume gigabytes of memory. - # TODO send multiple commands in a request once background buffering - # issues are resolved. - - added = [] - - for i in pycompat.xrange(0, len(fetchnodes), batchsize): - batch = [node for node in fetchnodes[i : i + batchsize]] - if not batch: - continue - - with remote.commandexecutor() as e: - objs = e.callcommand( - b'manifestdata', - { - b'tree': b'', - b'nodes': batch, - b'fields': {b'parents', b'revision'}, - b'haveparents': True, - }, - ).result() - - # Chomp off header object. - next(objs) - - def onchangeset(cl, rev): - added.append(cl.node(rev)) - - rootmanifest.addgroup( - iterrevisions(objs, progress), - linkrevs.__getitem__, - weakref.proxy(tr), - addrevisioncb=onchangeset, - duplicaterevisioncb=onchangeset, - ) - - progress.complete() - - return { - b'added': added, - b'linkrevs': linkrevs, - } - - -def _derivefilesfrommanifests(repo, matcher, manifestnodes): - """Determine what file nodes are relevant given a set of manifest nodes. - - Returns a dict mapping file paths to dicts of file node to first manifest - node. - """ - ml = repo.manifestlog - fnodes = collections.defaultdict(dict) - - progress = repo.ui.makeprogress( - _(b'scanning manifests'), total=len(manifestnodes) - ) - - with progress: - for manifestnode in manifestnodes: - m = ml.get(b'', manifestnode) - - # TODO this will pull in unwanted nodes because it takes the storage - # delta into consideration. What we really want is something that - # takes the delta between the manifest's parents. And ideally we - # would ignore file nodes that are known locally. For now, ignore - # both these limitations. This will result in incremental fetches - # requesting data we already have. So this is far from ideal. - md = m.readfast() - - for path, fnode in md.items(): - if matcher(path): - fnodes[path].setdefault(fnode, manifestnode) - - progress.increment() - - return fnodes - - -def _fetchfiles(repo, tr, remote, fnodes, linkrevs): - """Fetch file data from explicit file revisions.""" - - def iterrevisions(objs, progress): - for filerevision in objs: - node = filerevision[b'node'] - - extrafields = {} - - for field, size in filerevision.get(b'fieldsfollowing', []): - extrafields[field] = next(objs) - - if b'delta' in extrafields: - basenode = filerevision[b'deltabasenode'] - delta = extrafields[b'delta'] - elif b'revision' in extrafields: - basenode = repo.nullid - revision = extrafields[b'revision'] - delta = mdiff.trivialdiffheader(len(revision)) + revision - else: - continue - - yield ( - node, - filerevision[b'parents'][0], - filerevision[b'parents'][1], - node, - basenode, - delta, - # Flags not yet supported. - 0, - # Sidedata not yet supported. - {}, - ) - - progress.increment() - - progress = repo.ui.makeprogress( - _(b'files'), - unit=_(b'chunks'), - total=sum(len(v) for v in pycompat.itervalues(fnodes)), - ) - - # TODO make batch size configurable - batchsize = 10000 - fnodeslist = [x for x in sorted(fnodes.items())] - - for i in pycompat.xrange(0, len(fnodeslist), batchsize): - batch = [x for x in fnodeslist[i : i + batchsize]] - if not batch: - continue - - with remote.commandexecutor() as e: - fs = [] - locallinkrevs = {} - - for path, nodes in batch: - fs.append( - ( - path, - e.callcommand( - b'filedata', - { - b'path': path, - b'nodes': sorted(nodes), - b'fields': {b'parents', b'revision'}, - b'haveparents': True, - }, - ), - ) - ) - - locallinkrevs[path] = { - node: linkrevs[manifestnode] - for node, manifestnode in pycompat.iteritems(nodes) - } - - for path, f in fs: - objs = f.result() - - # Chomp off header objects. - next(objs) - - store = repo.file(path) - store.addgroup( - iterrevisions(objs, progress), - locallinkrevs[path].__getitem__, - weakref.proxy(tr), - ) - - -def _fetchfilesfromcsets( - repo, tr, remote, pathfilter, fnodes, csets, manlinkrevs, shallow=False -): - """Fetch file data from explicit changeset revisions.""" - - def iterrevisions(objs, remaining, progress): - while remaining: - filerevision = next(objs) - - node = filerevision[b'node'] - - extrafields = {} - - for field, size in filerevision.get(b'fieldsfollowing', []): - extrafields[field] = next(objs) - - if b'delta' in extrafields: - basenode = filerevision[b'deltabasenode'] - delta = extrafields[b'delta'] - elif b'revision' in extrafields: - basenode = repo.nullid - revision = extrafields[b'revision'] - delta = mdiff.trivialdiffheader(len(revision)) + revision - else: - continue - - if b'linknode' in filerevision: - linknode = filerevision[b'linknode'] - else: - linknode = node - - yield ( - node, - filerevision[b'parents'][0], - filerevision[b'parents'][1], - linknode, - basenode, - delta, - # Flags not yet supported. - 0, - # Sidedata not yet supported. - {}, - ) - - progress.increment() - remaining -= 1 - - progress = repo.ui.makeprogress( - _(b'files'), - unit=_(b'chunks'), - total=sum(len(v) for v in pycompat.itervalues(fnodes)), - ) - - commandmeta = remote.apidescriptor[b'commands'][b'filesdata'] - batchsize = commandmeta.get(b'recommendedbatchsize', 50000) - - shallowfiles = repository.REPO_FEATURE_SHALLOW_FILE_STORAGE in repo.features - fields = {b'parents', b'revision'} - clrev = repo.changelog.rev - - # There are no guarantees that we'll have ancestor revisions if - # a) this repo has shallow file storage b) shallow data fetching is enabled. - # Force remote to not delta against possibly unknown revisions when these - # conditions hold. - haveparents = not (shallowfiles or shallow) - - # Similarly, we may not have calculated linkrevs for all incoming file - # revisions. Ask the remote to do work for us in this case. - if not haveparents: - fields.add(b'linknode') - - for i in pycompat.xrange(0, len(csets), batchsize): - batch = [x for x in csets[i : i + batchsize]] - if not batch: - continue - - with remote.commandexecutor() as e: - args = { - b'revisions': [ - { - b'type': b'changesetexplicit', - b'nodes': batch, - } - ], - b'fields': fields, - b'haveparents': haveparents, - } - - if pathfilter: - args[b'pathfilter'] = pathfilter - - objs = e.callcommand(b'filesdata', args).result() - - # First object is an overall header. - overall = next(objs) - - # We have overall['totalpaths'] segments. - for i in pycompat.xrange(overall[b'totalpaths']): - header = next(objs) - - path = header[b'path'] - store = repo.file(path) - - linkrevs = { - fnode: manlinkrevs[mnode] - for fnode, mnode in pycompat.iteritems(fnodes[path]) - } - - def getlinkrev(node): - if node in linkrevs: - return linkrevs[node] - else: - return clrev(node) - - store.addgroup( - iterrevisions(objs, header[b'totalitems'], progress), - getlinkrev, - weakref.proxy(tr), - maybemissingparents=shallow, - ) diff -r d6c53b40b078 -r 04688c51f81f mercurial/helptext/internals/wireprotocol.txt --- a/mercurial/helptext/internals/wireprotocol.txt Thu Dec 30 13:25:44 2021 +0100 +++ b/mercurial/helptext/internals/wireprotocol.txt Tue Dec 07 16:44:22 2021 +0100 @@ -332,95 +332,6 @@ after responses. In other words, the length of the response contains the trailing ``\n``. -Clients supporting version 2 of the SSH transport send a line beginning -with ``upgrade`` before the ``hello`` and ``between`` commands. The line -(which isn't a well-formed command line because it doesn't consist of a -single command name) serves to both communicate the client's intent to -switch to transport version 2 (transports are version 1 by default) as -well as to advertise the client's transport-level capabilities so the -server may satisfy that request immediately. - -The upgrade line has the form: - - upgrade - -That is the literal string ``upgrade`` followed by a space, followed by -a randomly generated string, followed by a space, followed by a string -denoting the client's transport capabilities. - -The token can be anything. However, a random UUID is recommended. (Use -of version 4 UUIDs is recommended because version 1 UUIDs can leak the -client's MAC address.) - -The transport capabilities string is a URL/percent encoded string -containing key-value pairs defining the client's transport-level -capabilities. The following capabilities are defined: - -proto - A comma-delimited list of transport protocol versions the client - supports. e.g. ``ssh-v2``. - -If the server does not recognize the ``upgrade`` line, it should issue -an empty response and continue processing the ``hello`` and ``between`` -commands. Here is an example handshake between a version 2 aware client -and a non version 2 aware server: - - c: upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=ssh-v2 - c: hello\n - c: between\n - c: pairs 81\n - c: 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - s: 0\n - s: 324\n - s: capabilities: lookup changegroupsubset branchmap pushkey known getbundle ...\n - s: 1\n - s: \n - -(The initial ``0\n`` line from the server indicates an empty response to -the unknown ``upgrade ..`` command/line.) - -If the server recognizes the ``upgrade`` line and is willing to satisfy that -upgrade request, it replies to with a payload of the following form: - - upgraded \n - -This line is the literal string ``upgraded``, a space, the token that was -specified by the client in its ``upgrade ...`` request line, a space, and the -name of the transport protocol that was chosen by the server. The transport -name MUST match one of the names the client specified in the ``proto`` field -of its ``upgrade ...`` request line. - -If a server issues an ``upgraded`` response, it MUST also read and ignore -the lines associated with the ``hello`` and ``between`` command requests -that were issued by the server. It is assumed that the negotiated transport -will respond with equivalent requested information following the transport -handshake. - -All data following the ``\n`` terminating the ``upgraded`` line is the -domain of the negotiated transport. It is common for the data immediately -following to contain additional metadata about the state of the transport and -the server. However, this isn't strictly speaking part of the transport -handshake and isn't covered by this section. - -Here is an example handshake between a version 2 aware client and a version -2 aware server: - - c: upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=ssh-v2 - c: hello\n - c: between\n - c: pairs 81\n - c: 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - s: upgraded 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a ssh-v2\n - s: - -The client-issued token that is echoed in the response provides a more -resilient mechanism for differentiating *banner* output from Mercurial -output. In version 1, properly formatted banner output could get confused -for Mercurial server output. By submitting a randomly generated token -that is then present in the response, the client can look for that token -in response lines and have reasonable certainty that the line did not -originate from a *banner* message. - SSH Version 1 Transport ----------------------- @@ -488,31 +399,6 @@ should issue a ``protocaps`` command after the initial handshake to annonunce its own capabilities. The client capabilities are persistent. -SSH Version 2 Transport ------------------------ - -**Experimental and under development** - -Version 2 of the SSH transport behaves identically to version 1 of the SSH -transport with the exception of handshake semantics. See above for how -version 2 of the SSH transport is negotiated. - -Immediately following the ``upgraded`` line signaling a switch to version -2 of the SSH protocol, the server automatically sends additional details -about the capabilities of the remote server. This has the form: - - \n - capabilities: ...\n - -e.g. - - s: upgraded 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a ssh-v2\n - s: 240\n - s: capabilities: known getbundle batch ...\n - -Following capabilities advertisement, the peers communicate using version -1 of the SSH transport. - Capabilities ============ diff -r d6c53b40b078 -r 04688c51f81f mercurial/hgweb/hgweb_mod.py --- a/mercurial/hgweb/hgweb_mod.py Thu Dec 30 13:25:44 2021 +0100 +++ b/mercurial/hgweb/hgweb_mod.py Tue Dec 07 16:44:22 2021 +0100 @@ -366,17 +366,6 @@ # replace it. res.headers[b'Content-Security-Policy'] = rctx.csp - # /api/* is reserved for various API implementations. Dispatch - # accordingly. But URL paths can conflict with subrepos and virtual - # repos in hgwebdir. So until we have a workaround for this, only - # expose the URLs if the feature is enabled. - apienabled = rctx.repo.ui.configbool(b'experimental', b'web.apiserver') - if apienabled and req.dispatchparts and req.dispatchparts[0] == b'api': - wireprotoserver.handlewsgiapirequest( - rctx, req, res, self.check_perm - ) - return res.sendresponse() - handled = wireprotoserver.handlewsgirequest( rctx, req, res, self.check_perm ) diff -r d6c53b40b078 -r 04688c51f81f mercurial/httppeer.py --- a/mercurial/httppeer.py Thu Dec 30 13:25:44 2021 +0100 +++ b/mercurial/httppeer.py Tue Dec 07 16:44:22 2021 +0100 @@ -13,7 +13,6 @@ import os import socket import struct -import weakref from .i18n import _ from .pycompat import getattr @@ -25,21 +24,9 @@ statichttprepo, url as urlmod, util, - wireprotoframing, - wireprototypes, wireprotov1peer, - wireprotov2peer, - wireprotov2server, ) -from .interfaces import ( - repository, - util as interfaceutil, -) -from .utils import ( - cborutil, - stringutil, - urlutil, -) +from .utils import urlutil httplib = util.httplib urlerr = util.urlerr @@ -331,9 +318,7 @@ self.respurl = respurl -def parsev1commandresponse( - ui, baseurl, requrl, qs, resp, compressible, allowcbor=False -): +def parsev1commandresponse(ui, baseurl, requrl, qs, resp, compressible): # record the url we got redirected to redirected = False respurl = pycompat.bytesurl(resp.geturl()) @@ -376,17 +361,6 @@ try: subtype = proto.split(b'-', 1)[1] - # Unless we end up supporting CBOR in the legacy wire protocol, - # this should ONLY be encountered for the initial capabilities - # request during handshake. - if subtype == b'cbor': - if allowcbor: - return respurl, proto, resp - else: - raise error.RepoError( - _(b'unexpected CBOR response from server') - ) - version_info = tuple([int(n) for n in subtype.split(b'.')]) except ValueError: raise error.RepoError( @@ -564,85 +538,6 @@ raise exception -def sendv2request( - ui, opener, requestbuilder, apiurl, permission, requests, redirect -): - wireprotoframing.populatestreamencoders() - - uiencoders = ui.configlist(b'experimental', b'httppeer.v2-encoder-order') - - if uiencoders: - encoders = [] - - for encoder in uiencoders: - if encoder not in wireprotoframing.STREAM_ENCODERS: - ui.warn( - _( - b'wire protocol version 2 encoder referenced in ' - b'config (%s) is not known; ignoring\n' - ) - % encoder - ) - else: - encoders.append(encoder) - - else: - encoders = wireprotoframing.STREAM_ENCODERS_ORDER - - reactor = wireprotoframing.clientreactor( - ui, - hasmultiplesend=False, - buffersends=True, - clientcontentencoders=encoders, - ) - - handler = wireprotov2peer.clienthandler( - ui, reactor, opener=opener, requestbuilder=requestbuilder - ) - - url = b'%s/%s' % (apiurl, permission) - - if len(requests) > 1: - url += b'/multirequest' - else: - url += b'/%s' % requests[0][0] - - ui.debug(b'sending %d commands\n' % len(requests)) - for command, args, f in requests: - ui.debug( - b'sending command %s: %s\n' - % (command, stringutil.pprint(args, indent=2)) - ) - assert not list( - handler.callcommand(command, args, f, redirect=redirect) - ) - - # TODO stream this. - body = b''.join(map(bytes, handler.flushcommands())) - - # TODO modify user-agent to reflect v2 - headers = { - 'Accept': wireprotov2server.FRAMINGTYPE, - 'Content-Type': wireprotov2server.FRAMINGTYPE, - } - - req = requestbuilder(pycompat.strurl(url), body, headers) - req.add_unredirected_header('Content-Length', '%d' % len(body)) - - try: - res = opener.open(req) - except urlerr.httperror as e: - if e.code == 401: - raise error.Abort(_(b'authorization failed')) - - raise - except httplib.HTTPException as e: - ui.traceback() - raise IOError(None, e) - - return handler, res - - class queuedcommandfuture(pycompat.futures.Future): """Wraps result() on command futures to trigger submission on call.""" @@ -657,302 +552,6 @@ return self.result(timeout) -@interfaceutil.implementer(repository.ipeercommandexecutor) -class httpv2executor(object): - def __init__( - self, ui, opener, requestbuilder, apiurl, descriptor, redirect - ): - self._ui = ui - self._opener = opener - self._requestbuilder = requestbuilder - self._apiurl = apiurl - self._descriptor = descriptor - self._redirect = redirect - self._sent = False - self._closed = False - self._neededpermissions = set() - self._calls = [] - self._futures = weakref.WeakSet() - self._responseexecutor = None - self._responsef = None - - def __enter__(self): - return self - - def __exit__(self, exctype, excvalue, exctb): - self.close() - - def callcommand(self, command, args): - if self._sent: - raise error.ProgrammingError( - b'callcommand() cannot be used after commands are sent' - ) - - if self._closed: - raise error.ProgrammingError( - b'callcommand() cannot be used after close()' - ) - - # The service advertises which commands are available. So if we attempt - # to call an unknown command or pass an unknown argument, we can screen - # for this. - if command not in self._descriptor[b'commands']: - raise error.ProgrammingError( - b'wire protocol command %s is not available' % command - ) - - cmdinfo = self._descriptor[b'commands'][command] - unknownargs = set(args.keys()) - set(cmdinfo.get(b'args', {})) - - if unknownargs: - raise error.ProgrammingError( - b'wire protocol command %s does not accept argument: %s' - % (command, b', '.join(sorted(unknownargs))) - ) - - self._neededpermissions |= set(cmdinfo[b'permissions']) - - # TODO we /could/ also validate types here, since the API descriptor - # includes types... - - f = pycompat.futures.Future() - - # Monkeypatch it so result() triggers sendcommands(), otherwise result() - # could deadlock. - f.__class__ = queuedcommandfuture - f._peerexecutor = self - - self._futures.add(f) - self._calls.append((command, args, f)) - - return f - - def sendcommands(self): - if self._sent: - return - - if not self._calls: - return - - self._sent = True - - # Unhack any future types so caller sees a clean type and so we - # break reference cycle. - for f in self._futures: - if isinstance(f, queuedcommandfuture): - f.__class__ = pycompat.futures.Future - f._peerexecutor = None - - # Mark the future as running and filter out cancelled futures. - calls = [ - (command, args, f) - for command, args, f in self._calls - if f.set_running_or_notify_cancel() - ] - - # Clear out references, prevent improper object usage. - self._calls = None - - if not calls: - return - - permissions = set(self._neededpermissions) - - if b'push' in permissions and b'pull' in permissions: - permissions.remove(b'pull') - - if len(permissions) > 1: - raise error.RepoError( - _(b'cannot make request requiring multiple permissions: %s') - % _(b', ').join(sorted(permissions)) - ) - - permission = { - b'push': b'rw', - b'pull': b'ro', - }[permissions.pop()] - - handler, resp = sendv2request( - self._ui, - self._opener, - self._requestbuilder, - self._apiurl, - permission, - calls, - self._redirect, - ) - - # TODO we probably want to validate the HTTP code, media type, etc. - - self._responseexecutor = pycompat.futures.ThreadPoolExecutor(1) - self._responsef = self._responseexecutor.submit( - self._handleresponse, handler, resp - ) - - def close(self): - if self._closed: - return - - self.sendcommands() - - self._closed = True - - if not self._responsef: - return - - # TODO ^C here may not result in immediate program termination. - - try: - self._responsef.result() - finally: - self._responseexecutor.shutdown(wait=True) - self._responsef = None - self._responseexecutor = None - - # If any of our futures are still in progress, mark them as - # errored, otherwise a result() could wait indefinitely. - for f in self._futures: - if not f.done(): - f.set_exception( - error.ResponseError(_(b'unfulfilled command response')) - ) - - self._futures = None - - def _handleresponse(self, handler, resp): - # Called in a thread to read the response. - - while handler.readdata(resp): - pass - - -@interfaceutil.implementer(repository.ipeerv2) -class httpv2peer(object): - - limitedarguments = False - - def __init__( - self, ui, repourl, apipath, opener, requestbuilder, apidescriptor - ): - self.ui = ui - self.apidescriptor = apidescriptor - - if repourl.endswith(b'/'): - repourl = repourl[:-1] - - self._url = repourl - self._apipath = apipath - self._apiurl = b'%s/%s' % (repourl, apipath) - self._opener = opener - self._requestbuilder = requestbuilder - - self._redirect = wireprotov2peer.supportedredirects(ui, apidescriptor) - - # Start of ipeerconnection. - - def url(self): - return self._url - - def local(self): - return None - - def peer(self): - return self - - def canpush(self): - # TODO change once implemented. - return False - - def close(self): - self.ui.note( - _( - b'(sent %d HTTP requests and %d bytes; ' - b'received %d bytes in responses)\n' - ) - % ( - self._opener.requestscount, - self._opener.sentbytescount, - self._opener.receivedbytescount, - ) - ) - - # End of ipeerconnection. - - # Start of ipeercapabilities. - - def capable(self, name): - # The capabilities used internally historically map to capabilities - # advertised from the "capabilities" wire protocol command. However, - # version 2 of that command works differently. - - # Maps to commands that are available. - if name in ( - b'branchmap', - b'getbundle', - b'known', - b'lookup', - b'pushkey', - ): - return True - - # Other concepts. - if name in (b'bundle2',): - return True - - # Alias command-* to presence of command of that name. - if name.startswith(b'command-'): - return name[len(b'command-') :] in self.apidescriptor[b'commands'] - - return False - - def requirecap(self, name, purpose): - if self.capable(name): - return - - raise error.CapabilityError( - _( - b'cannot %s; client or remote repository does not support the ' - b'\'%s\' capability' - ) - % (purpose, name) - ) - - # End of ipeercapabilities. - - def _call(self, name, **args): - with self.commandexecutor() as e: - return e.callcommand(name, args).result() - - def commandexecutor(self): - return httpv2executor( - self.ui, - self._opener, - self._requestbuilder, - self._apiurl, - self.apidescriptor, - self._redirect, - ) - - -# Registry of API service names to metadata about peers that handle it. -# -# The following keys are meaningful: -# -# init -# Callable receiving (ui, repourl, servicepath, opener, requestbuilder, -# apidescriptor) to create a peer. -# -# priority -# Integer priority for the service. If we could choose from multiple -# services, we choose the one with the highest priority. -API_PEERS = { - wireprototypes.HTTP_WIREPROTO_V2: { - b'init': httpv2peer, - b'priority': 50, - }, -} - - def performhandshake(ui, url, opener, requestbuilder): # The handshake is a request to the capabilities command. @@ -963,28 +562,6 @@ args = {} - # The client advertises support for newer protocols by adding an - # X-HgUpgrade-* header with a list of supported APIs and an - # X-HgProto-* header advertising which serializing formats it supports. - # We only support the HTTP version 2 transport and CBOR responses for - # now. - advertisev2 = ui.configbool(b'experimental', b'httppeer.advertise-v2') - - if advertisev2: - args[b'headers'] = { - 'X-HgProto-1': 'cbor', - } - - args[b'headers'].update( - encodevalueinheaders( - b' '.join(sorted(API_PEERS)), - b'X-HgUpgrade', - # We don't know the header limit this early. - # So make it small. - 1024, - ) - ) - req, requrl, qs = makev1commandrequest( ui, requestbuilder, caps, capable, url, b'capabilities', args ) @@ -1004,7 +581,7 @@ # redirect that drops the query string to "just work." try: respurl, ct, resp = parsev1commandresponse( - ui, url, requrl, qs, resp, compressible=False, allowcbor=advertisev2 + ui, url, requrl, qs, resp, compressible=False ) except RedirectedRepoError as e: req, requrl, qs = makev1commandrequest( @@ -1012,7 +589,7 @@ ) resp = sendrequest(ui, opener, req) respurl, ct, resp = parsev1commandresponse( - ui, url, requrl, qs, resp, compressible=False, allowcbor=advertisev2 + ui, url, requrl, qs, resp, compressible=False ) try: @@ -1023,29 +600,7 @@ if not ct.startswith(b'application/mercurial-'): raise error.ProgrammingError(b'unexpected content-type: %s' % ct) - if advertisev2: - if ct == b'application/mercurial-cbor': - try: - info = cborutil.decodeall(rawdata)[0] - except cborutil.CBORDecodeError: - raise error.Abort( - _(b'error decoding CBOR from remote server'), - hint=_( - b'try again and consider contacting ' - b'the server operator' - ), - ) - - # We got a legacy response. That's fine. - elif ct in (b'application/mercurial-0.1', b'application/mercurial-0.2'): - info = {b'v1capabilities': set(rawdata.split())} - - else: - raise error.RepoError( - _(b'unexpected response type from server: %s') % ct - ) - else: - info = {b'v1capabilities': set(rawdata.split())} + info = {b'v1capabilities': set(rawdata.split())} return respurl, info @@ -1073,29 +628,6 @@ respurl, info = performhandshake(ui, url, opener, requestbuilder) - # Given the intersection of APIs that both we and the server support, - # sort by their advertised priority and pick the first one. - # - # TODO consider making this request-based and interface driven. For - # example, the caller could say "I want a peer that does X." It's quite - # possible that not all peers would do that. Since we know the service - # capabilities, we could filter out services not meeting the - # requirements. Possibly by consulting the interfaces defined by the - # peer type. - apipeerchoices = set(info.get(b'apis', {}).keys()) & set(API_PEERS.keys()) - - preferredchoices = sorted( - apipeerchoices, key=lambda x: API_PEERS[x][b'priority'], reverse=True - ) - - for service in preferredchoices: - apipath = b'%s/%s' % (info[b'apibase'].rstrip(b'/'), service) - - return API_PEERS[service][b'init']( - ui, respurl, apipath, opener, requestbuilder, info[b'apis'][service] - ) - - # Failed to construct an API peer. Fall back to legacy. return httppeer( ui, path, respurl, opener, requestbuilder, info[b'v1capabilities'] ) diff -r d6c53b40b078 -r 04688c51f81f mercurial/sshpeer.py --- a/mercurial/sshpeer.py Thu Dec 30 13:25:44 2021 +0100 +++ b/mercurial/sshpeer.py Tue Dec 07 16:44:22 2021 +0100 @@ -16,7 +16,6 @@ error, pycompat, util, - wireprotoserver, wireprototypes, wireprotov1peer, wireprotov1server, @@ -288,10 +287,6 @@ # Generate a random token to help identify responses to version 2 # upgrade request. token = pycompat.sysbytes(str(uuid.uuid4())) - upgradecaps = [ - (b'proto', wireprotoserver.SSHV2), - ] - upgradecaps = util.urlreq.urlencode(upgradecaps) try: pairsarg = b'%s-%s' % (b'0' * 40, b'0' * 40) @@ -302,11 +297,6 @@ pairsarg, ] - # Request upgrade to version 2 if configured. - if ui.configbool(b'experimental', b'sshpeer.advertise-v2'): - ui.debug(b'sending upgrade request: %s %s\n' % (token, upgradecaps)) - handshake.insert(0, b'upgrade %s %s\n' % (token, upgradecaps)) - if requestlog: ui.debug(b'devel-peer-request: hello+between\n') ui.debug(b'devel-peer-request: pairs: %d bytes\n' % len(pairsarg)) @@ -365,24 +355,6 @@ if l.startswith(b'capabilities:'): caps.update(l[:-1].split(b':')[1].split()) break - elif protoname == wireprotoserver.SSHV2: - # We see a line with number of bytes to follow and then a value - # looking like ``capabilities: *``. - line = stdout.readline() - try: - valuelen = int(line) - except ValueError: - badresponse() - - capsline = stdout.read(valuelen) - if not capsline.startswith(b'capabilities: '): - badresponse() - - ui.debug(b'remote: %s\n' % capsline) - - caps.update(capsline.split(b':')[1].split()) - # Trailing newline. - stdout.read(1) # Error if we couldn't find capabilities, this means: # @@ -601,14 +573,6 @@ self._readerr() -class sshv2peer(sshv1peer): - """A peer that speakers version 2 of the transport protocol.""" - - # Currently version 2 is identical to version 1 post handshake. - # And handshake is performed before the peer is instantiated. So - # we need no custom code. - - def makepeer(ui, path, proc, stdin, stdout, stderr, autoreadstderr=True): """Make a peer instance from existing pipes. @@ -640,17 +604,6 @@ caps, autoreadstderr=autoreadstderr, ) - elif protoname == wireprototypes.SSHV2: - return sshv2peer( - ui, - path, - proc, - stdin, - stdout, - stderr, - caps, - autoreadstderr=autoreadstderr, - ) else: _cleanuppipes(ui, stdout, stdin, stderr, warn=None) raise error.RepoError( diff -r d6c53b40b078 -r 04688c51f81f mercurial/wireprotoserver.py --- a/mercurial/wireprotoserver.py Thu Dec 30 13:25:44 2021 +0100 +++ b/mercurial/wireprotoserver.py Tue Dec 07 16:44:22 2021 +0100 @@ -18,11 +18,9 @@ util, wireprototypes, wireprotov1server, - wireprotov2server, ) from .interfaces import util as interfaceutil from .utils import ( - cborutil, compression, stringutil, ) @@ -39,7 +37,6 @@ HGERRTYPE = b'application/hg-error' SSHV1 = wireprototypes.SSHV1 -SSHV2 = wireprototypes.SSHV2 def decodevaluefromheaders(req, headerprefix): @@ -244,97 +241,6 @@ return True -def _availableapis(repo): - apis = set() - - # Registered APIs are made available via config options of the name of - # the protocol. - for k, v in API_HANDLERS.items(): - section, option = v[b'config'] # pytype: disable=attribute-error - if repo.ui.configbool(section, option): - apis.add(k) - - return apis - - -def handlewsgiapirequest(rctx, req, res, checkperm): - """Handle requests to /api/*.""" - assert req.dispatchparts[0] == b'api' - - repo = rctx.repo - - # This whole URL space is experimental for now. But we want to - # reserve the URL space. So, 404 all URLs if the feature isn't enabled. - if not repo.ui.configbool(b'experimental', b'web.apiserver'): - res.status = b'404 Not Found' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes(_(b'Experimental API server endpoint not enabled')) - return - - # The URL space is /api//*. The structure of URLs under varies - # by . - - availableapis = _availableapis(repo) - - # Requests to /api/ list available APIs. - if req.dispatchparts == [b'api']: - res.status = b'200 OK' - res.headers[b'Content-Type'] = b'text/plain' - lines = [ - _( - b'APIs can be accessed at /api/, where can be ' - b'one of the following:\n' - ) - ] - if availableapis: - lines.extend(sorted(availableapis)) - else: - lines.append(_(b'(no available APIs)\n')) - res.setbodybytes(b'\n'.join(lines)) - return - - proto = req.dispatchparts[1] - - if proto not in API_HANDLERS: - res.status = b'404 Not Found' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes( - _(b'Unknown API: %s\nKnown APIs: %s') - % (proto, b', '.join(sorted(availableapis))) - ) - return - - if proto not in availableapis: - res.status = b'404 Not Found' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes(_(b'API %s not enabled\n') % proto) - return - - API_HANDLERS[proto][b'handler']( - rctx, req, res, checkperm, req.dispatchparts[2:] - ) - - -# Maps API name to metadata so custom API can be registered. -# Keys are: -# -# config -# Config option that controls whether service is enabled. -# handler -# Callable receiving (rctx, req, res, checkperm, urlparts) that is called -# when a request to this API is received. -# apidescriptor -# Callable receiving (req, repo) that is called to obtain an API -# descriptor for this service. The response must be serializable to CBOR. -API_HANDLERS = { - wireprotov2server.HTTP_WIREPROTO_V2: { - b'config': (b'experimental', b'web.api.http-v2'), - b'handler': wireprotov2server.handlehttpv2request, - b'apidescriptor': wireprotov2server.httpv2apidescriptor, - }, -} - - def _httpresponsetype(ui, proto, prefer_uncompressed): """Determine the appropriate response type and compression settings. @@ -371,55 +277,6 @@ return HGTYPE, util.compengines[b'zlib'], opts -def processcapabilitieshandshake(repo, req, res, proto): - """Called during a ?cmd=capabilities request. - - If the client is advertising support for a newer protocol, we send - a CBOR response with information about available services. If no - advertised services are available, we don't handle the request. - """ - # Fall back to old behavior unless the API server is enabled. - if not repo.ui.configbool(b'experimental', b'web.apiserver'): - return False - - clientapis = decodevaluefromheaders(req, b'X-HgUpgrade') - protocaps = decodevaluefromheaders(req, b'X-HgProto') - if not clientapis or not protocaps: - return False - - # We currently only support CBOR responses. - protocaps = set(protocaps.split(b' ')) - if b'cbor' not in protocaps: - return False - - descriptors = {} - - for api in sorted(set(clientapis.split()) & _availableapis(repo)): - handler = API_HANDLERS[api] - - descriptorfn = handler.get(b'apidescriptor') - if not descriptorfn: - continue - - descriptors[api] = descriptorfn(req, repo) - - v1caps = wireprotov1server.dispatch(repo, proto, b'capabilities') - assert isinstance(v1caps, wireprototypes.bytesresponse) - - m = { - # TODO allow this to be configurable. - b'apibase': b'api/', - b'apis': descriptors, - b'v1capabilities': v1caps.data, - } - - res.status = b'200 OK' - res.headers[b'Content-Type'] = b'application/mercurial-cbor' - res.setbodybytes(b''.join(cborutil.streamencode(m))) - - return True - - def _callhttp(repo, req, res, proto, cmd): # Avoid cycle involving hg module. from .hgweb import common as hgwebcommon @@ -461,13 +318,6 @@ proto.checkperm(wireprotov1server.commands[cmd].permission) - # Possibly handle a modern client wanting to switch protocols. - if cmd == b'capabilities' and processcapabilitieshandshake( - repo, req, res, proto - ): - - return - rsp = wireprotov1server.dispatch(repo, proto, cmd) if isinstance(rsp, bytes): @@ -596,17 +446,6 @@ pass -class sshv2protocolhandler(sshv1protocolhandler): - """Protocol handler for version 2 of the SSH protocol.""" - - @property - def name(self): - return wireprototypes.SSHV2 - - def addcapabilities(self, repo, caps): - return caps - - def _runsshserver(ui, repo, fin, fout, ev): # This function operates like a state machine of sorts. The following # states are defined: @@ -616,19 +455,6 @@ # new lines. These commands are processed in this state, one command # after the other. # - # protov2-serving - # Server is in protocol version 2 serving mode. - # - # upgrade-initial - # The server is going to process an upgrade request. - # - # upgrade-v2-filter-legacy-handshake - # The protocol is being upgraded to version 2. The server is expecting - # the legacy handshake from version 1. - # - # upgrade-v2-finish - # The upgrade to version 2 of the protocol is imminent. - # # shutdown # The server is shutting down, possibly in reaction to a client event. # @@ -637,32 +463,9 @@ # protov1-serving -> shutdown # When server receives an empty request or encounters another # error. - # - # protov1-serving -> upgrade-initial - # An upgrade request line was seen. - # - # upgrade-initial -> upgrade-v2-filter-legacy-handshake - # Upgrade to version 2 in progress. Server is expecting to - # process a legacy handshake. - # - # upgrade-v2-filter-legacy-handshake -> shutdown - # Client did not fulfill upgrade handshake requirements. - # - # upgrade-v2-filter-legacy-handshake -> upgrade-v2-finish - # Client fulfilled version 2 upgrade requirements. Finishing that - # upgrade. - # - # upgrade-v2-finish -> protov2-serving - # Protocol upgrade to version 2 complete. Server can now speak protocol - # version 2. - # - # protov2-serving -> protov1-serving - # Ths happens by default since protocol version 2 is the same as - # version 1 except for the handshake. state = b'protov1-serving' proto = sshv1protocolhandler(ui, fin, fout) - protoswitched = False while not ev.is_set(): if state == b'protov1-serving': @@ -674,21 +477,6 @@ state = b'shutdown' continue - # It looks like a protocol upgrade request. Transition state to - # handle it. - if request.startswith(b'upgrade '): - if protoswitched: - _sshv1respondooberror( - fout, - ui.ferr, - b'cannot upgrade protocols multiple times', - ) - state = b'shutdown' - continue - - state = b'upgrade-initial' - continue - available = wireprotov1server.commands.commandavailable( request, proto ) @@ -724,108 +512,6 @@ b'wire protocol command: %s' % rsp ) - # For now, protocol version 2 serving just goes back to version 1. - elif state == b'protov2-serving': - state = b'protov1-serving' - continue - - elif state == b'upgrade-initial': - # We should never transition into this state if we've switched - # protocols. - assert not protoswitched - assert proto.name == wireprototypes.SSHV1 - - # Expected: upgrade - # If we get something else, the request is malformed. It could be - # from a future client that has altered the upgrade line content. - # We treat this as an unknown command. - try: - token, caps = request.split(b' ')[1:] - except ValueError: - _sshv1respondbytes(fout, b'') - state = b'protov1-serving' - continue - - # Send empty response if we don't support upgrading protocols. - if not ui.configbool(b'experimental', b'sshserver.support-v2'): - _sshv1respondbytes(fout, b'') - state = b'protov1-serving' - continue - - try: - caps = urlreq.parseqs(caps) - except ValueError: - _sshv1respondbytes(fout, b'') - state = b'protov1-serving' - continue - - # We don't see an upgrade request to protocol version 2. Ignore - # the upgrade request. - wantedprotos = caps.get(b'proto', [b''])[0] - if SSHV2 not in wantedprotos: - _sshv1respondbytes(fout, b'') - state = b'protov1-serving' - continue - - # It looks like we can honor this upgrade request to protocol 2. - # Filter the rest of the handshake protocol request lines. - state = b'upgrade-v2-filter-legacy-handshake' - continue - - elif state == b'upgrade-v2-filter-legacy-handshake': - # Client should have sent legacy handshake after an ``upgrade`` - # request. Expected lines: - # - # hello - # between - # pairs 81 - # 0000...-0000... - - ok = True - for line in (b'hello', b'between', b'pairs 81'): - request = fin.readline()[:-1] - - if request != line: - _sshv1respondooberror( - fout, - ui.ferr, - b'malformed handshake protocol: missing %s' % line, - ) - ok = False - state = b'shutdown' - break - - if not ok: - continue - - request = fin.read(81) - if request != b'%s-%s' % (b'0' * 40, b'0' * 40): - _sshv1respondooberror( - fout, - ui.ferr, - b'malformed handshake protocol: ' - b'missing between argument value', - ) - state = b'shutdown' - continue - - state = b'upgrade-v2-finish' - continue - - elif state == b'upgrade-v2-finish': - # Send the upgrade response. - fout.write(b'upgraded %s %s\n' % (token, SSHV2)) - servercaps = wireprotov1server.capabilities(repo, proto) - rsp = b'capabilities: %s' % servercaps.data - fout.write(b'%d\n%s\n' % (len(rsp), rsp)) - fout.flush() - - proto = sshv2protocolhandler(ui, fin, fout) - protoswitched = True - - state = b'protov2-serving' - continue - elif state == b'shutdown': break diff -r d6c53b40b078 -r 04688c51f81f mercurial/wireprototypes.py --- a/mercurial/wireprototypes.py Thu Dec 30 13:25:44 2021 +0100 +++ b/mercurial/wireprototypes.py Tue Dec 07 16:44:22 2021 +0100 @@ -21,10 +21,6 @@ # Names of the SSH protocol implementations. SSHV1 = b'ssh-v1' -# These are advertised over the wire. Increment the counters at the end -# to reflect BC breakages. -SSHV2 = b'exp-ssh-v2-0003' -HTTP_WIREPROTO_V2 = b'exp-http-v2-0003' NARROWCAP = b'exp-narrow-1' ELLIPSESCAP1 = b'exp-ellipses-1' @@ -37,19 +33,10 @@ b'transport': b'ssh', b'version': 1, }, - SSHV2: { - b'transport': b'ssh', - # TODO mark as version 2 once all commands are implemented. - b'version': 1, - }, b'http-v1': { b'transport': b'http', b'version': 1, }, - HTTP_WIREPROTO_V2: { - b'transport': b'http', - b'version': 2, - }, } diff -r d6c53b40b078 -r 04688c51f81f mercurial/wireprotov1server.py --- a/mercurial/wireprotov1server.py Thu Dec 30 13:25:44 2021 +0100 +++ b/mercurial/wireprotov1server.py Tue Dec 07 16:44:22 2021 +0100 @@ -147,12 +147,6 @@ k for k, v in wireprototypes.TRANSPORTS.items() if v[b'version'] == 1 } - # Because SSHv2 is a mirror of SSHv1, we allow "batch" commands through to - # SSHv2. - # TODO undo this hack when SSH is using the unified frame protocol. - if name == b'batch': - transports.add(wireprototypes.SSHV2) - if permission not in (b'push', b'pull'): raise error.ProgrammingError( b'invalid wire protocol permission; ' diff -r d6c53b40b078 -r 04688c51f81f mercurial/wireprotov2peer.py --- a/mercurial/wireprotov2peer.py Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,576 +0,0 @@ -# wireprotov2peer.py - client side code for wire protocol version 2 -# -# Copyright 2018 Gregory Szorc -# -# 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 - -import threading - -from .i18n import _ -from . import ( - encoding, - error, - pycompat, - sslutil, - url as urlmod, - util, - wireprotoframing, - wireprototypes, -) -from .utils import cborutil - - -def formatrichmessage(atoms): - """Format an encoded message from the framing protocol.""" - - chunks = [] - - for atom in atoms: - msg = _(atom[b'msg']) - - if b'args' in atom: - msg = msg % tuple(atom[b'args']) - - chunks.append(msg) - - return b''.join(chunks) - - -SUPPORTED_REDIRECT_PROTOCOLS = { - b'http', - b'https', -} - -SUPPORTED_CONTENT_HASHES = { - b'sha1', - b'sha256', -} - - -def redirecttargetsupported(ui, target): - """Determine whether a redirect target entry is supported. - - ``target`` should come from the capabilities data structure emitted by - the server. - """ - if target.get(b'protocol') not in SUPPORTED_REDIRECT_PROTOCOLS: - ui.note( - _(b'(remote redirect target %s uses unsupported protocol: %s)\n') - % (target[b'name'], target.get(b'protocol', b'')) - ) - return False - - if target.get(b'snirequired') and not sslutil.hassni: - ui.note( - _(b'(redirect target %s requires SNI, which is unsupported)\n') - % target[b'name'] - ) - return False - - if b'tlsversions' in target: - tlsversions = set(target[b'tlsversions']) - supported = set() - - for v in sslutil.supportedprotocols: - assert v.startswith(b'tls') - supported.add(v[3:]) - - if not tlsversions & supported: - ui.note( - _( - b'(remote redirect target %s requires unsupported TLS ' - b'versions: %s)\n' - ) - % (target[b'name'], b', '.join(sorted(tlsversions))) - ) - return False - - ui.note(_(b'(remote redirect target %s is compatible)\n') % target[b'name']) - - return True - - -def supportedredirects(ui, apidescriptor): - """Resolve the "redirect" command request key given an API descriptor. - - Given an API descriptor returned by the server, returns a data structure - that can be used in hte "redirect" field of command requests to advertise - support for compatible redirect targets. - - Returns None if no redirect targets are remotely advertised or if none are - supported. - """ - if not apidescriptor or b'redirect' not in apidescriptor: - return None - - targets = [ - t[b'name'] - for t in apidescriptor[b'redirect'][b'targets'] - if redirecttargetsupported(ui, t) - ] - - hashes = [ - h - for h in apidescriptor[b'redirect'][b'hashes'] - if h in SUPPORTED_CONTENT_HASHES - ] - - return { - b'targets': targets, - b'hashes': hashes, - } - - -class commandresponse(object): - """Represents the response to a command request. - - Instances track the state of the command and hold its results. - - An external entity is required to update the state of the object when - events occur. - """ - - def __init__(self, requestid, command, fromredirect=False): - self.requestid = requestid - self.command = command - self.fromredirect = fromredirect - - # Whether all remote input related to this command has been - # received. - self._inputcomplete = False - - # We have a lock that is acquired when important object state is - # mutated. This is to prevent race conditions between 1 thread - # sending us new data and another consuming it. - self._lock = threading.RLock() - - # An event is set when state of the object changes. This event - # is waited on by the generator emitting objects. - self._serviceable = threading.Event() - - self._pendingevents = [] - self._pendingerror = None - self._decoder = cborutil.bufferingdecoder() - self._seeninitial = False - self._redirect = None - - def _oninputcomplete(self): - with self._lock: - self._inputcomplete = True - self._serviceable.set() - - def _onresponsedata(self, data): - available, readcount, wanted = self._decoder.decode(data) - - if not available: - return - - with self._lock: - for o in self._decoder.getavailable(): - if not self._seeninitial and not self.fromredirect: - self._handleinitial(o) - continue - - # We should never see an object after a content redirect, - # as the spec says the main status object containing the - # content redirect is the only object in the stream. Fail - # if we see a misbehaving server. - if self._redirect: - raise error.Abort( - _( - b'received unexpected response data ' - b'after content redirect; the remote is ' - b'buggy' - ) - ) - - self._pendingevents.append(o) - - self._serviceable.set() - - def _onerror(self, e): - self._pendingerror = e - - with self._lock: - self._serviceable.set() - - def _handleinitial(self, o): - self._seeninitial = True - if o[b'status'] == b'ok': - return - - elif o[b'status'] == b'redirect': - l = o[b'location'] - self._redirect = wireprototypes.alternatelocationresponse( - url=l[b'url'], - mediatype=l[b'mediatype'], - size=l.get(b'size'), - fullhashes=l.get(b'fullhashes'), - fullhashseed=l.get(b'fullhashseed'), - serverdercerts=l.get(b'serverdercerts'), - servercadercerts=l.get(b'servercadercerts'), - ) - return - - atoms = [{b'msg': o[b'error'][b'message']}] - if b'args' in o[b'error']: - atoms[0][b'args'] = o[b'error'][b'args'] - - raise error.RepoError(formatrichmessage(atoms)) - - def objects(self): - """Obtained decoded objects from this response. - - This is a generator of data structures that were decoded from the - command response. - - Obtaining the next member of the generator may block due to waiting - on external data to become available. - - If the server encountered an error in the middle of serving the data - or if another error occurred, an exception may be raised when - advancing the generator. - """ - while True: - # TODO this can infinite loop if self._inputcomplete is never - # set. We likely want to tie the lifetime of this object/state - # to that of the background thread receiving frames and updating - # our state. - self._serviceable.wait(1.0) - - if self._pendingerror: - raise self._pendingerror - - with self._lock: - self._serviceable.clear() - - # Make copies because objects could be mutated during - # iteration. - stop = self._inputcomplete - pending = list(self._pendingevents) - self._pendingevents[:] = [] - - for o in pending: - yield o - - if stop: - break - - -class clienthandler(object): - """Object to handle higher-level client activities. - - The ``clientreactor`` is used to hold low-level state about the frame-based - protocol, such as which requests and streams are active. This type is used - for higher-level operations, such as reading frames from a socket, exposing - and managing a higher-level primitive for representing command responses, - etc. This class is what peers should probably use to bridge wire activity - with the higher-level peer API. - """ - - def __init__( - self, ui, clientreactor, opener=None, requestbuilder=util.urlreq.request - ): - self._ui = ui - self._reactor = clientreactor - self._requests = {} - self._futures = {} - self._responses = {} - self._redirects = [] - self._frameseof = False - self._opener = opener or urlmod.opener(ui) - self._requestbuilder = requestbuilder - - def callcommand(self, command, args, f, redirect=None): - """Register a request to call a command. - - Returns an iterable of frames that should be sent over the wire. - """ - request, action, meta = self._reactor.callcommand( - command, args, redirect=redirect - ) - - if action != b'noop': - raise error.ProgrammingError(b'%s not yet supported' % action) - - rid = request.requestid - self._requests[rid] = request - self._futures[rid] = f - # TODO we need some kind of lifetime on response instances otherwise - # objects() may deadlock. - self._responses[rid] = commandresponse(rid, command) - - return iter(()) - - def flushcommands(self): - """Flush all queued commands. - - Returns an iterable of frames that should be sent over the wire. - """ - action, meta = self._reactor.flushcommands() - - if action != b'sendframes': - raise error.ProgrammingError(b'%s not yet supported' % action) - - return meta[b'framegen'] - - def readdata(self, framefh): - """Attempt to read data and do work. - - Returns None if no data was read. Presumably this means we're - done with all read I/O. - """ - if not self._frameseof: - frame = wireprotoframing.readframe(framefh) - if frame is None: - # TODO tell reactor? - self._frameseof = True - else: - self._ui.debug(b'received %r\n' % frame) - self._processframe(frame) - - # Also try to read the first redirect. - if self._redirects: - if not self._processredirect(*self._redirects[0]): - self._redirects.pop(0) - - if self._frameseof and not self._redirects: - return None - - return True - - def _processframe(self, frame): - """Process a single read frame.""" - - action, meta = self._reactor.onframerecv(frame) - - if action == b'error': - e = error.RepoError(meta[b'message']) - - if frame.requestid in self._responses: - self._responses[frame.requestid]._oninputcomplete() - - if frame.requestid in self._futures: - self._futures[frame.requestid].set_exception(e) - del self._futures[frame.requestid] - else: - raise e - - return - elif action == b'noop': - return - elif action == b'responsedata': - # Handled below. - pass - else: - raise error.ProgrammingError(b'action not handled: %s' % action) - - if frame.requestid not in self._requests: - raise error.ProgrammingError( - b'received frame for unknown request; this is either a bug in ' - b'the clientreactor not screening for this or this instance was ' - b'never told about this request: %r' % frame - ) - - response = self._responses[frame.requestid] - - if action == b'responsedata': - # Any failures processing this frame should bubble up to the - # future tracking the request. - try: - self._processresponsedata(frame, meta, response) - except BaseException as e: - # If an exception occurs before the future is resolved, - # fail the future. Otherwise, we stuff the exception on - # the response object so it can be raised during objects() - # iteration. If nothing is consuming objects(), we could - # silently swallow this exception. That's a risk we'll have to - # take. - if frame.requestid in self._futures: - self._futures[frame.requestid].set_exception(e) - del self._futures[frame.requestid] - response._oninputcomplete() - else: - response._onerror(e) - else: - raise error.ProgrammingError( - b'unhandled action from clientreactor: %s' % action - ) - - def _processresponsedata(self, frame, meta, response): - # This can raise. The caller can handle it. - response._onresponsedata(meta[b'data']) - - # We need to be careful about resolving futures prematurely. If a - # response is a redirect response, resolving the future before the - # redirect is processed would result in the consumer seeing an - # empty stream of objects, since they'd be consuming our - # response.objects() instead of the redirect's response.objects(). - # - # Our strategy is to not resolve/finish the request until either - # EOS occurs or until the initial response object is fully received. - - # Always react to eos. - if meta[b'eos']: - response._oninputcomplete() - del self._requests[frame.requestid] - - # Not EOS but we haven't decoded the initial response object yet. - # Return and wait for more data. - elif not response._seeninitial: - return - - # The specification says no objects should follow the initial/redirect - # object. So it should be safe to handle the redirect object if one is - # decoded, without having to wait for EOS. - if response._redirect: - self._followredirect(frame.requestid, response._redirect) - return - - # If the command has a decoder, we wait until all input has been - # received before resolving the future. Otherwise we resolve the - # future immediately. - if frame.requestid not in self._futures: - return - - if response.command not in COMMAND_DECODERS: - self._futures[frame.requestid].set_result(response.objects()) - del self._futures[frame.requestid] - elif response._inputcomplete: - decoded = COMMAND_DECODERS[response.command](response.objects()) - self._futures[frame.requestid].set_result(decoded) - del self._futures[frame.requestid] - - def _followredirect(self, requestid, redirect): - """Called to initiate redirect following for a request.""" - self._ui.note(_(b'(following redirect to %s)\n') % redirect.url) - - # TODO handle framed responses. - if redirect.mediatype != b'application/mercurial-cbor': - raise error.Abort( - _(b'cannot handle redirects for the %s media type') - % redirect.mediatype - ) - - if redirect.fullhashes: - self._ui.warn( - _( - b'(support for validating hashes on content ' - b'redirects not supported)\n' - ) - ) - - if redirect.serverdercerts or redirect.servercadercerts: - self._ui.warn( - _( - b'(support for pinning server certificates on ' - b'content redirects not supported)\n' - ) - ) - - headers = { - 'Accept': redirect.mediatype, - } - - req = self._requestbuilder(pycompat.strurl(redirect.url), None, headers) - - try: - res = self._opener.open(req) - except util.urlerr.httperror as e: - if e.code == 401: - raise error.Abort(_(b'authorization failed')) - raise - except util.httplib.HTTPException as e: - self._ui.debug(b'http error requesting %s\n' % req.get_full_url()) - self._ui.traceback() - raise IOError(None, e) - - urlmod.wrapresponse(res) - - # The existing response object is associated with frame data. Rather - # than try to normalize its state, just create a new object. - oldresponse = self._responses[requestid] - self._responses[requestid] = commandresponse( - requestid, oldresponse.command, fromredirect=True - ) - - self._redirects.append((requestid, res)) - - def _processredirect(self, rid, res): - """Called to continue processing a response from a redirect. - - Returns a bool indicating if the redirect is still serviceable. - """ - response = self._responses[rid] - - try: - data = res.read(32768) - response._onresponsedata(data) - - # We're at end of stream. - if not data: - response._oninputcomplete() - - if rid not in self._futures: - return bool(data) - - if response.command not in COMMAND_DECODERS: - self._futures[rid].set_result(response.objects()) - del self._futures[rid] - elif response._inputcomplete: - decoded = COMMAND_DECODERS[response.command](response.objects()) - self._futures[rid].set_result(decoded) - del self._futures[rid] - - return bool(data) - - except BaseException as e: - self._futures[rid].set_exception(e) - del self._futures[rid] - response._oninputcomplete() - return False - - -def decodebranchmap(objs): - # Response should be a single CBOR map of branch name to array of nodes. - bm = next(objs) - - return {encoding.tolocal(k): v for k, v in bm.items()} - - -def decodeheads(objs): - # Array of node bytestrings. - return next(objs) - - -def decodeknown(objs): - # Bytestring where each byte is a 0 or 1. - raw = next(objs) - - return [True if raw[i : i + 1] == b'1' else False for i in range(len(raw))] - - -def decodelistkeys(objs): - # Map with bytestring keys and values. - return next(objs) - - -def decodelookup(objs): - return next(objs) - - -def decodepushkey(objs): - return next(objs) - - -COMMAND_DECODERS = { - b'branchmap': decodebranchmap, - b'heads': decodeheads, - b'known': decodeknown, - b'listkeys': decodelistkeys, - b'lookup': decodelookup, - b'pushkey': decodepushkey, -} diff -r d6c53b40b078 -r 04688c51f81f mercurial/wireprotov2server.py --- a/mercurial/wireprotov2server.py Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1617 +0,0 @@ -# Copyright 21 May 2005 - (c) 2005 Jake Edge -# Copyright 2005-2007 Olivia Mackall -# -# 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 - -import collections -import contextlib - -from .i18n import _ -from .node import hex -from . import ( - discovery, - encoding, - error, - match as matchmod, - narrowspec, - pycompat, - streamclone, - templatefilters, - util, - wireprotoframing, - wireprototypes, -) -from .interfaces import util as interfaceutil -from .utils import ( - cborutil, - hashutil, - stringutil, -) - -FRAMINGTYPE = b'application/mercurial-exp-framing-0006' - -HTTP_WIREPROTO_V2 = wireprototypes.HTTP_WIREPROTO_V2 - -COMMANDS = wireprototypes.commanddict() - -# Value inserted into cache key computation function. Change the value to -# force new cache keys for every command request. This should be done when -# there is a change to how caching works, etc. -GLOBAL_CACHE_VERSION = 1 - - -def handlehttpv2request(rctx, req, res, checkperm, urlparts): - from .hgweb import common as hgwebcommon - - # URL space looks like: /, where can - # be ``ro`` or ``rw`` to signal read-only or read-write, respectively. - - # Root URL does nothing meaningful... yet. - if not urlparts: - res.status = b'200 OK' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes(_(b'HTTP version 2 API handler')) - return - - if len(urlparts) == 1: - res.status = b'404 Not Found' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes( - _(b'do not know how to process %s\n') % req.dispatchpath - ) - return - - permission, command = urlparts[0:2] - - if permission not in (b'ro', b'rw'): - res.status = b'404 Not Found' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes(_(b'unknown permission: %s') % permission) - return - - if req.method != b'POST': - res.status = b'405 Method Not Allowed' - res.headers[b'Allow'] = b'POST' - res.setbodybytes(_(b'commands require POST requests')) - return - - # At some point we'll want to use our own API instead of recycling the - # behavior of version 1 of the wire protocol... - # TODO return reasonable responses - not responses that overload the - # HTTP status line message for error reporting. - try: - checkperm(rctx, req, b'pull' if permission == b'ro' else b'push') - except hgwebcommon.ErrorResponse as e: - res.status = hgwebcommon.statusmessage( - e.code, stringutil.forcebytestr(e) - ) - for k, v in e.headers: - res.headers[k] = v - res.setbodybytes(b'permission denied') - return - - # We have a special endpoint to reflect the request back at the client. - if command == b'debugreflect': - _processhttpv2reflectrequest(rctx.repo.ui, rctx.repo, req, res) - return - - # Extra commands that we handle that aren't really wire protocol - # commands. Think extra hard before making this hackery available to - # extension. - extracommands = {b'multirequest'} - - if command not in COMMANDS and command not in extracommands: - res.status = b'404 Not Found' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes(_(b'unknown wire protocol command: %s\n') % command) - return - - repo = rctx.repo - ui = repo.ui - - proto = httpv2protocolhandler(req, ui) - - if ( - not COMMANDS.commandavailable(command, proto) - and command not in extracommands - ): - res.status = b'404 Not Found' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes(_(b'invalid wire protocol command: %s') % command) - return - - # TODO consider cases where proxies may add additional Accept headers. - if req.headers.get(b'Accept') != FRAMINGTYPE: - res.status = b'406 Not Acceptable' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes( - _(b'client MUST specify Accept header with value: %s\n') - % FRAMINGTYPE - ) - return - - if req.headers.get(b'Content-Type') != FRAMINGTYPE: - res.status = b'415 Unsupported Media Type' - # TODO we should send a response with appropriate media type, - # since client does Accept it. - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes( - _(b'client MUST send Content-Type header with value: %s\n') - % FRAMINGTYPE - ) - return - - _processhttpv2request(ui, repo, req, res, permission, command, proto) - - -def _processhttpv2reflectrequest(ui, repo, req, res): - """Reads unified frame protocol request and dumps out state to client. - - This special endpoint can be used to help debug the wire protocol. - - Instead of routing the request through the normal dispatch mechanism, - we instead read all frames, decode them, and feed them into our state - tracker. We then dump the log of all that activity back out to the - client. - """ - # Reflection APIs have a history of being abused, accidentally disclosing - # sensitive data, etc. So we have a config knob. - if not ui.configbool(b'experimental', b'web.api.debugreflect'): - res.status = b'404 Not Found' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes(_(b'debugreflect service not available')) - return - - # We assume we have a unified framing protocol request body. - - reactor = wireprotoframing.serverreactor(ui) - states = [] - - while True: - frame = wireprotoframing.readframe(req.bodyfh) - - if not frame: - states.append(b'received: ') - break - - states.append( - b'received: %d %d %d %s' - % (frame.typeid, frame.flags, frame.requestid, frame.payload) - ) - - action, meta = reactor.onframerecv(frame) - states.append(templatefilters.json((action, meta))) - - action, meta = reactor.oninputeof() - meta[b'action'] = action - states.append(templatefilters.json(meta)) - - res.status = b'200 OK' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes(b'\n'.join(states)) - - -def _processhttpv2request(ui, repo, req, res, authedperm, reqcommand, proto): - """Post-validation handler for HTTPv2 requests. - - Called when the HTTP request contains unified frame-based protocol - frames for evaluation. - """ - # TODO Some HTTP clients are full duplex and can receive data before - # the entire request is transmitted. Figure out a way to indicate support - # for that so we can opt into full duplex mode. - reactor = wireprotoframing.serverreactor(ui, deferoutput=True) - seencommand = False - - outstream = None - - while True: - frame = wireprotoframing.readframe(req.bodyfh) - if not frame: - break - - action, meta = reactor.onframerecv(frame) - - if action == b'wantframe': - # Need more data before we can do anything. - continue - elif action == b'runcommand': - # Defer creating output stream because we need to wait for - # protocol settings frames so proper encoding can be applied. - if not outstream: - outstream = reactor.makeoutputstream() - - sentoutput = _httpv2runcommand( - ui, - repo, - req, - res, - authedperm, - reqcommand, - reactor, - outstream, - meta, - issubsequent=seencommand, - ) - - if sentoutput: - return - - seencommand = True - - elif action == b'error': - # TODO define proper error mechanism. - res.status = b'200 OK' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes(meta[b'message'] + b'\n') - return - else: - raise error.ProgrammingError( - b'unhandled action from frame processor: %s' % action - ) - - action, meta = reactor.oninputeof() - if action == b'sendframes': - # We assume we haven't started sending the response yet. If we're - # wrong, the response type will raise an exception. - res.status = b'200 OK' - res.headers[b'Content-Type'] = FRAMINGTYPE - res.setbodygen(meta[b'framegen']) - elif action == b'noop': - pass - else: - raise error.ProgrammingError( - b'unhandled action from frame processor: %s' % action - ) - - -def _httpv2runcommand( - ui, - repo, - req, - res, - authedperm, - reqcommand, - reactor, - outstream, - command, - issubsequent, -): - """Dispatch a wire protocol command made from HTTPv2 requests. - - The authenticated permission (``authedperm``) along with the original - command from the URL (``reqcommand``) are passed in. - """ - # We already validated that the session has permissions to perform the - # actions in ``authedperm``. In the unified frame protocol, the canonical - # command to run is expressed in a frame. However, the URL also requested - # to run a specific command. We need to be careful that the command we - # run doesn't have permissions requirements greater than what was granted - # by ``authedperm``. - # - # Our rule for this is we only allow one command per HTTP request and - # that command must match the command in the URL. However, we make - # an exception for the ``multirequest`` URL. This URL is allowed to - # execute multiple commands. We double check permissions of each command - # as it is invoked to ensure there is no privilege escalation. - # TODO consider allowing multiple commands to regular command URLs - # iff each command is the same. - - proto = httpv2protocolhandler(req, ui, args=command[b'args']) - - if reqcommand == b'multirequest': - if not COMMANDS.commandavailable(command[b'command'], proto): - # TODO proper error mechanism - res.status = b'200 OK' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes( - _(b'wire protocol command not available: %s') - % command[b'command'] - ) - return True - - # TODO don't use assert here, since it may be elided by -O. - assert authedperm in (b'ro', b'rw') - wirecommand = COMMANDS[command[b'command']] - assert wirecommand.permission in (b'push', b'pull') - - if authedperm == b'ro' and wirecommand.permission != b'pull': - # TODO proper error mechanism - res.status = b'403 Forbidden' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes( - _(b'insufficient permissions to execute command: %s') - % command[b'command'] - ) - return True - - # TODO should we also call checkperm() here? Maybe not if we're going - # to overhaul that API. The granted scope from the URL check should - # be good enough. - - else: - # Don't allow multiple commands outside of ``multirequest`` URL. - if issubsequent: - # TODO proper error mechanism - res.status = b'200 OK' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes( - _(b'multiple commands cannot be issued to this URL') - ) - return True - - if reqcommand != command[b'command']: - # TODO define proper error mechanism - res.status = b'200 OK' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes(_(b'command in frame must match command in URL')) - return True - - res.status = b'200 OK' - res.headers[b'Content-Type'] = FRAMINGTYPE - - try: - objs = dispatch(repo, proto, command[b'command'], command[b'redirect']) - - action, meta = reactor.oncommandresponsereadyobjects( - outstream, command[b'requestid'], objs - ) - - except error.WireprotoCommandError as e: - action, meta = reactor.oncommanderror( - outstream, command[b'requestid'], e.message, e.messageargs - ) - - except Exception as e: - action, meta = reactor.onservererror( - outstream, - command[b'requestid'], - _(b'exception when invoking command: %s') - % stringutil.forcebytestr(e), - ) - - if action == b'sendframes': - res.setbodygen(meta[b'framegen']) - return True - elif action == b'noop': - return False - else: - raise error.ProgrammingError( - b'unhandled event from reactor: %s' % action - ) - - -def getdispatchrepo(repo, proto, command): - viewconfig = repo.ui.config(b'server', b'view') - return repo.filtered(viewconfig) - - -def dispatch(repo, proto, command, redirect): - """Run a wire protocol command. - - Returns an iterable of objects that will be sent to the client. - """ - repo = getdispatchrepo(repo, proto, command) - - entry = COMMANDS[command] - func = entry.func - spec = entry.args - - args = proto.getargs(spec) - - # There is some duplicate boilerplate code here for calling the command and - # emitting objects. It is either that or a lot of indented code that looks - # like a pyramid (since there are a lot of code paths that result in not - # using the cacher). - callcommand = lambda: func(repo, proto, **pycompat.strkwargs(args)) - - # Request is not cacheable. Don't bother instantiating a cacher. - if not entry.cachekeyfn: - for o in callcommand(): - yield o - return - - if redirect: - redirecttargets = redirect[b'targets'] - redirecthashes = redirect[b'hashes'] - else: - redirecttargets = [] - redirecthashes = [] - - cacher = makeresponsecacher( - repo, - proto, - command, - args, - cborutil.streamencode, - redirecttargets=redirecttargets, - redirecthashes=redirecthashes, - ) - - # But we have no cacher. Do default handling. - if not cacher: - for o in callcommand(): - yield o - return - - with cacher: - cachekey = entry.cachekeyfn( - repo, proto, cacher, **pycompat.strkwargs(args) - ) - - # No cache key or the cacher doesn't like it. Do default handling. - if cachekey is None or not cacher.setcachekey(cachekey): - for o in callcommand(): - yield o - return - - # Serve it from the cache, if possible. - cached = cacher.lookup() - - if cached: - for o in cached[b'objs']: - yield o - return - - # Else call the command and feed its output into the cacher, allowing - # the cacher to buffer/mutate objects as it desires. - for o in callcommand(): - for o in cacher.onobject(o): - yield o - - for o in cacher.onfinished(): - yield o - - -@interfaceutil.implementer(wireprototypes.baseprotocolhandler) -class httpv2protocolhandler(object): - def __init__(self, req, ui, args=None): - self._req = req - self._ui = ui - self._args = args - - @property - def name(self): - return HTTP_WIREPROTO_V2 - - def getargs(self, args): - # First look for args that were passed but aren't registered on this - # command. - extra = set(self._args) - set(args) - if extra: - raise error.WireprotoCommandError( - b'unsupported argument to command: %s' - % b', '.join(sorted(extra)) - ) - - # And look for required arguments that are missing. - missing = {a for a in args if args[a][b'required']} - set(self._args) - - if missing: - raise error.WireprotoCommandError( - b'missing required arguments: %s' % b', '.join(sorted(missing)) - ) - - # Now derive the arguments to pass to the command, taking into - # account the arguments specified by the client. - data = {} - for k, meta in sorted(args.items()): - # This argument wasn't passed by the client. - if k not in self._args: - data[k] = meta[b'default']() - continue - - v = self._args[k] - - # Sets may be expressed as lists. Silently normalize. - if meta[b'type'] == b'set' and isinstance(v, list): - v = set(v) - - # TODO consider more/stronger type validation. - - data[k] = v - - return data - - def getprotocaps(self): - # Protocol capabilities are currently not implemented for HTTP V2. - return set() - - def getpayload(self): - raise NotImplementedError - - @contextlib.contextmanager - def mayberedirectstdio(self): - raise NotImplementedError - - def client(self): - raise NotImplementedError - - def addcapabilities(self, repo, caps): - return caps - - def checkperm(self, perm): - raise NotImplementedError - - -def httpv2apidescriptor(req, repo): - proto = httpv2protocolhandler(req, repo.ui) - - return _capabilitiesv2(repo, proto) - - -def _capabilitiesv2(repo, proto): - """Obtain the set of capabilities for version 2 transports. - - These capabilities are distinct from the capabilities for version 1 - transports. - """ - caps = { - b'commands': {}, - b'framingmediatypes': [FRAMINGTYPE], - b'pathfilterprefixes': set(narrowspec.VALID_PREFIXES), - } - - for command, entry in COMMANDS.items(): - args = {} - - for arg, meta in entry.args.items(): - args[arg] = { - # TODO should this be a normalized type using CBOR's - # terminology? - b'type': meta[b'type'], - b'required': meta[b'required'], - } - - if not meta[b'required']: - args[arg][b'default'] = meta[b'default']() - - if meta[b'validvalues']: - args[arg][b'validvalues'] = meta[b'validvalues'] - - # TODO this type of check should be defined in a per-command callback. - if ( - command == b'rawstorefiledata' - and not streamclone.allowservergeneration(repo) - ): - continue - - # pytype: disable=unsupported-operands - caps[b'commands'][command] = { - b'args': args, - b'permissions': [entry.permission], - } - # pytype: enable=unsupported-operands - - if entry.extracapabilitiesfn: - extracaps = entry.extracapabilitiesfn(repo, proto) - caps[b'commands'][command].update(extracaps) - - caps[b'rawrepoformats'] = sorted(repo.requirements & repo.supportedformats) - - targets = getadvertisedredirecttargets(repo, proto) - if targets: - caps[b'redirect'] = { - b'targets': [], - b'hashes': [b'sha256', b'sha1'], - } - - for target in targets: - entry = { - b'name': target[b'name'], - b'protocol': target[b'protocol'], - b'uris': target[b'uris'], - } - - for key in (b'snirequired', b'tlsversions'): - if key in target: - entry[key] = target[key] - - # pytype: disable=attribute-error - caps[b'redirect'][b'targets'].append(entry) - # pytype: enable=attribute-error - - return proto.addcapabilities(repo, caps) - - -def getadvertisedredirecttargets(repo, proto): - """Obtain a list of content redirect targets. - - Returns a list containing potential redirect targets that will be - advertised in capabilities data. Each dict MUST have the following - keys: - - name - The name of this redirect target. This is the identifier clients use - to refer to a target. It is transferred as part of every command - request. - - protocol - Network protocol used by this target. Typically this is the string - in front of the ``://`` in a URL. e.g. ``https``. - - uris - List of representative URIs for this target. Clients can use the - URIs to test parsing for compatibility or for ordering preference - for which target to use. - - The following optional keys are recognized: - - snirequired - Bool indicating if Server Name Indication (SNI) is required to - connect to this target. - - tlsversions - List of bytes indicating which TLS versions are supported by this - target. - - By default, clients reflect the target order advertised by servers - and servers will use the first client-advertised target when picking - a redirect target. So targets should be advertised in the order the - server prefers they be used. - """ - return [] - - -def wireprotocommand( - name, - args=None, - permission=b'push', - cachekeyfn=None, - extracapabilitiesfn=None, -): - """Decorator to declare a wire protocol command. - - ``name`` is the name of the wire protocol command being provided. - - ``args`` is a dict defining arguments accepted by the command. Keys are - the argument name. Values are dicts with the following keys: - - ``type`` - The argument data type. Must be one of the following string - literals: ``bytes``, ``int``, ``list``, ``dict``, ``set``, - or ``bool``. - - ``default`` - A callable returning the default value for this argument. If not - specified, ``None`` will be the default value. - - ``example`` - An example value for this argument. - - ``validvalues`` - Set of recognized values for this argument. - - ``permission`` defines the permission type needed to run this command. - Can be ``push`` or ``pull``. These roughly map to read-write and read-only, - respectively. Default is to assume command requires ``push`` permissions - because otherwise commands not declaring their permissions could modify - a repository that is supposed to be read-only. - - ``cachekeyfn`` defines an optional callable that can derive the - cache key for this request. - - ``extracapabilitiesfn`` defines an optional callable that defines extra - command capabilities/parameters that are advertised next to the command - in the capabilities data structure describing the server. The callable - receives as arguments the repository and protocol objects. It returns - a dict of extra fields to add to the command descriptor. - - Wire protocol commands are generators of objects to be serialized and - sent to the client. - - If a command raises an uncaught exception, this will be translated into - a command error. - - All commands can opt in to being cacheable by defining a function - (``cachekeyfn``) that is called to derive a cache key. This function - receives the same arguments as the command itself plus a ``cacher`` - argument containing the active cacher for the request and returns a bytes - containing the key in a cache the response to this command may be cached - under. - """ - transports = { - k for k, v in wireprototypes.TRANSPORTS.items() if v[b'version'] == 2 - } - - if permission not in (b'push', b'pull'): - raise error.ProgrammingError( - b'invalid wire protocol permission; ' - b'got %s; expected "push" or "pull"' % permission - ) - - if args is None: - args = {} - - if not isinstance(args, dict): - raise error.ProgrammingError( - b'arguments for version 2 commands must be declared as dicts' - ) - - for arg, meta in args.items(): - if arg == b'*': - raise error.ProgrammingError( - b'* argument name not allowed on version 2 commands' - ) - - if not isinstance(meta, dict): - raise error.ProgrammingError( - b'arguments for version 2 commands ' - b'must declare metadata as a dict' - ) - - if b'type' not in meta: - raise error.ProgrammingError( - b'%s argument for command %s does not ' - b'declare type field' % (arg, name) - ) - - if meta[b'type'] not in ( - b'bytes', - b'int', - b'list', - b'dict', - b'set', - b'bool', - ): - raise error.ProgrammingError( - b'%s argument for command %s has ' - b'illegal type: %s' % (arg, name, meta[b'type']) - ) - - if b'example' not in meta: - raise error.ProgrammingError( - b'%s argument for command %s does not ' - b'declare example field' % (arg, name) - ) - - meta[b'required'] = b'default' not in meta - - meta.setdefault(b'default', lambda: None) - meta.setdefault(b'validvalues', None) - - def register(func): - if name in COMMANDS: - raise error.ProgrammingError( - b'%s command already registered for version 2' % name - ) - - COMMANDS[name] = wireprototypes.commandentry( - func, - args=args, - transports=transports, - permission=permission, - cachekeyfn=cachekeyfn, - extracapabilitiesfn=extracapabilitiesfn, - ) - - return func - - return register - - -def makecommandcachekeyfn(command, localversion=None, allargs=False): - """Construct a cache key derivation function with common features. - - By default, the cache key is a hash of: - - * The command name. - * A global cache version number. - * A local cache version number (passed via ``localversion``). - * All the arguments passed to the command. - * The media type used. - * Wire protocol version string. - * The repository path. - """ - if not allargs: - raise error.ProgrammingError( - b'only allargs=True is currently supported' - ) - - if localversion is None: - raise error.ProgrammingError(b'must set localversion argument value') - - def cachekeyfn(repo, proto, cacher, **args): - spec = COMMANDS[command] - - # Commands that mutate the repo can not be cached. - if spec.permission == b'push': - return None - - # TODO config option to disable caching. - - # Our key derivation strategy is to construct a data structure - # holding everything that could influence cacheability and to hash - # the CBOR representation of that. Using CBOR seems like it might - # be overkill. However, simpler hashing mechanisms are prone to - # duplicate input issues. e.g. if you just concatenate two values, - # "foo"+"bar" is identical to "fo"+"obar". Using CBOR provides - # "padding" between values and prevents these problems. - - # Seed the hash with various data. - state = { - # To invalidate all cache keys. - b'globalversion': GLOBAL_CACHE_VERSION, - # More granular cache key invalidation. - b'localversion': localversion, - # Cache keys are segmented by command. - b'command': command, - # Throw in the media type and API version strings so changes - # to exchange semantics invalid cache. - b'mediatype': FRAMINGTYPE, - b'version': HTTP_WIREPROTO_V2, - # So same requests for different repos don't share cache keys. - b'repo': repo.root, - } - - # The arguments passed to us will have already been normalized. - # Default values will be set, etc. This is important because it - # means that it doesn't matter if clients send an explicit argument - # or rely on the default value: it will all normalize to the same - # set of arguments on the server and therefore the same cache key. - # - # Arguments by their very nature must support being encoded to CBOR. - # And the CBOR encoder is deterministic. So we hash the arguments - # by feeding the CBOR of their representation into the hasher. - if allargs: - state[b'args'] = pycompat.byteskwargs(args) - - cacher.adjustcachekeystate(state) - - hasher = hashutil.sha1() - for chunk in cborutil.streamencode(state): - hasher.update(chunk) - - return pycompat.sysbytes(hasher.hexdigest()) - - return cachekeyfn - - -def makeresponsecacher( - repo, proto, command, args, objencoderfn, redirecttargets, redirecthashes -): - """Construct a cacher for a cacheable command. - - Returns an ``iwireprotocolcommandcacher`` instance. - - Extensions can monkeypatch this function to provide custom caching - backends. - """ - return None - - -def resolvenodes(repo, revisions): - """Resolve nodes from a revisions specifier data structure.""" - cl = repo.changelog - clhasnode = cl.hasnode - - seen = set() - nodes = [] - - if not isinstance(revisions, list): - raise error.WireprotoCommandError( - b'revisions must be defined as an array' - ) - - for spec in revisions: - if b'type' not in spec: - raise error.WireprotoCommandError( - b'type key not present in revision specifier' - ) - - typ = spec[b'type'] - - if typ == b'changesetexplicit': - if b'nodes' not in spec: - raise error.WireprotoCommandError( - b'nodes key not present in changesetexplicit revision ' - b'specifier' - ) - - for node in spec[b'nodes']: - if node not in seen: - nodes.append(node) - seen.add(node) - - elif typ == b'changesetexplicitdepth': - for key in (b'nodes', b'depth'): - if key not in spec: - raise error.WireprotoCommandError( - b'%s key not present in changesetexplicitdepth revision ' - b'specifier', - (key,), - ) - - for rev in repo.revs( - b'ancestors(%ln, %s)', spec[b'nodes'], spec[b'depth'] - 1 - ): - node = cl.node(rev) - - if node not in seen: - nodes.append(node) - seen.add(node) - - elif typ == b'changesetdagrange': - for key in (b'roots', b'heads'): - if key not in spec: - raise error.WireprotoCommandError( - b'%s key not present in changesetdagrange revision ' - b'specifier', - (key,), - ) - - if not spec[b'heads']: - raise error.WireprotoCommandError( - b'heads key in changesetdagrange cannot be empty' - ) - - if spec[b'roots']: - common = [n for n in spec[b'roots'] if clhasnode(n)] - else: - common = [repo.nullid] - - for n in discovery.outgoing(repo, common, spec[b'heads']).missing: - if n not in seen: - nodes.append(n) - seen.add(n) - - else: - raise error.WireprotoCommandError( - b'unknown revision specifier type: %s', (typ,) - ) - - return nodes - - -@wireprotocommand(b'branchmap', permission=b'pull') -def branchmapv2(repo, proto): - yield { - encoding.fromlocal(k): v - for k, v in pycompat.iteritems(repo.branchmap()) - } - - -@wireprotocommand(b'capabilities', permission=b'pull') -def capabilitiesv2(repo, proto): - yield _capabilitiesv2(repo, proto) - - -@wireprotocommand( - b'changesetdata', - args={ - b'revisions': { - b'type': b'list', - b'example': [ - { - b'type': b'changesetexplicit', - b'nodes': [b'abcdef...'], - } - ], - }, - b'fields': { - b'type': b'set', - b'default': set, - b'example': {b'parents', b'revision'}, - b'validvalues': {b'bookmarks', b'parents', b'phase', b'revision'}, - }, - }, - permission=b'pull', -) -def changesetdata(repo, proto, revisions, fields): - # TODO look for unknown fields and abort when they can't be serviced. - # This could probably be validated by dispatcher using validvalues. - - cl = repo.changelog - outgoing = resolvenodes(repo, revisions) - publishing = repo.publishing() - - if outgoing: - repo.hook(b'preoutgoing', throw=True, source=b'serve') - - yield { - b'totalitems': len(outgoing), - } - - # The phases of nodes already transferred to the client may have changed - # since the client last requested data. We send phase-only records - # for these revisions, if requested. - # TODO actually do this. We'll probably want to emit phase heads - # in the ancestry set of the outgoing revisions. This will ensure - # that phase updates within that set are seen. - if b'phase' in fields: - pass - - nodebookmarks = {} - for mark, node in repo._bookmarks.items(): - nodebookmarks.setdefault(node, set()).add(mark) - - # It is already topologically sorted by revision number. - for node in outgoing: - d = { - b'node': node, - } - - if b'parents' in fields: - d[b'parents'] = cl.parents(node) - - if b'phase' in fields: - if publishing: - d[b'phase'] = b'public' - else: - ctx = repo[node] - d[b'phase'] = ctx.phasestr() - - if b'bookmarks' in fields and node in nodebookmarks: - d[b'bookmarks'] = sorted(nodebookmarks[node]) - del nodebookmarks[node] - - followingmeta = [] - followingdata = [] - - if b'revision' in fields: - revisiondata = cl.revision(node) - followingmeta.append((b'revision', len(revisiondata))) - followingdata.append(revisiondata) - - # TODO make it possible for extensions to wrap a function or register - # a handler to service custom fields. - - if followingmeta: - d[b'fieldsfollowing'] = followingmeta - - yield d - - for extra in followingdata: - yield extra - - # If requested, send bookmarks from nodes that didn't have revision - # data sent so receiver is aware of any bookmark updates. - if b'bookmarks' in fields: - for node, marks in sorted(pycompat.iteritems(nodebookmarks)): - yield { - b'node': node, - b'bookmarks': sorted(marks), - } - - -class FileAccessError(Exception): - """Represents an error accessing a specific file.""" - - def __init__(self, path, msg, args): - self.path = path - self.msg = msg - self.args = args - - -def getfilestore(repo, proto, path): - """Obtain a file storage object for use with wire protocol. - - Exists as a standalone function so extensions can monkeypatch to add - access control. - """ - # This seems to work even if the file doesn't exist. So catch - # "empty" files and return an error. - fl = repo.file(path) - - if not len(fl): - raise FileAccessError(path, b'unknown file: %s', (path,)) - - return fl - - -def emitfilerevisions(repo, path, revisions, linknodes, fields): - for revision in revisions: - d = { - b'node': revision.node, - } - - if b'parents' in fields: - d[b'parents'] = [revision.p1node, revision.p2node] - - if b'linknode' in fields: - d[b'linknode'] = linknodes[revision.node] - - followingmeta = [] - followingdata = [] - - if b'revision' in fields: - if revision.revision is not None: - followingmeta.append((b'revision', len(revision.revision))) - followingdata.append(revision.revision) - else: - d[b'deltabasenode'] = revision.basenode - followingmeta.append((b'delta', len(revision.delta))) - followingdata.append(revision.delta) - - if followingmeta: - d[b'fieldsfollowing'] = followingmeta - - yield d - - for extra in followingdata: - yield extra - - -def makefilematcher(repo, pathfilter): - """Construct a matcher from a path filter dict.""" - - # Validate values. - if pathfilter: - for key in (b'include', b'exclude'): - for pattern in pathfilter.get(key, []): - if not pattern.startswith((b'path:', b'rootfilesin:')): - raise error.WireprotoCommandError( - b'%s pattern must begin with `path:` or `rootfilesin:`; ' - b'got %s', - (key, pattern), - ) - - if pathfilter: - matcher = matchmod.match( - repo.root, - b'', - include=pathfilter.get(b'include', []), - exclude=pathfilter.get(b'exclude', []), - ) - else: - matcher = matchmod.match(repo.root, b'') - - # Requested patterns could include files not in the local store. So - # filter those out. - return repo.narrowmatch(matcher) - - -@wireprotocommand( - b'filedata', - args={ - b'haveparents': { - b'type': b'bool', - b'default': lambda: False, - b'example': True, - }, - b'nodes': { - b'type': b'list', - b'example': [b'0123456...'], - }, - b'fields': { - b'type': b'set', - b'default': set, - b'example': {b'parents', b'revision'}, - b'validvalues': {b'parents', b'revision', b'linknode'}, - }, - b'path': { - b'type': b'bytes', - b'example': b'foo.txt', - }, - }, - permission=b'pull', - # TODO censoring a file revision won't invalidate the cache. - # Figure out a way to take censoring into account when deriving - # the cache key. - cachekeyfn=makecommandcachekeyfn(b'filedata', 1, allargs=True), -) -def filedata(repo, proto, haveparents, nodes, fields, path): - # TODO this API allows access to file revisions that are attached to - # secret changesets. filesdata does not have this problem. Maybe this - # API should be deleted? - - try: - # Extensions may wish to access the protocol handler. - store = getfilestore(repo, proto, path) - except FileAccessError as e: - raise error.WireprotoCommandError(e.msg, e.args) - - clnode = repo.changelog.node - linknodes = {} - - # Validate requested nodes. - for node in nodes: - try: - store.rev(node) - except error.LookupError: - raise error.WireprotoCommandError( - b'unknown file node: %s', (hex(node),) - ) - - # TODO by creating the filectx against a specific file revision - # instead of changeset, linkrev() is always used. This is wrong for - # cases where linkrev() may refer to a hidden changeset. But since this - # API doesn't know anything about changesets, we're not sure how to - # disambiguate the linknode. Perhaps we should delete this API? - fctx = repo.filectx(path, fileid=node) - linknodes[node] = clnode(fctx.introrev()) - - revisions = store.emitrevisions( - nodes, - revisiondata=b'revision' in fields, - assumehaveparentrevisions=haveparents, - ) - - yield { - b'totalitems': len(nodes), - } - - for o in emitfilerevisions(repo, path, revisions, linknodes, fields): - yield o - - -def filesdatacapabilities(repo, proto): - batchsize = repo.ui.configint( - b'experimental', b'server.filesdata.recommended-batch-size' - ) - return { - b'recommendedbatchsize': batchsize, - } - - -@wireprotocommand( - b'filesdata', - args={ - b'haveparents': { - b'type': b'bool', - b'default': lambda: False, - b'example': True, - }, - b'fields': { - b'type': b'set', - b'default': set, - b'example': {b'parents', b'revision'}, - b'validvalues': { - b'firstchangeset', - b'linknode', - b'parents', - b'revision', - }, - }, - b'pathfilter': { - b'type': b'dict', - b'default': lambda: None, - b'example': {b'include': [b'path:tests']}, - }, - b'revisions': { - b'type': b'list', - b'example': [ - { - b'type': b'changesetexplicit', - b'nodes': [b'abcdef...'], - } - ], - }, - }, - permission=b'pull', - # TODO censoring a file revision won't invalidate the cache. - # Figure out a way to take censoring into account when deriving - # the cache key. - cachekeyfn=makecommandcachekeyfn(b'filesdata', 1, allargs=True), - extracapabilitiesfn=filesdatacapabilities, -) -def filesdata(repo, proto, haveparents, fields, pathfilter, revisions): - # TODO This should operate on a repo that exposes obsolete changesets. There - # is a race between a client making a push that obsoletes a changeset and - # another client fetching files data for that changeset. If a client has a - # changeset, it should probably be allowed to access files data for that - # changeset. - - outgoing = resolvenodes(repo, revisions) - filematcher = makefilematcher(repo, pathfilter) - - # path -> {fnode: linknode} - fnodes = collections.defaultdict(dict) - - # We collect the set of relevant file revisions by iterating the changeset - # revisions and either walking the set of files recorded in the changeset - # or by walking the manifest at that revision. There is probably room for a - # storage-level API to request this data, as it can be expensive to compute - # and would benefit from caching or alternate storage from what revlogs - # provide. - for node in outgoing: - ctx = repo[node] - mctx = ctx.manifestctx() - md = mctx.read() - - if haveparents: - checkpaths = ctx.files() - else: - checkpaths = md.keys() - - for path in checkpaths: - fnode = md[path] - - if path in fnodes and fnode in fnodes[path]: - continue - - if not filematcher(path): - continue - - fnodes[path].setdefault(fnode, node) - - yield { - b'totalpaths': len(fnodes), - b'totalitems': sum(len(v) for v in fnodes.values()), - } - - for path, filenodes in sorted(fnodes.items()): - try: - store = getfilestore(repo, proto, path) - except FileAccessError as e: - raise error.WireprotoCommandError(e.msg, e.args) - - yield { - b'path': path, - b'totalitems': len(filenodes), - } - - revisions = store.emitrevisions( - filenodes.keys(), - revisiondata=b'revision' in fields, - assumehaveparentrevisions=haveparents, - ) - - for o in emitfilerevisions(repo, path, revisions, filenodes, fields): - yield o - - -@wireprotocommand( - b'heads', - args={ - b'publiconly': { - b'type': b'bool', - b'default': lambda: False, - b'example': False, - }, - }, - permission=b'pull', -) -def headsv2(repo, proto, publiconly): - if publiconly: - repo = repo.filtered(b'immutable') - - yield repo.heads() - - -@wireprotocommand( - b'known', - args={ - b'nodes': { - b'type': b'list', - b'default': list, - b'example': [b'deadbeef'], - }, - }, - permission=b'pull', -) -def knownv2(repo, proto, nodes): - result = b''.join(b'1' if n else b'0' for n in repo.known(nodes)) - yield result - - -@wireprotocommand( - b'listkeys', - args={ - b'namespace': { - b'type': b'bytes', - b'example': b'ns', - }, - }, - permission=b'pull', -) -def listkeysv2(repo, proto, namespace): - keys = repo.listkeys(encoding.tolocal(namespace)) - keys = { - encoding.fromlocal(k): encoding.fromlocal(v) - for k, v in pycompat.iteritems(keys) - } - - yield keys - - -@wireprotocommand( - b'lookup', - args={ - b'key': { - b'type': b'bytes', - b'example': b'foo', - }, - }, - permission=b'pull', -) -def lookupv2(repo, proto, key): - key = encoding.tolocal(key) - - # TODO handle exception. - node = repo.lookup(key) - - yield node - - -def manifestdatacapabilities(repo, proto): - batchsize = repo.ui.configint( - b'experimental', b'server.manifestdata.recommended-batch-size' - ) - - return { - b'recommendedbatchsize': batchsize, - } - - -@wireprotocommand( - b'manifestdata', - args={ - b'nodes': { - b'type': b'list', - b'example': [b'0123456...'], - }, - b'haveparents': { - b'type': b'bool', - b'default': lambda: False, - b'example': True, - }, - b'fields': { - b'type': b'set', - b'default': set, - b'example': {b'parents', b'revision'}, - b'validvalues': {b'parents', b'revision'}, - }, - b'tree': { - b'type': b'bytes', - b'example': b'', - }, - }, - permission=b'pull', - cachekeyfn=makecommandcachekeyfn(b'manifestdata', 1, allargs=True), - extracapabilitiesfn=manifestdatacapabilities, -) -def manifestdata(repo, proto, haveparents, nodes, fields, tree): - store = repo.manifestlog.getstorage(tree) - - # Validate the node is known and abort on unknown revisions. - for node in nodes: - try: - store.rev(node) - except error.LookupError: - raise error.WireprotoCommandError(b'unknown node: %s', (node,)) - - revisions = store.emitrevisions( - nodes, - revisiondata=b'revision' in fields, - assumehaveparentrevisions=haveparents, - ) - - yield { - b'totalitems': len(nodes), - } - - for revision in revisions: - d = { - b'node': revision.node, - } - - if b'parents' in fields: - d[b'parents'] = [revision.p1node, revision.p2node] - - followingmeta = [] - followingdata = [] - - if b'revision' in fields: - if revision.revision is not None: - followingmeta.append((b'revision', len(revision.revision))) - followingdata.append(revision.revision) - else: - d[b'deltabasenode'] = revision.basenode - followingmeta.append((b'delta', len(revision.delta))) - followingdata.append(revision.delta) - - if followingmeta: - d[b'fieldsfollowing'] = followingmeta - - yield d - - for extra in followingdata: - yield extra - - -@wireprotocommand( - b'pushkey', - args={ - b'namespace': { - b'type': b'bytes', - b'example': b'ns', - }, - b'key': { - b'type': b'bytes', - b'example': b'key', - }, - b'old': { - b'type': b'bytes', - b'example': b'old', - }, - b'new': { - b'type': b'bytes', - b'example': b'new', - }, - }, - permission=b'push', -) -def pushkeyv2(repo, proto, namespace, key, old, new): - # TODO handle ui output redirection - yield repo.pushkey( - encoding.tolocal(namespace), - encoding.tolocal(key), - encoding.tolocal(old), - encoding.tolocal(new), - ) - - -@wireprotocommand( - b'rawstorefiledata', - args={ - b'files': { - b'type': b'list', - b'example': [b'changelog', b'manifestlog'], - }, - b'pathfilter': { - b'type': b'list', - b'default': lambda: None, - b'example': {b'include': [b'path:tests']}, - }, - }, - permission=b'pull', -) -def rawstorefiledata(repo, proto, files, pathfilter): - if not streamclone.allowservergeneration(repo): - raise error.WireprotoCommandError(b'stream clone is disabled') - - # TODO support dynamically advertising what store files "sets" are - # available. For now, we support changelog, manifestlog, and files. - files = set(files) - allowedfiles = {b'changelog', b'manifestlog'} - - unsupported = files - allowedfiles - if unsupported: - raise error.WireprotoCommandError( - b'unknown file type: %s', (b', '.join(sorted(unsupported)),) - ) - - with repo.lock(): - topfiles = list(repo.store.topfiles()) - - sendfiles = [] - totalsize = 0 - - # TODO this is a bunch of storage layer interface abstractions because - # it assumes revlogs. - for rl_type, name, size in topfiles: - # XXX use the `rl_type` for that - if b'changelog' in files and name.startswith(b'00changelog'): - pass - elif b'manifestlog' in files and name.startswith(b'00manifest'): - pass - else: - continue - - sendfiles.append((b'store', name, size)) - totalsize += size - - yield { - b'filecount': len(sendfiles), - b'totalsize': totalsize, - } - - for location, name, size in sendfiles: - yield { - b'location': location, - b'path': name, - b'size': size, - } - - # We have to use a closure for this to ensure the context manager is - # closed only after sending the final chunk. - def getfiledata(): - with repo.svfs(name, b'rb', auditpath=False) as fh: - for chunk in util.filechunkiter(fh, limit=size): - yield chunk - - yield wireprototypes.indefinitebytestringresponse(getfiledata()) diff -r d6c53b40b078 -r 04688c51f81f tests/test-bookmarks-pushpull.t --- a/tests/test-bookmarks-pushpull.t Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/test-bookmarks-pushpull.t Tue Dec 07 16:44:22 2021 +0100 @@ -715,14 +715,15 @@ $ cat < ../lookuphook.py > """small extensions adding a hook after wireprotocol lookup to test race""" > import functools - > from mercurial import wireprotov1server, wireprotov2server + > from mercurial import wireprotov1server > > def wrappedlookup(orig, repo, *args, **kwargs): > ret = orig(repo, *args, **kwargs) > repo.hook(b'lookup') > return ret - > for table in [wireprotov1server.commands, wireprotov2server.COMMANDS]: - > table[b'lookup'].func = functools.partial(wrappedlookup, table[b'lookup'].func) + > + > table = wireprotov1server.commands + > table[b'lookup'].func = functools.partial(wrappedlookup, table[b'lookup'].func) > EOF $ cat < ../pull-race/.hg/hgrc > [extensions] diff -r d6c53b40b078 -r 04688c51f81f tests/test-bundle2-exchange.t --- a/tests/test-bundle2-exchange.t Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/test-bundle2-exchange.t Tue Dec 07 16:44:22 2021 +0100 @@ -1,13 +1,3 @@ -#testcases sshv1 sshv2 - -#if sshv2 - $ cat >> $HGRCPATH << EOF - > [experimental] - > sshpeer.advertise-v2 = true - > sshserver.support-v2 = true - > EOF -#endif - Test exchange of common information using bundle2 diff -r d6c53b40b078 -r 04688c51f81f tests/test-bundle2-pushback.t --- a/tests/test-bundle2-pushback.t Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/test-bundle2-pushback.t Tue Dec 07 16:44:22 2021 +0100 @@ -1,13 +1,3 @@ -#testcases sshv1 sshv2 - -#if sshv2 - $ cat >> $HGRCPATH << EOF - > [experimental] - > sshpeer.advertise-v2 = true - > sshserver.support-v2 = true - > EOF -#endif - $ cat > bundle2.py << EOF > """A small extension to test bundle2 pushback parts. > Current bundle2 implementation doesn't provide a way to generate those diff -r d6c53b40b078 -r 04688c51f81f tests/test-bundle2-remote-changegroup.t --- a/tests/test-bundle2-remote-changegroup.t Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/test-bundle2-remote-changegroup.t Tue Dec 07 16:44:22 2021 +0100 @@ -1,13 +1,3 @@ -#testcases sshv1 sshv2 - -#if sshv2 - $ cat >> $HGRCPATH << EOF - > [experimental] - > sshpeer.advertise-v2 = true - > sshserver.support-v2 = true - > EOF -#endif - Create an extension to test bundle2 remote-changegroup parts $ cat > bundle2.py << EOF diff -r d6c53b40b078 -r 04688c51f81f tests/test-check-interfaces.py --- a/tests/test-check-interfaces.py Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/test-check-interfaces.py Tue Dec 07 16:44:22 2021 +0100 @@ -39,7 +39,6 @@ wireprotoserver, wireprototypes, wireprotov1peer, - wireprotov2server, ) testdir = os.path.dirname(__file__) @@ -129,9 +128,6 @@ ziverify.verifyClass(repository.ipeerbase, httppeer.httppeer) checkzobject(httppeer.httppeer(None, None, None, dummyopener(), None, None)) - ziverify.verifyClass(repository.ipeerv2, httppeer.httpv2peer) - checkzobject(httppeer.httpv2peer(None, b'', b'', None, None, None)) - ziverify.verifyClass(repository.ipeerbase, localrepo.localpeer) checkzobject(localrepo.localpeer(dummyrepo())) @@ -158,19 +154,6 @@ ) ) - ziverify.verifyClass(repository.ipeerbase, sshpeer.sshv2peer) - checkzobject( - sshpeer.sshv2peer( - ui, - b'ssh://localhost/foo', - b'', - dummypipe(), - dummypipe(), - None, - None, - ) - ) - ziverify.verifyClass(repository.ipeerbase, bundlerepo.bundlepeer) checkzobject(bundlerepo.bundlepeer(dummyrepo())) @@ -193,26 +176,15 @@ wireprototypes.baseprotocolhandler, wireprotoserver.sshv1protocolhandler ) ziverify.verifyClass( - wireprototypes.baseprotocolhandler, wireprotoserver.sshv2protocolhandler - ) - ziverify.verifyClass( wireprototypes.baseprotocolhandler, wireprotoserver.httpv1protocolhandler, ) - ziverify.verifyClass( - wireprototypes.baseprotocolhandler, - wireprotov2server.httpv2protocolhandler, - ) sshv1 = wireprotoserver.sshv1protocolhandler(None, None, None) checkzobject(sshv1) - sshv2 = wireprotoserver.sshv2protocolhandler(None, None, None) - checkzobject(sshv2) httpv1 = wireprotoserver.httpv1protocolhandler(None, None, None) checkzobject(httpv1) - httpv2 = wireprotov2server.httpv2protocolhandler(None, None) - checkzobject(httpv2) ziverify.verifyClass(repository.ifilestorage, filelog.filelog) ziverify.verifyClass(repository.imanifestdict, manifest.manifestdict) diff -r d6c53b40b078 -r 04688c51f81f tests/test-clone.t --- a/tests/test-clone.t Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/test-clone.t Tue Dec 07 16:44:22 2021 +0100 @@ -1,13 +1,3 @@ -#testcases sshv1 sshv2 - -#if sshv2 - $ cat >> $HGRCPATH << EOF - > [experimental] - > sshpeer.advertise-v2 = true - > sshserver.support-v2 = true - > EOF -#endif - Prepare repo a: $ hg init a @@ -1206,14 +1196,12 @@ #if windows $ hg clone "ssh://%26touch%20owned%20/" --debug running sh -c "read l; read l; read l" "&touch owned " "hg -R . serve --stdio" - sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !) sending hello command sending between command abort: no suitable response from remote hg [255] $ hg clone "ssh://example.com:%26touch%20owned%20/" --debug running sh -c "read l; read l; read l" -p "&touch owned " example.com "hg -R . serve --stdio" - sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !) sending hello command sending between command abort: no suitable response from remote hg @@ -1221,14 +1209,12 @@ #else $ hg clone "ssh://%3btouch%20owned%20/" --debug running sh -c "read l; read l; read l" ';touch owned ' 'hg -R . serve --stdio' - sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !) sending hello command sending between command abort: no suitable response from remote hg [255] $ hg clone "ssh://example.com:%3btouch%20owned%20/" --debug running sh -c "read l; read l; read l" -p ';touch owned ' example.com 'hg -R . serve --stdio' - sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !) sending hello command sending between command abort: no suitable response from remote hg @@ -1237,7 +1223,6 @@ $ hg clone "ssh://v-alid.example.com/" --debug running sh -c "read l; read l; read l" v-alid\.example\.com ['"]hg -R \. serve --stdio['"] (re) - sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !) sending hello command sending between command abort: no suitable response from remote hg diff -r d6c53b40b078 -r 04688c51f81f tests/test-http-api-httpv2.t --- a/tests/test-http-api-httpv2.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,743 +0,0 @@ -#require no-chg - - $ . $TESTDIR/wireprotohelpers.sh - $ enabledummycommands - - $ hg init server - $ cat > server/.hg/hgrc << EOF - > [experimental] - > web.apiserver = true - > EOF - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid - $ cat hg.pid > $DAEMON_PIDS - -HTTP v2 protocol not enabled by default - - $ sendhttpraw << EOF - > httprequest GET api/$HTTPV2 - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /api/exp-http-v2-0003 HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 404 Not Found\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 33\r\n - s> \r\n - s> API exp-http-v2-0003 not enabled\n - -Restart server with support for HTTP v2 API - - $ killdaemons.py - $ enablehttpv2 server - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid - $ cat hg.pid > $DAEMON_PIDS - -Request to unknown command yields 404 - - $ sendhttpraw << EOF - > httprequest POST api/$HTTPV2/ro/badcommand - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/badcommand HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 404 Not Found\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 42\r\n - s> \r\n - s> unknown wire protocol command: badcommand\n - -GET to read-only command yields a 405 - - $ sendhttpraw << EOF - > httprequest GET api/$HTTPV2/ro/customreadonly - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 405 Method Not Allowed\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Allow: POST\r\n - s> Content-Length: 30\r\n - s> \r\n - s> commands require POST requests - -Missing Accept header results in 406 - - $ sendhttpraw << EOF - > httprequest POST api/$HTTPV2/ro/customreadonly - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 406 Not Acceptable\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 85\r\n - s> \r\n - s> client MUST specify Accept header with value: application/mercurial-exp-framing-0006\n - -Bad Accept header results in 406 - - $ sendhttpraw << EOF - > httprequest POST api/$HTTPV2/ro/customreadonly - > accept: invalid - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: invalid\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 406 Not Acceptable\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 85\r\n - s> \r\n - s> client MUST specify Accept header with value: application/mercurial-exp-framing-0006\n - -Bad Content-Type header results in 415 - - $ sendhttpraw << EOF - > httprequest POST api/$HTTPV2/ro/customreadonly - > accept: $MEDIATYPE - > user-agent: test - > content-type: badmedia - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: badmedia\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 415 Unsupported Media Type\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 88\r\n - s> \r\n - s> client MUST send Content-Type header with value: application/mercurial-exp-framing-0006\n - -Request to read-only command works out of the box - - $ sendhttpraw << EOF - > httprequest POST api/$HTTPV2/ro/customreadonly - > accept: $MEDIATYPE - > content-type: $MEDIATYPE - > user-agent: test - > frame 1 1 stream-begin command-request new cbor:{b'name': b'customreadonly'} - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> *\r\n (glob) - s> content-type: application/mercurial-exp-framing-0006\r\n - s> user-agent: test\r\n - s> content-length: 29\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> \x15\x00\x00\x01\x00\x01\x01\x11\xa1DnameNcustomreadonly - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0006\r\n - s> Transfer-Encoding: chunked\r\n - s> \r\n - s> 11\r\n - s> \t\x00\x00\x01\x00\x02\x01\x92Hidentity - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x01\x00\x02\x041\xa1FstatusBok - s> \r\n - s> 27\r\n - s> \x1f\x00\x00\x01\x00\x02\x041X\x1dcustomreadonly bytes response - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x01\x00\x02\x002 - s> \r\n - s> 0\r\n - s> \r\n - - $ sendhttpv2peerverbose << EOF - > command customreadonly - > EOF - creating http peer for wire protocol version 2 - sending customreadonly command - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: application/mercurial-exp-framing-0006\r\n - s> content-length: 65\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x15\x00\x00\x01\x00\x01\x00\x11\xa1DnameNcustomreadonly - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0006\r\n - s> Transfer-Encoding: chunked\r\n - s> \r\n - s> 11\r\n - s> \t\x00\x00\x01\x00\x02\x01\x92 - s> Hidentity - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x01\x00\x02\x041 - s> \xa1FstatusBok - s> \r\n - s> 27\r\n - s> \x1f\x00\x00\x01\x00\x02\x041 - s> X\x1dcustomreadonly bytes response - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x01\x00\x02\x002 - s> \r\n - s> 0\r\n - s> \r\n - response: gen[ - b'customreadonly bytes response' - ] - (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob) - -Request to read-write command fails because server is read-only by default - -GET to read-write request yields 405 - - $ sendhttpraw << EOF - > httprequest GET api/$HTTPV2/rw/customreadonly - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /api/exp-http-v2-0003/rw/customreadonly HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 405 Method Not Allowed\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Allow: POST\r\n - s> Content-Length: 30\r\n - s> \r\n - s> commands require POST requests - -Even for unknown commands - - $ sendhttpraw << EOF - > httprequest GET api/$HTTPV2/rw/badcommand - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /api/exp-http-v2-0003/rw/badcommand HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 405 Method Not Allowed\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Allow: POST\r\n - s> Content-Length: 30\r\n - s> \r\n - s> commands require POST requests - -SSL required by default - - $ sendhttpraw << EOF - > httprequest POST api/$HTTPV2/rw/customreadonly - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/rw/customreadonly HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 403 ssl required\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Length: 17\r\n - s> \r\n - s> permission denied - -Restart server to allow non-ssl read-write operations - - $ killdaemons.py - $ cat > server/.hg/hgrc << EOF - > [experimental] - > web.apiserver = true - > web.api.http-v2 = true - > [web] - > push_ssl = false - > allow-push = * - > EOF - - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -Authorized request for valid read-write command works - - $ sendhttpraw << EOF - > httprequest POST api/$HTTPV2/rw/customreadonly - > user-agent: test - > accept: $MEDIATYPE - > content-type: $MEDIATYPE - > frame 1 1 stream-begin command-request new cbor:{b'name': b'customreadonly'} - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/rw/customreadonly HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: application/mercurial-exp-framing-0006\r\n - s> user-agent: test\r\n - s> content-length: 29\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> \x15\x00\x00\x01\x00\x01\x01\x11\xa1DnameNcustomreadonly - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0006\r\n - s> Transfer-Encoding: chunked\r\n - s> \r\n - s> 11\r\n - s> \t\x00\x00\x01\x00\x02\x01\x92Hidentity - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x01\x00\x02\x041\xa1FstatusBok - s> \r\n - s> 27\r\n - s> \x1f\x00\x00\x01\x00\x02\x041X\x1dcustomreadonly bytes response - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x01\x00\x02\x002 - s> \r\n - s> 0\r\n - s> \r\n - -Authorized request for unknown command is rejected - - $ sendhttpraw << EOF - > httprequest POST api/$HTTPV2/rw/badcommand - > user-agent: test - > accept: $MEDIATYPE - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/rw/badcommand HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 404 Not Found\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 42\r\n - s> \r\n - s> unknown wire protocol command: badcommand\n - -debugreflect isn't enabled by default - - $ sendhttpraw << EOF - > httprequest POST api/$HTTPV2/ro/debugreflect - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/debugreflect HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 404 Not Found\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 34\r\n - s> \r\n - s> debugreflect service not available - -Restart server to get debugreflect endpoint - - $ killdaemons.py - $ cat > server/.hg/hgrc << EOF - > [experimental] - > web.apiserver = true - > web.api.debugreflect = true - > web.api.http-v2 = true - > [web] - > push_ssl = false - > allow-push = * - > EOF - - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -Command frames can be reflected via debugreflect - - $ sendhttpraw << EOF - > httprequest POST api/$HTTPV2/ro/debugreflect - > accept: $MEDIATYPE - > content-type: $MEDIATYPE - > user-agent: test - > frame 1 1 stream-begin command-request new cbor:{b'name': b'command1', b'args': {b'foo': b'val1', b'bar1': b'val'}} - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/debugreflect HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: application/mercurial-exp-framing-0006\r\n - s> user-agent: test\r\n - s> content-length: 47\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> \'\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa2Dbar1CvalCfooDval1DnameHcommand1 - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 223\r\n - s> \r\n - s> received: 1 1 1 \xa2Dargs\xa2Dbar1CvalCfooDval1DnameHcommand1\n - s> ["runcommand", {"args": {"bar1": "val", "foo": "val1"}, "command": "command1", "data": null, "redirect": null, "requestid": 1}]\n - s> received: \n - s> {"action": "noop"} - -Multiple requests to regular command URL are not allowed - - $ sendhttpraw << EOF - > httprequest POST api/$HTTPV2/ro/customreadonly - > accept: $MEDIATYPE - > content-type: $MEDIATYPE - > user-agent: test - > frame 1 1 stream-begin command-request new cbor:{b'name': b'customreadonly'} - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: application/mercurial-exp-framing-0006\r\n - s> user-agent: test\r\n - s> content-length: 29\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> \x15\x00\x00\x01\x00\x01\x01\x11\xa1DnameNcustomreadonly - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0006\r\n - s> Transfer-Encoding: chunked\r\n - s> \r\n - s> 11\r\n - s> \t\x00\x00\x01\x00\x02\x01\x92Hidentity - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x01\x00\x02\x041\xa1FstatusBok - s> \r\n - s> 27\r\n - s> \x1f\x00\x00\x01\x00\x02\x041X\x1dcustomreadonly bytes response - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x01\x00\x02\x002 - s> \r\n - s> 0\r\n - s> \r\n - -Multiple requests to "multirequest" URL are allowed - - $ sendhttpraw << EOF - > httprequest POST api/$HTTPV2/ro/multirequest - > accept: $MEDIATYPE - > content-type: $MEDIATYPE - > user-agent: test - > frame 1 1 stream-begin command-request new cbor:{b'name': b'customreadonly'} - > frame 3 1 0 command-request new cbor:{b'name': b'customreadonly'} - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/multirequest HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> *\r\n (glob) - s> *\r\n (glob) - s> user-agent: test\r\n - s> content-length: 58\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> \x15\x00\x00\x01\x00\x01\x01\x11\xa1DnameNcustomreadonly\x15\x00\x00\x03\x00\x01\x00\x11\xa1DnameNcustomreadonly - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0006\r\n - s> Transfer-Encoding: chunked\r\n - s> \r\n - s> 11\r\n - s> \t\x00\x00\x01\x00\x02\x01\x92Hidentity - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x01\x00\x02\x041\xa1FstatusBok - s> \r\n - s> 27\r\n - s> \x1f\x00\x00\x01\x00\x02\x041X\x1dcustomreadonly bytes response - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x01\x00\x02\x002 - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x03\x00\x02\x041\xa1FstatusBok - s> \r\n - s> 27\r\n - s> \x1f\x00\x00\x03\x00\x02\x041X\x1dcustomreadonly bytes response - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x03\x00\x02\x002 - s> \r\n - s> 0\r\n - s> \r\n - -Interleaved requests to "multirequest" are processed - - $ sendhttpraw << EOF - > httprequest POST api/$HTTPV2/ro/multirequest - > accept: $MEDIATYPE - > content-type: $MEDIATYPE - > user-agent: test - > frame 1 1 stream-begin command-request new|more \xa2Dargs\xa1Inamespace - > frame 3 1 0 command-request new|more \xa2Dargs\xa1Inamespace - > frame 3 1 0 command-request continuation JnamespacesDnameHlistkeys - > frame 1 1 0 command-request continuation IbookmarksDnameHlistkeys - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/multirequest HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: application/mercurial-exp-framing-0006\r\n - s> user-agent: test\r\n - s> content-length: 115\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> \x11\x00\x00\x01\x00\x01\x01\x15\xa2Dargs\xa1Inamespace\x11\x00\x00\x03\x00\x01\x00\x15\xa2Dargs\xa1Inamespace\x19\x00\x00\x03\x00\x01\x00\x12JnamespacesDnameHlistkeys\x18\x00\x00\x01\x00\x01\x00\x12IbookmarksDnameHlistkeys - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0006\r\n - s> Transfer-Encoding: chunked\r\n - s> \r\n - s> 11\r\n - s> \t\x00\x00\x03\x00\x02\x01\x92Hidentity - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x03\x00\x02\x041\xa1FstatusBok - s> \r\n - s> 28\r\n - s> \x00\x00\x03\x00\x02\x041\xa3Ibookmarks@Jnamespaces@Fphases@ - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x03\x00\x02\x002 - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x01\x00\x02\x041\xa1FstatusBok - s> \r\n - s> 9\r\n - s> \x01\x00\x00\x01\x00\x02\x041\xa0 - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x01\x00\x02\x002 - s> \r\n - s> 0\r\n - s> \r\n - -Restart server to disable read-write access - - $ killdaemons.py - $ cat > server/.hg/hgrc << EOF - > [experimental] - > web.apiserver = true - > web.api.debugreflect = true - > web.api.http-v2 = true - > [web] - > push_ssl = false - > EOF - - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -Attempting to run a read-write command via multirequest on read-only URL is not allowed - - $ sendhttpraw << EOF - > httprequest POST api/$HTTPV2/ro/multirequest - > accept: $MEDIATYPE - > content-type: $MEDIATYPE - > user-agent: test - > frame 1 1 stream-begin command-request new cbor:{b'name': b'pushkey'} - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/multirequest HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: application/mercurial-exp-framing-0006\r\n - s> user-agent: test\r\n - s> content-length: 22\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> \x0e\x00\x00\x01\x00\x01\x01\x11\xa1DnameGpushkey - s> makefile('rb', None) - s> HTTP/1.1 403 Forbidden\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 52\r\n - s> \r\n - s> insufficient permissions to execute command: pushkey - -Defining an invalid content encoding results in warning - - $ hg --config experimental.httppeer.v2-encoder-order=identity,badencoder --verbose debugwireproto --nologhandshake --peer http2 http://$LOCALIP:$HGPORT/ << EOF - > command heads - > EOF - creating http peer for wire protocol version 2 - sending heads command - wire protocol version 2 encoder referenced in config (badencoder) is not known; ignoring - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/heads HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: application/mercurial-exp-framing-0006\r\n - s> content-length: 56\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x0c\x00\x00\x01\x00\x01\x00\x11\xa1DnameEheads - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0006\r\n - s> Transfer-Encoding: chunked\r\n - s> \r\n - s> 11\r\n - s> \t\x00\x00\x01\x00\x02\x01\x92 - s> Hidentity - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x01\x00\x02\x041 - s> \xa1FstatusBok - s> \r\n - s> 1e\r\n - s> \x16\x00\x00\x01\x00\x02\x041 - s> \x81T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x01\x00\x02\x002 - s> \r\n - s> 0\r\n - s> \r\n - response: [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob) - -#if zstd - - $ hg --verbose debugwireproto --nologhandshake --peer http2 http://$LOCALIP:$HGPORT/ << EOF - > command heads - > EOF - creating http peer for wire protocol version 2 - sending heads command - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/heads HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: application/mercurial-exp-framing-0006\r\n - s> content-length: 70\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> *\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x83Hzstd-8mbDzlibHidentity\x0c\x00\x00\x01\x00\x01\x00\x11\xa1DnameEheads - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0006\r\n - s> Transfer-Encoding: chunked\r\n - s> \r\n - s> 11\r\n - s> \t\x00\x00\x01\x00\x02\x01\x92 - s> Hzstd-8mb - s> \r\n - s> 25\r\n - s> \x1d\x00\x00\x01\x00\x02\x042 - s> (\xb5/\xfd\x00X\xa4\x00\x00p\xa1FstatusBok\x81T\x00\x01\x00\tP\x02 - s> \r\n - s> 0\r\n - s> \r\n - response: [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob) - -#endif - - $ cat error.log diff -r d6c53b40b078 -r 04688c51f81f tests/test-http-api.t --- a/tests/test-http-api.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,299 +0,0 @@ -#require no-chg - - $ send() { - > hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT/ - > } - - $ hg init server - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid - $ cat hg.pid > $DAEMON_PIDS - -Request to /api fails unless web.apiserver is enabled - - $ get-with-headers.py $LOCALIP:$HGPORT api - 400 no such method: api - - - - - - - - - - $TESTTMP/server: error - - - -
- - -
- - -

error

- - - - -
-

- An error occurred while processing your request: -

-

- no such method: api -

-
-
-
- - - - - - - [1] - - $ get-with-headers.py $LOCALIP:$HGPORT api/ - 400 no such method: api - - - - - - - - - - $TESTTMP/server: error - - - -
- - -
- - -

error

- - - - -
-

- An error occurred while processing your request: -

-

- no such method: api -

-
-
-
- - - - - - - [1] - -Restart server with support for API server - - $ killdaemons.py - $ cat > server/.hg/hgrc << EOF - > [experimental] - > web.apiserver = true - > EOF - - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid - $ cat hg.pid > $DAEMON_PIDS - -/api lists available APIs (empty since none are available by default) - - $ send << EOF - > httprequest GET api - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /api HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 100\r\n - s> \r\n - s> APIs can be accessed at /api/, where can be one of the following:\n - s> \n - s> (no available APIs)\n - - $ send << EOF - > httprequest GET api/ - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /api/ HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 100\r\n - s> \r\n - s> APIs can be accessed at /api/, where can be one of the following:\n - s> \n - s> (no available APIs)\n - -Accessing an unknown API yields a 404 - - $ send << EOF - > httprequest GET api/unknown - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /api/unknown HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 404 Not Found\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 33\r\n - s> \r\n - s> Unknown API: unknown\n - s> Known APIs: - -Accessing a known but not enabled API yields a different error - - $ send << EOF - > httprequest GET api/exp-http-v2-0003 - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /api/exp-http-v2-0003 HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 404 Not Found\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 33\r\n - s> \r\n - s> API exp-http-v2-0003 not enabled\n - -Restart server with support for HTTP v2 API - - $ killdaemons.py - $ cat > server/.hg/hgrc << EOF - > [experimental] - > web.apiserver = true - > web.api.http-v2 = true - > EOF - - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid - $ cat hg.pid > $DAEMON_PIDS - -/api lists the HTTP v2 protocol as available - - $ send << EOF - > httprequest GET api - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /api HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 96\r\n - s> \r\n - s> APIs can be accessed at /api/, where can be one of the following:\n - s> \n - s> exp-http-v2-0003 - - $ send << EOF - > httprequest GET api/ - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /api/ HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 96\r\n - s> \r\n - s> APIs can be accessed at /api/, where can be one of the following:\n - s> \n - s> exp-http-v2-0003 diff -r d6c53b40b078 -r 04688c51f81f tests/test-http-protocol.t --- a/tests/test-http-protocol.t Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/test-http-protocol.t Tue Dec 07 16:44:22 2021 +0100 @@ -252,121 +252,6 @@ s> bookmarks\t\n s> namespaces\t\n s> phases\t - -Client with HTTPv2 enabled advertises that and gets old capabilities response from old server - - $ hg --config experimental.httppeer.advertise-v2=true --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF - > command heads - > EOF - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> vary: X-HgProto-1,X-HgUpgrade-1\r\n - s> x-hgproto-1: cbor\r\n - s> x-hgupgrade-1: exp-http-v2-0003\r\n - s> accept: application/mercurial-0.1\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 Script output follows\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-0.1\r\n - s> Content-Length: *\r\n (glob) - s> \r\n - s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - sending heads command - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=heads HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> vary: X-HgProto-1\r\n - s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n - s> accept: application/mercurial-0.1\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 Script output follows\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-0.1\r\n - s> Content-Length: 41\r\n - s> \r\n - s> 0000000000000000000000000000000000000000\n - response: [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ killdaemons.py - $ enablehttpv2 empty - $ hg --config server.compressionengines=zlib -R empty serve -p $HGPORT -d --pid-file hg.pid - $ cat hg.pid > $DAEMON_PIDS - -Client with HTTPv2 enabled automatically upgrades if the server supports it - - $ hg --config experimental.httppeer.advertise-v2=true --config experimental.httppeer.v2-encoder-order=identity --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF - > command heads - > EOF - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> vary: X-HgProto-1,X-HgUpgrade-1\r\n - s> x-hgproto-1: cbor\r\n - s> x-hgupgrade-1: exp-http-v2-0003\r\n - s> accept: application/mercurial-0.1\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-cbor\r\n - s> Content-Length: *\r\n (glob) - s> \r\n - s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogNv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - sending heads command - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/heads HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: application/mercurial-exp-framing-0006\r\n - s> content-length: 56\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x0c\x00\x00\x01\x00\x01\x00\x11\xa1DnameEheads - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0006\r\n - s> Transfer-Encoding: chunked\r\n - s> \r\n - s> 11\r\n - s> \t\x00\x00\x01\x00\x02\x01\x92 - s> Hidentity - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x01\x00\x02\x041 - s> \xa1FstatusBok - s> \r\n - s> 1e\r\n - s> \x16\x00\x00\x01\x00\x02\x041 - s> \x81T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x01\x00\x02\x002 - s> \r\n - s> 0\r\n - s> \r\n - response: [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob) - $ killdaemons.py HTTP client follows HTTP redirect on handshake to new repo diff -r d6c53b40b078 -r 04688c51f81f tests/test-largefiles-wireproto.t --- a/tests/test-largefiles-wireproto.t Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/test-largefiles-wireproto.t Tue Dec 07 16:44:22 2021 +0100 @@ -1,13 +1,3 @@ -#testcases sshv1 sshv2 - -#if sshv2 - $ cat >> $HGRCPATH << EOF - > [experimental] - > sshpeer.advertise-v2 = true - > sshserver.support-v2 = true - > EOF -#endif - This file contains testcases that tend to be related to the wire protocol part of largefiles. diff -r d6c53b40b078 -r 04688c51f81f tests/test-pull-network.t --- a/tests/test-pull-network.t Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/test-pull-network.t Tue Dec 07 16:44:22 2021 +0100 @@ -1,15 +1,5 @@ #require serve -#testcases sshv1 sshv2 - -#if sshv2 - $ cat >> $HGRCPATH << EOF - > [experimental] - > sshpeer.advertise-v2 = true - > sshserver.support-v2 = true - > EOF -#endif - $ hg init test $ cd test diff -r d6c53b40b078 -r 04688c51f81f tests/test-ssh-bundle1.t --- a/tests/test-ssh-bundle1.t Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/test-ssh-bundle1.t Tue Dec 07 16:44:22 2021 +0100 @@ -1,16 +1,6 @@ This test is a duplicate of 'test-http.t' feel free to factor out parts that are not bundle1/bundle2 specific. -#testcases sshv1 sshv2 - -#if sshv2 - $ cat >> $HGRCPATH << EOF - > [experimental] - > sshpeer.advertise-v2 = true - > sshserver.support-v2 = true - > EOF -#endif - $ cat << EOF >> $HGRCPATH > [devel] > # This test is dedicated to interaction through old bundle @@ -483,15 +473,13 @@ $ hg pull --debug ssh://user@dummy/remote pulling from ssh://user@dummy/remote running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R remote serve --stdio['"] (re) - sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !) sending hello command sending between command - remote: 444 (sshv1 no-rust !) - remote: 463 (sshv1 rust !) - protocol upgraded to exp-ssh-v2-0003 (sshv2 !) + remote: 444 (no-rust !) + remote: 463 (rust !) remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash (no-rust !) remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,persistent-nodemap,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash (rust !) - remote: 1 (sshv1 !) + remote: 1 sending protocaps command preparing listkeys for "bookmarks" sending listkeys command diff -r d6c53b40b078 -r 04688c51f81f tests/test-ssh-clone-r.t --- a/tests/test-ssh-clone-r.t Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/test-ssh-clone-r.t Tue Dec 07 16:44:22 2021 +0100 @@ -1,15 +1,5 @@ This test tries to exercise the ssh functionality with a dummy script -#testcases sshv1 sshv2 - -#if sshv2 - $ cat >> $HGRCPATH << EOF - > [experimental] - > sshpeer.advertise-v2 = true - > sshserver.support-v2 = true - > EOF -#endif - creating 'remote' repo $ hg init remote diff -r d6c53b40b078 -r 04688c51f81f tests/test-ssh-proto-unbundle.t --- a/tests/test-ssh-proto-unbundle.t Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/test-ssh-proto-unbundle.t Tue Dec 07 16:44:22 2021 +0100 @@ -5,13 +5,6 @@ > use-persistent-nodemap = no > EOF - $ cat > hgrc-sshv2 << EOF - > %include $HGRCPATH - > [experimental] - > sshpeer.advertise-v2 = true - > sshserver.support-v2 = true - > EOF - $ debugwireproto() { > commands=`cat -` > echo 'testing ssh1' @@ -20,12 +13,6 @@ > if [ -n "$1" ]; then > hg --config extensions.strip= strip --no-backup -r "all() - ::${tip}" > fi - > echo "" - > echo 'testing ssh2' - > echo "${commands}" | HGRCPATH=$TESTTMP/hgrc-sshv2 hg --verbose debugwireproto --localssh --noreadstderr - > if [ -n "$1" ]; then - > hg --config extensions.strip= strip --no-backup -r "all() - ::${tip}" - > fi > } Generate some bundle files @@ -103,56 +90,6 @@ e> read(-1) -> 115: e> abort: incompatible Mercurial client; bundle2 required\n e> (see https://www.mercurial-scm.org/wiki/IncompatibleClient)\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 0 - result: 0 - remote output: - e> read(-1) -> 115: - e> abort: incompatible Mercurial client; bundle2 required\n - e> (see https://www.mercurial-scm.org/wiki/IncompatibleClient)\n $ cd .. @@ -287,61 +224,6 @@ e> transaction abort!\n e> rollback completed\n e> abort: pretxnchangegroup.fail hook failed\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 0 - result: 0 - remote output: - e> read(-1) -> 151: - e> adding changesets\n - e> adding manifests\n - e> adding file changes\n - e> ui.write 1 line\n - e> transaction abort!\n - e> rollback completed\n - e> abort: pretxnchangegroup.fail hook failed\n And a variation that writes multiple lines using ui.write @@ -412,62 +294,6 @@ e> transaction abort!\n e> rollback completed\n e> abort: pretxnchangegroup.fail hook failed\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 0 - result: 0 - remote output: - e> read(-1) -> 173: - e> adding changesets\n - e> adding manifests\n - e> adding file changes\n - e> ui.write 2 lines 1\n - e> ui.write 2 lines 2\n - e> transaction abort!\n - e> rollback completed\n - e> abort: pretxnchangegroup.fail hook failed\n And a variation that does a ui.flush() after writing output @@ -537,61 +363,6 @@ e> transaction abort!\n e> rollback completed\n e> abort: pretxnchangegroup.fail hook failed\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 0 - result: 0 - remote output: - e> read(-1) -> 157: - e> adding changesets\n - e> adding manifests\n - e> adding file changes\n - e> ui.write 1 line flush\n - e> transaction abort!\n - e> rollback completed\n - e> abort: pretxnchangegroup.fail hook failed\n Multiple writes + flush @@ -662,62 +433,6 @@ e> transaction abort!\n e> rollback completed\n e> abort: pretxnchangegroup.fail hook failed\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 0 - result: 0 - remote output: - e> read(-1) -> 161: - e> adding changesets\n - e> adding manifests\n - e> adding file changes\n - e> ui.write 1st\n - e> ui.write 2nd\n - e> transaction abort!\n - e> rollback completed\n - e> abort: pretxnchangegroup.fail hook failed\n ui.write() + ui.write_err() output is captured @@ -790,64 +505,7 @@ e> transaction abort!\n e> rollback completed\n e> abort: pretxnchangegroup.fail hook failed\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 0 - result: 0 - remote output: - e> read(-1) -> 187: - e> adding changesets\n - e> adding manifests\n - e> adding file changes\n - e> ui.write 1\n - e> ui.write_err 1\n - e> ui.write 2\n - e> ui.write_err 2\n - e> transaction abort!\n - e> rollback completed\n - e> abort: pretxnchangegroup.fail hook failed\n + print() output is captured @@ -917,61 +575,6 @@ e> transaction abort!\n e> rollback completed\n e> abort: pretxnchangegroup.fail hook failed\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 0 - result: 0 - remote output: - e> read(-1) -> 148: - e> adding changesets\n - e> adding manifests\n - e> adding file changes\n - e> printed line\n - e> transaction abort!\n - e> rollback completed\n - e> abort: pretxnchangegroup.fail hook failed\n Mixed print() and ui.write() are both captured @@ -1044,64 +647,6 @@ e> transaction abort!\n e> rollback completed\n e> abort: pretxnchangegroup.fail hook failed\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 0 - result: 0 - remote output: - e> read(-1) -> 173: - e> adding changesets\n - e> adding manifests\n - e> adding file changes\n - e> print 1\n - e> ui.write 1\n - e> print 2\n - e> ui.write 2\n - e> transaction abort!\n - e> rollback completed\n - e> abort: pretxnchangegroup.fail hook failed\n print() to stdout and stderr both get captured @@ -1174,64 +719,6 @@ e> transaction abort!\n e> rollback completed\n e> abort: pretxnchangegroup.fail hook failed\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 0 - result: 0 - remote output: - e> read(-1) -> 171: - e> adding changesets\n - e> adding manifests\n - e> adding file changes\n - e> stdout 1\n - e> stderr 1\n - e> stdout 2\n - e> stderr 2\n - e> transaction abort!\n - e> rollback completed\n - e> abort: pretxnchangegroup.fail hook failed\n Shell hook writing to stdout has output captured @@ -1308,63 +795,6 @@ e> transaction abort!\n e> rollback completed\n e> abort: pretxnchangegroup.fail hook exited with status 1\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 0 - result: 0 - remote output: - e> read(-1) -> 167: - e> adding changesets\n - e> adding manifests\n - e> adding file changes\n - e> stdout 1\n - e> stdout 2\n - e> transaction abort!\n - e> rollback completed\n - e> abort: pretxnchangegroup.fail hook exited with status 1\n - Shell hook writing to stderr has output captured $ cat > $TESTTMP/hook.sh << EOF @@ -1435,63 +865,6 @@ e> transaction abort!\n e> rollback completed\n e> abort: pretxnchangegroup.fail hook exited with status 1\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 0 - result: 0 - remote output: - e> read(-1) -> 167: - e> adding changesets\n - e> adding manifests\n - e> adding file changes\n - e> stderr 1\n - e> stderr 2\n - e> transaction abort!\n - e> rollback completed\n - e> abort: pretxnchangegroup.fail hook exited with status 1\n - Shell hook writing to stdout and stderr has output captured $ cat > $TESTTMP/hook.sh << EOF @@ -1566,65 +939,6 @@ e> transaction abort!\n e> rollback completed\n e> abort: pretxnchangegroup.fail hook exited with status 1\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 0 - result: 0 - remote output: - e> read(-1) -> 185: - e> adding changesets\n - e> adding manifests\n - e> adding file changes\n - e> stdout 1\n - e> stderr 1\n - e> stdout 2\n - e> stderr 2\n - e> transaction abort!\n - e> rollback completed\n - e> abort: pretxnchangegroup.fail hook exited with status 1\n - Shell and Python hooks writing to stdout and stderr have output captured $ cat > $TESTTMP/hook.sh << EOF @@ -1709,69 +1023,6 @@ e> transaction abort!\n e> rollback completed\n e> abort: pretxnchangegroup.b hook failed\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 0 - result: 0 - remote output: - e> read(-1) -> 228: - e> adding changesets\n - e> adding manifests\n - e> adding file changes\n - e> shell stdout 1\n - e> shell stderr 1\n - e> shell stdout 2\n - e> shell stderr 2\n - e> stdout 1\n - e> stderr 1\n - e> stdout 2\n - e> stderr 2\n - e> transaction abort!\n - e> rollback completed\n - e> abort: pretxnchangegroup.b hook failed\n - $ cd .. Pushing a bundle1 with no output @@ -1837,59 +1088,6 @@ e> adding manifests\n e> adding file changes\n e> added 1 changesets with 1 changes to 1 files\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 1 - result: 1 - remote output: - e> read(-1) -> 100: - e> adding changesets\n - e> adding manifests\n - e> adding file changes\n - e> added 1 changesets with 1 changes to 1 files\n - $ cd .. Pushing a bundle1 with ui.write() and ui.write_err() @@ -1971,59 +1169,3 @@ e> ui.write 2\n e> ui.write_err 2\n e> added 1 changesets with 1 changes to 1 files\n - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending unbundle command - i> write(9) -> 9: - i> unbundle\n - i> write(9) -> 9: - i> heads 10\n - i> write(10) -> 10: 666f726365 - i> flush() -> None - o> readline() -> 2: - o> 0\n - i> write(4) -> 4: - i> 426\n - i> write(426) -> 426: - i> HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n - i> test\n - i> 0 0\n - i> foo\n - i> \n - i> initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n - i> \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n - i> \x00\x00\x00\x00\x00\x00\x00\x00 - i> write(2) -> 2: - i> 0\n - i> flush() -> None - o> readline() -> 2: - o> 0\n - o> readline() -> 2: - o> 1\n - o> read(1) -> 1: 1 - result: 1 - remote output: - e> read(-1) -> 152: - e> adding changesets\n - e> adding manifests\n - e> adding file changes\n - e> ui.write 1\n - e> ui.write_err 1\n - e> ui.write 2\n - e> ui.write_err 2\n - e> added 1 changesets with 1 changes to 1 files\n diff -r d6c53b40b078 -r 04688c51f81f tests/test-ssh-proto.t --- a/tests/test-ssh-proto.t Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/test-ssh-proto.t Tue Dec 07 16:44:22 2021 +0100 @@ -7,13 +7,6 @@ > use-persistent-nodemap = no > EOF - $ cat > hgrc-sshv2 << EOF - > %include $HGRCPATH - > [experimental] - > sshpeer.advertise-v2 = true - > sshserver.support-v2 = true - > EOF - Helper function to run protocol tests against multiple protocol versions. This is easier than using #testcases because managing differences between protocols with inline conditional output is hard to read. @@ -22,9 +15,6 @@ > commands=`cat -` > echo 'testing ssh1' > echo "${commands}" | hg --verbose debugwireproto --localssh - > echo "" - > echo 'testing ssh2' - > echo "${commands}" | HGRCPATH=$TESTTMP/hgrc-sshv2 hg --verbose debugwireproto --localssh > } $ cat >> $HGRCPATH << EOF @@ -54,9 +44,6 @@ $ hg debugwireproto --localssh --peer ssh1 << EOF > EOF creating ssh peer for wire protocol version 1 - $ hg debugwireproto --localssh --peer ssh2 << EOF - > EOF - creating ssh peer for wire protocol version 2 Test a normal behaving server, for sanity @@ -916,410 +903,6 @@ o> readline() -> 4: o> 444\n -Send an upgrade request to a server that doesn't support that command - - $ hg debugwireproto --localssh --peer raw << EOF - > raw - > upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=irrelevant1%2Cirrelevant2\n - > readline - > raw - > hello\n - > between\n - > pairs 81\n - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - > readline - > readline - > readline - > readline - > EOF - using raw connection to peer - i> write(77) -> 77: - i> upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=irrelevant1%2Cirrelevant2\n - o> readline() -> 2: - o> 0\n - i> write(104) -> 104: - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - o> readline() -> 4: - o> 444\n - o> readline() -> 444: - o> capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash\n - o> readline() -> 2: - o> 1\n - o> readline() -> 1: - o> \n - - $ cd .. - - $ hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server - running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R server serve --stdio['"] (re) - sending upgrade request: * proto=exp-ssh-v2-0003 (glob) - devel-peer-request: hello+between - devel-peer-request: pairs: 81 bytes - sending hello command - sending between command - remote: 0 - remote: 444 - remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - remote: 1 - devel-peer-request: protocaps - devel-peer-request: caps: * bytes (glob) - sending protocaps command - url: ssh://user@dummy/server - local: no - pushable: yes - -Enable version 2 support on server. We need to do this in hgrc because we can't -use --config with `hg serve --stdio`. - - $ cat >> server/.hg/hgrc << EOF - > [experimental] - > sshserver.support-v2 = true - > EOF - -Send an upgrade request to a server that supports upgrade - - $ cd server - - $ hg debugwireproto --localssh --peer raw << EOF - > raw - > upgrade this-is-some-token proto=exp-ssh-v2-0003\n - > hello\n - > between\n - > pairs 81\n - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - > readline - > readline - > readline - > EOF - using raw connection to peer - i> write(153) -> 153: - i> upgrade this-is-some-token proto=exp-ssh-v2-0003\n - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - o> readline() -> 44: - o> upgraded this-is-some-token exp-ssh-v2-0003\n - o> readline() -> 4: - o> 443\n - o> readline() -> 444: - o> capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash\n - - $ cd .. - - $ hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server - running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R server serve --stdio['"] (re) - sending upgrade request: * proto=exp-ssh-v2-0003 (glob) - devel-peer-request: hello+between - devel-peer-request: pairs: 81 bytes - sending hello command - sending between command - protocol upgraded to exp-ssh-v2-0003 - remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - devel-peer-request: protocaps - devel-peer-request: caps: * bytes (glob) - sending protocaps command - url: ssh://user@dummy/server - local: no - pushable: yes - -Verify the peer has capabilities - - $ hg --config experimental.sshpeer.advertise-v2=true --debug debugcapabilities ssh://user@dummy/server - running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R server serve --stdio['"] (re) - sending upgrade request: * proto=exp-ssh-v2-0003 (glob) - devel-peer-request: hello+between - devel-peer-request: pairs: 81 bytes - sending hello command - sending between command - protocol upgraded to exp-ssh-v2-0003 - remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - devel-peer-request: protocaps - devel-peer-request: caps: * bytes (glob) - sending protocaps command - Main capabilities: - batch - branchmap - $USUAL_BUNDLE2_CAPS$ - changegroupsubset - getbundle - known - lookup - protocaps - pushkey - streamreqs=generaldelta,revlogv1,sparserevlog - unbundle=HG10GZ,HG10BZ,HG10UN - unbundlehash - Bundle2 capabilities: - HG20 - bookmarks - changegroup - 01 - 02 - checkheads - related - digests - md5 - sha1 - sha512 - error - abort - unsupportedcontent - pushraced - pushkey - hgtagsfnodes - listkeys - phases - heads - pushkey - remote-changegroup - http - https - stream - v2 - -Command after upgrade to version 2 is processed - - $ cd server - - $ hg debugwireproto --localssh --peer raw << EOF - > raw - > upgrade this-is-some-token proto=exp-ssh-v2-0003\n - > hello\n - > between\n - > pairs 81\n - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - > readline - > readline - > readline - > raw - > hello\n - > readline - > readline - > EOF - using raw connection to peer - i> write(153) -> 153: - i> upgrade this-is-some-token proto=exp-ssh-v2-0003\n - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - o> readline() -> 44: - o> upgraded this-is-some-token exp-ssh-v2-0003\n - o> readline() -> 4: - o> 443\n - o> readline() -> 444: - o> capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash\n - i> write(6) -> 6: - i> hello\n - o> readline() -> 4: - o> 428\n - o> readline() -> 428: - o> capabilities: branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash\n - -Multiple upgrades is not allowed - - $ hg debugwireproto --localssh --peer raw << EOF - > raw - > upgrade this-is-some-token proto=exp-ssh-v2-0003\n - > hello\n - > between\n - > pairs 81\n - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - > readline - > readline - > readline - > raw - > upgrade another-token proto=irrelevant\n - > hello\n - > readline - > readavailable - > EOF - using raw connection to peer - i> write(153) -> 153: - i> upgrade this-is-some-token proto=exp-ssh-v2-0003\n - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - o> readline() -> 44: - o> upgraded this-is-some-token exp-ssh-v2-0003\n - o> readline() -> 4: - o> 443\n - o> readline() -> 444: - o> capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash\n - i> write(45) -> 45: - i> upgrade another-token proto=irrelevant\n - i> hello\n - o> readline() -> 1: - o> \n - e> read(-1) -> 42: - e> cannot upgrade protocols multiple times\n - e> -\n - -Malformed upgrade request line (not exactly 3 space delimited tokens) - - $ hg debugwireproto --localssh --peer raw << EOF - > raw - > upgrade\n - > readline - > EOF - using raw connection to peer - i> write(8) -> 8: - i> upgrade\n - o> readline() -> 2: - o> 0\n - - $ hg debugwireproto --localssh --peer raw << EOF - > raw - > upgrade token\n - > readline - > EOF - using raw connection to peer - i> write(14) -> 14: - i> upgrade token\n - o> readline() -> 2: - o> 0\n - - $ hg debugwireproto --localssh --peer raw << EOF - > raw - > upgrade token foo=bar extra-token\n - > readline - > EOF - using raw connection to peer - i> write(34) -> 34: - i> upgrade token foo=bar extra-token\n - o> readline() -> 2: - o> 0\n - -Upgrade request to unsupported protocol is ignored - - $ hg debugwireproto --localssh --peer raw << EOF - > raw - > upgrade this-is-some-token proto=unknown1,unknown2\n - > readline - > raw - > hello\n - > readline - > readline - > raw - > between\n - > pairs 81\n - > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - > readline - > readline - > EOF - using raw connection to peer - i> write(51) -> 51: - i> upgrade this-is-some-token proto=unknown1,unknown2\n - o> readline() -> 2: - o> 0\n - i> write(6) -> 6: - i> hello\n - o> readline() -> 4: - o> 444\n - o> readline() -> 444: - o> capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash\n - i> write(98) -> 98: - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - o> readline() -> 2: - o> 1\n - o> readline() -> 1: - o> \n - -Upgrade request must be followed by hello + between - - $ hg debugwireproto --localssh --peer raw << EOF - > raw - > upgrade token proto=exp-ssh-v2-0003\n - > invalid\n - > readline - > readavailable - > EOF - using raw connection to peer - i> write(44) -> 44: - i> upgrade token proto=exp-ssh-v2-0003\n - i> invalid\n - o> readline() -> 1: - o> \n - e> read(-1) -> 46: - e> malformed handshake protocol: missing hello\n - e> -\n - - $ hg debugwireproto --localssh --peer raw << EOF - > raw - > upgrade token proto=exp-ssh-v2-0003\n - > hello\n - > invalid\n - > readline - > readavailable - > EOF - using raw connection to peer - i> write(50) -> 50: - i> upgrade token proto=exp-ssh-v2-0003\n - i> hello\n - i> invalid\n - o> readline() -> 1: - o> \n - e> read(-1) -> 48: - e> malformed handshake protocol: missing between\n - e> -\n - - $ hg debugwireproto --localssh --peer raw << EOF - > raw - > upgrade token proto=exp-ssh-v2-0003\n - > hello\n - > between\n - > invalid\n - > readline - > readavailable - > EOF - using raw connection to peer - i> write(58) -> 58: - i> upgrade token proto=exp-ssh-v2-0003\n - i> hello\n - i> between\n - i> invalid\n - o> readline() -> 1: - o> \n - e> read(-1) -> 49: - e> malformed handshake protocol: missing pairs 81\n - e> -\n - -Legacy commands are not exposed to version 2 of protocol - -TODO re-enable these once we're back to actually using v2 commands - -$ hg --config experimental.sshpeer.advertise-v2=true debugwireproto --localssh << EOF -> command branches -> nodes 0000000000000000000000000000000000000000 -> EOF -creating ssh peer from handshake results -sending branches command -response: - -$ hg --config experimental.sshpeer.advertise-v2=true debugwireproto --localssh << EOF -> command changegroup -> roots 0000000000000000000000000000000000000000 -> EOF -creating ssh peer from handshake results -sending changegroup command -response: - -$ hg --config experimental.sshpeer.advertise-v2=true debugwireproto --localssh << EOF -> command changegroupsubset -> bases 0000000000000000000000000000000000000000 -> heads 0000000000000000000000000000000000000000 -> EOF -creating ssh peer from handshake results -sending changegroupsubset command -response: - $ cd .. Test listkeys for listing namespaces @@ -1364,41 +947,6 @@ b'namespaces': b'', b'phases': b'' } - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending listkeys command - i> write(9) -> 9: - i> listkeys\n - i> write(13) -> 13: - i> namespace 10\n - i> write(10) -> 10: namespaces - i> flush() -> None - o> bufferedreadline() -> 3: - o> 30\n - o> bufferedread(30) -> 30: - o> bookmarks\t\n - o> namespaces\t\n - o> phases\t - response: { - b'bookmarks': b'', - b'namespaces': b'', - b'phases': b'' - } $ cd .. @@ -1444,33 +992,6 @@ o> bufferedreadline() -> 2: o> 0\n response: {} - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending listkeys command - i> write(9) -> 9: - i> listkeys\n - i> write(12) -> 12: - i> namespace 9\n - i> write(9) -> 9: bookmarks - i> flush() -> None - o> bufferedreadline() -> 2: - o> 0\n - response: {} With a single bookmark set @@ -1508,36 +1029,6 @@ response: { b'bookA': b'68986213bd4485ea51533535e3fc9e78007a711f' } - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending listkeys command - i> write(9) -> 9: - i> listkeys\n - i> write(12) -> 12: - i> namespace 9\n - i> write(9) -> 9: bookmarks - i> flush() -> None - o> bufferedreadline() -> 3: - o> 46\n - o> bufferedread(46) -> 46: bookA\t68986213bd4485ea51533535e3fc9e78007a711f - response: { - b'bookA': b'68986213bd4485ea51533535e3fc9e78007a711f' - } With multiple bookmarks set @@ -1578,39 +1069,6 @@ b'bookA': b'68986213bd4485ea51533535e3fc9e78007a711f', b'bookB': b'1880f3755e2e52e3199e0ee5638128b08642f34d' } - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending listkeys command - i> write(9) -> 9: - i> listkeys\n - i> write(12) -> 12: - i> namespace 9\n - i> write(9) -> 9: bookmarks - i> flush() -> None - o> bufferedreadline() -> 3: - o> 93\n - o> bufferedread(93) -> 93: - o> bookA\t68986213bd4485ea51533535e3fc9e78007a711f\n - o> bookB\t1880f3755e2e52e3199e0ee5638128b08642f34d - response: { - b'bookA': b'68986213bd4485ea51533535e3fc9e78007a711f', - b'bookB': b'1880f3755e2e52e3199e0ee5638128b08642f34d' - } Test pushkey for bookmarks @@ -1657,43 +1115,6 @@ o> bufferedread(2) -> 2: o> 1\n response: True - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending pushkey command - i> write(8) -> 8: - i> pushkey\n - i> write(6) -> 6: - i> key 6\n - i> write(6) -> 6: remote - i> write(12) -> 12: - i> namespace 9\n - i> write(9) -> 9: bookmarks - i> write(7) -> 7: - i> new 40\n - i> write(40) -> 40: 68986213bd4485ea51533535e3fc9e78007a711f - i> write(6) -> 6: - i> old 0\n - i> flush() -> None - o> bufferedreadline() -> 2: - o> 2\n - o> bufferedread(2) -> 2: - o> 1\n - response: True $ hg bookmarks bookA 0:68986213bd44 @@ -1742,36 +1163,6 @@ response: { b'publishing': b'True' } - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending listkeys command - i> write(9) -> 9: - i> listkeys\n - i> write(12) -> 12: - i> namespace 6\n - i> write(6) -> 6: phases - i> flush() -> None - o> bufferedreadline() -> 3: - o> 15\n - o> bufferedread(15) -> 15: publishing\tTrue - response: { - b'publishing': b'True' - } Create some commits @@ -1830,41 +1221,6 @@ b'c4750011d906c18ea2f0527419cbc1a544435150': b'1', b'publishing': b'True' } - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending listkeys command - i> write(9) -> 9: - i> listkeys\n - i> write(12) -> 12: - i> namespace 6\n - i> write(6) -> 6: phases - i> flush() -> None - o> bufferedreadline() -> 4: - o> 101\n - o> bufferedread(101) -> 101: - o> 20b8a89289d80036e6c4e87c2083e3bea1586637\t1\n - o> c4750011d906c18ea2f0527419cbc1a544435150\t1\n - o> publishing\tTrue - response: { - b'20b8a89289d80036e6c4e87c2083e3bea1586637': b'1', - b'c4750011d906c18ea2f0527419cbc1a544435150': b'1', - b'publishing': b'True' - } Single draft head @@ -1905,39 +1261,6 @@ b'c4750011d906c18ea2f0527419cbc1a544435150': b'1', b'publishing': b'True' } - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending listkeys command - i> write(9) -> 9: - i> listkeys\n - i> write(12) -> 12: - i> namespace 6\n - i> write(6) -> 6: phases - i> flush() -> None - o> bufferedreadline() -> 3: - o> 58\n - o> bufferedread(58) -> 58: - o> c4750011d906c18ea2f0527419cbc1a544435150\t1\n - o> publishing\tTrue - response: { - b'c4750011d906c18ea2f0527419cbc1a544435150': b'1', - b'publishing': b'True' - } All public heads @@ -1975,36 +1298,6 @@ response: { b'publishing': b'True' } - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending listkeys command - i> write(9) -> 9: - i> listkeys\n - i> write(12) -> 12: - i> namespace 6\n - i> write(6) -> 6: phases - i> flush() -> None - o> bufferedreadline() -> 3: - o> 15\n - o> bufferedread(15) -> 15: publishing\tTrue - response: { - b'publishing': b'True' - } Setting public phase via pushkey @@ -2054,44 +1347,6 @@ o> bufferedread(2) -> 2: o> 1\n response: True - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending pushkey command - i> write(8) -> 8: - i> pushkey\n - i> write(7) -> 7: - i> key 40\n - i> write(40) -> 40: 7127240a084fd9dc86fe8d1f98e26229161ec82b - i> write(12) -> 12: - i> namespace 6\n - i> write(6) -> 6: phases - i> write(6) -> 6: - i> new 1\n - i> write(1) -> 1: 0 - i> write(6) -> 6: - i> old 1\n - i> write(1) -> 1: 1 - i> flush() -> None - o> bufferedreadline() -> 2: - o> 2\n - o> bufferedread(2) -> 2: - o> 1\n - response: True $ hg phase . 4: public @@ -2160,40 +1415,3 @@ response #0: bfebe6bd38eebc6f8202e419c1171268987ea6a6 4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\n response #1: bookA\t4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\nbookB\tbfebe6bd38eebc6f8202e419c1171268987ea6a6 response #2: 4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\t1\nbfebe6bd38eebc6f8202e419c1171268987ea6a6\t1\npublishing\tTrue - - testing ssh2 - creating ssh peer from handshake results - i> write(171) -> 171: - i> upgrade * proto=exp-ssh-v2-0003\n (glob) - i> hello\n - i> between\n - i> pairs 81\n - i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 - i> flush() -> None - o> readline() -> 62: - o> upgraded * exp-ssh-v2-0003\n (glob) - o> readline() -> 4: - o> 443\n - o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - o> read(1) -> 1: - o> \n - sending batch with 3 sub-commands - i> write(6) -> 6: - i> batch\n - i> write(4) -> 4: - i> * 0\n - i> write(8) -> 8: - i> cmds 61\n - i> write(61) -> 61: heads ;listkeys namespace=bookmarks;listkeys namespace=phases - i> flush() -> None - o> bufferedreadline() -> 4: - o> 278\n - o> bufferedread(278) -> 278: - o> bfebe6bd38eebc6f8202e419c1171268987ea6a6 4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\n - o> ;bookA\t4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\n - o> bookB\tbfebe6bd38eebc6f8202e419c1171268987ea6a6;4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\t1\n - o> bfebe6bd38eebc6f8202e419c1171268987ea6a6\t1\n - o> publishing\tTrue - response #0: bfebe6bd38eebc6f8202e419c1171268987ea6a6 4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\n - response #1: bookA\t4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\nbookB\tbfebe6bd38eebc6f8202e419c1171268987ea6a6 - response #2: 4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\t1\nbfebe6bd38eebc6f8202e419c1171268987ea6a6\t1\npublishing\tTrue diff -r d6c53b40b078 -r 04688c51f81f tests/test-ssh.t --- a/tests/test-ssh.t Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/test-ssh.t Tue Dec 07 16:44:22 2021 +0100 @@ -1,13 +1,3 @@ -#testcases sshv1 sshv2 - -#if sshv2 - $ cat >> $HGRCPATH << EOF - > [experimental] - > sshpeer.advertise-v2 = true - > sshserver.support-v2 = true - > EOF -#endif - This test tries to exercise the ssh functionality with a dummy script creating 'remote' repo @@ -537,17 +527,15 @@ $ hg pull --debug ssh://user@dummy/remote --config devel.debug.peer-request=yes pulling from ssh://user@dummy/remote running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R remote serve --stdio['"] (re) - sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !) devel-peer-request: hello+between devel-peer-request: pairs: 81 bytes sending hello command sending between command - remote: 444 (sshv1 no-rust !) - remote: 463 (sshv1 rust !) - protocol upgraded to exp-ssh-v2-0003 (sshv2 !) + remote: 444 (no-rust !) + remote: 463 (rust !) remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash (no-rust !) remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,persistent-nodemap,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash (rust !) - remote: 1 (sshv1 !) + remote: 1 devel-peer-request: protocaps devel-peer-request: caps: * bytes (glob) sending protocaps command diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-caching.t --- a/tests/test-wireproto-caching.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,468 +0,0 @@ - $ . $TESTDIR/wireprotohelpers.sh - -persistent-nodemap is not enabled by default. It is not relevant for this test so disable it. - - $ cat >> $HGRCPATH << EOF - > [format] - > use-persistent-nodemap = no - > [extensions] - > blackbox = - > [blackbox] - > track = simplecache - > EOF - $ hg init server - $ enablehttpv2 server - $ cd server - $ cat >> .hg/hgrc << EOF - > [extensions] - > simplecache = $TESTDIR/wireprotosimplecache.py - > EOF - - $ echo a0 > a - $ echo b0 > b - $ hg -q commit -A -m 'commit 0' - $ echo a1 > a - $ hg commit -m 'commit 1' - $ echo b1 > b - $ hg commit -m 'commit 2' - $ echo a2 > a - $ echo b2 > b - $ hg commit -m 'commit 3' - - $ hg log -G -T '{rev}:{node} {desc}' - @ 3:50590a86f3ff5d1e9a1624a7a6957884565cc8e8 commit 3 - | - o 2:4d01eda50c6ac5f7e89cbe1880143a32f559c302 commit 2 - | - o 1:4432d83626e8a98655f062ec1f2a43b07f7fbbb0 commit 1 - | - o 0:3390ef850073fbc2f0dfff2244342c8e9229013a commit 0 - - - $ hg --debug debugindex -m - rev linkrev nodeid p1 p2 - 0 0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 - 1 1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 - 2 2 a8853dafacfca6fc807055a660d8b835141a3bb4 a988fb43583e871d1ed5750ee074c6d840bbbfc8 0000000000000000000000000000000000000000 - 3 3 3fe11dfbb13645782b0addafbe75a87c210ffddc a8853dafacfca6fc807055a660d8b835141a3bb4 0000000000000000000000000000000000000000 - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -Performing the same request should result in same result, with 2nd response -coming from cache. - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41'] - > tree eval:b'' - > fields eval:[b'parents'] - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - } - ] - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41'] - > tree eval:b'' - > fields eval:[b'parents'] - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - } - ] - -Sending different request doesn't yield cache hit. - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41', b'\xa9\x88\xfb\x43\x58\x3e\x87\x1d\x1e\xd5\x75\x0e\xe0\x74\xc6\xd8\x40\xbb\xbf\xc8'] - > tree eval:b'' - > fields eval:[b'parents'] - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 2 - }, - { - b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - }, - { - b'node': b'\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8', - b'parents': [ - b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - } - ] - - $ cat .hg/blackbox.log - *> cacher constructed for manifestdata (glob) - *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob) - *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob) - *> cacher constructed for manifestdata (glob) - *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob) - *> cacher constructed for manifestdata (glob) - *> cache miss for 37326a83e9843f15161fce9d1e92d06b795d5e8e (glob) - *> storing cache entry for 37326a83e9843f15161fce9d1e92d06b795d5e8e (glob) - - $ cat error.log - - $ killdaemons.py - $ rm .hg/blackbox.log - -Try with object caching mode - - $ cat >> .hg/hgrc << EOF - > [simplecache] - > cacheobjects = true - > EOF - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41'] - > tree eval:b'' - > fields eval:[b'parents'] - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - } - ] - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41'] - > tree eval:b'' - > fields eval:[b'parents'] - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - } - ] - - $ cat .hg/blackbox.log - *> cacher constructed for manifestdata (glob) - *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob) - *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob) - *> cacher constructed for manifestdata (glob) - *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob) - - $ cat error.log - - $ killdaemons.py - $ rm .hg/blackbox.log - -A non-cacheable command does not instantiate cacher - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - $ sendhttpv2peer << EOF - > command capabilities - > EOF - creating http peer for wire protocol version 2 - sending capabilities command - response: gen[ - { - b'commands': { - b'branchmap': { - b'args': {}, - b'permissions': [ - b'pull' - ] - }, - b'capabilities': { - b'args': {}, - b'permissions': [ - b'pull' - ] - }, - b'changesetdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'bookmarks', - b'parents', - b'phase', - b'revision' - ]) - }, - b'revisions': { - b'required': True, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'filedata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'linknode', - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'nodes': { - b'required': True, - b'type': b'list' - }, - b'path': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'filesdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'firstchangeset', - b'linknode', - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'pathfilter': { - b'default': None, - b'required': False, - b'type': b'dict' - }, - b'revisions': { - b'required': True, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ], - b'recommendedbatchsize': 50000 - }, - b'heads': { - b'args': { - b'publiconly': { - b'default': False, - b'required': False, - b'type': b'bool' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'known': { - b'args': { - b'nodes': { - b'default': [], - b'required': False, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'listkeys': { - b'args': { - b'namespace': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'lookup': { - b'args': { - b'key': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'manifestdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'nodes': { - b'required': True, - b'type': b'list' - }, - b'tree': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ], - b'recommendedbatchsize': 100000 - }, - b'pushkey': { - b'args': { - b'key': { - b'required': True, - b'type': b'bytes' - }, - b'namespace': { - b'required': True, - b'type': b'bytes' - }, - b'new': { - b'required': True, - b'type': b'bytes' - }, - b'old': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'push' - ] - }, - b'rawstorefiledata': { - b'args': { - b'files': { - b'required': True, - b'type': b'list' - }, - b'pathfilter': { - b'default': None, - b'required': False, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - } - }, - b'framingmediatypes': [ - b'application/mercurial-exp-framing-0006' - ], - b'pathfilterprefixes': set([ - b'path:', - b'rootfilesin:' - ]), - b'rawrepoformats': [ - b'generaldelta', - b'revlogv1', - b'sparserevlog' - ] - } - ] - - $ test -f .hg/blackbox.log - [1] - -An error is not cached - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'] - > tree eval:b'' - > fields eval:[b'parents'] - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - abort: unknown node: \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa (esc) - [255] - - $ cat .hg/blackbox.log - *> cacher constructed for manifestdata (glob) - *> cache miss for 2cba2a7d0d1575fea2fe68f597e97a7c2ac2f705 (glob) - *> cacher exiting due to error (glob) - - $ killdaemons.py - $ rm .hg/blackbox.log diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-command-branchmap.t --- a/tests/test-wireproto-command-branchmap.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ - $ . $TESTDIR/wireprotohelpers.sh - - $ hg init server - $ enablehttpv2 server - $ cd server - $ hg debugdrawdag << EOF - > C D - > |/ - > B - > | - > A - > EOF - - $ hg up B - 2 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ hg branch branch1 - marked working directory as branch branch1 - (branches are permanent and global, did you want a bookmark?) - $ echo b1 > foo - $ hg -q commit -A -m 'branch 1' - $ hg up B - 0 files updated, 0 files merged, 1 files removed, 0 files unresolved - $ hg branch branch2 - marked working directory as branch branch2 - $ echo b2 > foo - $ hg -q commit -A -m 'branch 2' - - $ hg log -T '{rev}:{node} {branch} {desc}\n' - 5:224161c7589aa48fa83a48feff5e95b56ae327fc branch2 branch 2 - 4:b5faacdfd2633768cb3152336cc0953381266688 branch1 branch 1 - 3:be0ef73c17ade3fc89dc41701eb9fc3a91b58282 default D - 2:26805aba1e600a82e93661149f2313866a221a7b default C - 1:112478962961147124edd43549aedd1a335e44bf default B - 0:426bada5c67598ca65036d57d9e4b64b0c1ce7a0 default A - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -No arguments returns something reasonable - - $ sendhttpv2peer << EOF - > command branchmap - > EOF - creating http peer for wire protocol version 2 - sending branchmap command - response: { - b'branch1': [ - b'\xb5\xfa\xac\xdf\xd2c7h\xcb1R3l\xc0\x953\x81&f\x88' - ], - b'branch2': [ - b'"Aa\xc7X\x9a\xa4\x8f\xa8:H\xfe\xff^\x95\xb5j\xe3\'\xfc' - ], - b'default': [ - b'&\x80Z\xba\x1e`\n\x82\xe96a\x14\x9f#\x13\x86j"\x1a{', - b'\xbe\x0e\xf7<\x17\xad\xe3\xfc\x89\xdcAp\x1e\xb9\xfc:\x91\xb5\x82\x82' - ] - } - - $ cat error.log diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-command-capabilities.t --- a/tests/test-wireproto-command-capabilities.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,762 +0,0 @@ -#require no-chg - - $ . $TESTDIR/wireprotohelpers.sh - -persistent-nodemap is not enabled by default. It is not relevant for this test so disable it. - - $ cat >> $HGRCPATH << EOF - > [format] - > use-persistent-nodemap = no - > EOF - - $ hg init server - -zstd isn't present in plain builds. Make tests easier by removing -zstd from the equation. - - $ cat >> server/.hg/hgrc << EOF - > [server] - > compressionengines = zlib - > EOF - - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -A normal capabilities request is serviced for version 1 - - $ sendhttpraw << EOF - > httprequest GET ?cmd=capabilities - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 Script output follows\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-0.1\r\n - s> Content-Length: *\r\n (glob) - s> \r\n - s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - -A proper request without the API server enabled returns the legacy response - - $ sendhttpraw << EOF - > httprequest GET ?cmd=capabilities - > user-agent: test - > x-hgupgrade-1: foo - > x-hgproto-1: cbor - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> x-hgproto-1: cbor\r\n - s> x-hgupgrade-1: foo\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 Script output follows\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-0.1\r\n - s> Content-Length: *\r\n (glob) - s> \r\n - s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - -Restart with just API server enabled. This enables serving the new format. - - $ killdaemons.py - $ cat error.log - - $ cat >> server/.hg/hgrc << EOF - > [experimental] - > web.apiserver = true - > EOF - - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -X-HgUpgrade- without CBOR advertisement uses legacy response - - $ sendhttpraw << EOF - > httprequest GET ?cmd=capabilities - > user-agent: test - > x-hgupgrade-1: foo bar - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> x-hgupgrade-1: foo bar\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 Script output follows\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-0.1\r\n - s> Content-Length: *\r\n (glob) - s> \r\n - s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - -X-HgUpgrade- without known serialization in X-HgProto- uses legacy response - - $ sendhttpraw << EOF - > httprequest GET ?cmd=capabilities - > user-agent: test - > x-hgupgrade-1: foo bar - > x-hgproto-1: some value - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> x-hgproto-1: some value\r\n - s> x-hgupgrade-1: foo bar\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 Script output follows\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-0.1\r\n - s> Content-Length: *\r\n (glob) - s> \r\n - s> batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - -X-HgUpgrade- + X-HgProto- headers trigger new response format - - $ sendhttpraw << EOF - > httprequest GET ?cmd=capabilities - > user-agent: test - > x-hgupgrade-1: foo bar - > x-hgproto-1: cbor - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> x-hgproto-1: cbor\r\n - s> x-hgupgrade-1: foo bar\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-cbor\r\n - s> Content-Length: *\r\n (glob) - s> \r\n - s> \xa3GapibaseDapi/Dapis\xa0Nv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - cbor> [ - { - b'apibase': b'api/', - b'apis': {}, - b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash' - } - ] - -Restart server to enable HTTPv2 - - $ killdaemons.py - $ enablehttpv2 server - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -Only requested API services are returned - - $ sendhttpraw << EOF - > httprequest GET ?cmd=capabilities - > user-agent: test - > x-hgupgrade-1: foo bar - > x-hgproto-1: cbor - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> x-hgproto-1: cbor\r\n - s> x-hgupgrade-1: foo bar\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-cbor\r\n - s> Content-Length: *\r\n (glob) - s> \r\n - s> \xa3GapibaseDapi/Dapis\xa0Nv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - cbor> [ - { - b'apibase': b'api/', - b'apis': {}, - b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash' - } - ] - -Request for HTTPv2 service returns information about it - - $ sendhttpraw << EOF - > httprequest GET ?cmd=capabilities - > user-agent: test - > x-hgupgrade-1: exp-http-v2-0003 foo bar - > x-hgproto-1: cbor - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> x-hgproto-1: cbor\r\n - s> x-hgupgrade-1: exp-http-v2-0003 foo bar\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-cbor\r\n - s> Content-Length: *\r\n (glob) - s> \r\n - s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogNv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - cbor> [ - { - b'apibase': b'api/', - b'apis': { - b'exp-http-v2-0003': { - b'commands': { - b'branchmap': { - b'args': {}, - b'permissions': [ - b'pull' - ] - }, - b'capabilities': { - b'args': {}, - b'permissions': [ - b'pull' - ] - }, - b'changesetdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'bookmarks', - b'parents', - b'phase', - b'revision' - ]) - }, - b'revisions': { - b'required': True, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'filedata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'linknode', - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'nodes': { - b'required': True, - b'type': b'list' - }, - b'path': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'filesdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'firstchangeset', - b'linknode', - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'pathfilter': { - b'default': None, - b'required': False, - b'type': b'dict' - }, - b'revisions': { - b'required': True, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ], - b'recommendedbatchsize': 50000 - }, - b'heads': { - b'args': { - b'publiconly': { - b'default': False, - b'required': False, - b'type': b'bool' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'known': { - b'args': { - b'nodes': { - b'default': [], - b'required': False, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'listkeys': { - b'args': { - b'namespace': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'lookup': { - b'args': { - b'key': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'manifestdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'nodes': { - b'required': True, - b'type': b'list' - }, - b'tree': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ], - b'recommendedbatchsize': 100000 - }, - b'pushkey': { - b'args': { - b'key': { - b'required': True, - b'type': b'bytes' - }, - b'namespace': { - b'required': True, - b'type': b'bytes' - }, - b'new': { - b'required': True, - b'type': b'bytes' - }, - b'old': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'push' - ] - }, - b'rawstorefiledata': { - b'args': { - b'files': { - b'required': True, - b'type': b'list' - }, - b'pathfilter': { - b'default': None, - b'required': False, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - } - }, - b'framingmediatypes': [ - b'application/mercurial-exp-framing-0006' - ], - b'pathfilterprefixes': set([ - b'path:', - b'rootfilesin:' - ]), - b'rawrepoformats': [ - b'generaldelta', - b'revlogv1', - b'sparserevlog' - ] - } - }, - b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash' - } - ] - -capabilities command returns expected info - - $ sendhttpv2peerhandshake << EOF - > command capabilities - > EOF - creating http peer for wire protocol version 2 - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> vary: X-HgProto-1,X-HgUpgrade-1\r\n - s> x-hgproto-1: cbor\r\n - s> x-hgupgrade-1: exp-http-v2-0003\r\n - s> accept: application/mercurial-0.1\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-cbor\r\n - s> Content-Length: *\r\n (glob) - s> \r\n - s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogNv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - sending capabilities command - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: application/mercurial-exp-framing-0006\r\n - s> content-length: 63\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x13\x00\x00\x01\x00\x01\x00\x11\xa1DnameLcapabilities - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0006\r\n - s> Transfer-Encoding: chunked\r\n - s> \r\n - s> 11\r\n - s> \t\x00\x00\x01\x00\x02\x01\x92 - s> Hidentity - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x01\x00\x02\x041 - s> \xa1FstatusBok - s> \r\n - s> 65e\r\n - s> V\x06\x00\x01\x00\x02\x041 - s> \xa4Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1Lsparserevlog - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x01\x00\x02\x002 - s> \r\n - s> 0\r\n - s> \r\n - response: gen[ - { - b'commands': { - b'branchmap': { - b'args': {}, - b'permissions': [ - b'pull' - ] - }, - b'capabilities': { - b'args': {}, - b'permissions': [ - b'pull' - ] - }, - b'changesetdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'bookmarks', - b'parents', - b'phase', - b'revision' - ]) - }, - b'revisions': { - b'required': True, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'filedata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'linknode', - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'nodes': { - b'required': True, - b'type': b'list' - }, - b'path': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'filesdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'firstchangeset', - b'linknode', - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'pathfilter': { - b'default': None, - b'required': False, - b'type': b'dict' - }, - b'revisions': { - b'required': True, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ], - b'recommendedbatchsize': 50000 - }, - b'heads': { - b'args': { - b'publiconly': { - b'default': False, - b'required': False, - b'type': b'bool' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'known': { - b'args': { - b'nodes': { - b'default': [], - b'required': False, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'listkeys': { - b'args': { - b'namespace': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'lookup': { - b'args': { - b'key': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'manifestdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'nodes': { - b'required': True, - b'type': b'list' - }, - b'tree': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ], - b'recommendedbatchsize': 100000 - }, - b'pushkey': { - b'args': { - b'key': { - b'required': True, - b'type': b'bytes' - }, - b'namespace': { - b'required': True, - b'type': b'bytes' - }, - b'new': { - b'required': True, - b'type': b'bytes' - }, - b'old': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'push' - ] - }, - b'rawstorefiledata': { - b'args': { - b'files': { - b'required': True, - b'type': b'list' - }, - b'pathfilter': { - b'default': None, - b'required': False, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - } - }, - b'framingmediatypes': [ - b'application/mercurial-exp-framing-0006' - ], - b'pathfilterprefixes': set([ - b'path:', - b'rootfilesin:' - ]), - b'rawrepoformats': [ - b'generaldelta', - b'revlogv1', - b'sparserevlog' - ] - } - ] - (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ cat error.log diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-command-changesetdata.t --- a/tests/test-wireproto-command-changesetdata.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,613 +0,0 @@ - $ . $TESTDIR/wireprotohelpers.sh - - $ hg init server - $ enablehttpv2 server - $ cd server - $ cat >> .hg/hgrc << EOF - > [phases] - > publish = false - > EOF - $ echo a0 > a - $ echo b0 > b - - $ hg -q commit -A -m 'commit 0' - - $ echo a1 > a - $ echo b1 > b - $ hg commit -m 'commit 1' - $ echo b2 > b - $ hg commit -m 'commit 2' - $ hg phase --public -r . - - $ hg -q up -r 0 - $ echo a2 > a - $ hg commit -m 'commit 3' - created new head - - $ hg log -G -T '{rev}:{node} {desc}\n' - @ 3:eae5f82c2e622368d27daecb76b7e393d0f24211 commit 3 - | - | o 2:0bb8ad894a15b15380b2a2a5b183e20f2a4b28dd commit 2 - | | - | o 1:7592917e1c3e82677cb0a4bc715ca25dd12d28c1 commit 1 - |/ - o 0:3390ef850073fbc2f0dfff2244342c8e9229013a commit 0 - - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -No arguments is an invalid request - - $ sendhttpv2peer << EOF - > command changesetdata - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - abort: missing required arguments: revisions - [255] - -Missing nodes for changesetexplicit results in error - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[{b'type': b'changesetexplicit'}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - abort: nodes key not present in changesetexplicit revision specifier - [255] - -changesetexplicitdepth requires nodes and depth keys - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[{b'type': b'changesetexplicitdepth'}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - abort: nodes key not present in changesetexplicitdepth revision specifier - [255] - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[{b'type': b'changesetexplicitdepth', b'nodes': []}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - abort: depth key not present in changesetexplicitdepth revision specifier - [255] - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[{b'type': b'changesetexplicitdepth', b'depth': 42}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - abort: nodes key not present in changesetexplicitdepth revision specifier - [255] - -changesetdagrange requires roots and heads keys - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[{b'type': b'changesetdagrange'}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - abort: roots key not present in changesetdagrange revision specifier - [255] - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[{b'type': b'changesetdagrange', b'roots': []}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - abort: heads key not present in changesetdagrange revision specifier - [255] - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[{b'type': b'changesetdagrange', b'heads': [b'dummy']}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - abort: roots key not present in changesetdagrange revision specifier - [255] - -Empty changesetdagrange heads results in an error - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[{b'type': b'changesetdagrange', b'heads': [], b'roots': []}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - abort: heads key in changesetdagrange cannot be empty - [255] - -Sending just dagrange heads sends all revisions - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[{ - > b'type': b'changesetdagrange', - > b'roots': [], - > b'heads': [ - > b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd', - > b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11', - > ]}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 4 - }, - { - b'node': b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:' - }, - { - b'node': b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1' - }, - { - b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd' - }, - { - b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11' - } - ] - -Sending root nodes limits what data is sent - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[{ - > b'type': b'changesetdagrange', - > b'roots': [b'\x33\x90\xef\x85\x00\x73\xfb\xc2\xf0\xdf\xff\x22\x44\x34\x2c\x8e\x92\x29\x01\x3a'], - > b'heads': [ - > b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd', - > ]}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 2 - }, - { - b'node': b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1' - }, - { - b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd' - } - ] - -Requesting data on a single node by node works - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [b'\x33\x90\xef\x85\x00\x73\xfb\xc2\xf0\xdf\xff\x22\x44\x34\x2c\x8e\x92\x29\x01\x3a']}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'node': b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:' - } - ] - -Specifying a noderange and nodes takes union - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[ - > { - > b'type': b'changesetexplicit', - > b'nodes': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11'], - > }, - > { - > b'type': b'changesetdagrange', - > b'roots': [b'\x75\x92\x91\x7e\x1c\x3e\x82\x67\x7c\xb0\xa4\xbc\x71\x5c\xa2\x5d\xd1\x2d\x28\xc1'], - > b'heads': [b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd'], - > }] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 2 - }, - { - b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11' - }, - { - b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd' - } - ] - -nodesdepth of 1 limits to exactly requested nodes - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[{ - > b'type': b'changesetexplicitdepth', - > b'nodes': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11'], - > b'depth': 1}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11' - } - ] - -nodesdepth of 2 limits to first ancestor - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[{ - > b'type': b'changesetexplicitdepth', - > b'nodes': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11'], - > b'depth': 2}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 2 - }, - { - b'node': b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:' - }, - { - b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11' - } - ] - -nodesdepth with multiple nodes - - $ sendhttpv2peer << EOF - > command changesetdata - > revisions eval:[{ - > b'type': b'changesetexplicitdepth', - > b'nodes': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11', b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd'], - > b'depth': 2}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 4 - }, - { - b'node': b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:' - }, - { - b'node': b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1' - }, - { - b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd' - }, - { - b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11' - } - ] - -Parents data is transferred upon request - - $ sendhttpv2peer << EOF - > command changesetdata - > fields eval:[b'parents'] - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11', - > ]}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11', - b'parents': [ - b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - } - ] - -Phase data is transferred upon request - - $ sendhttpv2peer << EOF - > command changesetdata - > fields eval:[b'phase'] - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd', - > ]}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd', - b'phase': b'public' - } - ] - -Revision data is transferred upon request - - $ sendhttpv2peer << EOF - > command changesetdata - > fields eval:[b'revision'] - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11', - > ]}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 61 - ] - ], - b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11' - }, - b'1b74476799ec8318045db759b1b4bcc9b839d0aa\ntest\n0 0\na\n\ncommit 3' - ] - -Bookmarks key isn't present if no bookmarks data - - $ sendhttpv2peer << EOF - > command changesetdata - > fields eval:[b'bookmarks'] - > revisions eval:[{ - > b'type': b'changesetdagrange', - > b'roots': [], - > b'heads': [ - > b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd', - > b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11', - > ]}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 4 - }, - { - b'node': b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:' - }, - { - b'node': b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1' - }, - { - b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd' - }, - { - b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11' - } - ] - -Bookmarks are sent when requested - - $ hg -R ../server bookmark -r 0bb8ad894a15b15380b2a2a5b183e20f2a4b28dd book-1 - $ hg -R ../server bookmark -r eae5f82c2e622368d27daecb76b7e393d0f24211 book-2 - $ hg -R ../server bookmark -r eae5f82c2e622368d27daecb76b7e393d0f24211 book-3 - - $ sendhttpv2peer << EOF - > command changesetdata - > fields eval:[b'bookmarks'] - > revisions eval:[{ - > b'type': b'changesetdagrange', - > b'roots': [], - > b'heads': [ - > b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd', - > b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11', - > ]}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 4 - }, - { - b'node': b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:' - }, - { - b'node': b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1' - }, - { - b'bookmarks': [ - b'book-1' - ], - b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd' - }, - { - b'bookmarks': [ - b'book-2', - b'book-3' - ], - b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11' - } - ] - -Bookmarks are sent when we make a no-new-revisions request - - $ sendhttpv2peer << EOF - > command changesetdata - > fields eval:[b'bookmarks', b'revision'] - > revisions eval:[{ - > b'type': b'changesetdagrange', - > b'roots': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11'], - > b'heads': [ - > b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd', - > b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11', - > ]}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 2 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 63 - ] - ], - b'node': b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1' - }, - b'7f144aea0ba742713887b564d57e9d12f12ff382\ntest\n0 0\na\nb\n\ncommit 1', - { - b'bookmarks': [ - b'book-1' - ], - b'fieldsfollowing': [ - [ - b'revision', - 61 - ] - ], - b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd' - }, - b'37f0a2d1c28ffe4b879109a7d1bbf8f07b3c763b\ntest\n0 0\nb\n\ncommit 2', - { - b'bookmarks': [ - b'book-2', - b'book-3' - ], - b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11' - } - ] - -Multiple fields can be transferred - - $ sendhttpv2peer << EOF - > command changesetdata - > fields eval:[b'parents', b'revision'] - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11', - > ]}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 61 - ] - ], - b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11', - b'parents': [ - b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - }, - b'1b74476799ec8318045db759b1b4bcc9b839d0aa\ntest\n0 0\na\n\ncommit 3' - ] - -Base nodes have just their metadata (e.g. phase) transferred -TODO this doesn't work - - $ sendhttpv2peer << EOF - > command changesetdata - > fields eval:[b'phase', b'parents', b'revision'] - > revisions eval:[{ - > b'type': b'changesetdagrange', - > b'roots': [b'\x33\x90\xef\x85\x00\x73\xfb\xc2\xf0\xdf\xff\x22\x44\x34\x2c\x8e\x92\x29\x01\x3a'], - > b'heads': [ - > b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd', - > b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11', - > ]}] - > EOF - creating http peer for wire protocol version 2 - sending changesetdata command - response: gen[ - { - b'totalitems': 3 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 63 - ] - ], - b'node': b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1', - b'parents': [ - b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ], - b'phase': b'public' - }, - b'7f144aea0ba742713887b564d57e9d12f12ff382\ntest\n0 0\na\nb\n\ncommit 1', - { - b'fieldsfollowing': [ - [ - b'revision', - 61 - ] - ], - b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd', - b'parents': [ - b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ], - b'phase': b'public' - }, - b'37f0a2d1c28ffe4b879109a7d1bbf8f07b3c763b\ntest\n0 0\nb\n\ncommit 2', - { - b'fieldsfollowing': [ - [ - b'revision', - 61 - ] - ], - b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11', - b'parents': [ - b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ], - b'phase': b'draft' - }, - b'1b74476799ec8318045db759b1b4bcc9b839d0aa\ntest\n0 0\na\n\ncommit 3' - ] - - $ cat error.log diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-command-filedata.t --- a/tests/test-wireproto-command-filedata.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,364 +0,0 @@ - $ . $TESTDIR/wireprotohelpers.sh - - $ hg init server - $ enablehttpv2 server - $ cd server - $ cat > a << EOF - > a0 - > 00000000000000000000000000000000000000 - > 11111111111111111111111111111111111111 - > EOF - $ echo b0 > b - $ mkdir -p dir0/child0 dir0/child1 dir1 - $ echo c0 > dir0/c - $ echo d0 > dir0/d - $ echo e0 > dir0/child0/e - $ echo f0 > dir0/child1/f - $ hg -q commit -A -m 'commit 0' - - $ echo a1 >> a - $ echo d1 > dir0/d - $ hg commit -m 'commit 1' - $ echo f1 > dir0/child1/f - $ hg commit -m 'commit 2' - - $ hg -q up -r 0 - $ echo a2 >> a - $ hg commit -m 'commit 3' - created new head - -Create multiple heads introducing the same changeset - - $ hg -q up -r 0 - $ echo foo > dupe-file - $ hg commit -Am 'dupe 1' - adding dupe-file - created new head - $ hg -q up -r 0 - $ echo foo > dupe-file - $ hg commit -Am 'dupe 2' - adding dupe-file - created new head - - $ hg log -G -T '{rev}:{node} {desc}\n' - @ 5:732c3dd7bee94242de656000e5f458e7ccfe2828 dupe 2 - | - | o 4:4334f10897d13c3e8beb4b636f7272b4ec2d0322 dupe 1 - |/ - | o 3:5ce944d7fece1252dae06c34422b573c191b9489 commit 3 - |/ - | o 2:b3c27db01410dae01e5485d425b1440078df540c commit 2 - | | - | o 1:3ef5e551f219ba505481d34d6b0316b017fa3f00 commit 1 - |/ - o 0:91b232a2253ce0638496f67bdfd7a4933fb51b25 commit 0 - - - $ hg --debug debugindex a - rev linkrev nodeid p1 p2 - 0 0 649d149df43d83882523b7fb1e6a3af6f1907b39 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 - 1 1 0a86321f1379d1a9ecd0579a22977af7a5acaf11 649d149df43d83882523b7fb1e6a3af6f1907b39 0000000000000000000000000000000000000000 - 2 3 7e5801b6d5f03a5a54f3c47b583f7567aad43e5b 649d149df43d83882523b7fb1e6a3af6f1907b39 0000000000000000000000000000000000000000 - - $ hg --debug debugindex dir0/child0/e - rev linkrev nodeid p1 p2 - 0 0 bbba6c06b30f443d34ff841bc985c4d0827c6be4 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 - - $ hg --debug debugindex dupe-file - rev linkrev nodeid p1 p2 - 0 4 2ed2a3912a0b24502043eae84ee4b279c18b90dd 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -Missing arguments is an error - - $ sendhttpv2peer << EOF - > command filedata - > EOF - creating http peer for wire protocol version 2 - sending filedata command - abort: missing required arguments: nodes, path - [255] - - $ sendhttpv2peer << EOF - > command filedata - > nodes eval:[] - > EOF - creating http peer for wire protocol version 2 - sending filedata command - abort: missing required arguments: path - [255] - -Unknown node is an error - - $ sendhttpv2peer << EOF - > command filedata - > nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'] - > path eval:b'a' - > EOF - creating http peer for wire protocol version 2 - sending filedata command - abort: unknown file node: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - [255] - -Fetching a single revision returns just metadata by default - - $ sendhttpv2peer << EOF - > command filedata - > nodes eval:[b'\x0a\x86\x32\x1f\x13\x79\xd1\xa9\xec\xd0\x57\x9a\x22\x97\x7a\xf7\xa5\xac\xaf\x11'] - > path eval:b'a' - > EOF - creating http peer for wire protocol version 2 - sending filedata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - } - ] - -Requesting parents works - - $ sendhttpv2peer << EOF - > command filedata - > nodes eval:[b'\x0a\x86\x32\x1f\x13\x79\xd1\xa9\xec\xd0\x57\x9a\x22\x97\x7a\xf7\xa5\xac\xaf\x11'] - > path eval:b'a' - > fields eval:[b'parents'] - > EOF - creating http peer for wire protocol version 2 - sending filedata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11', - b'parents': [ - b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - } - ] - -Requesting revision data works -(haveparents defaults to False, so fulltext is emitted) - - $ sendhttpv2peer << EOF - > command filedata - > nodes eval:[b'\x0a\x86\x32\x1f\x13\x79\xd1\xa9\xec\xd0\x57\x9a\x22\x97\x7a\xf7\xa5\xac\xaf\x11'] - > path eval:b'a' - > fields eval:[b'revision'] - > EOF - creating http peer for wire protocol version 2 - sending filedata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 84 - ] - ], - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - }, - b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n' - ] - -haveparents=False should be same as above - - $ sendhttpv2peer << EOF - > command filedata - > nodes eval:[b'\x0a\x86\x32\x1f\x13\x79\xd1\xa9\xec\xd0\x57\x9a\x22\x97\x7a\xf7\xa5\xac\xaf\x11'] - > path eval:b'a' - > fields eval:[b'revision'] - > haveparents eval:False - > EOF - creating http peer for wire protocol version 2 - sending filedata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 84 - ] - ], - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - }, - b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n' - ] - -haveparents=True should emit a delta - - $ sendhttpv2peer << EOF - > command filedata - > nodes eval:[b'\x0a\x86\x32\x1f\x13\x79\xd1\xa9\xec\xd0\x57\x9a\x22\x97\x7a\xf7\xa5\xac\xaf\x11'] - > path eval:b'a' - > fields eval:[b'revision'] - > haveparents eval:True - > EOF - creating http peer for wire protocol version 2 - sending filedata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9', - b'fieldsfollowing': [ - [ - b'delta', - 15 - ] - ], - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - }, - b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n' - ] - -Requesting multiple revisions works -(first revision is a fulltext since haveparents=False by default) - - $ sendhttpv2peer << EOF - > command filedata - > nodes eval:[b'\x64\x9d\x14\x9d\xf4\x3d\x83\x88\x25\x23\xb7\xfb\x1e\x6a\x3a\xf6\xf1\x90\x7b\x39', b'\x0a\x86\x32\x1f\x13\x79\xd1\xa9\xec\xd0\x57\x9a\x22\x97\x7a\xf7\xa5\xac\xaf\x11'] - > path eval:b'a' - > fields eval:[b'revision'] - > EOF - creating http peer for wire protocol version 2 - sending filedata command - response: gen[ - { - b'totalitems': 2 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 81 - ] - ], - b'node': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9' - }, - b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\n', - { - b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9', - b'fieldsfollowing': [ - [ - b'delta', - 15 - ] - ], - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - }, - b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n' - ] - -Revisions are sorted by DAG order, parents first - - $ sendhttpv2peer << EOF - > command filedata - > nodes eval:[b'\x0a\x86\x32\x1f\x13\x79\xd1\xa9\xec\xd0\x57\x9a\x22\x97\x7a\xf7\xa5\xac\xaf\x11', b'\x64\x9d\x14\x9d\xf4\x3d\x83\x88\x25\x23\xb7\xfb\x1e\x6a\x3a\xf6\xf1\x90\x7b\x39'] - > path eval:b'a' - > fields eval:[b'revision'] - > EOF - creating http peer for wire protocol version 2 - sending filedata command - response: gen[ - { - b'totalitems': 2 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 81 - ] - ], - b'node': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9' - }, - b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\n', - { - b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9', - b'fieldsfollowing': [ - [ - b'delta', - 15 - ] - ], - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - }, - b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n' - ] - -Requesting parents and revision data works - - $ sendhttpv2peer << EOF - > command filedata - > nodes eval:[b'\x7e\x58\x01\xb6\xd5\xf0\x3a\x5a\x54\xf3\xc4\x7b\x58\x3f\x75\x67\xaa\xd4\x3e\x5b'] - > path eval:b'a' - > fields eval:[b'parents', b'revision'] - > EOF - creating http peer for wire protocol version 2 - sending filedata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 84 - ] - ], - b'node': b'~X\x01\xb6\xd5\xf0:ZT\xf3\xc4{X?ug\xaa\xd4>[', - b'parents': [ - b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - }, - b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na2\n' - ] - -Linknode for duplicate revision is the initial revision - - $ sendhttpv2peer << EOF - > command filedata - > nodes eval:[b'\x2e\xd2\xa3\x91\x2a\x0b\x24\x50\x20\x43\xea\xe8\x4e\xe4\xb2\x79\xc1\x8b\x90\xdd'] - > path eval:b'dupe-file' - > fields eval:[b'linknode', b'parents', b'revision'] - > EOF - creating http peer for wire protocol version 2 - sending filedata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 4 - ] - ], - b'linknode': b'C4\xf1\x08\x97\xd1<>\x8b\xebKcorr\xb4\xec-\x03"', - b'node': b'.\xd2\xa3\x91*\x0b$P C\xea\xe8N\xe4\xb2y\xc1\x8b\x90\xdd', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - }, - b'foo\n' - ] - - $ cat error.log diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-command-filesdata.t --- a/tests/test-wireproto-command-filesdata.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1298 +0,0 @@ - $ . $TESTDIR/wireprotohelpers.sh - - $ hg init server - $ enablehttpv2 server - $ cd server - $ cat > a << EOF - > a0 - > 00000000000000000000000000000000000000 - > 11111111111111111111111111111111111111 - > EOF - $ cat > b << EOF - > b0 - > aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - > bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb - > EOF - $ mkdir -p dir0/child0 dir0/child1 dir1 - $ echo c0 > dir0/c - $ echo d0 > dir0/d - $ echo e0 > dir0/child0/e - $ echo f0 > dir0/child1/f - $ hg -q commit -A -m 'commit 0' - - $ echo a1 >> a - $ echo d1 > dir0/d - $ echo g0 > g - $ echo h0 > h - $ hg -q commit -A -m 'commit 1' - $ echo f1 > dir0/child1/f - $ echo i0 > dir0/i - $ hg -q commit -A -m 'commit 2' - - $ hg -q up -r 0 - $ echo a2 >> a - $ hg commit -m 'commit 3' - created new head - -Create multiple heads introducing the same file nodefile node - - $ hg -q up -r 0 - $ echo foo > dupe-file - $ hg commit -Am 'dupe 1' - adding dupe-file - created new head - $ hg -q up -r 0 - $ echo foo > dupe-file - $ hg commit -Am 'dupe 2' - adding dupe-file - created new head - - $ hg log -G -T '{rev}:{node} {desc}\n' - @ 5:47fc30580911232cb264675b402819deddf6c6f0 dupe 2 - | - | o 4:b16cce2967c1749ef4f4e3086a806cfbad8a3af7 dupe 1 - |/ - | o 3:476fbf122cd82f6726f0191ff146f67140946abc commit 3 - |/ - | o 2:b91c03cbba3519ab149b6cd0a0afbdb5cf1b5c8a commit 2 - | | - | o 1:5b0b1a23577e205ea240e39c9704e28d7697cbd8 commit 1 - |/ - o 0:6e875ff18c227659ad6143bb3580c65700734884 commit 0 - - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -Missing arguments is an error - - $ sendhttpv2peer << EOF - > command filesdata - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - abort: missing required arguments: revisions - [255] - -Bad pattern to pathfilter is rejected - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8', - > ]}] - > pathfilter eval:{b'include': [b'bad:foo']} - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - abort: include pattern must begin with `path:` or `rootfilesin:`; got bad:foo - [255] - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8', - > ]}] - > pathfilter eval:{b'exclude': [b'glob:foo']} - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - abort: exclude pattern must begin with `path:` or `rootfilesin:`; got glob:foo - [255] - -Fetching a single changeset without parents fetches all files - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8', - > ]}] - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 8, - b'totalpaths': 8 - }, - { - b'path': b'a', - b'totalitems': 1 - }, - { - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - }, - { - b'path': b'b', - b'totalitems': 1 - }, - { - b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2' - }, - { - b'path': b'dir0/c', - b'totalitems': 1 - }, - { - b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01' - }, - { - b'path': b'dir0/child0/e', - b'totalitems': 1 - }, - { - b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4' - }, - { - b'path': b'dir0/child1/f', - b'totalitems': 1 - }, - { - b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4' - }, - { - b'path': b'dir0/d', - b'totalitems': 1 - }, - { - b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G' - }, - { - b'path': b'g', - b'totalitems': 1 - }, - { - b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c' - }, - { - b'path': b'h', - b'totalitems': 1 - }, - { - b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K' - } - ] - -Fetching a single changeset saying parents data is available fetches just new files - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8', - > ]}] - > haveparents eval:True - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 4, - b'totalpaths': 4 - }, - { - b'path': b'a', - b'totalitems': 1 - }, - { - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - }, - { - b'path': b'dir0/d', - b'totalitems': 1 - }, - { - b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G' - }, - { - b'path': b'g', - b'totalitems': 1 - }, - { - b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c' - }, - { - b'path': b'h', - b'totalitems': 1 - }, - { - b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K' - } - ] - -A path filter for a sub-directory is honored - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8', - > ]}] - > haveparents eval:True - > pathfilter eval:{b'include': [b'path:dir0']} - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 1, - b'totalpaths': 1 - }, - { - b'path': b'dir0/d', - b'totalitems': 1 - }, - { - b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G' - } - ] - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8', - > ]}] - > haveparents eval:True - > pathfilter eval:{b'exclude': [b'path:a', b'path:g']} - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 2, - b'totalpaths': 2 - }, - { - b'path': b'dir0/d', - b'totalitems': 1 - }, - { - b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G' - }, - { - b'path': b'h', - b'totalitems': 1 - }, - { - b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K' - } - ] - -Requesting multiple changeset nodes without haveparents sends all data for both - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8', - > b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a', - > ]}] - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 10, - b'totalpaths': 9 - }, - { - b'path': b'a', - b'totalitems': 1 - }, - { - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - }, - { - b'path': b'b', - b'totalitems': 1 - }, - { - b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2' - }, - { - b'path': b'dir0/c', - b'totalitems': 1 - }, - { - b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01' - }, - { - b'path': b'dir0/child0/e', - b'totalitems': 1 - }, - { - b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4' - }, - { - b'path': b'dir0/child1/f', - b'totalitems': 2 - }, - { - b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4' - }, - { - b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e' - }, - { - b'path': b'dir0/d', - b'totalitems': 1 - }, - { - b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G' - }, - { - b'path': b'dir0/i', - b'totalitems': 1 - }, - { - b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7' - }, - { - b'path': b'g', - b'totalitems': 1 - }, - { - b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c' - }, - { - b'path': b'h', - b'totalitems': 1 - }, - { - b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K' - } - ] - -Requesting multiple changeset nodes with haveparents sends incremental data for both - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8', - > b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a', - > ]}] - > haveparents eval:True - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 6, - b'totalpaths': 6 - }, - { - b'path': b'a', - b'totalitems': 1 - }, - { - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - }, - { - b'path': b'dir0/child1/f', - b'totalitems': 1 - }, - { - b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e' - }, - { - b'path': b'dir0/d', - b'totalitems': 1 - }, - { - b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G' - }, - { - b'path': b'dir0/i', - b'totalitems': 1 - }, - { - b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7' - }, - { - b'path': b'g', - b'totalitems': 1 - }, - { - b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c' - }, - { - b'path': b'h', - b'totalitems': 1 - }, - { - b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K' - } - ] - -Requesting parents works - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8', - > ]}] - > fields eval:[b'parents'] - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 8, - b'totalpaths': 8 - }, - { - b'path': b'a', - b'totalitems': 1 - }, - { - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11', - b'parents': [ - b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - }, - { - b'path': b'b', - b'totalitems': 1 - }, - { - b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - }, - { - b'path': b'dir0/c', - b'totalitems': 1 - }, - { - b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - }, - { - b'path': b'dir0/child0/e', - b'totalitems': 1 - }, - { - b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - }, - { - b'path': b'dir0/child1/f', - b'totalitems': 1 - }, - { - b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - }, - { - b'path': b'dir0/d', - b'totalitems': 1 - }, - { - b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G', - b'parents': [ - b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - }, - { - b'path': b'g', - b'totalitems': 1 - }, - { - b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - }, - { - b'path': b'h', - b'totalitems': 1 - }, - { - b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - } - ] - -Requesting revision data works -(haveparents defaults to False, so fulltext is emitted) - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8', - > ]}] - > fields eval:[b'revision'] - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 8, - b'totalpaths': 8 - }, - { - b'path': b'a', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 84 - ] - ], - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - }, - b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n', - { - b'path': b'b', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 81 - ] - ], - b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2' - }, - b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n', - { - b'path': b'dir0/c', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01' - }, - b'c0\n', - { - b'path': b'dir0/child0/e', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4' - }, - b'e0\n', - { - b'path': b'dir0/child1/f', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4' - }, - b'f0\n', - { - b'path': b'dir0/d', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G' - }, - b'd1\n', - { - b'path': b'g', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c' - }, - b'g0\n', - { - b'path': b'h', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K' - }, - b'h0\n' - ] - -haveparents=False should be same as above - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8', - > ]}] - > fields eval:[b'revision'] - > haveparents eval:False - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 8, - b'totalpaths': 8 - }, - { - b'path': b'a', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 84 - ] - ], - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - }, - b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n', - { - b'path': b'b', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 81 - ] - ], - b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2' - }, - b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n', - { - b'path': b'dir0/c', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01' - }, - b'c0\n', - { - b'path': b'dir0/child0/e', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4' - }, - b'e0\n', - { - b'path': b'dir0/child1/f', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4' - }, - b'f0\n', - { - b'path': b'dir0/d', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G' - }, - b'd1\n', - { - b'path': b'g', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c' - }, - b'g0\n', - { - b'path': b'h', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K' - }, - b'h0\n' - ] - -haveparents=True should emit a delta - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8', - > ]}] - > fields eval:[b'revision'] - > haveparents eval:True - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 4, - b'totalpaths': 4 - }, - { - b'path': b'a', - b'totalitems': 1 - }, - { - b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9', - b'fieldsfollowing': [ - [ - b'delta', - 15 - ] - ], - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - }, - b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n', - { - b'path': b'dir0/d', - b'totalitems': 1 - }, - { - b'deltabasenode': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&', - b'fieldsfollowing': [ - [ - b'delta', - 15 - ] - ], - b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G' - }, - b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03d1\n', - { - b'path': b'g', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c' - }, - b'g0\n', - { - b'path': b'h', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K' - }, - b'h0\n' - ] - -Requesting multiple revisions works -(first revision is a fulltext since haveparents=False by default) - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x6e\x87\x5f\xf1\x8c\x22\x76\x59\xad\x61\x43\xbb\x35\x80\xc6\x57\x00\x73\x48\x84', - > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8', - > b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a', - > ]}] - > fields eval:[b'revision'] - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 12, - b'totalpaths': 9 - }, - { - b'path': b'a', - b'totalitems': 2 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 81 - ] - ], - b'node': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9' - }, - b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\n', - { - b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9', - b'fieldsfollowing': [ - [ - b'delta', - 15 - ] - ], - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - }, - b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n', - { - b'path': b'b', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 81 - ] - ], - b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2' - }, - b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n', - { - b'path': b'dir0/c', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01' - }, - b'c0\n', - { - b'path': b'dir0/child0/e', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4' - }, - b'e0\n', - { - b'path': b'dir0/child1/f', - b'totalitems': 2 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4' - }, - b'f0\n', - { - b'deltabasenode': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4', - b'fieldsfollowing': [ - [ - b'delta', - 15 - ] - ], - b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e' - }, - b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03f1\n', - { - b'path': b'dir0/d', - b'totalitems': 2 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&' - }, - b'd0\n', - { - b'deltabasenode': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&', - b'fieldsfollowing': [ - [ - b'delta', - 15 - ] - ], - b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G' - }, - b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03d1\n', - { - b'path': b'dir0/i', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7' - }, - b'i0\n', - { - b'path': b'g', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c' - }, - b'g0\n', - { - b'path': b'h', - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 3 - ] - ], - b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K' - }, - b'h0\n' - ] - -Requesting linknode field works - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x6e\x87\x5f\xf1\x8c\x22\x76\x59\xad\x61\x43\xbb\x35\x80\xc6\x57\x00\x73\x48\x84', - > b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8', - > b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a', - > ]}] - > fields eval:[b'linknode'] - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 12, - b'totalpaths': 9 - }, - { - b'path': b'a', - b'totalitems': 2 - }, - { - b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84', - b'node': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9' - }, - { - b'linknode': b'[\x0b\x1a#W~ ^\xa2@\xe3\x9c\x97\x04\xe2\x8dv\x97\xcb\xd8', - b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11' - }, - { - b'path': b'b', - b'totalitems': 1 - }, - { - b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84', - b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2' - }, - { - b'path': b'dir0/c', - b'totalitems': 1 - }, - { - b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84', - b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01' - }, - { - b'path': b'dir0/child0/e', - b'totalitems': 1 - }, - { - b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84', - b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4' - }, - { - b'path': b'dir0/child1/f', - b'totalitems': 2 - }, - { - b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84', - b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4' - }, - { - b'linknode': b'\xb9\x1c\x03\xcb\xba5\x19\xab\x14\x9bl\xd0\xa0\xaf\xbd\xb5\xcf\x1b\\\x8a', - b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e' - }, - { - b'path': b'dir0/d', - b'totalitems': 2 - }, - { - b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84', - b'node': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&' - }, - { - b'linknode': b'[\x0b\x1a#W~ ^\xa2@\xe3\x9c\x97\x04\xe2\x8dv\x97\xcb\xd8', - b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G' - }, - { - b'path': b'dir0/i', - b'totalitems': 1 - }, - { - b'linknode': b'\xb9\x1c\x03\xcb\xba5\x19\xab\x14\x9bl\xd0\xa0\xaf\xbd\xb5\xcf\x1b\\\x8a', - b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7' - }, - { - b'path': b'g', - b'totalitems': 1 - }, - { - b'linknode': b'[\x0b\x1a#W~ ^\xa2@\xe3\x9c\x97\x04\xe2\x8dv\x97\xcb\xd8', - b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c' - }, - { - b'path': b'h', - b'totalitems': 1 - }, - { - b'linknode': b'[\x0b\x1a#W~ ^\xa2@\xe3\x9c\x97\x04\xe2\x8dv\x97\xcb\xd8', - b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K' - } - ] - -Test behavior where a file node is introduced in 2 DAG heads - -Request for changeset introducing filenode returns linknode as self - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\xb1\x6c\xce\x29\x67\xc1\x74\x9e\xf4\xf4\xe3\x08\x6a\x80\x6c\xfb\xad\x8a\x3a\xf7', - > ]}] - > fields eval:[b'linknode'] - > pathfilter eval:{b'include': [b'path:dupe-file']} - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 1, - b'totalpaths': 1 - }, - { - b'path': b'dupe-file', - b'totalitems': 1 - }, - { - b'linknode': b'\xb1l\xce)g\xc1t\x9e\xf4\xf4\xe3\x08j\x80l\xfb\xad\x8a:\xf7', - b'node': b'.\xd2\xa3\x91*\x0b$P C\xea\xe8N\xe4\xb2y\xc1\x8b\x90\xdd' - } - ] - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\xb1\x6c\xce\x29\x67\xc1\x74\x9e\xf4\xf4\xe3\x08\x6a\x80\x6c\xfb\xad\x8a\x3a\xf7', - > ]}] - > fields eval:[b'linknode'] - > haveparents eval:True - > pathfilter eval:{b'include': [b'path:dupe-file']} - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 1, - b'totalpaths': 1 - }, - { - b'path': b'dupe-file', - b'totalitems': 1 - }, - { - b'linknode': b'\xb1l\xce)g\xc1t\x9e\xf4\xf4\xe3\x08j\x80l\xfb\xad\x8a:\xf7', - b'node': b'.\xd2\xa3\x91*\x0b$P C\xea\xe8N\xe4\xb2y\xc1\x8b\x90\xdd' - } - ] - -Request for changeset where recorded linknode isn't in DAG ancestry will get -rewritten accordingly - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x47\xfc\x30\x58\x09\x11\x23\x2c\xb2\x64\x67\x5b\x40\x28\x19\xde\xdd\xf6\xc6\xf0', - > ]}] - > fields eval:[b'linknode'] - > pathfilter eval:{b'include': [b'path:dupe-file']} - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 1, - b'totalpaths': 1 - }, - { - b'path': b'dupe-file', - b'totalitems': 1 - }, - { - b'linknode': b'G\xfc0X\t\x11#,\xb2dg[@(\x19\xde\xdd\xf6\xc6\xf0', - b'node': b'.\xd2\xa3\x91*\x0b$P C\xea\xe8N\xe4\xb2y\xc1\x8b\x90\xdd' - } - ] - - $ sendhttpv2peer << EOF - > command filesdata - > revisions eval:[{ - > b'type': b'changesetexplicit', - > b'nodes': [ - > b'\x47\xfc\x30\x58\x09\x11\x23\x2c\xb2\x64\x67\x5b\x40\x28\x19\xde\xdd\xf6\xc6\xf0', - > ]}] - > fields eval:[b'linknode'] - > haveparents eval:True - > pathfilter eval:{b'include': [b'path:dupe-file']} - > EOF - creating http peer for wire protocol version 2 - sending filesdata command - response: gen[ - { - b'totalitems': 1, - b'totalpaths': 1 - }, - { - b'path': b'dupe-file', - b'totalitems': 1 - }, - { - b'linknode': b'G\xfc0X\t\x11#,\xb2dg[@(\x19\xde\xdd\xf6\xc6\xf0', - b'node': b'.\xd2\xa3\x91*\x0b$P C\xea\xe8N\xe4\xb2y\xc1\x8b\x90\xdd' - } - ] - - $ cat error.log diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-command-heads.t --- a/tests/test-wireproto-command-heads.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ - $ . $TESTDIR/wireprotohelpers.sh - - $ hg init server - $ enablehttpv2 server - $ cd server - $ hg debugdrawdag << EOF - > H I J - > | | | - > E F G - > | |/ - > C D - > |/ - > B - > | - > A - > EOF - - $ hg phase --force --secret J - $ hg phase --public E - - $ hg log -r 'E + H + I + G + J' -T '{rev}:{node} {desc} {phase}\n' - 4:78d2dca436b2f5b188ac267e29b81e07266d38fc E public - 7:ae492e36b0c8339ffaf328d00b85b4525de1165e H draft - 8:1d6f6b91d44aaba6d5e580bc30a9948530dbe00b I draft - 6:29446d2dc5419c5f97447a8bc062e4cc328bf241 G draft - 9:dec04b246d7cbb670c6689806c05ad17c835284e J secret - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -All non-secret heads returned by default - - $ sendhttpv2peer << EOF - > command heads - > EOF - creating http peer for wire protocol version 2 - sending heads command - response: [ - b'\x1dok\x91\xd4J\xab\xa6\xd5\xe5\x80\xbc0\xa9\x94\x850\xdb\xe0\x0b', - b'\xaeI.6\xb0\xc83\x9f\xfa\xf3(\xd0\x0b\x85\xb4R]\xe1\x16^', - b')Dm-\xc5A\x9c_\x97Dz\x8b\xc0b\xe4\xcc2\x8b\xf2A' - ] - -Requesting just the public heads works - - $ sendhttpv2peer << EOF - > command heads - > publiconly 1 - > EOF - creating http peer for wire protocol version 2 - sending heads command - response: [ - b'x\xd2\xdc\xa46\xb2\xf5\xb1\x88\xac&~)\xb8\x1e\x07&m8\xfc' - ] - - $ cat error.log diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-command-known.t --- a/tests/test-wireproto-command-known.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ - $ . $TESTDIR/wireprotohelpers.sh - - $ hg init server - $ enablehttpv2 server - $ cd server - $ hg debugdrawdag << EOF - > C D - > |/ - > B - > | - > A - > EOF - - $ hg log -T '{rev}:{node} {desc}\n' - 3:be0ef73c17ade3fc89dc41701eb9fc3a91b58282 D - 2:26805aba1e600a82e93661149f2313866a221a7b C - 1:112478962961147124edd43549aedd1a335e44bf B - 0:426bada5c67598ca65036d57d9e4b64b0c1ce7a0 A - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -No arguments returns something reasonable - - $ sendhttpv2peer << EOF - > command known - > EOF - creating http peer for wire protocol version 2 - sending known command - response: [] - -Single known node works - - $ sendhttpv2peer << EOF - > command known - > nodes eval:[b'\x42\x6b\xad\xa5\xc6\x75\x98\xca\x65\x03\x6d\x57\xd9\xe4\xb6\x4b\x0c\x1c\xe7\xa0'] - > EOF - creating http peer for wire protocol version 2 - sending known command - response: [ - True - ] - -Multiple nodes works - - $ sendhttpv2peer << EOF - > command known - > nodes eval:[b'\x42\x6b\xad\xa5\xc6\x75\x98\xca\x65\x03\x6d\x57\xd9\xe4\xb6\x4b\x0c\x1c\xe7\xa0', b'00000000000000000000', b'\x11\x24\x78\x96\x29\x61\x14\x71\x24\xed\xd4\x35\x49\xae\xdd\x1a\x33\x5e\x44\xbf'] - > EOF - creating http peer for wire protocol version 2 - sending known command - response: [ - True, - False, - True - ] - - $ cat error.log diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-command-listkeys.t --- a/tests/test-wireproto-command-listkeys.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ - $ . $TESTDIR/wireprotohelpers.sh - - $ hg init server - $ enablehttpv2 server - $ cd server - $ hg debugdrawdag << EOF - > C D - > |/ - > B - > | - > A - > EOF - - $ hg phase --public -r C - $ hg book -r C @ - - $ hg log -T '{rev}:{node} {desc}\n' - 3:be0ef73c17ade3fc89dc41701eb9fc3a91b58282 D - 2:26805aba1e600a82e93661149f2313866a221a7b C - 1:112478962961147124edd43549aedd1a335e44bf B - 0:426bada5c67598ca65036d57d9e4b64b0c1ce7a0 A - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -Request for namespaces works - - $ sendhttpv2peer << EOF - > command listkeys - > namespace namespaces - > EOF - creating http peer for wire protocol version 2 - sending listkeys command - response: { - b'bookmarks': b'', - b'namespaces': b'', - b'phases': b'' - } - -Request for phases works - - $ sendhttpv2peer << EOF - > command listkeys - > namespace phases - > EOF - creating http peer for wire protocol version 2 - sending listkeys command - response: { - b'be0ef73c17ade3fc89dc41701eb9fc3a91b58282': b'1', - b'publishing': b'True' - } - -Request for bookmarks works - - $ sendhttpv2peer << EOF - > command listkeys - > namespace bookmarks - > EOF - creating http peer for wire protocol version 2 - sending listkeys command - response: { - b'@': b'26805aba1e600a82e93661149f2313866a221a7b' - } - - $ cat error.log diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-command-lookup.t --- a/tests/test-wireproto-command-lookup.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ - $ . $TESTDIR/wireprotohelpers.sh - - $ hg init server - $ enablehttpv2 server - $ cd server - $ cat >> .hg/hgrc << EOF - > [web] - > push_ssl = false - > allow-push = * - > EOF - $ hg debugdrawdag << EOF - > C D - > |/ - > B - > | - > A - > EOF - $ root_node=$(hg log -r A -T '{node}') - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -lookup for known node works - - $ sendhttpv2peer << EOF - > command lookup - > key $root_node - > EOF - creating http peer for wire protocol version 2 - sending lookup command - response: b'Bk\xad\xa5\xc6u\x98\xcae\x03mW\xd9\xe4\xb6K\x0c\x1c\xe7\xa0' - - $ cat error.log diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-command-manifestdata.t --- a/tests/test-wireproto-command-manifestdata.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,358 +0,0 @@ - $ . $TESTDIR/wireprotohelpers.sh - - $ hg init server - $ enablehttpv2 server - $ cd server - $ echo a0 > a - $ echo b0 > b - $ mkdir -p dir0/child0 dir0/child1 dir1 - $ echo c0 > dir0/c - $ echo d0 > dir0/d - $ echo e0 > dir0/child0/e - $ echo f0 > dir0/child1/f - $ hg -q commit -A -m 'commit 0' - - $ echo a1 > a - $ echo d1 > dir0/d - $ hg commit -m 'commit 1' - $ echo f0 > dir0/child1/f - $ hg commit -m 'commit 2' - nothing changed - [1] - - $ hg -q up -r 0 - $ echo a2 > a - $ hg commit -m 'commit 3' - created new head - - $ hg log -G -T '{rev}:{node} {desc}\n' - @ 2:c8757a2ffe552850d1e0dfe60d295ebf64c196d9 commit 3 - | - | o 1:650165e803375748a94df471e5b58d85763e0b29 commit 1 - |/ - o 0:6d85ca1270b377d320098556ba5bfad34a9ee12d commit 0 - - - $ hg --debug debugindex -m - rev linkrev nodeid p1 p2 - 0 0 1b175b595f022cfab5b809cc0ed551bd0b3ff5e4 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 - 1 1 91e0bdbfb0dde0023fa063edc1445f207a22eac7 1b175b595f022cfab5b809cc0ed551bd0b3ff5e4 0000000000000000000000000000000000000000 - 2 2 46a6721b5edaf0ea04b79a5cb3218854a4d2aba0 1b175b595f022cfab5b809cc0ed551bd0b3ff5e4 0000000000000000000000000000000000000000 - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -Missing arguments is an error - - $ sendhttpv2peer << EOF - > command manifestdata - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - abort: missing required arguments: nodes, tree - [255] - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[] - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - abort: missing required arguments: tree - [255] - -Unknown node is an error - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'] - > tree eval:b'' - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - abort: unknown node: \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa (esc) - [255] - -Fetching a single revision returns just metadata by default - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0'] - > tree eval:b'' - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0' - } - ] - -Requesting parents works - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0'] - > tree eval:b'' - > fields eval:[b'parents'] - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0', - b'parents': [ - b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - } - ] - -Requesting revision data works -(haveparents defaults to false, so fulltext is emitted) - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0'] - > tree eval:b'' - > fields eval:[b'revision'] - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 292 - ] - ], - b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0' - }, - b'a\x000879345e39377229634b420c639454156726c6b6\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n' - ] - -haveparents=False yields same output - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0'] - > tree eval:b'' - > fields eval:[b'revision'] - > haveparents eval:False - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 292 - ] - ], - b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0' - }, - b'a\x000879345e39377229634b420c639454156726c6b6\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n' - ] - -haveparents=True will emit delta - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0'] - > tree eval:b'' - > fields eval:[b'revision'] - > haveparents eval:True - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4', - b'fieldsfollowing': [ - [ - b'delta', - 55 - ] - ], - b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0' - }, - b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n' - ] - -Requesting multiple revisions works -(haveparents defaults to false, so fulltext is emitted unless a parent -has been emitted) - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x1b\x17\x5b\x59\x5f\x02\x2c\xfa\xb5\xb8\x09\xcc\x0e\xd5\x51\xbd\x0b\x3f\xf5\xe4', b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0'] - > tree eval:b'' - > fields eval:[b'revision'] - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 2 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 292 - ] - ], - b'node': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4' - }, - b'a\x002b4eb07319bfa077a40a2f04913659aef0da42da\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n', - { - b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4', - b'fieldsfollowing': [ - [ - b'delta', - 55 - ] - ], - b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0' - }, - b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n' - ] - -With haveparents=True, first revision is a delta instead of fulltext - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x1b\x17\x5b\x59\x5f\x02\x2c\xfa\xb5\xb8\x09\xcc\x0e\xd5\x51\xbd\x0b\x3f\xf5\xe4', b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0'] - > tree eval:b'' - > fields eval:[b'revision'] - > haveparents eval:True - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 2 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 292 - ] - ], - b'node': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4' - }, - b'a\x002b4eb07319bfa077a40a2f04913659aef0da42da\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n', - { - b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4', - b'fieldsfollowing': [ - [ - b'delta', - 55 - ] - ], - b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0' - }, - b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n' - ] - -Revisions are sorted by DAG order, parents first - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0', b'\x1b\x17\x5b\x59\x5f\x02\x2c\xfa\xb5\xb8\x09\xcc\x0e\xd5\x51\xbd\x0b\x3f\xf5\xe4'] - > tree eval:b'' - > fields eval:[b'revision'] - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 2 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 292 - ] - ], - b'node': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4' - }, - b'a\x002b4eb07319bfa077a40a2f04913659aef0da42da\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n', - { - b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4', - b'fieldsfollowing': [ - [ - b'delta', - 55 - ] - ], - b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0' - }, - b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n' - ] - -Requesting parents and revision data works - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x1b\x17\x5b\x59\x5f\x02\x2c\xfa\xb5\xb8\x09\xcc\x0e\xd5\x51\xbd\x0b\x3f\xf5\xe4', b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0'] - > tree eval:b'' - > fields eval:[b'parents', b'revision'] - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 2 - }, - { - b'fieldsfollowing': [ - [ - b'revision', - 292 - ] - ], - b'node': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - }, - b'a\x002b4eb07319bfa077a40a2f04913659aef0da42da\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n', - { - b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4', - b'fieldsfollowing': [ - [ - b'delta', - 55 - ] - ], - b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0', - b'parents': [ - b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - }, - b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n' - ] - - $ cat error.log diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-command-pushkey.t --- a/tests/test-wireproto-command-pushkey.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ - $ . $TESTDIR/wireprotohelpers.sh - - $ hg init server - $ enablehttpv2 server - $ cd server - $ cat >> .hg/hgrc << EOF - > [web] - > push_ssl = false - > allow-push = * - > EOF - $ hg debugdrawdag << EOF - > C D - > |/ - > B - > | - > A - > EOF - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -pushkey for a bookmark works - - $ sendhttpv2peer << EOF - > command pushkey - > namespace bookmarks - > key @ - > old - > new 426bada5c67598ca65036d57d9e4b64b0c1ce7a0 - > EOF - creating http peer for wire protocol version 2 - sending pushkey command - response: True - - $ sendhttpv2peer << EOF - > command listkeys - > namespace bookmarks - > EOF - creating http peer for wire protocol version 2 - sending listkeys command - response: { - b'@': b'426bada5c67598ca65036d57d9e4b64b0c1ce7a0' - } - - $ cat error.log diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-command-rawstorefiledata.t --- a/tests/test-wireproto-command-rawstorefiledata.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ - $ . $TESTDIR/wireprotohelpers.sh - $ hg init server - $ enablehttpv2 server - $ cd server - $ echo a0 > a - $ echo b0 > b - $ hg -q commit -A -m 'commit 0' - $ echo a1 > a - $ hg commit -m 'commit 1' - $ mkdir dir0 - $ mkdir dir1 - $ echo c0 > dir0/c - $ echo d0 > dir0/d - $ echo e0 > dir1/e - $ echo f0 > dir1/f - $ hg commit -A -m 'commit 2' - adding dir0/c - adding dir0/d - adding dir1/e - adding dir1/f - $ echo f1 > dir1/f - $ hg commit -m 'commit 3' - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - -Missing requirement argument results in error - - $ sendhttpv2peer << EOF - > command rawstorefiledata - > EOF - creating http peer for wire protocol version 2 - sending rawstorefiledata command - abort: missing required arguments: files - [255] - -Unknown files value results in error - - $ sendhttpv2peer << EOF - > command rawstorefiledata - > files eval:[b'unknown'] - > EOF - creating http peer for wire protocol version 2 - sending rawstorefiledata command - abort: unknown file type: unknown - [255] - -Requesting just changelog works - - $ sendhttpv2peer << EOF - > command rawstorefiledata - > files eval:[b'changelog'] - > EOF - creating http peer for wire protocol version 2 - sending rawstorefiledata command - response: gen[ - { - b'filecount': 1, - b'totalsize': 527 (no-zstd !) - b'totalsize': 530 (zstd !) - }, - { - b'location': b'store', - b'path': b'00changelog.i', - b'size': 527 (no-zstd !) - b'size': 530 (zstd !) - }, - b'\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00?\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u992f4779029a3df8d0666d00bb924f69634e2641\ntest\n0 0\na\nb\n\ncommit 0\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00>\x00\x00\x00=\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xffD2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ua988fb43583e871d1ed5750ee074c6d840bbbfc8\ntest\n0 0\na\n\ncommit 1\x00\x00\x00\x00\x00~\x00\x00\x00\x00\x00N\x00\x00\x00W\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xa4r\xd2\xea\x96U\x1a\x1e\xbb\x011-\xb2\xe6\xa7\x86\xd0F\x96o\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x9c%\xc5\xc1\t\xc0 \x0c\x05\xd0{\xa6p\x03cjI\xd71\xf9\x11\x00\x00\x00=\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xffD2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ua988fb43583e871d1ed5750ee074c6d840bbbfc8\ntest\n0 0\na\n\ncommit 1\x00\x00\x00\x00\x00~\x00\x00\x00\x00\x00Q\x00\x00\x00W\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xa4r\xd2\xea\x96U\x1a\x1e\xbb\x011-\xb2\xe6\xa7\x86\xd0F\x96o\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xb5/\xfd WE\x02\x00r\x04\x0f\x14\x90\x01\x0e#\xf7h$;NQC%\xf8f\xd7\xb1\x81\x8d+\x01\x16+)5\xa8\x19\xdaA\xae\xe3\x00\xe9v\xe2l\x05v\x19\x11\xd4\xc1onK\xa2\x17c\xb4\xf3\xe7 z\x13\x8f\x1c\xf3j4\x03\x03\x00`\x06\x84\x8b\x1a\n\x14\x00\x00\x00\x00\x00\xcf\x00\x00\x00\x00\x00C\x00\x00\x00B\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x85kg{\x94a\x12i\xc5lW5[\x85\xf9\x95|\xfc\xc1\xb9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u90231ddca36fa178a0eed99bd03078112487dda3\ntest\n0 0\ndir1/f\n\ncommit 3', (zstd !) - b'' - ] - -Requesting just manifestlog works (as impractical as that operation may be). - - $ sendhttpv2peer << EOF - > command rawstorefiledata - > files eval:[b'manifestlog'] - > EOF - creating http peer for wire protocol version 2 - sending rawstorefiledata command - response: gen[ - { - b'filecount': 1, - b'totalsize': 584 (no-zstd !) - b'totalsize': 588 (zstd !) - }, - { - b'location': b'store', - b'path': b'00manifest.i', - b'size': 584 (no-zstd !) - b'size': 588 (zstd !) - }, - b'\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00I\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x9c\r\xca\xc1\x11\x00!\x08\x040\xdfV\x03+\xa2\x94\xb3\x8c\xd0\x7f\twy\x87\x03i\x95r\x96F6\xe5\x1c\x9a\x10-\x16\xba|\x07\xab\xe5\xd1\xf08s\\\x8d\xc2\xbeo)w\xa9\x8b;\xa2\xff\x95\x19\x02jB\xab\x0c\xea\xf3\x03\xcf\x1d\x16\t\x00\x00\x00\x00\x00I\x00\x00\x00\x00\x007\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xff\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x009a38122997b3ac97be2a9aa2e556838341fdf2cc\n\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x8c\x00\x00\x01\x16\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xbcL\xdb}\x10{\xe2w\xaa\xdb"rC\xdf\xb3\xe0M\xd5,\x81\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x9c%\xcd\xb9\rB1\x10\x00Q\xc7\xbf\x19\xf6\xb6\xdd\x08\xb9\xf7\x92H\xa9\x90\xd2\xb8\x82\xc9\x9e4c\x8c\xfb\xf8\xf7\xca\xc7\x13n16\x8a\x88\xb2\xd8\x818`\xb4=eF\xb9f\x17\xcc\x92\x94hR\xc0\xeb\xe7s(/\x02\xcb\xd8\x13K\tU m\t\x1f\xef\xb2D\x03\xa6\xb6\x14\xb2\xaf\xc7[\rw?\x16`\xce\xd0"\x9c,\xddK\xd0c/\rIX4\xc3\xbc\xe4\xef{ u\xcc\x8c\x9c\x93]\x0f\x9cM;\n\xb7\x12-X\x1c\x96\x9fuT\xc8\xf5\x06\x88\xa25W\x00\x00\x00\x00\x01\x0c\x00\x00\x00\x00\x00<\x00\x00\x01\x16\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x90#\x1d\xdc\xa3o\xa1x\xa0\xee\xd9\x9b\xd00x\x11$\x87\xdd\xa3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x00\x00\x01\x16\x00\x00\x000dir1/f\x0028c776ae08d0d55eb40648b401b90ff54448348e\n', (no-zstd !) - b'\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00H\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xb5/\xfd V\xfd\x01\x00b\xc5\x0e\x0f\xc0\xd1\x00\xfb\x0c\xb9\xca\xdf\xb2R\xba!\xf2\xf6\x1d\x80\xd5\x95Yc\xef9DaT\xcefcM\xf1\x12\t\x84\xf3\x1a\x04\x04N\\\'S\xf2\'\x8cz5\xc5\x9f\xfa\x18\xf3\x82W\x1a\x83Y\xe8\xf0\x00\x00\x00\x00\x00\x00H\x00\x00\x00\x00\x007\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xff\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x009a38122997b3ac97be2a9aa2e556838341fdf2cc\n\x00\x00\x00\x00\x00\x7f\x00\x00\x00\x00\x00\x91\x00\x00\x01\x16\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xbcL\xdb}\x10{\xe2w\xaa\xdb"rC\xdf\xb3\xe0M\xd5,\x81\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xb5/\xfd \xccE\x04\x00bK\x1e\x17\xb0A0\xff\xff\x9b\xb5V\x99\x99\xfa\xb6\xae\xf5n),"\xf1\n\x02\xb5\x07\x82++\xd1]T\x1b3\xaa\x8e\x10+)R\xa6\\\x9a\x10\xab+\xb4\x8bB\x9f\x13U\xd4\x98\xbd\xde \x9a\xf4\xd1}[\xfb{,q\x14Kf\x06\x1e\x10\xd6\x17\xbbl\x90\x16\xb9\xb3\xd8\x07\xee\xfc\xa8\x8eI\x10]\x9c\x1ava\x054W\xad\xdf\xb3\x18\xee\xbdd\x15\xdf$\x85St\n\xde\xee?\x91\xa0\x83\x11\x08\xd8\x01\x80\x10B\x04\x00\x04S\x04B\xc7Tw\x9f\xb9,\x00\x00\x00\x00\x01\x10\x00\x00\x00\x00\x00<\x00\x00\x01\x16\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x90#\x1d\xdc\xa3o\xa1x\xa0\xee\xd9\x9b\xd00x\x11$\x87\xdd\xa3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x00\x00\x01\x16\x00\x00\x000dir1/f\x0028c776ae08d0d55eb40648b401b90ff54448348e\n', (zstd !) - b'' - ] - -Requesting both changelog and manifestlog works. - - $ sendhttpv2peer << EOF - > command rawstorefiledata - > files eval:[b'changelog', b'manifestlog'] - > EOF - creating http peer for wire protocol version 2 - sending rawstorefiledata command - response: gen[ - { - b'filecount': 2, - b'totalsize': 1111 (no-zstd !) - b'totalsize': 1118 (zstd !) - }, - { - b'location': b'store', - b'path': b'00manifest.i', - b'size': 584 (no-zstd !) - b'size': 588 (zstd !) - }, - b'\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00I\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x9c\r\xca\xc1\x11\x00!\x08\x040\xdfV\x03+\xa2\x94\xb3\x8c\xd0\x7f\twy\x87\x03i\x95r\x96F6\xe5\x1c\x9a\x10-\x16\xba|\x07\xab\xe5\xd1\xf08s\\\x8d\xc2\xbeo)w\xa9\x8b;\xa2\xff\x95\x19\x02jB\xab\x0c\xea\xf3\x03\xcf\x1d\x16\t\x00\x00\x00\x00\x00I\x00\x00\x00\x00\x007\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xff\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x009a38122997b3ac97be2a9aa2e556838341fdf2cc\n\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x8c\x00\x00\x01\x16\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xbcL\xdb}\x10{\xe2w\xaa\xdb"rC\xdf\xb3\xe0M\xd5,\x81\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x9c%\xcd\xb9\rB1\x10\x00Q\xc7\xbf\x19\xf6\xb6\xdd\x08\xb9\xf7\x92H\xa9\x90\xd2\xb8\x82\xc9\x9e4c\x8c\xfb\xf8\xf7\xca\xc7\x13n16\x8a\x88\xb2\xd8\x818`\xb4=eF\xb9f\x17\xcc\x92\x94hR\xc0\xeb\xe7s(/\x02\xcb\xd8\x13K\tU m\t\x1f\xef\xb2D\x03\xa6\xb6\x14\xb2\xaf\xc7[\rw?\x16`\xce\xd0"\x9c,\xddK\xd0c/\rIX4\xc3\xbc\xe4\xef{ u\xcc\x8c\x9c\x93]\x0f\x9cM;\n\xb7\x12-X\x1c\x96\x9fuT\xc8\xf5\x06\x88\xa25W\x00\x00\x00\x00\x01\x0c\x00\x00\x00\x00\x00<\x00\x00\x01\x16\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x90#\x1d\xdc\xa3o\xa1x\xa0\xee\xd9\x9b\xd00x\x11$\x87\xdd\xa3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x00\x00\x01\x16\x00\x00\x000dir1/f\x0028c776ae08d0d55eb40648b401b90ff54448348e\n', (no-zstd !) - b'\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00H\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xb5/\xfd V\xfd\x01\x00b\xc5\x0e\x0f\xc0\xd1\x00\xfb\x0c\xb9\xca\xdf\xb2R\xba!\xf2\xf6\x1d\x80\xd5\x95Yc\xef9DaT\xcefcM\xf1\x12\t\x84\xf3\x1a\x04\x04N\\\'S\xf2\'\x8cz5\xc5\x9f\xfa\x18\xf3\x82W\x1a\x83Y\xe8\xf0\x00\x00\x00\x00\x00\x00H\x00\x00\x00\x00\x007\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xff\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x009a38122997b3ac97be2a9aa2e556838341fdf2cc\n\x00\x00\x00\x00\x00\x7f\x00\x00\x00\x00\x00\x91\x00\x00\x01\x16\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xbcL\xdb}\x10{\xe2w\xaa\xdb"rC\xdf\xb3\xe0M\xd5,\x81\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xb5/\xfd \xccE\x04\x00bK\x1e\x17\xb0A0\xff\xff\x9b\xb5V\x99\x99\xfa\xb6\xae\xf5n),"\xf1\n\x02\xb5\x07\x82++\xd1]T\x1b3\xaa\x8e\x10+)R\xa6\\\x9a\x10\xab+\xb4\x8bB\x9f\x13U\xd4\x98\xbd\xde \x9a\xf4\xd1}[\xfb{,q\x14Kf\x06\x1e\x10\xd6\x17\xbbl\x90\x16\xb9\xb3\xd8\x07\xee\xfc\xa8\x8eI\x10]\x9c\x1ava\x054W\xad\xdf\xb3\x18\xee\xbdd\x15\xdf$\x85St\n\xde\xee?\x91\xa0\x83\x11\x08\xd8\x01\x80\x10B\x04\x00\x04S\x04B\xc7Tw\x9f\xb9,\x00\x00\x00\x00\x01\x10\x00\x00\x00\x00\x00<\x00\x00\x01\x16\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x90#\x1d\xdc\xa3o\xa1x\xa0\xee\xd9\x9b\xd00x\x11$\x87\xdd\xa3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x00\x00\x01\x16\x00\x00\x000dir1/f\x0028c776ae08d0d55eb40648b401b90ff54448348e\n', (zstd !) - b'', - { - b'location': b'store', - b'path': b'00changelog.i', - b'size': 527 (no-zstd !) - b'size': 530 (zstd !) - }, - b'\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00?\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u992f4779029a3df8d0666d00bb924f69634e2641\ntest\n0 0\na\nb\n\ncommit 0\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00>\x00\x00\x00=\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xffD2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ua988fb43583e871d1ed5750ee074c6d840bbbfc8\ntest\n0 0\na\n\ncommit 1\x00\x00\x00\x00\x00~\x00\x00\x00\x00\x00N\x00\x00\x00W\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xa4r\xd2\xea\x96U\x1a\x1e\xbb\x011-\xb2\xe6\xa7\x86\xd0F\x96o\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x9c%\xc5\xc1\t\xc0 \x0c\x05\xd0{\xa6p\x03cjI\xd71\xf9\x11\x00\x00\x00=\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xffD2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ua988fb43583e871d1ed5750ee074c6d840bbbfc8\ntest\n0 0\na\n\ncommit 1\x00\x00\x00\x00\x00~\x00\x00\x00\x00\x00Q\x00\x00\x00W\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xa4r\xd2\xea\x96U\x1a\x1e\xbb\x011-\xb2\xe6\xa7\x86\xd0F\x96o\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xb5/\xfd WE\x02\x00r\x04\x0f\x14\x90\x01\x0e#\xf7h$;NQC%\xf8f\xd7\xb1\x81\x8d+\x01\x16+)5\xa8\x19\xdaA\xae\xe3\x00\xe9v\xe2l\x05v\x19\x11\xd4\xc1onK\xa2\x17c\xb4\xf3\xe7 z\x13\x8f\x1c\xf3j4\x03\x03\x00`\x06\x84\x8b\x1a\n\x14\x00\x00\x00\x00\x00\xcf\x00\x00\x00\x00\x00C\x00\x00\x00B\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x85kg{\x94a\x12i\xc5lW5[\x85\xf9\x95|\xfc\xc1\xb9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u90231ddca36fa178a0eed99bd03078112487dda3\ntest\n0 0\ndir1/f\n\ncommit 3', (zstd !) - b'' - ] - - $ cat error.log diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-content-redirects.t --- a/tests/test-wireproto-content-redirects.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1475 +0,0 @@ - $ . $TESTDIR/wireprotohelpers.sh - -persistent-nodemap is not enabled by default. It is not relevant for this test so disable it. - - $ cat >> $HGRCPATH << EOF - > [format] - > use-persistent-nodemap = no - > [extensions] - > blackbox = - > [blackbox] - > track = simplecache - > EOF - - $ hg init server - $ enablehttpv2 server - $ cd server - $ cat >> .hg/hgrc << EOF - > [server] - > compressionengines = zlib - > [extensions] - > simplecache = $TESTDIR/wireprotosimplecache.py - > [simplecache] - > cacheapi = true - > EOF - - $ echo a0 > a - $ echo b0 > b - $ hg -q commit -A -m 'commit 0' - $ echo a1 > a - $ hg commit -m 'commit 1' - - $ hg --debug debugindex -m - rev linkrev nodeid p1 p2 - 0 0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 - 1 1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 - - $ hg --config simplecache.redirectsfile=redirects.py serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - - $ cat > redirects.py << EOF - > [ - > { - > b'name': b'target-a', - > b'protocol': b'http', - > b'snirequired': False, - > b'tlsversions': [b'1.2', b'1.3'], - > b'uris': [b'http://example.com/'], - > }, - > ] - > EOF - -Redirect targets advertised when configured - - $ sendhttpv2peerhandshake << EOF - > command capabilities - > EOF - creating http peer for wire protocol version 2 - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> vary: X-HgProto-1,X-HgUpgrade-1\r\n - s> x-hgproto-1: cbor\r\n - s> x-hgupgrade-1: exp-http-v2-0003\r\n - s> accept: application/mercurial-0.1\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-cbor\r\n - s> Content-Length: 2289\r\n - s> \r\n - s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/Nv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - (remote redirect target target-a is compatible) (tls1.2 !) - (remote redirect target target-a requires unsupported TLS versions: 1.2, 1.3) (no-tls1.2 !) - sending capabilities command - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: application/mercurial-exp-framing-0006\r\n - s> content-length: 111\r\n (tls1.2 !) - s> content-length: 102\r\n (no-tls1.2 !) - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81HidentityC\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a (tls1.2 !) - s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80 (no-tls1.2 !) - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0006\r\n - s> Transfer-Encoding: chunked\r\n - s> \r\n - s> 11\r\n - s> \t\x00\x00\x01\x00\x02\x01\x92 - s> Hidentity - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x01\x00\x02\x041 - s> \xa1FstatusBok - s> \r\n - s> 6de\r\n - s> \xd6\x06\x00\x01\x00\x02\x041 - s> \xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/ - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x01\x00\x02\x002 - s> \r\n - s> 0\r\n - s> \r\n - response: gen[ - { - b'commands': { - b'branchmap': { - b'args': {}, - b'permissions': [ - b'pull' - ] - }, - b'capabilities': { - b'args': {}, - b'permissions': [ - b'pull' - ] - }, - b'changesetdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'bookmarks', - b'parents', - b'phase', - b'revision' - ]) - }, - b'revisions': { - b'required': True, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'filedata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'linknode', - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'nodes': { - b'required': True, - b'type': b'list' - }, - b'path': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'filesdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'firstchangeset', - b'linknode', - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'pathfilter': { - b'default': None, - b'required': False, - b'type': b'dict' - }, - b'revisions': { - b'required': True, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ], - b'recommendedbatchsize': 50000 - }, - b'heads': { - b'args': { - b'publiconly': { - b'default': False, - b'required': False, - b'type': b'bool' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'known': { - b'args': { - b'nodes': { - b'default': [], - b'required': False, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'listkeys': { - b'args': { - b'namespace': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'lookup': { - b'args': { - b'key': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'manifestdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'nodes': { - b'required': True, - b'type': b'list' - }, - b'tree': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ], - b'recommendedbatchsize': 100000 - }, - b'pushkey': { - b'args': { - b'key': { - b'required': True, - b'type': b'bytes' - }, - b'namespace': { - b'required': True, - b'type': b'bytes' - }, - b'new': { - b'required': True, - b'type': b'bytes' - }, - b'old': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'push' - ] - }, - b'rawstorefiledata': { - b'args': { - b'files': { - b'required': True, - b'type': b'list' - }, - b'pathfilter': { - b'default': None, - b'required': False, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - } - }, - b'framingmediatypes': [ - b'application/mercurial-exp-framing-0006' - ], - b'pathfilterprefixes': set([ - b'path:', - b'rootfilesin:' - ]), - b'rawrepoformats': [ - b'generaldelta', - b'revlogv1', - b'sparserevlog' - ], - b'redirect': { - b'hashes': [ - b'sha256', - b'sha1' - ], - b'targets': [ - { - b'name': b'target-a', - b'protocol': b'http', - b'snirequired': False, - b'tlsversions': [ - b'1.2', - b'1.3' - ], - b'uris': [ - b'http://example.com/' - ] - } - ] - } - } - ] - (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob) - -Unknown protocol is filtered from compatible targets - - $ cat > redirects.py << EOF - > [ - > { - > b'name': b'target-a', - > b'protocol': b'http', - > b'uris': [b'http://example.com/'], - > }, - > { - > b'name': b'target-b', - > b'protocol': b'unknown', - > b'uris': [b'unknown://example.com/'], - > }, - > ] - > EOF - - $ sendhttpv2peerhandshake << EOF - > command capabilities - > EOF - creating http peer for wire protocol version 2 - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> vary: X-HgProto-1,X-HgUpgrade-1\r\n - s> x-hgproto-1: cbor\r\n - s> x-hgupgrade-1: exp-http-v2-0003\r\n - s> accept: application/mercurial-0.1\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-cbor\r\n - s> Content-Length: 2316\r\n - s> \r\n - s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/Nv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - (remote redirect target target-a is compatible) - (remote redirect target target-b uses unsupported protocol: unknown) - sending capabilities command - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: application/mercurial-exp-framing-0006\r\n - s> content-length: 111\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81HidentityC\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0006\r\n - s> Transfer-Encoding: chunked\r\n - s> \r\n - s> 11\r\n - s> \t\x00\x00\x01\x00\x02\x01\x92 - s> Hidentity - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x01\x00\x02\x041 - s> \xa1FstatusBok - s> \r\n - s> 6f9\r\n - s> \xf1\x06\x00\x01\x00\x02\x041 - s> \xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/ - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x01\x00\x02\x002 - s> \r\n - s> 0\r\n - s> \r\n - response: gen[ - { - b'commands': { - b'branchmap': { - b'args': {}, - b'permissions': [ - b'pull' - ] - }, - b'capabilities': { - b'args': {}, - b'permissions': [ - b'pull' - ] - }, - b'changesetdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'bookmarks', - b'parents', - b'phase', - b'revision' - ]) - }, - b'revisions': { - b'required': True, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'filedata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'linknode', - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'nodes': { - b'required': True, - b'type': b'list' - }, - b'path': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'filesdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'firstchangeset', - b'linknode', - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'pathfilter': { - b'default': None, - b'required': False, - b'type': b'dict' - }, - b'revisions': { - b'required': True, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ], - b'recommendedbatchsize': 50000 - }, - b'heads': { - b'args': { - b'publiconly': { - b'default': False, - b'required': False, - b'type': b'bool' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'known': { - b'args': { - b'nodes': { - b'default': [], - b'required': False, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'listkeys': { - b'args': { - b'namespace': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'lookup': { - b'args': { - b'key': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'manifestdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'nodes': { - b'required': True, - b'type': b'list' - }, - b'tree': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ], - b'recommendedbatchsize': 100000 - }, - b'pushkey': { - b'args': { - b'key': { - b'required': True, - b'type': b'bytes' - }, - b'namespace': { - b'required': True, - b'type': b'bytes' - }, - b'new': { - b'required': True, - b'type': b'bytes' - }, - b'old': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'push' - ] - }, - b'rawstorefiledata': { - b'args': { - b'files': { - b'required': True, - b'type': b'list' - }, - b'pathfilter': { - b'default': None, - b'required': False, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - } - }, - b'framingmediatypes': [ - b'application/mercurial-exp-framing-0006' - ], - b'pathfilterprefixes': set([ - b'path:', - b'rootfilesin:' - ]), - b'rawrepoformats': [ - b'generaldelta', - b'revlogv1', - b'sparserevlog' - ], - b'redirect': { - b'hashes': [ - b'sha256', - b'sha1' - ], - b'targets': [ - { - b'name': b'target-a', - b'protocol': b'http', - b'uris': [ - b'http://example.com/' - ] - }, - { - b'name': b'target-b', - b'protocol': b'unknown', - b'uris': [ - b'unknown://example.com/' - ] - } - ] - } - } - ] - (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob) - -Missing SNI support filters targets that require SNI - - $ cat > nosni.py << EOF - > from mercurial import sslutil - > sslutil.hassni = False - > EOF - $ cat >> $HGRCPATH << EOF - > [extensions] - > nosni=`pwd`/nosni.py - > EOF - - $ cat > redirects.py << EOF - > [ - > { - > b'name': b'target-bad-tls', - > b'protocol': b'https', - > b'uris': [b'https://example.com/'], - > b'snirequired': True, - > }, - > ] - > EOF - - $ sendhttpv2peerhandshake << EOF - > command capabilities - > EOF - creating http peer for wire protocol version 2 - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> vary: X-HgProto-1,X-HgUpgrade-1\r\n - s> x-hgproto-1: cbor\r\n - s> x-hgupgrade-1: exp-http-v2-0003\r\n - s> accept: application/mercurial-0.1\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-cbor\r\n - s> Content-Length: 2276\r\n - s> \r\n - s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - (redirect target target-bad-tls requires SNI, which is unsupported) - sending capabilities command - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: application/mercurial-exp-framing-0006\r\n - s> content-length: 102\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80 - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0006\r\n - s> Transfer-Encoding: chunked\r\n - s> \r\n - s> 11\r\n - s> \t\x00\x00\x01\x00\x02\x01\x92 - s> Hidentity - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x01\x00\x02\x041 - s> \xa1FstatusBok - s> \r\n - s> 6d1\r\n - s> \xc9\x06\x00\x01\x00\x02\x041 - s> \xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/ - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x01\x00\x02\x002 - s> \r\n - s> 0\r\n - s> \r\n - response: gen[ - { - b'commands': { - b'branchmap': { - b'args': {}, - b'permissions': [ - b'pull' - ] - }, - b'capabilities': { - b'args': {}, - b'permissions': [ - b'pull' - ] - }, - b'changesetdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'bookmarks', - b'parents', - b'phase', - b'revision' - ]) - }, - b'revisions': { - b'required': True, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'filedata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'linknode', - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'nodes': { - b'required': True, - b'type': b'list' - }, - b'path': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'filesdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'firstchangeset', - b'linknode', - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'pathfilter': { - b'default': None, - b'required': False, - b'type': b'dict' - }, - b'revisions': { - b'required': True, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ], - b'recommendedbatchsize': 50000 - }, - b'heads': { - b'args': { - b'publiconly': { - b'default': False, - b'required': False, - b'type': b'bool' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'known': { - b'args': { - b'nodes': { - b'default': [], - b'required': False, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'listkeys': { - b'args': { - b'namespace': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'lookup': { - b'args': { - b'key': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'manifestdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'nodes': { - b'required': True, - b'type': b'list' - }, - b'tree': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ], - b'recommendedbatchsize': 100000 - }, - b'pushkey': { - b'args': { - b'key': { - b'required': True, - b'type': b'bytes' - }, - b'namespace': { - b'required': True, - b'type': b'bytes' - }, - b'new': { - b'required': True, - b'type': b'bytes' - }, - b'old': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'push' - ] - }, - b'rawstorefiledata': { - b'args': { - b'files': { - b'required': True, - b'type': b'list' - }, - b'pathfilter': { - b'default': None, - b'required': False, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - } - }, - b'framingmediatypes': [ - b'application/mercurial-exp-framing-0006' - ], - b'pathfilterprefixes': set([ - b'path:', - b'rootfilesin:' - ]), - b'rawrepoformats': [ - b'generaldelta', - b'revlogv1', - b'sparserevlog' - ], - b'redirect': { - b'hashes': [ - b'sha256', - b'sha1' - ], - b'targets': [ - { - b'name': b'target-bad-tls', - b'protocol': b'https', - b'snirequired': True, - b'uris': [ - b'https://example.com/' - ] - } - ] - } - } - ] - (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ cat >> $HGRCPATH << EOF - > [extensions] - > nosni=! - > EOF - -Unknown tls value is filtered from compatible targets - - $ cat > redirects.py << EOF - > [ - > { - > b'name': b'target-bad-tls', - > b'protocol': b'https', - > b'uris': [b'https://example.com/'], - > b'tlsversions': [b'42', b'39'], - > }, - > ] - > EOF - - $ sendhttpv2peerhandshake << EOF - > command capabilities - > EOF - creating http peer for wire protocol version 2 - s> setsockopt(6, 1, 1) -> None (?) - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> vary: X-HgProto-1,X-HgUpgrade-1\r\n - s> x-hgproto-1: cbor\r\n - s> x-hgupgrade-1: exp-http-v2-0003\r\n - s> accept: application/mercurial-0.1\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-cbor\r\n - s> Content-Length: 2282\r\n - s> \r\n - s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash - (remote redirect target target-bad-tls requires unsupported TLS versions: 39, 42) - sending capabilities command - s> setsockopt(6, 1, 1) -> None (?) - s> POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0006\r\n - s> content-type: application/mercurial-exp-framing-0006\r\n - s> content-length: 102\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80 - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0006\r\n - s> Transfer-Encoding: chunked\r\n - s> \r\n - s> 11\r\n - s> \t\x00\x00\x01\x00\x02\x01\x92 - s> Hidentity - s> \r\n - s> 13\r\n - s> \x0b\x00\x00\x01\x00\x02\x041 - s> \xa1FstatusBok - s> \r\n - s> 6d7\r\n - s> \xcf\x06\x00\x01\x00\x02\x041 - s> \xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/ - s> \r\n - s> 8\r\n - s> \x00\x00\x00\x01\x00\x02\x002 - s> \r\n - s> 0\r\n - s> \r\n - response: gen[ - { - b'commands': { - b'branchmap': { - b'args': {}, - b'permissions': [ - b'pull' - ] - }, - b'capabilities': { - b'args': {}, - b'permissions': [ - b'pull' - ] - }, - b'changesetdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'bookmarks', - b'parents', - b'phase', - b'revision' - ]) - }, - b'revisions': { - b'required': True, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'filedata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'linknode', - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'nodes': { - b'required': True, - b'type': b'list' - }, - b'path': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'filesdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'firstchangeset', - b'linknode', - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'pathfilter': { - b'default': None, - b'required': False, - b'type': b'dict' - }, - b'revisions': { - b'required': True, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ], - b'recommendedbatchsize': 50000 - }, - b'heads': { - b'args': { - b'publiconly': { - b'default': False, - b'required': False, - b'type': b'bool' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'known': { - b'args': { - b'nodes': { - b'default': [], - b'required': False, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'listkeys': { - b'args': { - b'namespace': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'lookup': { - b'args': { - b'key': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ] - }, - b'manifestdata': { - b'args': { - b'fields': { - b'default': set([]), - b'required': False, - b'type': b'set', - b'validvalues': set([ - b'parents', - b'revision' - ]) - }, - b'haveparents': { - b'default': False, - b'required': False, - b'type': b'bool' - }, - b'nodes': { - b'required': True, - b'type': b'list' - }, - b'tree': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'pull' - ], - b'recommendedbatchsize': 100000 - }, - b'pushkey': { - b'args': { - b'key': { - b'required': True, - b'type': b'bytes' - }, - b'namespace': { - b'required': True, - b'type': b'bytes' - }, - b'new': { - b'required': True, - b'type': b'bytes' - }, - b'old': { - b'required': True, - b'type': b'bytes' - } - }, - b'permissions': [ - b'push' - ] - }, - b'rawstorefiledata': { - b'args': { - b'files': { - b'required': True, - b'type': b'list' - }, - b'pathfilter': { - b'default': None, - b'required': False, - b'type': b'list' - } - }, - b'permissions': [ - b'pull' - ] - } - }, - b'framingmediatypes': [ - b'application/mercurial-exp-framing-0006' - ], - b'pathfilterprefixes': set([ - b'path:', - b'rootfilesin:' - ]), - b'rawrepoformats': [ - b'generaldelta', - b'revlogv1', - b'sparserevlog' - ], - b'redirect': { - b'hashes': [ - b'sha256', - b'sha1' - ], - b'targets': [ - { - b'name': b'target-bad-tls', - b'protocol': b'https', - b'tlsversions': [ - b'42', - b'39' - ], - b'uris': [ - b'https://example.com/' - ] - } - ] - } - } - ] - (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob) - -Set up the server to issue content redirects to its built-in API server. - - $ cat > redirects.py << EOF - > [ - > { - > b'name': b'local', - > b'protocol': b'http', - > b'uris': [b'http://example.com/'], - > }, - > ] - > EOF - -Request to eventual cache URL should return 404 (validating the cache server works) - - $ sendhttpraw << EOF - > httprequest GET api/simplecache/missingkey - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /api/simplecache/missingkey HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 404 Not Found\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: text/plain\r\n - s> Content-Length: 22\r\n - s> \r\n - s> key not found in cache - -Send a cacheable request - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41'] - > tree eval:b'' - > fields eval:[b'parents'] - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - } - ] - -Cached entry should be available on server - - $ sendhttpraw << EOF - > httprequest GET api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c - > user-agent: test - > EOF - using raw connection to peer - s> setsockopt(6, 1, 1) -> None (?) - s> GET /api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-cbor\r\n - s> Content-Length: 91\r\n - s> \r\n - s> \xa1Jtotalitems\x01\xa2DnodeT\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&AGparents\x82T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 - cbor> [ - { - b'totalitems': 1 - }, - { - b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - } - ] - -2nd request should result in content redirect response - - $ sendhttpv2peer << EOF - > command manifestdata - > nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41'] - > tree eval:b'' - > fields eval:[b'parents'] - > EOF - creating http peer for wire protocol version 2 - sending manifestdata command - response: gen[ - { - b'totalitems': 1 - }, - { - b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - b'parents': [ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - ] - } - ] - - $ cat error.log - $ killdaemons.py - - $ cat .hg/blackbox.log - *> cacher constructed for manifestdata (glob) - *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob) - *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob) - *> cacher constructed for manifestdata (glob) - *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob) - *> sending content redirect for 47abb8efa5f01b8964d74917793ad2464db0fa2c to http://*:$HGPORT/api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c (glob) diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-exchangev2-shallow.t --- a/tests/test-wireproto-exchangev2-shallow.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,597 +0,0 @@ -#require sqlite - -Tests for wire protocol version 2 exchange. -Tests in this file should be folded into existing tests once protocol -v2 has enough features that it can be enabled via #testcase in existing -tests. - - $ . $TESTDIR/wireprotohelpers.sh - $ enablehttpv2client - $ cat >> $HGRCPATH << EOF - > [extensions] - > sqlitestore = - > pullext = $TESTDIR/pullext.py - > [storage] - > new-repo-backend=sqlite - > EOF - -Configure a server - - $ hg init server-basic - $ enablehttpv2 server-basic - $ cd server-basic - $ mkdir dir0 dir1 - $ echo a0 > a - $ echo b0 > b - $ hg -q commit -A -m 'commit 0' - $ echo c0 > dir0/c - $ echo d0 > dir0/d - $ hg -q commit -A -m 'commit 1' - $ echo e0 > dir1/e - $ echo f0 > dir1/f - $ hg -q commit -A -m 'commit 2' - $ echo c1 > dir0/c - $ echo e1 > dir1/e - $ hg commit -m 'commit 3' - $ echo c2 > dir0/c - $ echo e2 > dir1/e - $ echo f1 > dir1/f - $ hg commit -m 'commit 4' - $ echo a1 > a - $ echo b1 > b - $ hg commit -m 'commit 5' - - $ hg log -G -T '{node} {desc}' - @ 93a8bd067ed2840d9aa810ad598168383a3a2c3a commit 5 - | - o dc666cf9ecf3d94e6b830f30e5f1272e2a9164d9 commit 4 - | - o 97765fc3cd624fd1fa0176932c21ffd16adf432e commit 3 - | - o 47fe012ab237a8c7fc0c78f9f26d5866eef3f825 commit 2 - | - o b709380892b193c1091d3a817f706052e346821b commit 1 - | - o 3390ef850073fbc2f0dfff2244342c8e9229013a commit 0 - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - - $ cd .. - -Shallow clone pulls down latest revision of every file - - $ hg --debug clone --depth 1 http://localhost:$HGPORT client-shallow-1 - using http://localhost:$HGPORT/ - sending capabilities command - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [] - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\x93\xa8\xbd\x06~\xd2\x84\r\x9a\xa8\x10\xadY\x81h8::,:' - ], - 'roots': [], - 'type': 'changesetdagrange' - } - ] - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1170; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset 3390ef850073 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset b709380892b1 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset 47fe012ab237 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset 97765fc3cd62 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset dc666cf9ecf3 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset 93a8bd067ed2 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - checking for updated bookmarks - sending 1 commands - sending command manifestdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'nodes': [ - '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - '|2 \x1a\xa3\xa1R\xa9\xe6\xa9"+?\xa8\xd0\xe3\x0f\xc2V\xe8', - '\x8d\xd0W<\x7f\xaf\xe2\x04F\xcc\xea\xac\x05N\xea\xa4x\x91M\xdb', - '113\x85\xf2!\x8b\x08^\xb2Z\x821\x1e*\xdd\x0e\xeb\x8c3', - 'H]O\xc2`\xef\\\xb9\xc0p6\x88K\x00k\x11\x0ej\xdby', - '\xd9;\xc4\x0b\x0e*GMp\xee\xf7}^\x91/f\x7fSd\x83' - ], - 'tree': '' - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1515; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - sending 1 commands - sending command filesdata: { - 'fields': set([ - 'linknode', - 'parents', - 'revision' - ]), - 'haveparents': False, - 'revisions': [ - { - 'nodes': [ - '\x93\xa8\xbd\x06~\xd2\x84\r\x9a\xa8\x10\xadY\x81h8::,:' - ], - 'type': 'changesetexplicit' - } - ] - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1005; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - updating the branch cache - new changesets 3390ef850073:93a8bd067ed2 - updating to branch default - resolving manifests - branchmerge: False, force: False, partial: False - ancestor: 000000000000, local: 000000000000+, remote: 93a8bd067ed2 - a: remote created -> g - getting a - b: remote created -> g - getting b - dir0/c: remote created -> g - getting dir0/c - dir0/d: remote created -> g - getting dir0/d - dir1/e: remote created -> g - getting dir1/e - dir1/f: remote created -> g - getting dir1/f - 6 files updated, 0 files merged, 0 files removed, 0 files unresolved - updating the branch cache - (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob) - -#if chg - $ hg --kill-chg-daemon - $ sleep 2 -#endif - $ sqlite3 -line client-shallow-1/.hg/store/db.sqlite << EOF - > SELECT id, path, revnum, node, p1rev, p2rev, linkrev, flags FROM filedata ORDER BY id ASC; - > EOF - id = 1 - path = a - revnum = 0 - node = \x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xcc (esc) - p1rev = -1 - p2rev = -1 - linkrev = 5 - flags = 2 - - id = 2 - path = b - revnum = 0 - node = \xb1zk\xd3g=\x9a\xb8\xce\xd5\x81\xa2 \xf6/=\xa5\xccEx (esc) - p1rev = -1 - p2rev = -1 - linkrev = 5 - flags = 2 - - id = 3 - path = dir0/c - revnum = 0 - node = I\x1d\xa1\xbb\x89\xeax\xc0\xc0\xa2s[\x16\xce}\x93\x1d\xc8\xe2\r (esc) - p1rev = -1 - p2rev = -1 - linkrev = 5 - flags = 2 - - id = 4 - path = dir0/d - revnum = 0 - node = S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4& (esc) - p1rev = -1 - p2rev = -1 - linkrev = 5 - flags = 0 - - id = 5 - path = dir1/e - revnum = 0 - node = ]\xf3\xac\xd8\xd0\xc7\xfaP\x98\xd0'\x9a\x044\xc3\x02\x9e+x\xe1 (esc) - p1rev = -1 - p2rev = -1 - linkrev = 5 - flags = 2 - - id = 6 - path = dir1/f - revnum = 0 - node = (\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e (esc) - p1rev = -1 - p2rev = -1 - linkrev = 5 - flags = 2 - -Test a shallow clone with only some files - - $ hg --debug clone --depth 1 --include dir0/ http://localhost:$HGPORT client-shallow-narrow-1 - using http://localhost:$HGPORT/ - sending capabilities command - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [] - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\x93\xa8\xbd\x06~\xd2\x84\r\x9a\xa8\x10\xadY\x81h8::,:' - ], - 'roots': [], - 'type': 'changesetdagrange' - } - ] - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1170; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset 3390ef850073 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset b709380892b1 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset 47fe012ab237 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset 97765fc3cd62 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset dc666cf9ecf3 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset 93a8bd067ed2 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - checking for updated bookmarks - sending 1 commands - sending command manifestdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'nodes': [ - '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - '|2 \x1a\xa3\xa1R\xa9\xe6\xa9"+?\xa8\xd0\xe3\x0f\xc2V\xe8', - '\x8d\xd0W<\x7f\xaf\xe2\x04F\xcc\xea\xac\x05N\xea\xa4x\x91M\xdb', - '113\x85\xf2!\x8b\x08^\xb2Z\x821\x1e*\xdd\x0e\xeb\x8c3', - 'H]O\xc2`\xef\\\xb9\xc0p6\x88K\x00k\x11\x0ej\xdby', - '\xd9;\xc4\x0b\x0e*GMp\xee\xf7}^\x91/f\x7fSd\x83' - ], - 'tree': '' - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1515; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - sending 1 commands - sending command filesdata: { - 'fields': set([ - 'linknode', - 'parents', - 'revision' - ]), - 'haveparents': False, - 'pathfilter': { - 'include': [ - 'path:dir0' - ] - }, - 'revisions': [ - { - 'nodes': [ - '\x93\xa8\xbd\x06~\xd2\x84\r\x9a\xa8\x10\xadY\x81h8::,:' - ], - 'type': 'changesetexplicit' - } - ] - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=355; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - updating the branch cache - new changesets 3390ef850073:93a8bd067ed2 - updating to branch default - resolving manifests - branchmerge: False, force: False, partial: False - ancestor: 000000000000, local: 000000000000+, remote: 93a8bd067ed2 - dir0/c: remote created -> g - getting dir0/c - dir0/d: remote created -> g - getting dir0/d - 2 files updated, 0 files merged, 0 files removed, 0 files unresolved - updating the branch cache - (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob) - -#if chg - $ hg --kill-chg-daemon - $ sleep 2 -#endif - $ sqlite3 -line client-shallow-narrow-1/.hg/store/db.sqlite << EOF - > SELECT id, path, revnum, node, p1rev, p2rev, linkrev, flags FROM filedata ORDER BY id ASC; - > EOF - id = 1 - path = dir0/c - revnum = 0 - node = I\x1d\xa1\xbb\x89\xeax\xc0\xc0\xa2s[\x16\xce}\x93\x1d\xc8\xe2\r (esc) - p1rev = -1 - p2rev = -1 - linkrev = 5 - flags = 2 - - id = 2 - path = dir0/d - revnum = 0 - node = S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4& (esc) - p1rev = -1 - p2rev = -1 - linkrev = 5 - flags = 0 - -Cloning an old revision with depth=1 works - - $ hg --debug clone --depth 1 -r 97765fc3cd624fd1fa0176932c21ffd16adf432e http://localhost:$HGPORT client-shallow-2 - using http://localhost:$HGPORT/ - sending capabilities command - sending 1 commands - sending command lookup: { - 'key': '97765fc3cd624fd1fa0176932c21ffd16adf432e' - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=21; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [] - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'roots': [], - 'type': 'changesetdagrange' - } - ] - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=783; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset 3390ef850073 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset b709380892b1 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset 47fe012ab237 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset 97765fc3cd62 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - checking for updated bookmarks - sending 1 commands - sending command manifestdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'nodes': [ - '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - '|2 \x1a\xa3\xa1R\xa9\xe6\xa9"+?\xa8\xd0\xe3\x0f\xc2V\xe8', - '\x8d\xd0W<\x7f\xaf\xe2\x04F\xcc\xea\xac\x05N\xea\xa4x\x91M\xdb', - '113\x85\xf2!\x8b\x08^\xb2Z\x821\x1e*\xdd\x0e\xeb\x8c3' - ], - 'tree': '' - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=967; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - sending 1 commands - sending command filesdata: { - 'fields': set([ - 'linknode', - 'parents', - 'revision' - ]), - 'haveparents': False, - 'revisions': [ - { - 'nodes': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'type': 'changesetexplicit' - } - ] - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1005; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - updating the branch cache - new changesets 3390ef850073:97765fc3cd62 - updating to branch default - resolving manifests - branchmerge: False, force: False, partial: False - ancestor: 000000000000, local: 000000000000+, remote: 97765fc3cd62 - a: remote created -> g - getting a - b: remote created -> g - getting b - dir0/c: remote created -> g - getting dir0/c - dir0/d: remote created -> g - getting dir0/d - dir1/e: remote created -> g - getting dir1/e - dir1/f: remote created -> g - getting dir1/f - 6 files updated, 0 files merged, 0 files removed, 0 files unresolved - updating the branch cache - (sent 6 HTTP requests and * bytes; received * bytes in responses) (glob) - -Incremental pull of shallow clone fetches new changesets - - $ hg --cwd client-shallow-2 --debug pull http://localhost:$HGPORT - pulling from http://localhost:$HGPORT/ - using http://localhost:$HGPORT/ - sending capabilities command - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ] - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=2; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - searching for changes - all local changesets known remotely - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\x93\xa8\xbd\x06~\xd2\x84\r\x9a\xa8\x10\xadY\x81h8::,:' - ], - 'roots': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'type': 'changesetdagrange' - } - ] - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=400; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset dc666cf9ecf3 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - add changeset 93a8bd067ed2 - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?) - checking for updated bookmarks - sending 1 commands - sending command manifestdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'nodes': [ - 'H]O\xc2`\xef\\\xb9\xc0p6\x88K\x00k\x11\x0ej\xdby', - '\xd9;\xc4\x0b\x0e*GMp\xee\xf7}^\x91/f\x7fSd\x83' - ], - 'tree': '' - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=561; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - sending 1 commands - sending command filesdata: { - 'fields': set([ - 'linknode', - 'parents', - 'revision' - ]), - 'haveparents': False, - 'revisions': [ - { - 'nodes': [ - '\xdcfl\xf9\xec\xf3\xd9Nk\x83\x0f0\xe5\xf1\'.*\x91d\xd9', - '\x93\xa8\xbd\x06~\xd2\x84\r\x9a\xa8\x10\xadY\x81h8::,:' - ], - 'type': 'changesetexplicit' - } - ] - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1373; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - updating the branch cache - new changesets dc666cf9ecf3:93a8bd067ed2 - (run 'hg update' to get a working copy) - (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ hg --cwd client-shallow-2 up tip - merging dir0/c - merging dir1/e - 3 files updated, 2 files merged, 0 files removed, 0 files unresolved diff -r d6c53b40b078 -r 04688c51f81f tests/test-wireproto-exchangev2.t --- a/tests/test-wireproto-exchangev2.t Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1392 +0,0 @@ -Tests for wire protocol version 2 exchange. -Tests in this file should be folded into existing tests once protocol -v2 has enough features that it can be enabled via #testcase in existing -tests. - - $ . $TESTDIR/wireprotohelpers.sh - $ enablehttpv2client - - $ hg init server-simple - $ enablehttpv2 server-simple - $ cd server-simple - $ cat >> .hg/hgrc << EOF - > [phases] - > publish = false - > EOF - $ echo a0 > a - $ echo b0 > b - $ hg -q commit -A -m 'commit 0' - - $ echo a1 > a - $ hg commit -m 'commit 1' - $ hg phase --public -r . - $ echo a2 > a - $ hg commit -m 'commit 2' - - $ hg -q up -r 0 - $ echo b1 > b - $ hg -q commit -m 'head 2 commit 1' - $ echo b2 > b - $ hg -q commit -m 'head 2 commit 2' - - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - - $ cd .. - -Test basic clone - -Output is flaky, save it in a file and check part independently - $ hg --debug clone -U http://localhost:$HGPORT client-simple > clone-output - - $ cat clone-output | grep -v "received frame" - using http://localhost:$HGPORT/ - sending capabilities command - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [] - } - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1', - '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f' - ], - 'roots': [], - 'type': 'changesetdagrange' - } - ] - } - add changeset 3390ef850073 - add changeset 4432d83626e8 - add changeset cd2534766bec - add changeset e96ae20f4188 - add changeset caa2a465451d - checking for updated bookmarks - sending 1 commands - sending command manifestdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'nodes': [ - '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - '\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8', - '\xec\x80NH\x8c \x88\xc25\t\x9a\x10 u\x13\xbe\xcd\xc3\xdd\xa5', - '\x04\\\x7f9\'\xda\x13\xe7Z\xf8\xf0\xe4\xf0HI\xe4a\xa9x\x0f', - '7\x9c\xb0\xc2\xe6d\\y\xdd\xc5\x9a\x1dG\'\xa9\xfb\x83\n\xeb&' - ], - 'tree': '' - } - sending 1 commands - sending command filesdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'revisions': [ - { - 'nodes': [ - '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:', - 'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0', - '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f', - '\xe9j\xe2\x0fA\x88H{\x9a\xe4\xef9A\xc2|\x81\x141F\xe5', - '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1' - ], - 'type': 'changesetexplicit' - } - ] - } - updating the branch cache - new changesets 3390ef850073:caa2a465451d (3 drafts) - updating the branch cache - (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ cat clone-output | grep "received frame" - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=43; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=941; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=992; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=901; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - - $ rm clone-output - -All changesets should have been transferred - - $ hg -R client-simple debugindex -c - rev linkrev nodeid p1 p2 - 0 0 3390ef850073 000000000000 000000000000 - 1 1 4432d83626e8 3390ef850073 000000000000 - 2 2 cd2534766bec 4432d83626e8 000000000000 - 3 3 e96ae20f4188 3390ef850073 000000000000 - 4 4 caa2a465451d e96ae20f4188 000000000000 - - $ hg -R client-simple log -G -T '{rev} {node} {phase}\n' - o 4 caa2a465451dd1facda0f5b12312c355584188a1 draft - | - o 3 e96ae20f4188487b9ae4ef3941c27c81143146e5 draft - | - | o 2 cd2534766bece138c7c1afdc6825302f0f62d81f draft - | | - | o 1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public - |/ - o 0 3390ef850073fbc2f0dfff2244342c8e9229013a public - - -All manifests should have been transferred - - $ hg -R client-simple debugindex -m - rev linkrev nodeid p1 p2 - 0 0 992f4779029a 000000000000 000000000000 - 1 1 a988fb43583e 992f4779029a 000000000000 - 2 2 ec804e488c20 a988fb43583e 000000000000 - 3 3 045c7f3927da 992f4779029a 000000000000 - 4 4 379cb0c2e664 045c7f3927da 000000000000 - -Cloning only a specific revision works - -Output is flaky, save it in a file and check part independently - $ hg --debug clone -U -r 4432d83626e8 http://localhost:$HGPORT client-singlehead > clone-output - - $ cat clone-output | grep -v "received frame" - using http://localhost:$HGPORT/ - sending capabilities command - sending 1 commands - sending command lookup: { - 'key': '4432d83626e8' - } - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [] - } - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - 'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0' - ], - 'roots': [], - 'type': 'changesetdagrange' - } - ] - } - add changeset 3390ef850073 - add changeset 4432d83626e8 - checking for updated bookmarks - sending 1 commands - sending command manifestdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'nodes': [ - '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - '\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8' - ], - 'tree': '' - } - sending 1 commands - sending command filesdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'revisions': [ - { - 'nodes': [ - '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:', - 'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0' - ], - 'type': 'changesetexplicit' - } - ] - } - updating the branch cache - new changesets 3390ef850073:4432d83626e8 - updating the branch cache - (sent 6 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ cat clone-output | grep "received frame" - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=21; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=43; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=381; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=404; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=439; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - - $ rm clone-output - - $ cd client-singlehead - - $ hg log -G -T '{rev} {node} {phase}\n' - o 1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public - | - o 0 3390ef850073fbc2f0dfff2244342c8e9229013a public - - - $ hg debugindex -m - rev linkrev nodeid p1 p2 - 0 0 992f4779029a 000000000000 000000000000 - 1 1 a988fb43583e 992f4779029a 000000000000 - -Incremental pull works - -Output is flaky, save it in a file and check part independently - $ hg --debug pull > pull-output - - $ cat pull-output | grep -v "received frame" - pulling from http://localhost:$HGPORT/ - using http://localhost:$HGPORT/ - sending capabilities command - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [ - 'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0' - ] - } - searching for changes - all local changesets known remotely - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1', - '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f' - ], - 'roots': [ - 'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0' - ], - 'type': 'changesetdagrange' - } - ] - } - add changeset cd2534766bec - add changeset e96ae20f4188 - add changeset caa2a465451d - checking for updated bookmarks - sending 1 commands - sending command manifestdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'nodes': [ - '\xec\x80NH\x8c \x88\xc25\t\x9a\x10 u\x13\xbe\xcd\xc3\xdd\xa5', - '\x04\\\x7f9\'\xda\x13\xe7Z\xf8\xf0\xe4\xf0HI\xe4a\xa9x\x0f', - '7\x9c\xb0\xc2\xe6d\\y\xdd\xc5\x9a\x1dG\'\xa9\xfb\x83\n\xeb&' - ], - 'tree': '' - } - sending 1 commands - sending command filesdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'revisions': [ - { - 'nodes': [ - '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f', - '\xe9j\xe2\x0fA\x88H{\x9a\xe4\xef9A\xc2|\x81\x141F\xe5', - '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1' - ], - 'type': 'changesetexplicit' - } - ] - } - updating the branch cache - new changesets cd2534766bec:caa2a465451d (3 drafts) - (run 'hg update' to get a working copy) - (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ cat pull-output | grep "received frame" - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=43; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=2; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=573; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=601; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=527; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - - $ rm pull-output - - $ hg log -G -T '{rev} {node} {phase}\n' - o 4 caa2a465451dd1facda0f5b12312c355584188a1 draft - | - o 3 e96ae20f4188487b9ae4ef3941c27c81143146e5 draft - | - | o 2 cd2534766bece138c7c1afdc6825302f0f62d81f draft - | | - | o 1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public - |/ - o 0 3390ef850073fbc2f0dfff2244342c8e9229013a public - - - $ hg debugindex -m - rev linkrev nodeid p1 p2 - 0 0 992f4779029a 000000000000 000000000000 - 1 1 a988fb43583e 992f4779029a 000000000000 - 2 2 ec804e488c20 a988fb43583e 000000000000 - 3 3 045c7f3927da 992f4779029a 000000000000 - 4 4 379cb0c2e664 045c7f3927da 000000000000 - -Phase-only update works -TODO this doesn't work - - $ hg -R ../server-simple phase --public -r caa2a465451dd - $ hg --debug pull - pulling from http://localhost:$HGPORT/ - using http://localhost:$HGPORT/ - sending capabilities command - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [ - '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f', - '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1' - ] - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=43; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=3; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - searching for changes - all remote heads known locally - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1', - '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f' - ], - 'roots': [ - '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1', - '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f' - ], - 'type': 'changesetdagrange' - } - ] - } - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=13; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - checking for updated bookmarks - (run 'hg update' to get a working copy) - (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ hg log -G -T '{rev} {node} {phase}\n' - o 4 caa2a465451dd1facda0f5b12312c355584188a1 draft - | - o 3 e96ae20f4188487b9ae4ef3941c27c81143146e5 draft - | - | o 2 cd2534766bece138c7c1afdc6825302f0f62d81f draft - | | - | o 1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public - |/ - o 0 3390ef850073fbc2f0dfff2244342c8e9229013a public - - - $ cd .. - -Bookmarks are transferred on clone - - $ hg -R server-simple bookmark -r 3390ef850073fbc2f0dfff2244342c8e9229013a book-1 - $ hg -R server-simple bookmark -r cd2534766bece138c7c1afdc6825302f0f62d81f book-2 - -Output is flaky, save it in a file and check part independently - $ hg --debug clone -U http://localhost:$HGPORT/ client-bookmarks > clone-output - - $ cat clone-output | grep -v "received frame" - using http://localhost:$HGPORT/ - sending capabilities command - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [] - } - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1', - '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f' - ], - 'roots': [], - 'type': 'changesetdagrange' - } - ] - } - add changeset 3390ef850073 - add changeset 4432d83626e8 - add changeset cd2534766bec - add changeset e96ae20f4188 - add changeset caa2a465451d - checking for updated bookmarks - adding remote bookmark book-1 - adding remote bookmark book-2 - sending 1 commands - sending command manifestdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'nodes': [ - '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - '\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8', - '\xec\x80NH\x8c \x88\xc25\t\x9a\x10 u\x13\xbe\xcd\xc3\xdd\xa5', - '\x04\\\x7f9\'\xda\x13\xe7Z\xf8\xf0\xe4\xf0HI\xe4a\xa9x\x0f', - '7\x9c\xb0\xc2\xe6d\\y\xdd\xc5\x9a\x1dG\'\xa9\xfb\x83\n\xeb&' - ], - 'tree': '' - } - sending 1 commands - sending command filesdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'revisions': [ - { - 'nodes': [ - '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:', - 'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0', - '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f', - '\xe9j\xe2\x0fA\x88H{\x9a\xe4\xef9A\xc2|\x81\x141F\xe5', - '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1' - ], - 'type': 'changesetexplicit' - } - ] - } - updating the branch cache - new changesets 3390ef850073:caa2a465451d (1 drafts) - updating the branch cache - (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ cat clone-output | grep "received frame" - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=43; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=979; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=992; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=901; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - - $ rm clone-output - - $ hg -R client-bookmarks bookmarks - book-1 0:3390ef850073 - book-2 2:cd2534766bec - -Server-side bookmark moves are reflected during `hg pull` - - $ hg -R server-simple bookmark -r cd2534766bece138c7c1afdc6825302f0f62d81f book-1 - moving bookmark 'book-1' forward from 3390ef850073 - -Output is flaky, save it in a file and check part independently - $ hg -R client-bookmarks --debug pull > pull-output - - $ cat pull-output | grep -v "received frame" - pulling from http://localhost:$HGPORT/ - using http://localhost:$HGPORT/ - sending capabilities command - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [ - '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f', - '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1' - ] - } - searching for changes - all remote heads known locally - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1', - '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f' - ], - 'roots': [ - '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1', - '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f' - ], - 'type': 'changesetdagrange' - } - ] - } - checking for updated bookmarks - updating bookmark book-1 - (run 'hg update' to get a working copy) - (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ cat pull-output | grep "received frame" - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=43; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=3; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=65; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - - $ rm pull-output - - $ hg -R client-bookmarks bookmarks - book-1 2:cd2534766bec - book-2 2:cd2534766bec - - $ killdaemons.py - -Let's set up a slightly more complicated server - - $ hg init server-2 - $ enablehttpv2 server-2 - $ cd server-2 - $ mkdir dir0 dir1 - $ echo a0 > a - $ echo b0 > b - $ hg -q commit -A -m 'commit 0' - $ echo c0 > dir0/c - $ echo d0 > dir0/d - $ hg -q commit -A -m 'commit 1' - $ echo e0 > dir1/e - $ echo f0 > dir1/f - $ hg -q commit -A -m 'commit 2' - $ echo c1 > dir0/c - $ echo e1 > dir1/e - $ hg commit -m 'commit 3' - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - - $ cd .. - -Narrow clone only fetches some files - -Output is flaky, save it in a file and check part independently - $ hg --config extensions.pullext=$TESTDIR/pullext.py --debug clone -U --include dir0/ http://localhost:$HGPORT/ client-narrow-0 > clone-output - - $ cat clone-output | grep -v "received frame" - using http://localhost:$HGPORT/ - sending capabilities command - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [] - } - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'roots': [], - 'type': 'changesetdagrange' - } - ] - } - add changeset 3390ef850073 - add changeset b709380892b1 - add changeset 47fe012ab237 - add changeset 97765fc3cd62 - checking for updated bookmarks - sending 1 commands - sending command manifestdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'nodes': [ - '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - '|2 \x1a\xa3\xa1R\xa9\xe6\xa9"+?\xa8\xd0\xe3\x0f\xc2V\xe8', - '\x8d\xd0W<\x7f\xaf\xe2\x04F\xcc\xea\xac\x05N\xea\xa4x\x91M\xdb', - '113\x85\xf2!\x8b\x08^\xb2Z\x821\x1e*\xdd\x0e\xeb\x8c3' - ], - 'tree': '' - } - sending 1 commands - sending command filesdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'pathfilter': { - 'include': [ - 'path:dir0' - ] - }, - 'revisions': [ - { - 'nodes': [ - '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:', - '\xb7\t8\x08\x92\xb1\x93\xc1\t\x1d:\x81\x7fp`R\xe3F\x82\x1b', - 'G\xfe\x01*\xb27\xa8\xc7\xfc\x0cx\xf9\xf2mXf\xee\xf3\xf8%', - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'type': 'changesetexplicit' - } - ] - } - updating the branch cache - new changesets 3390ef850073:97765fc3cd62 - updating the branch cache - (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ cat clone-output | grep "received frame" - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=783; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=967; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=449; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - - $ rm clone-output - -#if reporevlogstore - $ find client-narrow-0/.hg/store -type f -name '*.i' | sort - client-narrow-0/.hg/store/00changelog.i - client-narrow-0/.hg/store/00manifest.i - client-narrow-0/.hg/store/data/dir0/c.i - client-narrow-0/.hg/store/data/dir0/d.i -#endif - ---exclude by itself works - -Output is flaky, save it in a file and check part independently - $ hg --config extensions.pullext=$TESTDIR/pullext.py --debug clone -U --exclude dir0/ http://localhost:$HGPORT/ client-narrow-1 > clone-output - - $ cat clone-output | grep -v "received frame" - using http://localhost:$HGPORT/ - sending capabilities command - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [] - } - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'roots': [], - 'type': 'changesetdagrange' - } - ] - } - add changeset 3390ef850073 - add changeset b709380892b1 - add changeset 47fe012ab237 - add changeset 97765fc3cd62 - checking for updated bookmarks - sending 1 commands - sending command manifestdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'nodes': [ - '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - '|2 \x1a\xa3\xa1R\xa9\xe6\xa9"+?\xa8\xd0\xe3\x0f\xc2V\xe8', - '\x8d\xd0W<\x7f\xaf\xe2\x04F\xcc\xea\xac\x05N\xea\xa4x\x91M\xdb', - '113\x85\xf2!\x8b\x08^\xb2Z\x821\x1e*\xdd\x0e\xeb\x8c3' - ], - 'tree': '' - } - sending 1 commands - sending command filesdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'pathfilter': { - 'exclude': [ - 'path:dir0' - ], - 'include': [ - 'path:.' - ] - }, - 'revisions': [ - { - 'nodes': [ - '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:', - '\xb7\t8\x08\x92\xb1\x93\xc1\t\x1d:\x81\x7fp`R\xe3F\x82\x1b', - 'G\xfe\x01*\xb27\xa8\xc7\xfc\x0cx\xf9\xf2mXf\xee\xf3\xf8%', - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'type': 'changesetexplicit' - } - ] - } - updating the branch cache - new changesets 3390ef850073:97765fc3cd62 - updating the branch cache - (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ cat clone-output | grep "received frame" - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=783; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=967; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=709; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - - $ rm clone-output - -#if reporevlogstore - $ find client-narrow-1/.hg/store -type f -name '*.i' | sort - client-narrow-1/.hg/store/00changelog.i - client-narrow-1/.hg/store/00manifest.i - client-narrow-1/.hg/store/data/a.i - client-narrow-1/.hg/store/data/b.i - client-narrow-1/.hg/store/data/dir1/e.i - client-narrow-1/.hg/store/data/dir1/f.i -#endif - -Mixing --include and --exclude works - -Output is flaky, save it in a file and check part independently - $ hg --config extensions.pullext=$TESTDIR/pullext.py --debug clone -U --include dir0/ --exclude dir0/c http://localhost:$HGPORT/ client-narrow-2 > clone-output - - $ cat clone-output | grep -v "received frame" - using http://localhost:$HGPORT/ - sending capabilities command - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [] - } - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'roots': [], - 'type': 'changesetdagrange' - } - ] - } - add changeset 3390ef850073 - add changeset b709380892b1 - add changeset 47fe012ab237 - add changeset 97765fc3cd62 - checking for updated bookmarks - sending 1 commands - sending command manifestdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'nodes': [ - '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - '|2 \x1a\xa3\xa1R\xa9\xe6\xa9"+?\xa8\xd0\xe3\x0f\xc2V\xe8', - '\x8d\xd0W<\x7f\xaf\xe2\x04F\xcc\xea\xac\x05N\xea\xa4x\x91M\xdb', - '113\x85\xf2!\x8b\x08^\xb2Z\x821\x1e*\xdd\x0e\xeb\x8c3' - ], - 'tree': '' - } - sending 1 commands - sending command filesdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'pathfilter': { - 'exclude': [ - 'path:dir0/c' - ], - 'include': [ - 'path:dir0' - ] - }, - 'revisions': [ - { - 'nodes': [ - '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:', - '\xb7\t8\x08\x92\xb1\x93\xc1\t\x1d:\x81\x7fp`R\xe3F\x82\x1b', - 'G\xfe\x01*\xb27\xa8\xc7\xfc\x0cx\xf9\xf2mXf\xee\xf3\xf8%', - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'type': 'changesetexplicit' - } - ] - } - updating the branch cache - new changesets 3390ef850073:97765fc3cd62 - updating the branch cache - (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ cat clone-output | grep "received frame" - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=783; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=967; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=160; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - - $ rm clone-output - -#if reporevlogstore - $ find client-narrow-2/.hg/store -type f -name '*.i' | sort - client-narrow-2/.hg/store/00changelog.i - client-narrow-2/.hg/store/00manifest.i - client-narrow-2/.hg/store/data/dir0/d.i -#endif - ---stream will use rawfiledata to transfer changelog and manifestlog, then -fall through to get files data - -Output is flaky, save it in a file and check part independently - $ hg --debug clone --stream -U http://localhost:$HGPORT client-stream-0 > clone-output - - $ cat clone-output | grep -v "received frame" - using http://localhost:$HGPORT/ - sending capabilities command - sending 1 commands - sending command rawstorefiledata: { - 'files': [ - 'changelog', - 'manifestlog' - ] - } - updating the branch cache - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ] - } - searching for changes - all remote heads known locally - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'roots': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'type': 'changesetdagrange' - } - ] - } - checking for updated bookmarks - sending 1 commands - sending command filesdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'revisions': [ - { - 'nodes': [ - '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:', - '\xb7\t8\x08\x92\xb1\x93\xc1\t\x1d:\x81\x7fp`R\xe3F\x82\x1b', - 'G\xfe\x01*\xb27\xa8\xc7\xfc\x0cx\xf9\xf2mXf\xee\xf3\xf8%', - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'type': 'changesetexplicit' - } - ] - } - updating the branch cache - (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ cat clone-output | grep "received frame" - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1275; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) (no-zstd !) - received frame(size=1283; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) (zstd !) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=2; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=13; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1133; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - - $ rm clone-output - ---stream + --include/--exclude will only obtain some files - -Output is flaky, save it in a file and check part independently - $ hg --debug --config extensions.pullext=$TESTDIR/pullext.py clone --stream --include dir0/ -U http://localhost:$HGPORT client-stream-2 > clone-output - - $ cat clone-output | grep -v "received frame" - using http://localhost:$HGPORT/ - sending capabilities command - sending 1 commands - sending command rawstorefiledata: { - 'files': [ - 'changelog', - 'manifestlog' - ] - } - updating the branch cache - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ] - } - searching for changes - all remote heads known locally - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'roots': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'type': 'changesetdagrange' - } - ] - } - checking for updated bookmarks - sending 1 commands - sending command filesdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'pathfilter': { - 'include': [ - 'path:dir0' - ] - }, - 'revisions': [ - { - 'nodes': [ - '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:', - '\xb7\t8\x08\x92\xb1\x93\xc1\t\x1d:\x81\x7fp`R\xe3F\x82\x1b', - 'G\xfe\x01*\xb27\xa8\xc7\xfc\x0cx\xf9\xf2mXf\xee\xf3\xf8%', - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'type': 'changesetexplicit' - } - ] - } - updating the branch cache - (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ cat clone-output | grep "received frame" - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1275; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) (no-zstd !) - received frame(size=1283; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) (zstd !) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=2; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=13; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=449; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - - $ rm clone-output - -#if reporevlogstore - $ find client-stream-2/.hg/store -type f -name '*.i' | sort - client-stream-2/.hg/store/00changelog.i - client-stream-2/.hg/store/00manifest.i - client-stream-2/.hg/store/data/dir0/c.i - client-stream-2/.hg/store/data/dir0/d.i -#endif - -Shallow clone doesn't work with revlogs - -Output is flaky, save it in a file and check part independently - $ hg --debug --config extensions.pullext=$TESTDIR/pullext.py clone --depth 1 -U http://localhost:$HGPORT client-shallow-revlogs > clone-output - transaction abort! - rollback completed - abort: revlog storage does not support missing parents write mode - [255] - - $ cat clone-output | grep -v "received frame" - using http://localhost:$HGPORT/ - sending capabilities command - query 1; heads - sending 2 commands - sending command heads: {} - sending command known: { - 'nodes': [] - } - sending 1 commands - sending command changesetdata: { - 'fields': set([ - 'bookmarks', - 'parents', - 'phase', - 'revision' - ]), - 'revisions': [ - { - 'heads': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'roots': [], - 'type': 'changesetdagrange' - } - ] - } - add changeset 3390ef850073 - add changeset b709380892b1 - add changeset 47fe012ab237 - add changeset 97765fc3cd62 - checking for updated bookmarks - sending 1 commands - sending command manifestdata: { - 'fields': set([ - 'parents', - 'revision' - ]), - 'haveparents': True, - 'nodes': [ - '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A', - '|2 \x1a\xa3\xa1R\xa9\xe6\xa9"+?\xa8\xd0\xe3\x0f\xc2V\xe8', - '\x8d\xd0W<\x7f\xaf\xe2\x04F\xcc\xea\xac\x05N\xea\xa4x\x91M\xdb', - '113\x85\xf2!\x8b\x08^\xb2Z\x821\x1e*\xdd\x0e\xeb\x8c3' - ], - 'tree': '' - } - sending 1 commands - sending command filesdata: { - 'fields': set([ - 'linknode', - 'parents', - 'revision' - ]), - 'haveparents': False, - 'revisions': [ - { - 'nodes': [ - '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.' - ], - 'type': 'changesetexplicit' - } - ] - } - (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob) - - $ cat clone-output | grep "received frame" - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=783; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=967; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos) - received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=1005; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) - received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) - - $ rm clone-output - - $ killdaemons.py - -Repo with 2 DAG branches introducing same filenode, to test linknode adjustment - - $ hg init server-linknode - $ enablehttpv2 server-linknode - $ cd server-linknode - $ touch foo - $ hg -q commit -Am initial - $ echo foo > dupe-file - $ hg commit -Am 'dupe 1' - adding dupe-file - $ hg -q up -r 0 - $ echo foo > dupe-file - $ hg commit -Am 'dupe 2' - adding dupe-file - created new head - $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log - $ cat hg.pid > $DAEMON_PIDS - $ cd .. - -Perform an incremental pull of both heads and ensure linkrev is written out properly - - $ hg clone -r 96ee1d7354c4 http://localhost:$HGPORT client-linknode-1 - new changesets 96ee1d7354c4 - updating to branch default - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ cd client-linknode-1 - $ touch extra - $ hg commit -Am extra - adding extra - $ cd .. - - $ hg clone -r 96ee1d7354c4 http://localhost:$HGPORT client-linknode-2 - new changesets 96ee1d7354c4 - updating to branch default - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ cd client-linknode-2 - $ touch extra - $ hg commit -Am extra - adding extra - $ cd .. - - $ hg -R client-linknode-1 pull -r 1681c33f9f80 - pulling from http://localhost:$HGPORT/ - searching for changes - new changesets 1681c33f9f80 - (run 'hg update' to get a working copy) - -#if reporevlogstore - $ hg -R client-linknode-1 debugrevlogindex dupe-file - rev linkrev nodeid p1 p2 - 0 2 2ed2a3912a0b 000000000000 000000000000 -#endif - - $ hg -R client-linknode-2 pull -r 639c8990d6a5 - pulling from http://localhost:$HGPORT/ - searching for changes - new changesets 639c8990d6a5 - (run 'hg update' to get a working copy) - -#if reporevlogstore - $ hg -R client-linknode-2 debugrevlogindex dupe-file - rev linkrev nodeid p1 p2 - 0 2 2ed2a3912a0b 000000000000 000000000000 -#endif diff -r d6c53b40b078 -r 04688c51f81f tests/wireprotohelpers.sh --- a/tests/wireprotohelpers.sh Thu Dec 30 13:25:44 2021 +0100 +++ b/tests/wireprotohelpers.sh Tue Dec 07 16:44:22 2021 +0100 @@ -1,44 +1,23 @@ -HTTPV2=exp-http-v2-0003 MEDIATYPE=application/mercurial-exp-framing-0006 sendhttpraw() { hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT/ } -sendhttpv2peer() { - hg --config experimental.httppeer.v2-encoder-order=identity debugwireproto --nologhandshake --peer http2 http://$LOCALIP:$HGPORT/ -} - -sendhttpv2peerverbose() { - hg --config experimental.httppeer.v2-encoder-order=identity --verbose debugwireproto --nologhandshake --peer http2 http://$LOCALIP:$HGPORT/ -} - -sendhttpv2peerhandshake() { - hg --config experimental.httppeer.v2-encoder-order=identity --verbose debugwireproto --peer http2 http://$LOCALIP:$HGPORT/ -} - cat > dummycommands.py << EOF from mercurial import ( wireprototypes, wireprotov1server, - wireprotov2server, ) @wireprotov1server.wireprotocommand(b'customreadonly', permission=b'pull') def customreadonlyv1(repo, proto): return wireprototypes.bytesresponse(b'customreadonly bytes response') -@wireprotov2server.wireprotocommand(b'customreadonly', permission=b'pull') -def customreadonlyv2(repo, proto): - yield b'customreadonly bytes response' - @wireprotov1server.wireprotocommand(b'customreadwrite', permission=b'push') def customreadwrite(repo, proto): return wireprototypes.bytesresponse(b'customreadwrite bytes response') -@wireprotov2server.wireprotocommand(b'customreadwrite', permission=b'push') -def customreadwritev2(repo, proto): - yield b'customreadwrite bytes response' EOF cat >> $HGRCPATH << EOF @@ -53,20 +32,3 @@ EOF } -enablehttpv2() { - cat >> $1/.hg/hgrc << EOF -[experimental] -web.apiserver = true -web.api.http-v2 = true -EOF -} - -enablehttpv2client() { - cat >> $HGRCPATH << EOF -[experimental] -httppeer.advertise-v2 = true -# So tests are in plain text. Also, zstd isn't available in all installs, -# which would make tests non-deterministic. -httppeer.v2-encoder-order = identity -EOF -} diff -r d6c53b40b078 -r 04688c51f81f tests/wireprotosimplecache.py --- a/tests/wireprotosimplecache.py Thu Dec 30 13:25:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,220 +0,0 @@ -# wireprotosimplecache.py - Extension providing in-memory wire protocol cache -# -# Copyright 2018 Gregory Szorc -# -# 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 ( - extensions, - registrar, - util, - wireprotoserver, - wireprototypes, - wireprotov2server, -) -from mercurial.interfaces import ( - repository, - util as interfaceutil, -) -from mercurial.utils import stringutil - -CACHE = None - -configtable = {} -configitem = registrar.configitem(configtable) - -configitem(b'simplecache', b'cacheapi', default=False) -configitem(b'simplecache', b'cacheobjects', default=False) -configitem(b'simplecache', b'redirectsfile', default=None) - -# API handler that makes cached keys available. -def handlecacherequest(rctx, req, res, checkperm, urlparts): - if rctx.repo.ui.configbool(b'simplecache', b'cacheobjects'): - res.status = b'500 Internal Server Error' - res.setbodybytes(b'cacheobjects not supported for api server') - return - - if not urlparts: - res.status = b'200 OK' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes(b'simple cache server') - return - - key = b'/'.join(urlparts) - - if key not in CACHE: - res.status = b'404 Not Found' - res.headers[b'Content-Type'] = b'text/plain' - res.setbodybytes(b'key not found in cache') - return - - res.status = b'200 OK' - res.headers[b'Content-Type'] = b'application/mercurial-cbor' - res.setbodybytes(CACHE[key]) - - -def cachedescriptor(req, repo): - return {} - - -wireprotoserver.API_HANDLERS[b'simplecache'] = { - b'config': (b'simplecache', b'cacheapi'), - b'handler': handlecacherequest, - b'apidescriptor': cachedescriptor, -} - - -@interfaceutil.implementer(repository.iwireprotocolcommandcacher) -class memorycacher(object): - def __init__( - self, ui, command, encodefn, redirecttargets, redirecthashes, req - ): - self.ui = ui - self.encodefn = encodefn - self.redirecttargets = redirecttargets - self.redirecthashes = redirecthashes - self.req = req - self.key = None - self.cacheobjects = ui.configbool(b'simplecache', b'cacheobjects') - self.cacheapi = ui.configbool(b'simplecache', b'cacheapi') - self.buffered = [] - - ui.log(b'simplecache', b'cacher constructed for %s\n', command) - - def __enter__(self): - return self - - def __exit__(self, exctype, excvalue, exctb): - if exctype: - self.ui.log(b'simplecache', b'cacher exiting due to error\n') - - def adjustcachekeystate(self, state): - # Needed in order to make tests deterministic. Don't copy this - # pattern for production caches! - del state[b'repo'] - - def setcachekey(self, key): - self.key = key - return True - - def lookup(self): - if self.key not in CACHE: - self.ui.log(b'simplecache', b'cache miss for %s\n', self.key) - return None - - entry = CACHE[self.key] - self.ui.log(b'simplecache', b'cache hit for %s\n', self.key) - - redirectable = True - - if not self.cacheapi: - redirectable = False - elif not self.redirecttargets: - redirectable = False - else: - clienttargets = set(self.redirecttargets) - ourtargets = {t[b'name'] for t in loadredirecttargets(self.ui)} - - # We only ever redirect to a single target (for now). So we don't - # need to store which target matched. - if not clienttargets & ourtargets: - redirectable = False - - if redirectable: - paths = self.req.dispatchparts[:-3] - paths.append(b'simplecache') - paths.append(self.key) - - url = b'%s/%s' % (self.req.baseurl, b'/'.join(paths)) - - # url = b'http://example.com/%s' % self.key - self.ui.log( - b'simplecache', - b'sending content redirect for %s to ' b'%s\n', - self.key, - url, - ) - response = wireprototypes.alternatelocationresponse( - url=url, mediatype=b'application/mercurial-cbor' - ) - - return {b'objs': [response]} - - if self.cacheobjects: - return { - b'objs': entry, - } - else: - return { - b'objs': [wireprototypes.encodedresponse(entry)], - } - - def onobject(self, obj): - if self.cacheobjects: - self.buffered.append(obj) - else: - self.buffered.extend(self.encodefn(obj)) - - yield obj - - def onfinished(self): - self.ui.log(b'simplecache', b'storing cache entry for %s\n', self.key) - if self.cacheobjects: - CACHE[self.key] = self.buffered - else: - CACHE[self.key] = b''.join(self.buffered) - - return [] - - -def makeresponsecacher( - orig, - repo, - proto, - command, - args, - objencoderfn, - redirecttargets, - redirecthashes, -): - return memorycacher( - repo.ui, - command, - objencoderfn, - redirecttargets, - redirecthashes, - proto._req, - ) - - -def loadredirecttargets(ui): - path = ui.config(b'simplecache', b'redirectsfile') - if not path: - return [] - - with open(path, 'rb') as fh: - s = fh.read() - - return stringutil.evalpythonliteral(s) - - -def getadvertisedredirecttargets(orig, repo, proto): - return loadredirecttargets(repo.ui) - - -def extsetup(ui): - global CACHE - - CACHE = util.lrucachedict(10000) - - extensions.wrapfunction( - wireprotov2server, b'makeresponsecacher', makeresponsecacher - ) - extensions.wrapfunction( - wireprotov2server, - b'getadvertisedredirecttargets', - getadvertisedredirecttargets, - )