merge with stable
authorGregory Szorc <gregory.szorc@gmail.com>
Sat, 05 May 2018 18:06:45 -0700
changeset 37836 86e7a57449fa
parent 37787 92213f6745ed (current diff)
parent 37835 1f65d7d46545 (diff)
child 37837 e0f30c91dfd8
merge with stable
mercurial/diffhelper.py
mercurial/diffhelpers.py
--- a/.hgsigs	Sun Mar 04 15:29:41 2018 -0500
+++ b/.hgsigs	Sat May 05 18:06:45 2018 -0700
@@ -160,3 +160,7 @@
 d334afc585e29577f271c5eda03378736a16ca6b 0 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
+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
--- a/.hgtags	Sun Mar 04 15:29:41 2018 -0500
+++ b/.hgtags	Sat May 05 18:06:45 2018 -0700
@@ -173,3 +173,7 @@
 d334afc585e29577f271c5eda03378736a16ca6b 4.5
 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
 8bba684efde7f45add05f737952093bb2aa07155 4.5.2
+7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3
+ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0
+1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1
+6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6
--- a/contrib/phabricator.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/contrib/phabricator.py	Sat May 05 18:06:45 2018 -0700
@@ -68,6 +68,7 @@
 )
 from mercurial.utils import (
     procutil,
+    stringutil,
 )
 
 cmdtable = {}
@@ -328,6 +329,19 @@
     }
     callconduit(ctx.repo(), 'differential.setdiffproperty', params)
 
+    params = {
+        'diff_id': diff[r'id'],
+        'name': 'local:commits',
+        'data': json.dumps({
+            ctx.hex(): {
+                'author': stringutil.person(ctx.user()),
+                'authorEmail': stringutil.email(ctx.user()),
+                'time': ctx.date()[0],
+            },
+        }),
+    }
+    callconduit(ctx.repo(), 'differential.setdiffproperty', params)
+
 def createdifferentialrevision(ctx, revid=None, parentrevid=None, oldnode=None,
                                olddiff=None, actions=None):
     """create or update a Differential Revision
--- a/hgext/infinitepush/__init__.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/hgext/infinitepush/__init__.py	Sat May 05 18:06:45 2018 -0700
@@ -1067,7 +1067,7 @@
         bookmarknode = nodesctx[-1].hex() if nodesctx else None
         key = None
         if newheadscount:
-            with open(bundlefile, 'r') as f:
+            with open(bundlefile, 'rb') as f:
                 bundledata = f.read()
                 with logservicecall(log, 'bundlestore',
                                     bundlesize=len(bundledata)):
--- a/hgext/infinitepush/fileindexapi.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/hgext/infinitepush/fileindexapi.py	Sat May 05 18:06:45 2018 -0700
@@ -15,6 +15,8 @@
 
 import os
 
+from mercurial import util
+
 from mercurial.utils import stringutil
 
 from . import indexapi
@@ -82,6 +84,7 @@
         for dirpath, _, books in self._repo.vfs.walk(self._bookmarkmap):
             for book in books:
                 bookmark = os.path.join(dirpath, book)[prefixlen:]
+                bookmark = util.pconvert(bookmark)
                 if not matcher(bookmark):
                     continue
                 yield bookmark, self._read(os.path.join(dirpath, book))
--- a/hgext/infinitepush/store.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/hgext/infinitepush/store.py	Sat May 05 18:06:45 2018 -0700
@@ -79,19 +79,18 @@
         if not os.path.exists(dirpath):
             os.makedirs(dirpath)
 
-        with open(self._filepath(filename), 'w') as f:
+        with open(self._filepath(filename), 'wb') as f:
             f.write(data)
 
         return filename
 
     def read(self, key):
         try:
-            f = open(self._filepath(key), 'r')
+            with open(self._filepath(key), 'rb') as f:
+                return f.read()
         except IOError:
             return None
 
-        return f.read()
-
 class externalbundlestore(abstractbundlestore):
     def __init__(self, put_binary, put_args, get_binary, get_args):
         """
--- a/hgext/notify.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/hgext/notify.py	Sat May 05 18:06:45 2018 -0700
@@ -455,7 +455,7 @@
     changegroup. else send one email per changeset.'''
 
     n = notifier(ui, repo, hooktype)
-    ctx = repo[node]
+    ctx = repo.unfiltered()[node]
 
     if not n.subs:
         ui.debug('notify: no subscribers to repository %s\n' % n.root)
@@ -469,8 +469,7 @@
     count = 0
     author = ''
     if hooktype == 'changegroup' or hooktype == 'outgoing':
-        start, end = ctx.rev(), len(repo)
-        for rev in xrange(start, end):
+        for rev in repo.changelog.revs(start=ctx.rev()):
             if n.node(repo[rev]):
                 count += 1
                 if not author:
@@ -482,7 +481,7 @@
                 ui.pushbuffer()
         if count:
             n.diff(ctx, repo['tip'])
-    else:
+    elif ctx.rev() in repo:
         if not n.node(ctx):
             ui.popbuffer()
             ui.note(_('notify: suppressing notification for merge %d:%s\n') %
--- a/hgext/remotenames.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/hgext/remotenames.py	Sat May 05 18:06:45 2018 -0700
@@ -6,7 +6,7 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-""" showing remotebookmarks and remotebranches in UI
+""" showing remotebookmarks and remotebranches in UI (EXPERIMENTAL)
 
 By default both remotebookmarks and remotebranches are turned on. Config knob to
 control the individually are as follows.
--- a/mercurial/cmdutil.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/cmdutil.py	Sat May 05 18:06:45 2018 -0700
@@ -1537,7 +1537,7 @@
         # --exact with --no-commit is still useful in that it does merge
         # and branch bits
         ui.warn(_("warning: can't check exact import with --no-commit\n"))
-    elif opts.get('exact') and hex(n) != nodeid:
+    elif opts.get('exact') and (not n or hex(n) != nodeid):
         raise error.Abort(_('patch is damaged or loses information'))
     msg = _('applied to working directory')
     if n:
--- a/mercurial/color.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/color.py	Sat May 05 18:06:45 2018 -0700
@@ -90,16 +90,16 @@
     'branches.inactive': 'none',
     'diff.changed': 'white',
     'diff.deleted': 'red',
-    'diff.deleted.changed': 'red',
-    'diff.deleted.unchanged': 'red dim',
+    'diff.deleted.changed': 'red bold underline',
+    'diff.deleted.unchanged': 'red',
     'diff.diffline': 'bold',
     'diff.extended': 'cyan bold',
     'diff.file_a': 'red bold',
     'diff.file_b': 'green bold',
     'diff.hunk': 'magenta',
     'diff.inserted': 'green',
-    'diff.inserted.changed': 'green',
-    'diff.inserted.unchanged': 'green dim',
+    'diff.inserted.changed': 'green bold underline',
+    'diff.inserted.unchanged': 'green',
     'diff.tab': '',
     'diff.trailingwhitespace': 'bold red_background',
     'changeset.public': '',
--- a/mercurial/context.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/context.py	Sat May 05 18:06:45 2018 -0700
@@ -497,8 +497,10 @@
                     changeid = hex(changeid)
             except TypeError:
                 pass
-        except (error.FilteredIndexError, error.FilteredLookupError,
-                error.FilteredRepoLookupError):
+        except (error.FilteredIndexError, error.FilteredLookupError):
+            raise error.FilteredRepoLookupError(_("filtered revision '%s'")
+                                                % changeid)
+        except error.FilteredRepoLookupError:
             raise
         except IndexError:
             pass
--- a/mercurial/debugcommands.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/debugcommands.py	Sat May 05 18:06:45 2018 -0700
@@ -462,6 +462,8 @@
 
 def _debugdisplaystyle(ui):
     ui.write(_('available style:\n'))
+    if not ui._styles:
+        return
     width = max(len(s) for s in ui._styles)
     for label, effects in sorted(ui._styles.items()):
         ui.write('%s' % label, label=label)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/diffhelper.py	Sat May 05 18:06:45 2018 -0700
@@ -0,0 +1,77 @@
+# diffhelper.py - helper routines for patch
+#
+# Copyright 2009 Matt Mackall <mpm@selenic.com> and others
+#
+# 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 .i18n import _
+
+from . import (
+    error,
+)
+
+def addlines(fp, hunk, lena, lenb, a, b):
+    """Read lines from fp into the hunk
+
+    The hunk is parsed into two arrays, a and b. a gets the old state of
+    the text, b gets the new state. The control char from the hunk is saved
+    when inserting into a, but not b (for performance while deleting files.)
+    """
+    while True:
+        todoa = lena - len(a)
+        todob = lenb - len(b)
+        num = max(todoa, todob)
+        if num == 0:
+            break
+        for i in xrange(num):
+            s = fp.readline()
+            if not s:
+                raise error.ParseError(_('incomplete hunk'))
+            if s == "\\ No newline at end of file\n":
+                fixnewline(hunk, a, b)
+                continue
+            if s == '\n' or s == '\r\n':
+                # Some patches may be missing the control char
+                # on empty lines. Supply a leading space.
+                s = ' ' + s
+            hunk.append(s)
+            if s.startswith('+'):
+                b.append(s[1:])
+            elif s.startswith('-'):
+                a.append(s)
+            else:
+                b.append(s[1:])
+                a.append(s)
+
+def fixnewline(hunk, a, b):
+    """Fix up the last lines of a and b when the patch has no newline at EOF"""
+    l = hunk[-1]
+    # tolerate CRLF in last line
+    if l.endswith('\r\n'):
+        hline = l[:-2]
+    else:
+        hline = l[:-1]
+
+    if hline.startswith((' ', '+')):
+        b[-1] = hline[1:]
+    if hline.startswith((' ', '-')):
+        a[-1] = hline
+    hunk[-1] = hline
+
+def testhunk(a, b, bstart):
+    """Compare the lines in a with the lines in b
+
+    a is assumed to have a control char at the start of each line, this char
+    is ignored in the compare.
+    """
+    alen = len(a)
+    blen = len(b)
+    if alen > blen - bstart or bstart < 0:
+        return False
+    for i in xrange(alen):
+        if a[i][1:] != b[i + bstart]:
+            return False
+    return True
--- a/mercurial/diffhelpers.py	Sun Mar 04 15:29:41 2018 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-# diffhelpers.py - helper routines for patch
-#
-# Copyright 2009 Matt Mackall <mpm@selenic.com> and others
-#
-# 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 .i18n import _
-
-from . import (
-    error,
-)
-
-def addlines(fp, hunk, lena, lenb, a, b):
-    """Read lines from fp into the hunk
-
-    The hunk is parsed into two arrays, a and b. a gets the old state of
-    the text, b gets the new state. The control char from the hunk is saved
-    when inserting into a, but not b (for performance while deleting files.)
-    """
-    while True:
-        todoa = lena - len(a)
-        todob = lenb - len(b)
-        num = max(todoa, todob)
-        if num == 0:
-            break
-        for i in xrange(num):
-            s = fp.readline()
-            if not s:
-                raise error.ParseError(_('incomplete hunk'))
-            if s == "\\ No newline at end of file\n":
-                fixnewline(hunk, a, b)
-                continue
-            if s == '\n' or s == '\r\n':
-                # Some patches may be missing the control char
-                # on empty lines. Supply a leading space.
-                s = ' ' + s
-            hunk.append(s)
-            if s.startswith('+'):
-                b.append(s[1:])
-            elif s.startswith('-'):
-                a.append(s)
-            else:
-                b.append(s[1:])
-                a.append(s)
-
-def fixnewline(hunk, a, b):
-    """Fix up the last lines of a and b when the patch has no newline at EOF"""
-    l = hunk[-1]
-    # tolerate CRLF in last line
-    if l.endswith('\r\n'):
-        hline = l[:-2]
-    else:
-        hline = l[:-1]
-
-    if hline.startswith((' ', '+')):
-        b[-1] = hline[1:]
-    if hline.startswith((' ', '-')):
-        a[-1] = hline
-    hunk[-1] = hline
-
-def testhunk(a, b, bstart):
-    """Compare the lines in a with the lines in b
-
-    a is assumed to have a control char at the start of each line, this char
-    is ignored in the compare.
-    """
-    alen = len(a)
-    blen = len(b)
-    if alen > blen - bstart:
-        return False
-    for i in xrange(alen):
-        if a[i][1:] != b[i + bstart]:
-            return False
-    return True
--- a/mercurial/filelog.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/filelog.py	Sat May 05 18:06:45 2018 -0700
@@ -7,16 +7,16 @@
 
 from __future__ import absolute_import
 
-from .thirdparty.zope import (
-    interface as zi,
-)
 from . import (
     error,
     repository,
     revlog,
 )
+from .utils import (
+    interfaceutil,
+)
 
-@zi.implementer(repository.ifilestorage)
+@interfaceutil.implementer(repository.ifilestorage)
 class filelog(object):
     def __init__(self, opener, path):
         self._revlog = revlog.revlog(opener,
@@ -135,7 +135,9 @@
             return False
         t = self.revision(node)
         m = revlog.parsemeta(t)[0]
-        if m and "copy" in m:
+        # copy and copyrev occur in pairs. In rare cases due to bugs,
+        # one can occur without the other.
+        if m and "copy" in m and "copyrev" in m:
             return (m["copy"], revlog.bin(m["copyrev"]))
         return False
 
--- a/mercurial/help/internals/bundle2.txt	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/help/internals/bundle2.txt	Sat May 05 18:06:45 2018 -0700
@@ -61,7 +61,7 @@
 
 The following stream level parameters are defined:
 
-compression
+Compression
    Compression format of payload data. ``GZ`` denotes zlib. ``BZ``
    denotes bzip2. ``ZS`` denotes zstandard.
 
--- a/mercurial/hgweb/hgweb_mod.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/hgweb/hgweb_mod.py	Sat May 05 18:06:45 2018 -0700
@@ -399,6 +399,12 @@
                 tag = 'W/"%d"' % self.mtime
                 if req.headers.get('If-None-Match') == tag:
                     res.status = '304 Not Modified'
+                    # Content-Type may be defined globally. It isn't valid on a
+                    # 304, so discard it.
+                    try:
+                        del res.headers[b'Content-Type']
+                    except KeyError:
+                        pass
                     # Response body not allowed on 304.
                     res.setbodybytes('')
                     return res.sendresponse()
--- a/mercurial/hgweb/hgwebdir_mod.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/hgweb/hgwebdir_mod.py	Sat May 05 18:06:45 2018 -0700
@@ -428,7 +428,10 @@
                                 uenv.iteritems()}
                     req = requestmod.parserequestfromenv(
                         uenv, reponame=virtualrepo,
-                        altbaseurl=self.ui.config('web', 'baseurl'))
+                        altbaseurl=self.ui.config('web', 'baseurl'),
+                        # Reuse wrapped body file object otherwise state
+                        # tracking can get confused.
+                        bodyfh=req.bodyfh)
                     try:
                         # ensure caller gets private copy of ui
                         repo = hg.repository(self.ui.copy(), real)
--- a/mercurial/hgweb/request.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/hgweb/request.py	Sat May 05 18:06:45 2018 -0700
@@ -124,7 +124,7 @@
     # WSGI environment dict, unmodified.
     rawenv = attr.ib()
 
-def parserequestfromenv(env, reponame=None, altbaseurl=None):
+def parserequestfromenv(env, reponame=None, altbaseurl=None, bodyfh=None):
     """Parse URL components from environment variables.
 
     WSGI defines request attributes via environment variables. This function
@@ -144,6 +144,9 @@
     if the request were to ``http://myserver:9000/prefix/rev/@``. In other
     words, ``wsgi.url_scheme``, ``SERVER_NAME``, ``SERVER_PORT``, and
     ``SCRIPT_NAME`` are all effectively replaced by components from this URL.
+
+    ``bodyfh`` can be used to specify a file object to read the request body
+    from. If not defined, ``wsgi.input`` from the environment dict is used.
     """
     # PEP 3333 defines the WSGI spec and is a useful reference for this code.
 
@@ -307,9 +310,11 @@
     if 'CONTENT_TYPE' in env and 'HTTP_CONTENT_TYPE' not in env:
         headers['Content-Type'] = env['CONTENT_TYPE']
 
-    bodyfh = env['wsgi.input']
-    if 'Content-Length' in headers:
-        bodyfh = util.cappedreader(bodyfh, int(headers['Content-Length']))
+    if bodyfh is None:
+        bodyfh = env['wsgi.input']
+        if 'Content-Length' in headers:
+            bodyfh = util.cappedreader(bodyfh,
+                                       int(headers['Content-Length'] or '0'))
 
     return parsedrequest(method=env['REQUEST_METHOD'],
                          url=fullurl, baseurl=baseurl,
@@ -468,6 +473,7 @@
                           if k.lower() not in ('date', 'etag', 'expires',
                                                'cache-control',
                                                'content-location',
+                                               'content-security-policy',
                                                'vary')}
             if badheaders:
                 raise error.ProgrammingError(
--- a/mercurial/hgweb/server.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/hgweb/server.py	Sat May 05 18:06:45 2018 -0700
@@ -122,6 +122,14 @@
         self.sent_headers = False
         path, query = _splitURI(self.path)
 
+        # Ensure the slicing of path below is valid
+        if (path != self.server.prefix
+            and not path.startswith(self.server.prefix + b'/')):
+            self._start_response(common.statusmessage(404), [])
+            self._write("Not Found")
+            self._done()
+            return
+
         env = {}
         env[r'GATEWAY_INTERFACE'] = r'CGI/1.1'
         env[r'REQUEST_METHOD'] = self.command
--- a/mercurial/httppeer.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/httppeer.py	Sat May 05 18:06:45 2018 -0700
@@ -20,9 +20,6 @@
 from .thirdparty import (
     cbor,
 )
-from .thirdparty.zope import (
-    interface as zi,
-)
 from . import (
     bundle2,
     error,
@@ -38,6 +35,9 @@
     wireprotov2peer,
     wireprotov2server,
 )
+from .utils import (
+    interfaceutil,
+)
 
 httplib = util.httplib
 urlerr = util.urlerr
@@ -328,13 +328,24 @@
 
     return res
 
+class RedirectedRepoError(error.RepoError):
+    def __init__(self, msg, respurl):
+        super(RedirectedRepoError, self).__init__(msg)
+        self.respurl = respurl
+
 def parsev1commandresponse(ui, baseurl, requrl, qs, resp, compressible,
                            allowcbor=False):
     # record the url we got redirected to
+    redirected = False
     respurl = pycompat.bytesurl(resp.geturl())
     if respurl.endswith(qs):
         respurl = respurl[:-len(qs)]
+        qsdropped = False
+    else:
+        qsdropped = True
+
     if baseurl.rstrip('/') != respurl.rstrip('/'):
+        redirected = True
         if not ui.quiet:
             ui.warn(_('real URL is %s\n') % respurl)
 
@@ -351,10 +362,16 @@
     # application/hg-changegroup. We don't support such old servers.
     if not proto.startswith('application/mercurial-'):
         ui.debug("requested URL: '%s'\n" % util.hidepassword(requrl))
-        raise error.RepoError(
-            _("'%s' does not appear to be an hg repository:\n"
-              "---%%<--- (%s)\n%s\n---%%<---\n")
-            % (safeurl, proto or 'no content-type', resp.read(1024)))
+        msg = _("'%s' does not appear to be an hg repository:\n"
+                "---%%<--- (%s)\n%s\n---%%<---\n") % (
+            safeurl, proto or 'no content-type', resp.read(1024))
+
+        # Some servers may strip the query string from the redirect. We
+        # raise a special error type so callers can react to this specially.
+        if redirected and qsdropped:
+            raise RedirectedRepoError(msg, respurl)
+        else:
+            raise error.RepoError(msg)
 
     try:
         subtype = proto.split('-', 1)[1]
@@ -434,8 +451,6 @@
 
     # End of ipeercommands interface.
 
-    # look up capabilities only when needed
-
     def _callstream(self, cmd, _compressible=False, **args):
         args = pycompat.byteskwargs(args)
 
@@ -582,7 +597,7 @@
         # will resolve to Future.result.
         return self.result(timeout)
 
-@zi.implementer(repository.ipeercommandexecutor)
+@interfaceutil.implementer(repository.ipeercommandexecutor)
 class httpv2executor(object):
     def __init__(self, ui, opener, requestbuilder, apiurl, descriptor):
         self._ui = ui
@@ -731,8 +746,9 @@
             pass
 
 # TODO implement interface for version 2 peers
-@zi.implementer(repository.ipeerconnection, repository.ipeercapabilities,
-                repository.ipeerrequests)
+@interfaceutil.implementer(repository.ipeerconnection,
+                           repository.ipeercapabilities,
+                           repository.ipeerrequests)
 class httpv2peer(object):
     def __init__(self, ui, repourl, apipath, opener, requestbuilder,
                  apidescriptor):
@@ -852,12 +868,32 @@
     req, requrl, qs = makev1commandrequest(ui, requestbuilder, caps,
                                            capable, url, 'capabilities',
                                            args)
-
     resp = sendrequest(ui, opener, req)
 
-    respurl, ct, resp = parsev1commandresponse(ui, url, requrl, qs, resp,
-                                               compressible=False,
-                                               allowcbor=advertisev2)
+    # The server may redirect us to the repo root, stripping the
+    # ?cmd=capabilities query string from the URL. The server would likely
+    # return HTML in this case and ``parsev1commandresponse()`` would raise.
+    # We catch this special case and re-issue the capabilities request against
+    # the new URL.
+    #
+    # We should ideally not do this, as a redirect that drops the query
+    # string from the URL is arguably a server bug. (Garbage in, garbage out).
+    # However,  Mercurial clients for several years appeared to handle this
+    # issue without behavior degradation. And according to issue 5860, it may
+    # be a longstanding bug in some server implementations. So we allow a
+    # redirect that drops the query string to "just work."
+    try:
+        respurl, ct, resp = parsev1commandresponse(ui, url, requrl, qs, resp,
+                                                   compressible=False,
+                                                   allowcbor=advertisev2)
+    except RedirectedRepoError as e:
+        req, requrl, qs = makev1commandrequest(ui, requestbuilder, caps,
+                                               capable, e.respurl,
+                                               'capabilities', args)
+        resp = sendrequest(ui, opener, req)
+        respurl, ct, resp = parsev1commandresponse(ui, url, requrl, qs, resp,
+                                                   compressible=False,
+                                                   allowcbor=advertisev2)
 
     try:
         rawdata = resp.read()
--- a/mercurial/localrepo.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/localrepo.py	Sat May 05 18:06:45 2018 -0700
@@ -21,9 +21,6 @@
     nullid,
     short,
 )
-from .thirdparty.zope import (
-    interface as zi,
-)
 from . import (
     bookmarks,
     branchmap,
@@ -68,6 +65,7 @@
     vfs as vfsmod,
 )
 from .utils import (
+    interfaceutil,
     procutil,
     stringutil,
 )
@@ -153,7 +151,7 @@
               'unbundle'}
 legacycaps = moderncaps.union({'changegroupsubset'})
 
-@zi.implementer(repository.ipeercommandexecutor)
+@interfaceutil.implementer(repository.ipeercommandexecutor)
 class localcommandexecutor(object):
     def __init__(self, peer):
         self._peer = peer
@@ -196,7 +194,7 @@
     def close(self):
         self._closed = True
 
-@zi.implementer(repository.ipeercommands)
+@interfaceutil.implementer(repository.ipeercommands)
 class localpeer(repository.peer):
     '''peer for a local repo; reflects only the most recent API'''
 
@@ -324,7 +322,7 @@
 
     # End of peer interface.
 
-@zi.implementer(repository.ipeerlegacycommands)
+@interfaceutil.implementer(repository.ipeerlegacycommands)
 class locallegacypeer(localpeer):
     '''peer extension which implements legacy methods too; used for tests with
     restricted capabilities'''
@@ -365,7 +363,7 @@
 # set to reflect that the extension knows how to handle that requirements.
 featuresetupfuncs = set()
 
-@zi.implementer(repository.completelocalrepository)
+@interfaceutil.implementer(repository.completelocalrepository)
 class localrepository(object):
 
     # obsolete experimental requirements:
@@ -850,8 +848,7 @@
         try:
             self[changeid]
             return True
-        except (error.RepoLookupError, error.FilteredIndexError,
-                error.FilteredLookupError):
+        except error.RepoLookupError:
             return False
 
     def __nonzero__(self):
--- a/mercurial/patch.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/patch.py	Sat May 05 18:06:45 2018 -0700
@@ -28,7 +28,7 @@
 )
 from . import (
     copies,
-    diffhelpers,
+    diffhelper,
     encoding,
     error,
     mail,
@@ -800,7 +800,7 @@
         # if there's skew we want to emit the "(offset %d lines)" even
         # when the hunk cleanly applies at start + skew, so skip the
         # fast case code
-        if self.skew == 0 and diffhelpers.testhunk(old, self.lines, oldstart):
+        if self.skew == 0 and diffhelper.testhunk(old, self.lines, oldstart):
             if self.remove:
                 self.backend.unlink(self.fname)
             else:
@@ -827,7 +827,7 @@
                     cand = [oldstart]
 
                 for l in cand:
-                    if not old or diffhelpers.testhunk(old, self.lines, l):
+                    if not old or diffhelper.testhunk(old, self.lines, l):
                         self.lines[l : l + len(old)] = new
                         self.offset += len(new) - len(old)
                         self.skew = l - orig_start
@@ -1259,8 +1259,8 @@
         self.starta = int(self.starta)
         self.startb = int(self.startb)
         try:
-            diffhelpers.addlines(lr, self.hunk, self.lena, self.lenb,
-                                 self.a, self.b)
+            diffhelper.addlines(lr, self.hunk, self.lena, self.lenb,
+                                self.a, self.b)
         except error.ParseError as e:
             raise PatchError(_("bad hunk #%d: %s") % (self.number, e))
         # if we hit eof before finishing out the hunk, the last line will
@@ -1379,7 +1379,7 @@
     def _fixnewline(self, lr):
         l = lr.readline()
         if l.startswith('\ '):
-            diffhelpers.fixnewline(self.hunk, self.a, self.b)
+            diffhelper.fixnewline(self.hunk, self.a, self.b)
         else:
             lr.push(l)
 
--- a/mercurial/repository.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/repository.py	Sat May 05 18:06:45 2018 -0700
@@ -8,14 +8,14 @@
 from __future__ import absolute_import
 
 from .i18n import _
-from .thirdparty.zope import (
-    interface as zi,
-)
 from . import (
     error,
 )
+from .utils import (
+    interfaceutil,
+)
 
-class ipeerconnection(zi.Interface):
+class ipeerconnection(interfaceutil.Interface):
     """Represents a "connection" to a repository.
 
     This is the base interface for representing a connection to a repository.
@@ -24,7 +24,7 @@
     This is not a complete interface definition and should not be used
     outside of this module.
     """
-    ui = zi.Attribute("""ui.ui instance""")
+    ui = interfaceutil.Attribute("""ui.ui instance""")
 
     def url():
         """Returns a URL string representing this peer.
@@ -61,7 +61,7 @@
         associated with the peer should be cleaned up.
         """
 
-class ipeercapabilities(zi.Interface):
+class ipeercapabilities(interfaceutil.Interface):
     """Peer sub-interface related to capabilities."""
 
     def capable(name):
@@ -81,7 +81,7 @@
         Raises a ``CapabilityError`` if the capability isn't present.
         """
 
-class ipeercommands(zi.Interface):
+class ipeercommands(interfaceutil.Interface):
     """Client-side interface for communicating over the wire protocol.
 
     This interface is used as a gateway to the Mercurial wire protocol.
@@ -170,7 +170,7 @@
         Returns the integer number of heads added to the peer.
         """
 
-class ipeerlegacycommands(zi.Interface):
+class ipeerlegacycommands(interfaceutil.Interface):
     """Interface for implementing support for legacy wire protocol commands.
 
     Wire protocol commands transition to legacy status when they are no longer
@@ -202,7 +202,7 @@
     def changegroupsubset(bases, heads, source):
         pass
 
-class ipeercommandexecutor(zi.Interface):
+class ipeercommandexecutor(interfaceutil.Interface):
     """Represents a mechanism to execute remote commands.
 
     This is the primary interface for requesting that wire protocol commands
@@ -259,7 +259,7 @@
         This method may call ``sendcommands()`` if there are buffered commands.
         """
 
-class ipeerrequests(zi.Interface):
+class ipeerrequests(interfaceutil.Interface):
     """Interface for executing commands on a peer."""
 
     def commandexecutor():
@@ -290,7 +290,7 @@
     All peer instances must conform to this interface.
     """
 
-@zi.implementer(ipeerbase)
+@interfaceutil.implementer(ipeerbase)
 class peer(object):
     """Base class for peer repositories."""
 
@@ -314,7 +314,7 @@
             _('cannot %s; remote repository does not support the %r '
               'capability') % (purpose, name))
 
-class ifilerevisionssequence(zi.Interface):
+class ifilerevisionssequence(interfaceutil.Interface):
     """Contains index data for all revisions of a file.
 
     Types implementing this behave like lists of tuples. The index
@@ -365,7 +365,7 @@
     def insert(self, i, entry):
         """Add an item to the index at specific revision."""
 
-class ifileindex(zi.Interface):
+class ifileindex(interfaceutil.Interface):
     """Storage interface for index data of a single file.
 
     File storage data is divided into index metadata and data storage.
@@ -377,7 +377,7 @@
     * DAG data (storing and querying the relationship between nodes).
     * Metadata to facilitate storage.
     """
-    index = zi.Attribute(
+    index = interfaceutil.Attribute(
         """An ``ifilerevisionssequence`` instance.""")
 
     def __len__():
@@ -470,7 +470,7 @@
     def candelta(baserev, rev):
         """"Whether a delta can be generated between two revisions."""
 
-class ifiledata(zi.Interface):
+class ifiledata(interfaceutil.Interface):
     """Storage interface for data storage of a specific file.
 
     This complements ``ifileindex`` and provides an interface for accessing
@@ -536,7 +536,7 @@
         revision data.
         """
 
-class ifilemutation(zi.Interface):
+class ifilemutation(interfaceutil.Interface):
     """Storage interface for mutation events of a tracked file."""
 
     def add(filedata, meta, transaction, linkrev, p1, p2):
@@ -608,13 +608,13 @@
 class ifilestorage(ifileindex, ifiledata, ifilemutation):
     """Complete storage interface for a single tracked file."""
 
-    version = zi.Attribute(
+    version = interfaceutil.Attribute(
         """Version number of storage.
 
         TODO this feels revlog centric and could likely be removed.
         """)
 
-    storedeltachains = zi.Attribute(
+    storedeltachains = interfaceutil.Attribute(
         """Whether the store stores deltas.
 
         TODO deltachains are revlog centric. This can probably removed
@@ -622,7 +622,7 @@
         data.
         """)
 
-    _generaldelta = zi.Attribute(
+    _generaldelta = interfaceutil.Attribute(
         """Whether deltas can be against any parent revision.
 
         TODO this is used by changegroup code and it could probably be
@@ -642,59 +642,59 @@
         TODO this is used by verify and it should not be part of the interface.
         """
 
-class completelocalrepository(zi.Interface):
+class completelocalrepository(interfaceutil.Interface):
     """Monolithic interface for local repositories.
 
     This currently captures the reality of things - not how things should be.
     """
 
-    supportedformats = zi.Attribute(
+    supportedformats = interfaceutil.Attribute(
         """Set of requirements that apply to stream clone.
 
         This is actually a class attribute and is shared among all instances.
         """)
 
-    openerreqs = zi.Attribute(
+    openerreqs = interfaceutil.Attribute(
         """Set of requirements that are passed to the opener.
 
         This is actually a class attribute and is shared among all instances.
         """)
 
-    supported = zi.Attribute(
+    supported = interfaceutil.Attribute(
         """Set of requirements that this repo is capable of opening.""")
 
-    requirements = zi.Attribute(
+    requirements = interfaceutil.Attribute(
         """Set of requirements this repo uses.""")
 
-    filtername = zi.Attribute(
+    filtername = interfaceutil.Attribute(
         """Name of the repoview that is active on this repo.""")
 
-    wvfs = zi.Attribute(
+    wvfs = interfaceutil.Attribute(
         """VFS used to access the working directory.""")
 
-    vfs = zi.Attribute(
+    vfs = interfaceutil.Attribute(
         """VFS rooted at the .hg directory.
 
         Used to access repository data not in the store.
         """)
 
-    svfs = zi.Attribute(
+    svfs = interfaceutil.Attribute(
         """VFS rooted at the store.
 
         Used to access repository data in the store. Typically .hg/store.
         But can point elsewhere if the store is shared.
         """)
 
-    root = zi.Attribute(
+    root = interfaceutil.Attribute(
         """Path to the root of the working directory.""")
 
-    path = zi.Attribute(
+    path = interfaceutil.Attribute(
         """Path to the .hg directory.""")
 
-    origroot = zi.Attribute(
+    origroot = interfaceutil.Attribute(
         """The filesystem path that was used to construct the repo.""")
 
-    auditor = zi.Attribute(
+    auditor = interfaceutil.Attribute(
         """A pathauditor for the working directory.
 
         This checks if a path refers to a nested repository.
@@ -702,40 +702,40 @@
         Operates on the filesystem.
         """)
 
-    nofsauditor = zi.Attribute(
+    nofsauditor = interfaceutil.Attribute(
         """A pathauditor for the working directory.
 
         This is like ``auditor`` except it doesn't do filesystem checks.
         """)
 
-    baseui = zi.Attribute(
+    baseui = interfaceutil.Attribute(
         """Original ui instance passed into constructor.""")
 
-    ui = zi.Attribute(
+    ui = interfaceutil.Attribute(
         """Main ui instance for this instance.""")
 
-    sharedpath = zi.Attribute(
+    sharedpath = interfaceutil.Attribute(
         """Path to the .hg directory of the repo this repo was shared from.""")
 
-    store = zi.Attribute(
+    store = interfaceutil.Attribute(
         """A store instance.""")
 
-    spath = zi.Attribute(
+    spath = interfaceutil.Attribute(
         """Path to the store.""")
 
-    sjoin = zi.Attribute(
+    sjoin = interfaceutil.Attribute(
         """Alias to self.store.join.""")
 
-    cachevfs = zi.Attribute(
+    cachevfs = interfaceutil.Attribute(
         """A VFS used to access the cache directory.
 
         Typically .hg/cache.
         """)
 
-    filteredrevcache = zi.Attribute(
+    filteredrevcache = interfaceutil.Attribute(
         """Holds sets of revisions to be filtered.""")
 
-    names = zi.Attribute(
+    names = interfaceutil.Attribute(
         """A ``namespaces`` instance.""")
 
     def close():
@@ -750,19 +750,19 @@
     def filtered(name, visibilityexceptions=None):
         """Obtain a named view of this repository."""
 
-    obsstore = zi.Attribute(
+    obsstore = interfaceutil.Attribute(
         """A store of obsolescence data.""")
 
-    changelog = zi.Attribute(
+    changelog = interfaceutil.Attribute(
         """A handle on the changelog revlog.""")
 
-    manifestlog = zi.Attribute(
+    manifestlog = interfaceutil.Attribute(
         """A handle on the root manifest revlog.""")
 
-    dirstate = zi.Attribute(
+    dirstate = interfaceutil.Attribute(
         """Working directory state.""")
 
-    narrowpats = zi.Attribute(
+    narrowpats = interfaceutil.Attribute(
         """Matcher patterns for this repository's narrowspec.""")
 
     def narrowmatch():
@@ -978,7 +978,7 @@
     def checkpush(pushop):
         pass
 
-    prepushoutgoinghooks = zi.Attribute(
+    prepushoutgoinghooks = interfaceutil.Attribute(
         """util.hooks instance.""")
 
     def pushkey(namespace, key, old, new):
--- a/mercurial/revlog.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/revlog.py	Sat May 05 18:06:45 2018 -0700
@@ -1466,7 +1466,7 @@
         if id in self._pcache:
             return self._pcache[id]
 
-        if len(id) < 40:
+        if len(id) <= 40:
             try:
                 # hex(node)[:...]
                 l = len(id) // 2  # grab an even number of digits
--- a/mercurial/sshpeer.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/sshpeer.py	Sat May 05 18:06:45 2018 -0700
@@ -261,11 +261,9 @@
             handshake.insert(0, 'upgrade %s %s\n' % (token, upgradecaps))
 
         if requestlog:
-            ui.debug('devel-peer-request: hello\n')
+            ui.debug('devel-peer-request: hello+between\n')
+            ui.debug('devel-peer-request:   pairs: %d bytes\n' % len(pairsarg))
         ui.debug('sending hello command\n')
-        if requestlog:
-            ui.debug('devel-peer-request: between\n')
-            ui.debug('devel-peer-request:   pairs: %d bytes\n' % len(pairsarg))
         ui.debug('sending between command\n')
 
         stdin.write(''.join(handshake))
--- a/mercurial/templates/paper/changeset.tmpl	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/templates/paper/changeset.tmpl	Sat May 05 18:06:45 2018 -0700
@@ -73,9 +73,9 @@
   <th class="diffstat">diffstat</th>
   <td class="diffstat">
     {diffsummary}
-    <a id="diffstatexpand" href="javascript:toggleDiffstat()">[<tt>+</tt>]</a>
+    <a id="diffstatexpand" class="diffstattoggle" href="#">[<tt>+</tt>]</a>
     <div id="diffstatdetails" style="display:none;">
-      <a href="javascript:toggleDiffstat()">[<tt>-</tt>]</a>
+      <a class="diffstattoggle" href="#">[<tt>-</tt>]</a>
       <table class="diffstat-table stripes2">{diffstat}</table>
     </div>
   </td>
@@ -83,7 +83,7 @@
 </table>
 
 <div class="overflow">
-<div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
+<div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
 <div class="sourcefirst"> line diff</div>
 <div class="stripes2 diffblocks">
 {diff}
--- a/mercurial/templates/paper/filediff.tmpl	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/templates/paper/filediff.tmpl	Sat May 05 18:06:45 2018 -0700
@@ -65,7 +65,7 @@
 </table>
 
 <div class="overflow">
-<div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
+<div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
 <div class="sourcefirst"> line diff</div>
 <div class="stripes2 diffblocks">
 {diff}
--- a/mercurial/templates/paper/filerevision.tmpl	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/templates/paper/filerevision.tmpl	Sat May 05 18:06:45 2018 -0700
@@ -65,7 +65,7 @@
 </table>
 
 <div class="overflow">
-<div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
+<div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
 <div class="sourcefirst"> line source</div>
 <pre class="sourcelines stripes4 wrap bottomline"
      data-logurl="{url|urlescape}log/{symrev}/{file|urlescape}"
--- a/mercurial/templates/static/mercurial.js	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/templates/static/mercurial.js	Sat May 05 18:06:45 2018 -0700
@@ -328,14 +328,15 @@
 	}
 }
 
-function toggleDiffstat() {
+function toggleDiffstat(event) {
     var curdetails = document.getElementById('diffstatdetails').style.display;
     var curexpand = curdetails === 'none' ? 'inline' : 'none';
     document.getElementById('diffstatdetails').style.display = curexpand;
     document.getElementById('diffstatexpand').style.display = curdetails;
+    event.preventDefault();
 }
 
-function toggleLinewrap() {
+function toggleLinewrap(event) {
     function getLinewrap() {
         var nodes = document.getElementsByClassName('sourcelines');
         // if there are no such nodes, error is thrown here
@@ -360,6 +361,7 @@
     }
 
     setLinewrap(!getLinewrap());
+    event.preventDefault();
 }
 
 function format(str, replacements) {
@@ -551,6 +553,28 @@
     form.style.display = 'block';
 }
 
+function addDiffStatToggle() {
+    var els = document.getElementsByClassName("diffstattoggle");
+
+    for (var i = 0; i < els.length; i++) {
+        els[i].addEventListener("click", toggleDiffstat, false);
+    }
+}
+
+function addLineWrapToggle() {
+    var els = document.getElementsByClassName("linewraptoggle");
+
+    for (var i = 0; i < els.length; i++) {
+        var nodes = els[i].getElementsByClassName("linewraplink");
+
+        for (var j = 0; j < nodes.length; j++) {
+            nodes[j].addEventListener("click", toggleLinewrap, false);
+        }
+    }
+}
+
 document.addEventListener('DOMContentLoaded', function() {
    process_dates();
+   addDiffStatToggle();
+   addLineWrapToggle();
 }, false);
--- a/mercurial/util.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/util.py	Sat May 05 18:06:45 2018 -0700
@@ -1037,14 +1037,27 @@
     (3, 9, None)
     >>> versiontuple(v, 4)
     (3, 9, None, 'rc+2-02a8fea4289b')
+
+    >>> versiontuple(b'4.6rc0')
+    (4, 6, None, 'rc0')
+    >>> versiontuple(b'4.6rc0+12-425d55e54f98')
+    (4, 6, None, 'rc0+12-425d55e54f98')
+    >>> versiontuple(b'.1.2.3')
+    (None, None, None, '.1.2.3')
+    >>> versiontuple(b'12.34..5')
+    (12, 34, None, '..5')
+    >>> versiontuple(b'1.2.3.4.5.6')
+    (1, 2, 3, '.4.5.6')
     """
     if not v:
         v = version()
-    parts = remod.split('[\+-]', v, 1)
-    if len(parts) == 1:
-        vparts, extra = parts[0], None
+    m = remod.match(br'(\d+(?:\.\d+){,2})[\+-]?(.*)', v)
+    if not m:
+        vparts, extra = '', v
+    elif m.group(2):
+        vparts, extra = m.groups()
     else:
-        vparts, extra = parts
+        vparts, extra = m.group(1), None
 
     vints = []
     for i in vparts.split('.'):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/utils/interfaceutil.py	Sat May 05 18:06:45 2018 -0700
@@ -0,0 +1,40 @@
+# interfaceutil.py - Utilities for declaring interfaces.
+#
+# Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+# zope.interface imposes a run-time cost due to module import overhead and
+# bookkeeping for declaring interfaces. So, we use stubs for various
+# zope.interface primitives unless instructed otherwise.
+
+from __future__ import absolute_import
+
+from .. import (
+    encoding,
+)
+
+if encoding.environ.get('HGREALINTERFACES'):
+    from ..thirdparty.zope import (
+        interface as zi,
+    )
+
+    Attribute = zi.Attribute
+    Interface = zi.Interface
+    implementer = zi.implementer
+else:
+    class Attribute(object):
+        def __init__(self, __name__, __doc__=''):
+            pass
+
+    class Interface(object):
+        def __init__(self, name, bases=(), attrs=None, __doc__=None,
+                 __module__=None):
+            pass
+
+    def implementer(*ifaces):
+        def wrapper(cls):
+            return cls
+
+        return wrapper
--- a/mercurial/wireprotoserver.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/wireprotoserver.py	Sat May 05 18:06:45 2018 -0700
@@ -15,9 +15,6 @@
 from .thirdparty import (
     cbor,
 )
-from .thirdparty.zope import (
-    interface as zi,
-)
 from . import (
     encoding,
     error,
@@ -29,6 +26,7 @@
     wireprotov2server,
 )
 from .utils import (
+    interfaceutil,
     procutil,
 )
 
@@ -62,7 +60,7 @@
 
     return ''.join(chunks)
 
-@zi.implementer(wireprototypes.baseprotocolhandler)
+@interfaceutil.implementer(wireprototypes.baseprotocolhandler)
 class httpv1protocolhandler(object):
     def __init__(self, req, ui, checkperm):
         self._req = req
@@ -489,7 +487,7 @@
     fout.write(b'\n')
     fout.flush()
 
-@zi.implementer(wireprototypes.baseprotocolhandler)
+@interfaceutil.implementer(wireprototypes.baseprotocolhandler)
 class sshv1protocolhandler(object):
     """Handler for requests services via version 1 of SSH protocol."""
     def __init__(self, ui, fin, fout):
--- a/mercurial/wireprototypes.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/wireprototypes.py	Sat May 05 18:06:45 2018 -0700
@@ -9,14 +9,14 @@
     bin,
     hex,
 )
-from .thirdparty.zope import (
-    interface as zi,
-)
 from .i18n import _
 from . import (
     error,
     util,
 )
+from .utils import (
+    interfaceutil,
+)
 
 # Names of the SSH protocol implementations.
 SSHV1 = 'ssh-v1'
@@ -179,7 +179,7 @@
     'stream': 'boolean',
 }
 
-class baseprotocolhandler(zi.Interface):
+class baseprotocolhandler(interfaceutil.Interface):
     """Abstract base class for wire protocol handlers.
 
     A wire protocol handler serves as an interface between protocol command
@@ -188,7 +188,7 @@
     the request, handle response types, etc.
     """
 
-    name = zi.Attribute(
+    name = interfaceutil.Attribute(
         """The name of the protocol implementation.
 
         Used for uniquely identifying the transport type.
--- a/mercurial/wireprotov1peer.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/wireprotov1peer.py	Sat May 05 18:06:45 2018 -0700
@@ -15,9 +15,6 @@
 from .node import (
     bin,
 )
-from .thirdparty.zope import (
-    interface as zi,
-)
 from . import (
     bundle2,
     changegroup as changegroupmod,
@@ -29,6 +26,9 @@
     util,
     wireprototypes,
 )
+from .utils import (
+    interfaceutil,
+)
 
 urlreq = util.urlreq
 
@@ -110,7 +110,7 @@
         # on that.
         return self.result(timeout)
 
-@zi.implementer(repository.ipeercommandexecutor)
+@interfaceutil.implementer(repository.ipeercommandexecutor)
 class peerexecutor(object):
     def __init__(self, peer):
         self._peer = peer
@@ -308,7 +308,8 @@
             else:
                 f.set_result(result)
 
-@zi.implementer(repository.ipeercommands, repository.ipeerlegacycommands)
+@interfaceutil.implementer(repository.ipeercommands,
+                           repository.ipeerlegacycommands)
 class wirepeer(repository.peer):
     """Client-side interface for communicating with a peer repository.
 
--- a/mercurial/wireprotov2server.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/wireprotov2server.py	Sat May 05 18:06:45 2018 -0700
@@ -12,9 +12,6 @@
 from .thirdparty import (
     cbor,
 )
-from .thirdparty.zope import (
-    interface as zi,
-)
 from . import (
     encoding,
     error,
@@ -24,6 +21,9 @@
     wireprotoframing,
     wireprototypes,
 )
+from .utils import (
+    interfaceutil,
+)
 
 FRAMINGTYPE = b'application/mercurial-exp-framing-0005'
 
@@ -340,7 +340,7 @@
 
     return func(repo, proto, **args)
 
-@zi.implementer(wireprototypes.baseprotocolhandler)
+@interfaceutil.implementer(wireprototypes.baseprotocolhandler)
 class httpv2protocolhandler(object):
     def __init__(self, req, ui, args=None):
         self._req = req
--- a/tests/test-check-code.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-check-code.t	Sat May 05 18:06:45 2018 -0700
@@ -51,3 +51,15 @@
   hgeditor
   hgweb.cgi
   setup.py
+
+Prevent adding modules which could be shadowed by ancient .so/.dylib.
+
+  $ testrepohg files \
+  > mercurial/base85.py \
+  > mercurial/bdiff.py \
+  > mercurial/diffhelpers.py \
+  > mercurial/mpatch.py \
+  > mercurial/osutil.py \
+  > mercurial/parsers.py \
+  > mercurial/zstd.py
+  [1]
--- a/tests/test-check-commit.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-check-commit.t	Sat May 05 18:06:45 2018 -0700
@@ -8,16 +8,20 @@
 
   $ cd $TESTDIR/..
 
+  $ REVSET='not public() and ::. and not desc("# no-check-commit")'
+
   $ mkdir "$TESTTMP/p"
-  $ testrepohg export --git -o "$TESTTMP/p/%n-%h" \
-  > -r 'not public() and ::. and not desc("# no-check-commit")'
-  $ for f in `ls "$TESTTMP/p"`; do
-  >    contrib/check-commit < "$TESTTMP/p/$f" > "$TESTTMP/check-commit.out"
-  >    if [ $? -ne 0 ]; then
-  >        node="${f##*-}"
-  >        echo "Revision $node does not comply with rules"
-  >        echo '------------------------------------------------------'
-  >        cat ${TESTTMP}/check-commit.out
-  >        echo
-  >   fi
-  > done
+  $ REVS=`testrepohg log -r "$REVSET" -T.`
+  $ if [ -n "$REVS" ] ; then
+  >   testrepohg export --git -o "$TESTTMP/p/%n-%h" -r "$REVSET"
+  >   for f in `ls "$TESTTMP/p"`; do
+  >      contrib/check-commit < "$TESTTMP/p/$f" > "$TESTTMP/check-commit.out"
+  >      if [ $? -ne 0 ]; then
+  >          node="${f##*-}"
+  >          echo "Revision $node does not comply with rules"
+  >          echo '------------------------------------------------------'
+  >          cat ${TESTTMP}/check-commit.out
+  >          echo
+  >     fi
+  >   done
+  > fi
--- a/tests/test-check-interfaces.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-check-interfaces.py	Sat May 05 18:06:45 2018 -0700
@@ -2,7 +2,17 @@
 
 from __future__ import absolute_import, print_function
 
+from mercurial import encoding
+encoding.environ[b'HGREALINTERFACES'] = b'1'
+
 import os
+import subprocess
+import sys
+
+# Only run if tests are run in a repo
+if subprocess.call(['python', '%s/hghave' % os.environ['TESTDIR'],
+                    'test-repo']):
+    sys.exit(80)
 
 from mercurial.thirdparty.zope import (
     interface as zi,
--- a/tests/test-check-module-imports.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-check-module-imports.t	Sat May 05 18:06:45 2018 -0700
@@ -27,6 +27,7 @@
   > -X i18n/posplit \
   > -X mercurial/thirdparty \
   > -X tests/hypothesishelpers.py \
+  > -X tests/test-check-interfaces.py \
   > -X tests/test-commit-interactive.t \
   > -X tests/test-contrib-check-code.t \
   > -X tests/test-demandimport.py \
--- a/tests/test-debugcommands.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-debugcommands.t	Sat May 05 18:06:45 2018 -0700
@@ -333,6 +333,19 @@
   .hg/cache/rbc-names-v1
   .hg/cache/branch2-served
 
+Test debugcolor
+
+#if no-windows
+  $ hg debugcolor --style --color always | egrep 'mode|style|log\.'
+  color mode: ansi
+  available style:
+  \x1b[0;33mlog.changeset\x1b[0m:                      \x1b[0;33myellow\x1b[0m (esc)
+#endif
+
+  $ hg debugcolor --style --color never
+  color mode: None
+  available style:
+
   $ cd ..
 
 Test internal debugstacktrace command
@@ -411,10 +424,9 @@
   $ hg --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" --debug debugpeer ssh://user@dummy/debugrevlog
   running "*" "*/tests/dummyssh" 'user@dummy' 'hg -R debugrevlog serve --stdio' (glob) (no-windows !)
   running "*" "*\tests/dummyssh" "user@dummy" "hg -R debugrevlog serve --stdio" (glob) (windows !)
-  devel-peer-request: hello
+  devel-peer-request: hello+between
+  devel-peer-request:   pairs: 81 bytes
   sending hello command
-  devel-peer-request: between
-  devel-peer-request:   pairs: 81 bytes
   sending between command
   remote: 413
   remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
--- a/tests/test-fix.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-fix.t	Sat May 05 18:06:45 2018 -0700
@@ -493,11 +493,12 @@
   $ printf "NO FIX NEEDED\n" > foo.whole
   $ hg add
   adding foo.whole
-  $ cp foo.whole foo.whole.orig
+  $ cp -p foo.whole foo.whole.orig
+  $ cp -p foo.whole.orig foo.whole
   $ sleep 2 # mtime has a resolution of one or two seconds.
   $ hg fix --working-dir
-  $ f foo.whole --newer foo.whole.orig
-  foo.whole: older than foo.whole.orig
+  $ f foo.whole.orig --newer foo.whole
+  foo.whole.orig: newer than foo.whole
 
   $ cd ..
 
@@ -514,8 +515,11 @@
   $ printf "hello\n" > hello.txt
   $ hg add
   adding hello.txt
-  $ hg --config "fix.fail:command=printf 'HELLO\n' ; \
-  >                               printf '{rootpath}: some\nerror' >&2" \
+  $ cat >> $TESTTMP/cmd.sh <<'EOF'
+  > printf 'HELLO\n'
+  > printf "$@: some\nerror" >&2
+  > EOF
+  $ hg --config "fix.fail:command=sh $TESTTMP/cmd.sh {rootpath}" \
   >    --config "fix.fail:fileset=hello.txt" \
   >    fix --working-dir
   [wdir] fail: hello.txt: some
--- a/tests/test-help.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-help.t	Sat May 05 18:06:45 2018 -0700
@@ -278,7 +278,6 @@
        purge         command to delete untracked files from the working
                      directory
        relink        recreates hardlinks between repository clones
-       remotenames   showing remotebookmarks and remotebranches in UI
        schemes       extend schemes with shortcuts to repository swarms
        share         share a common history between several working directories
        shelve        save and restore changes to the working directory
--- a/tests/test-hgweb-commands.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-hgweb-commands.t	Sat May 05 18:06:45 2018 -0700
@@ -916,9 +916,9 @@
     <td class="diffstat">
        2 files changed, 2 insertions(+), 0 deletions(-)
   
-      <a id="diffstatexpand" href="javascript:toggleDiffstat()">[<tt>+</tt>]</a>
+      <a id="diffstatexpand" class="diffstattoggle" href="#">[<tt>+</tt>]</a>
       <div id="diffstatdetails" style="display:none;">
-        <a href="javascript:toggleDiffstat()">[<tt>-</tt>]</a>
+        <a class="diffstattoggle" href="#">[<tt>-</tt>]</a>
         <table class="diffstat-table stripes2">  <tr>
       <td class="diffstat-file"><a href="#l1.1">da/foo</a></td>
       <td class="diffstat-total" align="right">1</td>
@@ -942,7 +942,7 @@
   </table>
   
   <div class="overflow">
-  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
+  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
   <div class="sourcefirst"> line diff</div>
   <div class="stripes2 diffblocks">
   <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
@@ -1342,7 +1342,7 @@
   </table>
   
   <div class="overflow">
-  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
+  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
   <div class="sourcefirst"> line source</div>
   <pre class="sourcelines stripes4 wrap bottomline"
        data-logurl="/log/1/foo"
@@ -1476,7 +1476,7 @@
   </table>
   
   <div class="overflow">
-  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
+  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
   <div class="sourcefirst"> line source</div>
   <pre class="sourcelines stripes4 wrap bottomline"
        data-logurl="/log/2/foo"
--- a/tests/test-hgweb-csp.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-hgweb-csp.t	Sat May 05 18:06:45 2018 -0700
@@ -54,6 +54,12 @@
   200 Script output follows
   content-security-policy: script-src https://example.com/ 'unsafe-inline'
 
+  $ get-with-headers.py --twice --headeronly localhost:$HGPORT repo1/static/style.css content-security-policy
+  200 Script output follows
+  content-security-policy: script-src https://example.com/ 'unsafe-inline'
+  304 Not Modified
+  content-security-policy: script-src https://example.com/ 'unsafe-inline'
+
 repo page should send CSP by default, include etag w/o nonce
 
   $ get-with-headers.py --headeronly localhost:$HGPORT repo1 content-security-policy etag
--- a/tests/test-hgweb-diffs.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-hgweb-diffs.t	Sat May 05 18:06:45 2018 -0700
@@ -122,9 +122,9 @@
     <td class="diffstat">
        2 files changed, 2 insertions(+), 0 deletions(-)
   
-      <a id="diffstatexpand" href="javascript:toggleDiffstat()">[<tt>+</tt>]</a>
+      <a id="diffstatexpand" class="diffstattoggle" href="#">[<tt>+</tt>]</a>
       <div id="diffstatdetails" style="display:none;">
-        <a href="javascript:toggleDiffstat()">[<tt>-</tt>]</a>
+        <a class="diffstattoggle" href="#">[<tt>-</tt>]</a>
         <table class="diffstat-table stripes2">  <tr>
       <td class="diffstat-file"><a href="#l1.1">a</a></td>
       <td class="diffstat-total" align="right">1</td>
@@ -148,7 +148,7 @@
   </table>
   
   <div class="overflow">
-  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
+  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
   <div class="sourcefirst"> line diff</div>
   <div class="stripes2 diffblocks">
   <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
@@ -289,7 +289,7 @@
   </table>
   
   <div class="overflow">
-  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
+  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
   <div class="sourcefirst"> line diff</div>
   <div class="stripes2 diffblocks">
   <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
@@ -419,9 +419,9 @@
     <td class="diffstat">
        2 files changed, 2 insertions(+), 0 deletions(-)
   
-      <a id="diffstatexpand" href="javascript:toggleDiffstat()">[<tt>+</tt>]</a>
+      <a id="diffstatexpand" class="diffstattoggle" href="#">[<tt>+</tt>]</a>
       <div id="diffstatdetails" style="display:none;">
-        <a href="javascript:toggleDiffstat()">[<tt>-</tt>]</a>
+        <a class="diffstattoggle" href="#">[<tt>-</tt>]</a>
         <table class="diffstat-table stripes2">  <tr>
       <td class="diffstat-file"><a href="#l1.1">a</a></td>
       <td class="diffstat-total" align="right">1</td>
@@ -445,7 +445,7 @@
   </table>
   
   <div class="overflow">
-  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
+  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
   <div class="sourcefirst"> line diff</div>
   <div class="stripes2 diffblocks">
   <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
@@ -590,7 +590,7 @@
   </table>
   
   <div class="overflow">
-  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
+  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
   <div class="sourcefirst"> line diff</div>
   <div class="stripes2 diffblocks">
   <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
--- a/tests/test-hgweb-removed.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-hgweb-removed.t	Sat May 05 18:06:45 2018 -0700
@@ -103,9 +103,9 @@
     <td class="diffstat">
        1 files changed, 0 insertions(+), 1 deletions(-)
   
-      <a id="diffstatexpand" href="javascript:toggleDiffstat()">[<tt>+</tt>]</a>
+      <a id="diffstatexpand" class="diffstattoggle" href="#">[<tt>+</tt>]</a>
       <div id="diffstatdetails" style="display:none;">
-        <a href="javascript:toggleDiffstat()">[<tt>-</tt>]</a>
+        <a class="diffstattoggle" href="#">[<tt>-</tt>]</a>
         <table class="diffstat-table stripes2">  <tr>
       <td class="diffstat-file"><a href="#l1.1">a</a></td>
       <td class="diffstat-total" align="right">1</td>
@@ -121,7 +121,7 @@
   </table>
   
   <div class="overflow">
-  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
+  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
   <div class="sourcefirst"> line diff</div>
   <div class="stripes2 diffblocks">
   <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
@@ -225,7 +225,7 @@
   </table>
   
   <div class="overflow">
-  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
+  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
   <div class="sourcefirst"> line diff</div>
   <div class="stripes2 diffblocks">
   <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
--- a/tests/test-hgweb.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-hgweb.t	Sat May 05 18:06:45 2018 -0700
@@ -875,4 +875,23 @@
   Internal Server Error (no-eol)
 
   $ killdaemons.py
+
+HTTP 304 works with hgwebdir (issue5844)
+
+  $ cat > hgweb.conf << EOF
+  > [paths]
+  > /repo = $TESTTMP/test
+  > EOF
+
+  $ hg serve --web-conf hgweb.conf -p $HGPORT -d --pid-file hg.pid -E error.log
+  $ cat hg.pid >> $DAEMON_PIDS
+
+  $ get-with-headers.py --twice --headeronly localhost:$HGPORT 'repo/static/style.css' - date etag server
+  200 Script output follows
+  content-length: 2677
+  content-type: text/css
+  304 Not Modified
+
+  $ killdaemons.py
+
   $ cd ..
--- a/tests/test-highlight.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-highlight.t	Sat May 05 18:06:45 2018 -0700
@@ -146,7 +146,7 @@
   </table>
   
   <div class="overflow">
-  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
+  <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="#">on</a></div>
   <div class="sourcefirst"> line source</div>
   <pre class="sourcelines stripes4 wrap bottomline"
        data-logurl="/log/tip/primes.py"
--- a/tests/test-http-protocol.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-http-protocol.t	Sat May 05 18:06:45 2018 -0700
@@ -257,7 +257,7 @@
   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: 458\r\n
+  s>     Content-Length: *\r\n (glob)
   s>     \r\n
   s>     batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   sending heads command
@@ -281,7 +281,7 @@
 
   $ killdaemons.py
   $ enablehttpv2 empty
-  $ hg -R empty serve -p $HGPORT -d --pid-file hg.pid
+  $ 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
@@ -305,7 +305,7 @@
   s>     Content-Type: application/mercurial-cbor\r\n
   s>     Content-Length: *\r\n (glob)
   s>     \r\n
-  s>     \xa3Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x82\xa1DnameDzstd\xa1DnameDzlibNrawrepoformats\x82LgeneraldeltaHrevlogv1Qframingmediatypes\x81X&application/mercurial-exp-framing-0005GapibaseDapi/Nv1capabilitiesY\x01\xcabatch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  s>     \xa3Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x81\xa1DnameDzlibNrawrepoformats\x82LgeneraldeltaHrevlogv1Qframingmediatypes\x81X&application/mercurial-exp-framing-0005GapibaseDapi/Nv1capabilitiesY\x01\xc5batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   sending heads command
   s>     POST /api/exp-http-v2-0001/ro/heads HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
@@ -333,3 +333,394 @@
   response: [b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00']
 
   $ killdaemons.py
+
+HTTP client follows HTTP redirect on handshake to new repo
+
+  $ cd $TESTTMP
+
+  $ hg init redirector
+  $ hg init redirected
+  $ cd redirected
+  $ touch foo
+  $ hg -q commit -A -m initial
+  $ cd ..
+
+  $ cat > paths.conf << EOF
+  > [paths]
+  > / = $TESTTMP/*
+  > EOF
+
+  $ cat > redirectext.py << EOF
+  > from mercurial import extensions, wireprotoserver
+  > def wrappedcallhttp(orig, repo, req, res, proto, cmd):
+  >     path = req.advertisedurl[len(req.advertisedbaseurl):]
+  >     if not path.startswith(b'/redirector'):
+  >         return orig(repo, req, res, proto, cmd)
+  >     relpath = path[len(b'/redirector'):]
+  >     res.status = b'301 Redirect'
+  >     newurl = b'%s/redirected%s' % (req.baseurl, relpath)
+  >     if not repo.ui.configbool('testing', 'redirectqs', True) and b'?' in newurl:
+  >         newurl = newurl[0:newurl.index(b'?')]
+  >     res.headers[b'Location'] = newurl
+  >     res.headers[b'Content-Type'] = b'text/plain'
+  >     res.setbodybytes(b'redirected')
+  >     return True
+  > 
+  > extensions.wrapfunction(wireprotoserver, '_callhttp', wrappedcallhttp)
+  > EOF
+
+  $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
+  >    --config server.compressionengines=zlib \
+  >     serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
+  $ cat hg.pid > $DAEMON_PIDS
+
+Verify our HTTP 301 is served properly
+
+  $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
+  > httprequest GET /redirector?cmd=capabilities
+  >     user-agent: test
+  > EOF
+  using raw connection to peer
+  s>     GET /redirector?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 301 Redirect\r\n
+  s>     Server: testing stub value\r\n
+  s>     Date: $HTTP_DATE$\r\n
+  s>     Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
+  s>     Content-Type: text/plain\r\n
+  s>     Content-Length: 10\r\n
+  s>     \r\n
+  s>     redirected
+  s>     GET /redirected?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: 453\r\n
+  s>     \r\n
+  s>     batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+
+Test with the HTTP peer
+
+  $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
+  > command heads
+  > EOF
+  s>     GET /redirector?cmd=capabilities HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\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 301 Redirect\r\n
+  s>     Server: testing stub value\r\n
+  s>     Date: $HTTP_DATE$\r\n
+  s>     Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
+  s>     Content-Type: text/plain\r\n
+  s>     Content-Length: 10\r\n
+  s>     \r\n
+  s>     redirected
+  s>     GET /redirected?cmd=capabilities HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\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: 453\r\n
+  s>     \r\n
+  real URL is http://$LOCALIP:$HGPORT/redirected (glob)
+  s>     batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  sending heads command
+  s>     GET /redirected?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>     96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
+  response: [b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL']
+
+  $ killdaemons.py
+
+Now test a variation where we strip the query string from the redirect URL.
+(SCM Manager apparently did this and clients would recover from it)
+
+  $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
+  >    --config server.compressionengines=zlib \
+  >    --config testing.redirectqs=false \
+  >     serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
+  $ cat hg.pid > $DAEMON_PIDS
+
+  $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
+  > httprequest GET /redirector?cmd=capabilities
+  >     user-agent: test
+  > EOF
+  using raw connection to peer
+  s>     GET /redirector?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 301 Redirect\r\n
+  s>     Server: testing stub value\r\n
+  s>     Date: $HTTP_DATE$\r\n
+  s>     Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
+  s>     Content-Type: text/plain\r\n
+  s>     Content-Length: 10\r\n
+  s>     \r\n
+  s>     redirected
+  s>     GET /redirected 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>     ETag: W/"*"\r\n (glob)
+  s>     Content-Type: text/html; charset=ascii\r\n
+  s>     Transfer-Encoding: chunked\r\n
+  s>     \r\n
+  s>     414\r\n
+  s>     <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
+  s>     <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
+  s>     <head>\n
+  s>     <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
+  s>     <meta name="robots" content="index, nofollow" />\n
+  s>     <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
+  s>     <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
+  s>     \n
+  s>     <title>redirected: log</title>\n
+  s>     <link rel="alternate" type="application/atom+xml"\n
+  s>        href="/redirected/atom-log" title="Atom feed for redirected" />\n
+  s>     <link rel="alternate" type="application/rss+xml"\n
+  s>        href="/redirected/rss-log" title="RSS feed for redirected" />\n
+  s>     </head>\n
+  s>     <body>\n
+  s>     \n
+  s>     <div class="container">\n
+  s>     <div class="menu">\n
+  s>     <div class="logo">\n
+  s>     <a href="https://mercurial-scm.org/">\n
+  s>     <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
+  s>     </div>\n
+  s>     <ul>\n
+  s>     <li class="active">log</li>\n
+  s>     <li><a href="/redirected/graph/tip">graph</a></li>\n
+  s>     <li><a href="/redirected/tags">tags</a></li>\n
+  s>     <li><a href="
+  s>     \r\n
+  s>     810\r\n
+  s>     /redirected/bookmarks">bookmarks</a></li>\n
+  s>     <li><a href="/redirected/branches">branches</a></li>\n
+  s>     </ul>\n
+  s>     <ul>\n
+  s>     <li><a href="/redirected/rev/tip">changeset</a></li>\n
+  s>     <li><a href="/redirected/file/tip">browse</a></li>\n
+  s>     </ul>\n
+  s>     <ul>\n
+  s>     \n
+  s>     </ul>\n
+  s>     <ul>\n
+  s>      <li><a href="/redirected/help">help</a></li>\n
+  s>     </ul>\n
+  s>     <div class="atom-logo">\n
+  s>     <a href="/redirected/atom-log" title="subscribe to atom feed">\n
+  s>     <img class="atom-logo" src="/redirected/static/feed-icon-14x14.png" alt="atom feed" />\n
+  s>     </a>\n
+  s>     </div>\n
+  s>     </div>\n
+  s>     \n
+  s>     <div class="main">\n
+  s>     <h2 class="breadcrumb"><a href="/">Mercurial</a> &gt; <a href="/redirected">redirected</a> </h2>\n
+  s>     <h3>log</h3>\n
+  s>     \n
+  s>     \n
+  s>     <form class="search" action="/redirected/log">\n
+  s>     \n
+  s>     <p><input name="rev" id="search1" type="text" size="30" value="" /></p>\n
+  s>     <div id="hint">Find changesets by keywords (author, files, the commit message), revision\n
+  s>     number or hash, or <a href="/redirected/help/revsets">revset expression</a>.</div>\n
+  s>     </form>\n
+  s>     \n
+  s>     <div class="navigate">\n
+  s>     <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
+  s>     <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
+  s>     | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
+  s>     </div>\n
+  s>     \n
+  s>     <table class="bigtable">\n
+  s>     <thead>\n
+  s>      <tr>\n
+  s>       <th class="age">age</th>\n
+  s>       <th class="author">author</th>\n
+  s>       <th class="description">description</th>\n
+  s>      </tr>\n
+  s>     </thead>\n
+  s>     <tbody class="stripes2">\n
+  s>      <tr>\n
+  s>       <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>\n
+  s>       <td class="author">test</td>\n
+  s>       <td class="description">\n
+  s>        <a href="/redirected/rev/96ee1d7354c4">initial</a>\n
+  s>        <span class="phase">draft</span> <span class="branchhead">default</span> <span class="tag">tip</span> \n
+  s>       </td>\n
+  s>      </tr>\n
+  s>     \n
+  s>     </tbody>\n
+  s>     </table>\n
+  s>     \n
+  s>     <div class="navigate">\n
+  s>     <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
+  s>     <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
+  s>     | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
+  s>     </div>\n
+  s>     \n
+  s>     <script type="text/javascript">\n
+  s>         ajaxScrollInit(\n
+  s>                 \'/redirected/shortlog/%next%\',\n
+  s>                 \'\', <!-- NEXTHASH\n
+  s>                 function (htmlText) {
+  s>     \r\n
+  s>     14a\r\n
+  s>     \n
+  s>                     var m = htmlText.match(/\'(\\w+)\', <!-- NEXTHASH/);\n
+  s>                     return m ? m[1] : null;\n
+  s>                 },\n
+  s>                 \'.bigtable > tbody\',\n
+  s>                 \'<tr class="%class%">\\\n
+  s>                 <td colspan="3" style="text-align: center;">%text%</td>\\\n
+  s>                 </tr>\'\n
+  s>         );\n
+  s>     </script>\n
+  s>     \n
+  s>     </div>\n
+  s>     </div>\n
+  s>     \n
+  s>     \n
+  s>     \n
+  s>     </body>\n
+  s>     </html>\n
+  s>     \n
+  s>     \r\n
+  s>     0\r\n
+  s>     \r\n
+
+  $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
+  > command heads
+  > EOF
+  s>     GET /redirector?cmd=capabilities HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\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 301 Redirect\r\n
+  s>     Server: testing stub value\r\n
+  s>     Date: $HTTP_DATE$\r\n
+  s>     Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
+  s>     Content-Type: text/plain\r\n
+  s>     Content-Length: 10\r\n
+  s>     \r\n
+  s>     redirected
+  s>     GET /redirected HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\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>     ETag: W/"*"\r\n (glob)
+  s>     Content-Type: text/html; charset=ascii\r\n
+  s>     Transfer-Encoding: chunked\r\n
+  s>     \r\n
+  real URL is http://$LOCALIP:$HGPORT/redirected (glob)
+  s>     414\r\n
+  s>     <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
+  s>     <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
+  s>     <head>\n
+  s>     <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
+  s>     <meta name="robots" content="index, nofollow" />\n
+  s>     <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
+  s>     <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
+  s>     \n
+  s>     <title>redirected: log</title>\n
+  s>     <link rel="alternate" type="application/atom+xml"\n
+  s>        href="/redirected/atom-log" title="Atom feed for redirected" />\n
+  s>     <link rel="alternate" type="application/rss+xml"\n
+  s>        href="/redirected/rss-log" title="RSS feed for redirected" />\n
+  s>     </head>\n
+  s>     <body>\n
+  s>     \n
+  s>     <div class="container">\n
+  s>     <div class="menu">\n
+  s>     <div class="logo">\n
+  s>     <a href="https://mercurial-scm.org/">\n
+  s>     <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
+  s>     </div>\n
+  s>     <ul>\n
+  s>     <li class="active">log</li>\n
+  s>     <li><a href="/redirected/graph/tip">graph</a></li>\n
+  s>     <li><a href="/redirected/tags">tags</a
+  s>     GET /redirected?cmd=capabilities HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\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: 453\r\n
+  s>     \r\n
+  real URL is http://$LOCALIP:$HGPORT/redirected (glob)
+  s>     batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  sending heads command
+  s>     GET /redirected?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>     96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
+  response: [b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL']
--- a/tests/test-import.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-import.t	Sat May 05 18:06:45 2018 -0700
@@ -734,6 +734,42 @@
   $ hg revert -a
   reverting a
 
+Test --exact failure
+
+  $ sed 's/^# Parent .*/# Parent '"`hg log -r. -T '{node}'`"'/' \
+  > < fuzzy-tip.patch > fuzzy-reparent.patch
+  $ hg import --config patch.fuzz=0 --exact fuzzy-reparent.patch
+  applying fuzzy-reparent.patch
+  patching file a
+  Hunk #1 FAILED at 0
+  1 out of 1 hunks FAILED -- saving rejects to file a.rej
+  abort: patch failed to apply
+  [255]
+  $ hg up -qC
+  $ hg import --config patch.fuzz=2 --exact fuzzy-reparent.patch
+  applying fuzzy-reparent.patch
+  patching file a
+  Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
+  transaction abort!
+  rollback completed
+  abort: patch is damaged or loses information
+  [255]
+  $ hg up -qC
+
+  $ grep '^#' fuzzy-tip.patch > empty.patch
+  $ cat <<'EOF' >> empty.patch
+  > change
+  > 
+  > diff -r bb90ef1daa38 -r 0e9b883378d4 a
+  > --- a/a	Thu Jan 01 00:00:00 1970 +0000
+  > --- b/a	Thu Jan 01 00:00:00 1970 +0000
+  > EOF
+  $ hg import --exact empty.patch
+  applying empty.patch
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  abort: patch is damaged or loses information
+  [255]
+  $ hg up -qC
 
 import with --no-commit should have written .hg/last-message.txt
 
--- a/tests/test-infinitepush-bundlestore.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-infinitepush-bundlestore.t	Sat May 05 18:06:45 2018 -0700
@@ -281,7 +281,7 @@
   $ echo 1 > amend
   $ hg add amend
   $ hg ci --amend -m 'scratch amended commit'
-  saved backup bundle to $TESTTMP/client/.hg/strip-backup/6c10d49fe927-c99ffec5-amend.hg (glob)
+  saved backup bundle to $TESTTMP/client/.hg/strip-backup/6c10d49fe927-c99ffec5-amend.hg
   $ hg log -G -T '{desc} {phase} {bookmarks}'
   @  scratch amended commit draft scratch/mybranch
   |
--- a/tests/test-push-http.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-push-http.t	Sat May 05 18:06:45 2018 -0700
@@ -380,3 +380,47 @@
 #endif
 
   $ cd ..
+
+Pushing via hgwebdir works
+
+  $ hg init hgwebdir
+  $ cd hgwebdir
+  $ echo 0 > a
+  $ hg -q commit -A -m initial
+  $ cd ..
+
+  $ cat > web.conf << EOF
+  > [paths]
+  > / = *
+  > [web]
+  > push_ssl = false
+  > allow_push = *
+  > EOF
+
+  $ hg serve --web-conf web.conf -p $HGPORT -d --pid-file hg.pid
+  $ cat hg.pid >> $DAEMON_PIDS
+
+  $ hg clone http://localhost:$HGPORT/hgwebdir hgwebdir-local
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  new changesets 98a3f8f02ba7
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd hgwebdir-local
+  $ echo commit > a
+  $ hg commit -m 'local commit'
+
+  $ hg push
+  pushing to http://localhost:$HGPORT/hgwebdir
+  searching for changes
+  remote: adding changesets
+  remote: adding manifests
+  remote: adding file changes
+  remote: added 1 changesets with 1 changes to 1 files
+
+  $ killdaemons.py
+
+  $ cd ..
--- a/tests/test-serve.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-serve.t	Sat May 05 18:06:45 2018 -0700
@@ -78,4 +78,24 @@
   listening at http://localhost/foo/ (bound to *$LOCALIP*:HGPORT1) (glob) (?)
   % errors
 
+  $ $PYTHON $RUNTESTDIR/killdaemons.py $DAEMON_PIDS
+
+With out of bounds accesses
+
+  $ rm access.log
+  $ hg serve -a localhost -p $HGPORT -d --prefix some/dir \
+  >    --pid-file=hg.pid -E errors.log
+  $ cat hg.pid >> "$DAEMON_PIDS"
+
+  $ hg id http://localhost:$HGPORT/some/dir7
+  abort: HTTP Error 404: Not Found
+  [255]
+  $ hg id http://localhost:$HGPORT/some
+  abort: HTTP Error 404: Not Found
+  [255]
+
+  $ cat access.log errors.log
+  $LOCALIP - - [$LOGDATE$] "GET /some/dir7?cmd=capabilities HTTP/1.1" 404 - (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /some?cmd=capabilities HTTP/1.1" 404 - (glob)
+
   $ cd ..
--- a/tests/test-ssh-proto.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-ssh-proto.t	Sat May 05 18:06:45 2018 -0700
@@ -58,10 +58,9 @@
   $ hg --debug debugpeer ssh://user@dummy/server
   running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
   running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !)
-  devel-peer-request: hello
+  devel-peer-request: hello+between
+  devel-peer-request:   pairs: 81 bytes
   sending hello command
-  devel-peer-request: between
-  devel-peer-request:   pairs: 81 bytes
   sending between command
   remote: 413
   remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -170,10 +169,9 @@
   $ SSHSERVERMODE=banner hg --debug debugpeer ssh://user@dummy/server
   running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
   running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !)
-  devel-peer-request: hello
+  devel-peer-request: hello+between
+  devel-peer-request:   pairs: 81 bytes
   sending hello command
-  devel-peer-request: between
-  devel-peer-request:   pairs: 81 bytes
   sending between command
   remote: banner: line 0
   remote: banner: line 1
@@ -262,10 +260,9 @@
   $ SSHSERVERMODE=no-hello hg --debug debugpeer ssh://user@dummy/server
   running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
   running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !)
-  devel-peer-request: hello
+  devel-peer-request: hello+between
+  devel-peer-request:   pairs: 81 bytes
   sending hello command
-  devel-peer-request: between
-  devel-peer-request:   pairs: 81 bytes
   sending between command
   remote: 0
   remote: 1
@@ -310,10 +307,9 @@
   running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
   running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !)
   sending no-args command
-  devel-peer-request: hello
+  devel-peer-request: hello+between
+  devel-peer-request:   pairs: 81 bytes
   sending hello command
-  devel-peer-request: between
-  devel-peer-request:   pairs: 81 bytes
   sending between command
   remote: 0
   remote: 413
@@ -383,10 +379,9 @@
   sending unknown1 command
   sending unknown2 command
   sending unknown3 command
-  devel-peer-request: hello
+  devel-peer-request: hello+between
+  devel-peer-request:   pairs: 81 bytes
   sending hello command
-  devel-peer-request: between
-  devel-peer-request:   pairs: 81 bytes
   sending between command
   remote: 0
   remote: 0
@@ -958,10 +953,9 @@
   running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
   running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !)
   sending upgrade request: * proto=exp-ssh-v2-0001 (glob)
-  devel-peer-request: hello
+  devel-peer-request: hello+between
+  devel-peer-request:   pairs: 81 bytes
   sending hello command
-  devel-peer-request: between
-  devel-peer-request:   pairs: 81 bytes
   sending between command
   remote: 0
   remote: 413
@@ -1017,10 +1011,9 @@
   running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
   running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !)
   sending upgrade request: * proto=exp-ssh-v2-0001 (glob)
-  devel-peer-request: hello
+  devel-peer-request: hello+between
+  devel-peer-request:   pairs: 81 bytes
   sending hello command
-  devel-peer-request: between
-  devel-peer-request:   pairs: 81 bytes
   sending between command
   protocol upgraded to exp-ssh-v2-0001
   remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1037,10 +1030,9 @@
   running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
   running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !)
   sending upgrade request: * proto=exp-ssh-v2-0001 (glob)
-  devel-peer-request: hello
+  devel-peer-request: hello+between
+  devel-peer-request:   pairs: 81 bytes
   sending hello command
-  devel-peer-request: between
-  devel-peer-request:   pairs: 81 bytes
   sending between command
   protocol upgraded to exp-ssh-v2-0001
   remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
--- a/tests/test-ssh.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-ssh.t	Sat May 05 18:06:45 2018 -0700
@@ -490,10 +490,9 @@
   pulling from ssh://user@dummy/remote
   running .* ".*/dummyssh" ['"]user@dummy['"] ('|")hg -R remote serve --stdio('|") (re)
   sending upgrade request: * proto=exp-ssh-v2-0001 (glob) (sshv2 !)
-  devel-peer-request: hello
+  devel-peer-request: hello+between
+  devel-peer-request:   pairs: 81 bytes
   sending hello command
-  devel-peer-request: between
-  devel-peer-request:   pairs: 81 bytes
   sending between command
   remote: 413 (sshv1 !)
   protocol upgraded to exp-ssh-v2-0001 (sshv2 !)
--- a/tests/test-treediscovery.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-treediscovery.t	Sat May 05 18:06:45 2018 -0700
@@ -568,7 +568,6 @@
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
-  "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
   "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=686173686564+1827a5bb63e602382eb89dd58f2ac9f3b007ad91* (glob)
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
--- a/tests/test-wireproto-command-capabilities.t	Sun Mar 04 15:29:41 2018 -0500
+++ b/tests/test-wireproto-command-capabilities.t	Sat May 05 18:06:45 2018 -0700
@@ -1,6 +1,15 @@
   $ . $TESTDIR/wireprotohelpers.sh
 
   $ 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
 
@@ -21,7 +30,7 @@
   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: 458\r\n
+  s>     Content-Length: *\r\n (glob)
   s>     \r\n
   s>     batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
 
@@ -46,7 +55,7 @@
   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: 458\r\n
+  s>     Content-Length: *\r\n (glob)
   s>     \r\n
   s>     batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
 
@@ -82,7 +91,7 @@
   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: 458\r\n
+  s>     Content-Length: *\r\n (glob)
   s>     \r\n
   s>     batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
 
@@ -107,7 +116,7 @@
   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: 458\r\n
+  s>     Content-Length: *\r\n (glob)
   s>     \r\n
   s>     batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
 
@@ -132,9 +141,9 @@
   s>     Server: testing stub value\r\n
   s>     Date: $HTTP_DATE$\r\n
   s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: 496\r\n
+  s>     Content-Length: *\r\n (glob)
   s>     \r\n
-  s>     \xa3Dapis\xa0GapibaseDapi/Nv1capabilitiesY\x01\xcabatch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  s>     \xa3Dapis\xa0GapibaseDapi/Nv1capabilitiesY\x01\xc5batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   cbor> {b'apibase': b'api/', b'apis': {}, b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'}
 
 Restart server to enable HTTPv2
@@ -165,9 +174,9 @@
   s>     Server: testing stub value\r\n
   s>     Date: $HTTP_DATE$\r\n
   s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: 496\r\n
+  s>     Content-Length: *\r\n (glob)
   s>     \r\n
-  s>     \xa3Dapis\xa0GapibaseDapi/Nv1capabilitiesY\x01\xcabatch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  s>     \xa3Dapis\xa0GapibaseDapi/Nv1capabilitiesY\x01\xc5batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   cbor> {b'apibase': b'api/', b'apis': {}, b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'}
 
 Request for HTTPv2 service returns information about it
@@ -193,8 +202,8 @@
   s>     Content-Type: application/mercurial-cbor\r\n
   s>     Content-Length: *\r\n (glob)
   s>     \r\n
-  s>     \xa3Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x82\xa1DnameDzstd\xa1DnameDzlibNrawrepoformats\x82LgeneraldeltaHrevlogv1Qframingmediatypes\x81X&application/mercurial-exp-framing-0005GapibaseDapi/Nv1capabilitiesY\x01\xcabatch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  cbor> {b'apibase': b'api/', b'apis': {b'exp-http-v2-0001': {b'commands': {b'branchmap': {b'args': {}, b'permissions': [b'pull']}, b'capabilities': {b'args': {}, b'permissions': [b'pull']}, b'heads': {b'args': {b'publiconly': False}, b'permissions': [b'pull']}, b'known': {b'args': {b'nodes': [b'deadbeef']}, b'permissions': [b'pull']}, b'listkeys': {b'args': {b'namespace': b'ns'}, b'permissions': [b'pull']}, b'lookup': {b'args': {b'key': b'foo'}, b'permissions': [b'pull']}, b'pushkey': {b'args': {b'key': b'key', b'namespace': b'ns', b'new': b'new', b'old': b'old'}, b'permissions': [b'push']}}, b'compression': [{b'name': b'zstd'}, {b'name': b'zlib'}], b'framingmediatypes': [b'application/mercurial-exp-framing-0005'], b'rawrepoformats': [b'generaldelta', b'revlogv1']}}, b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'}
+  s>     \xa3Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x81\xa1DnameDzlibNrawrepoformats\x82LgeneraldeltaHrevlogv1Qframingmediatypes\x81X&application/mercurial-exp-framing-0005GapibaseDapi/Nv1capabilitiesY\x01\xc5batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  cbor> {b'apibase': b'api/', b'apis': {b'exp-http-v2-0001': {b'commands': {b'branchmap': {b'args': {}, b'permissions': [b'pull']}, b'capabilities': {b'args': {}, b'permissions': [b'pull']}, b'heads': {b'args': {b'publiconly': False}, b'permissions': [b'pull']}, b'known': {b'args': {b'nodes': [b'deadbeef']}, b'permissions': [b'pull']}, b'listkeys': {b'args': {b'namespace': b'ns'}, b'permissions': [b'pull']}, b'lookup': {b'args': {b'key': b'foo'}, b'permissions': [b'pull']}, b'pushkey': {b'args': {b'key': b'key', b'namespace': b'ns', b'new': b'new', b'old': b'old'}, b'permissions': [b'push']}}, b'compression': [{b'name': b'zlib'}], b'framingmediatypes': [b'application/mercurial-exp-framing-0005'], b'rawrepoformats': [b'generaldelta', b'revlogv1']}}, b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'}
 
 capabilities command returns expected info
 
@@ -218,7 +227,7 @@
   s>     Content-Type: application/mercurial-cbor\r\n
   s>     Content-Length: *\r\n (glob)
   s>     \r\n
-  s>     \xa3Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x82\xa1DnameDzstd\xa1DnameDzlibNrawrepoformats\x82LgeneraldeltaHrevlogv1Qframingmediatypes\x81X&application/mercurial-exp-framing-0005GapibaseDapi/Nv1capabilitiesY\x01\xcabatch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  s>     \xa3Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x81\xa1DnameDzlibNrawrepoformats\x82LgeneraldeltaHrevlogv1Qframingmediatypes\x81X&application/mercurial-exp-framing-0005GapibaseDapi/Nv1capabilitiesY\x01\xc5batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   sending capabilities command
   s>     POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
@@ -236,13 +245,13 @@
   s>     Content-Type: application/mercurial-exp-framing-0005\r\n
   s>     Transfer-Encoding: chunked\r\n
   s>     \r\n
-  s>     1e2\r\n
-  s>     \xda\x01\x00\x01\x00\x02\x012
-  s>     \xa1FstatusBok\xa4Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x82\xa1DnameDzstd\xa1DnameDzlibNrawrepoformats\x82LgeneraldeltaHrevlogv1Qframingmediatypes\x81X&application/mercurial-exp-framing-0005
+  s>     1d7\r\n
+  s>     \xcf\x01\x00\x01\x00\x02\x012
+  s>     \xa1FstatusBok\xa4Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x81\xa1DnameDzlibNrawrepoformats\x82LgeneraldeltaHrevlogv1Qframingmediatypes\x81X&application/mercurial-exp-framing-0005
   s>     \r\n
-  received frame(size=474; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=eos)
+  received frame(size=463; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=eos)
   s>     0\r\n
   s>     \r\n
-  response: [{b'status': b'ok'}, {b'commands': {b'branchmap': {b'args': {}, b'permissions': [b'pull']}, b'capabilities': {b'args': {}, b'permissions': [b'pull']}, b'heads': {b'args': {b'publiconly': False}, b'permissions': [b'pull']}, b'known': {b'args': {b'nodes': [b'deadbeef']}, b'permissions': [b'pull']}, b'listkeys': {b'args': {b'namespace': b'ns'}, b'permissions': [b'pull']}, b'lookup': {b'args': {b'key': b'foo'}, b'permissions': [b'pull']}, b'pushkey': {b'args': {b'key': b'key', b'namespace': b'ns', b'new': b'new', b'old': b'old'}, b'permissions': [b'push']}}, b'compression': [{b'name': b'zstd'}, {b'name': b'zlib'}], b'framingmediatypes': [b'application/mercurial-exp-framing-0005'], b'rawrepoformats': [b'generaldelta', b'revlogv1']}]
+  response: [{b'status': b'ok'}, {b'commands': {b'branchmap': {b'args': {}, b'permissions': [b'pull']}, b'capabilities': {b'args': {}, b'permissions': [b'pull']}, b'heads': {b'args': {b'publiconly': False}, b'permissions': [b'pull']}, b'known': {b'args': {b'nodes': [b'deadbeef']}, b'permissions': [b'pull']}, b'listkeys': {b'args': {b'namespace': b'ns'}, b'permissions': [b'pull']}, b'lookup': {b'args': {b'key': b'foo'}, b'permissions': [b'pull']}, b'pushkey': {b'args': {b'key': b'key', b'namespace': b'ns', b'new': b'new', b'old': b'old'}, b'permissions': [b'push']}}, b'compression': [{b'name': b'zlib'}], b'framingmediatypes': [b'application/mercurial-exp-framing-0005'], b'rawrepoformats': [b'generaldelta', b'revlogv1']}]
 
   $ cat error.log