changeset 30417:854190becacb

merge with stable
author Augie Fackler <augie@google.com>
date Wed, 16 Nov 2016 23:29:28 -0500
parents c27614f2dec1 (diff) e0ff47999b13 (current diff)
children 1156ec81f709
files mercurial/scmutil.py mercurial/util.py
diffstat 134 files changed, 3136 insertions(+), 1452 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Sun Nov 13 06:12:22 2016 +0900
+++ b/.hgignore	Wed Nov 16 23:29:28 2016 -0500
@@ -49,6 +49,7 @@
 tags
 cscope.*
 .idea/*
+.asv/*
 i18n/hg.pot
 locale/*/LC_MESSAGES/hg.mo
 hgext/__index__.py
--- a/Makefile	Sun Nov 13 06:12:22 2016 +0900
+++ b/Makefile	Wed Nov 16 23:29:28 2016 -0500
@@ -207,6 +207,12 @@
 docker-ubuntu-xenial-ppa: contrib/docker/ubuntu-xenial
 	contrib/dockerdeb ubuntu xenial --source-only
 
+docker-ubuntu-yakkety: contrib/docker/ubuntu-yakkety
+	contrib/dockerdeb ubuntu yakkety
+
+docker-ubuntu-yakkety-ppa: contrib/docker/ubuntu-yakkety
+	contrib/dockerdeb ubuntu yakkety --source-only
+
 fedora20:
 	mkdir -p packages/fedora20
 	contrib/buildrpm
--- a/contrib/all-revsets.txt	Sun Nov 13 06:12:22 2016 +0900
+++ b/contrib/all-revsets.txt	Wed Nov 16 23:29:28 2016 -0500
@@ -8,7 +8,7 @@
 #
 # Please update this file with any revsets you use for benchmarking a change so
 # that future contributors can easily find and retest it when doing further
-# modification. Feel free to highlight interresting variants if needed.
+# modification. Feel free to highlight interesting variants if needed.
 
 
 ## Revset from this section are all extracted from changelog when this file was
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/asv.conf.json	Wed Nov 16 23:29:28 2016 -0500
@@ -0,0 +1,13 @@
+{
+    "version": 1,
+    "project": "mercurial",
+    "project_url": "https://mercurial-scm.org/",
+    "repo": "..",
+    "branches": ["default", "stable"],
+    "environment_type": "virtualenv",
+    "show_commit_url": "https://www.mercurial-scm.org/repo/hg/rev/",
+    "benchmark_dir": "benchmarks",
+    "env_dir": "../.asv/env",
+    "results_dir": "../.asv/results",
+    "html_dir": "../.asv/html"
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/benchmarks/__init__.py	Wed Nov 16 23:29:28 2016 -0500
@@ -0,0 +1,102 @@
+# __init__.py - asv benchmark suite
+#
+# Copyright 2016 Logilab SA <contact@logilab.fr>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+'''ASV (https://asv.readthedocs.io) benchmark suite
+
+Benchmark are parameterized against reference repositories found in the
+directory pointed by the REPOS_DIR environment variable.
+
+Invocation example:
+
+    $ export REPOS_DIR=~/hgperf/repos
+    # run suite on given revision
+    $ asv --config contrib/asv.conf.json run REV
+    # run suite on new changesets found in stable and default branch
+    $ asv --config contrib/asv.conf.json run NEW
+    # display a comparative result table of benchmark results between two given
+    # revisions
+    $ asv --config contrib/asv.conf.json compare REV1 REV2
+    # compute regression detection and generate ASV static website
+    $ asv --config contrib/asv.conf.json publish
+    # serve the static website
+    $ asv --config contrib/asv.conf.json preview
+'''
+
+from __future__ import absolute_import
+
+import functools
+import os
+import re
+
+from mercurial import (
+    extensions,
+    hg,
+    ui as uimod,
+)
+
+basedir = os.path.abspath(os.path.join(os.path.dirname(__file__),
+                          os.path.pardir, os.path.pardir))
+reposdir = os.environ['REPOS_DIR']
+reposnames = [name for name in os.listdir(reposdir)
+              if os.path.isdir(os.path.join(reposdir, name, ".hg"))]
+if not reposnames:
+    raise ValueError("No repositories found in $REPO_DIR")
+outputre = re.compile((r'! wall (\d+.\d+) comb \d+.\d+ user \d+.\d+ sys '
+                       r'\d+.\d+ \(best of \d+\)'))
+
+def runperfcommand(reponame, command, *args, **kwargs):
+    os.environ["HGRCPATH"] = os.environ.get("ASVHGRCPATH", "")
+    ui = uimod.ui()
+    repo = hg.repository(ui, os.path.join(reposdir, reponame))
+    perfext = extensions.load(ui, 'perfext',
+                              os.path.join(basedir, 'contrib', 'perf.py'))
+    cmd = getattr(perfext, command)
+    ui.pushbuffer()
+    cmd(ui, repo, *args, **kwargs)
+    output = ui.popbuffer()
+    match = outputre.search(output)
+    if not match:
+        raise ValueError("Invalid output {0}".format(output))
+    return float(match.group(1))
+
+def perfbench(repos=reposnames, name=None, params=None):
+    """decorator to declare ASV benchmark based on contrib/perf.py extension
+
+    An ASV benchmark is a python function with the given attributes:
+
+    __name__: should start with track_, time_ or mem_ to be collected by ASV
+    params and param_name: parameter matrix to display multiple graphs on the
+    same page.
+    pretty_name: If defined it's displayed in web-ui instead of __name__
+    (useful for revsets)
+    the module name is prepended to the benchmark name and displayed as
+    "category" in webui.
+
+    Benchmarks are automatically parameterized with repositories found in the
+    REPOS_DIR environment variable.
+
+    `params` is the param matrix in the form of a list of tuple
+    (param_name, [value0, value1])
+
+    For example [(x, [a, b]), (y, [c, d])] declare benchmarks for
+    (a, c), (a, d), (b, c) and (b, d).
+    """
+    params = list(params or [])
+    params.insert(0, ("repo", repos))
+
+    def decorator(func):
+        @functools.wraps(func)
+        def wrapped(repo, *args):
+            def perf(command, *a, **kw):
+                return runperfcommand(repo, command, *a, **kw)
+            return func(perf, *args)
+
+        wrapped.params = [p[1] for p in params]
+        wrapped.param_names = [p[0] for p in params]
+        wrapped.pretty_name = name
+        return wrapped
+    return decorator
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/benchmarks/perf.py	Wed Nov 16 23:29:28 2016 -0500
@@ -0,0 +1,26 @@
+# perf.py - asv benchmarks using contrib/perf.py extension
+#
+# Copyright 2016 Logilab SA <contact@logilab.fr>
+#
+# 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 . import perfbench
+
+@perfbench()
+def track_tags(perf):
+    return perf("perftags")
+
+@perfbench()
+def track_status(perf):
+    return perf("perfstatus", unknown=False)
+
+@perfbench(params=[('rev', ['1000', '10000', 'tip'])])
+def track_manifest(perf, rev):
+    return perf("perfmanifest", rev)
+
+@perfbench()
+def track_heads(perf):
+    return perf("perfheads")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/benchmarks/revset.py	Wed Nov 16 23:29:28 2016 -0500
@@ -0,0 +1,53 @@
+# revset.py - asv revset benchmarks
+#
+# Copyright 2016 Logilab SA <contact@logilab.fr>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+'''ASV revset benchmarks generated from contrib/base-revsets.txt
+
+Each revset benchmark is parameterized with variants (first, last, sort, ...)
+'''
+
+from __future__ import absolute_import
+
+import os
+import string
+import sys
+
+from . import basedir, perfbench
+
+def createrevsetbenchmark(baseset, variants=None):
+    if variants is None:
+        # Default variants
+        variants = ["plain", "first", "last", "sort", "sort+first",
+                    "sort+last"]
+    fname = "track_" + "_".join("".join([
+        c if c in string.digits + string.letters else " "
+        for c in baseset
+    ]).split())
+
+    def wrap(fname, baseset):
+        @perfbench(name=baseset, params=[("variant", variants)])
+        def f(perf, variant):
+            revset = baseset
+            if variant != "plain":
+                for var in variant.split("+"):
+                    revset = "%s(%s)" % (var, revset)
+            return perf("perfrevset", revset)
+        f.__name__ = fname
+        return f
+    return wrap(fname, baseset)
+
+def initializerevsetbenchmarks():
+    mod = sys.modules[__name__]
+    with open(os.path.join(basedir, 'contrib', 'base-revsets.txt'),
+              'rb') as fh:
+        for line in fh:
+            baseset = line.strip()
+            if baseset and not baseset.startswith('#'):
+                func = createrevsetbenchmark(baseset)
+                setattr(mod, func.__name__, func)
+
+initializerevsetbenchmarks()
--- a/contrib/debugshell.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/contrib/debugshell.py	Wed Nov 16 23:29:28 2016 -0500
@@ -18,7 +18,7 @@
         'mercurial': mercurial,
         'repo': repo,
         'cl': repo.changelog,
-        'mf': repo.manifest,
+        'mf': repo.manifestlog,
     }
 
     code.interact(msg, local=objects)
@@ -27,7 +27,7 @@
     import IPython
 
     cl = repo.changelog
-    mf = repo.manifest
+    mf = repo.manifestlog
     cl, mf # use variables to appease pyflakes
 
     IPython.embed()
--- a/contrib/memory.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/contrib/memory.py	Wed Nov 16 23:29:28 2016 -0500
@@ -25,8 +25,8 @@
             key = parts[0][2:-1].lower()
             if key in result:
                 result[key] = int(parts[1])
-    ui.write_err(", ".join(["%s: %.1f MiB" % (key, value / 1024.0)
-                            for key, value in result.iteritems()]) + "\n")
+    ui.write_err(", ".join(["%s: %.1f MiB" % (k, v / 1024.0)
+                            for k, v in result.iteritems()]) + "\n")
 
 def extsetup(ui):
     atexit.register(memusage, ui)
--- a/contrib/perf.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/contrib/perf.py	Wed Nov 16 23:29:28 2016 -0500
@@ -25,6 +25,7 @@
 import sys
 import time
 from mercurial import (
+    bdiff,
     changegroup,
     cmdutil,
     commands,
@@ -135,13 +136,14 @@
 
     if opts is None:
         opts = {}
-    # redirect all to stderr
-    ui = ui.copy()
-    uifout = safeattrsetter(ui, 'fout', ignoremissing=True)
-    if uifout:
-        # for "historical portability":
-        # ui.fout/ferr have been available since 1.9 (or 4e1ccd4c2b6d)
-        uifout.set(ui.ferr)
+    # redirect all to stderr unless buffer api is in use
+    if not ui._buffers:
+        ui = ui.copy()
+        uifout = safeattrsetter(ui, 'fout', ignoremissing=True)
+        if uifout:
+            # for "historical portability":
+            # ui.fout/ferr have been available since 1.9 (or 4e1ccd4c2b6d)
+            uifout.set(ui.ferr)
 
     # get a formatter
     uiformatter = getattr(ui, 'formatter', None)
@@ -565,8 +567,8 @@
     ctx = scmutil.revsingle(repo, rev, rev)
     t = ctx.manifestnode()
     def d():
-        repo.manifest.clearcaches()
-        repo.manifest.read(t)
+        repo.manifestlog.clearcaches()
+        repo.manifestlog[t].read()
     timer(d)
     fm.end()
 
@@ -746,6 +748,64 @@
     timer(d)
     fm.end()
 
+@command('perfbdiff', revlogopts + formatteropts + [
+    ('', 'count', 1, 'number of revisions to test (when using --startrev)'),
+    ('', 'alldata', False, 'test bdiffs for all associated revisions')],
+    '-c|-m|FILE REV')
+def perfbdiff(ui, repo, file_, rev=None, count=None, **opts):
+    """benchmark a bdiff between revisions
+
+    By default, benchmark a bdiff between its delta parent and itself.
+
+    With ``--count``, benchmark bdiffs between delta parents and self for N
+    revisions starting at the specified revision.
+
+    With ``--alldata``, assume the requested revision is a changeset and
+    measure bdiffs for all changes related to that changeset (manifest
+    and filelogs).
+    """
+    if opts['alldata']:
+        opts['changelog'] = True
+
+    if opts.get('changelog') or opts.get('manifest'):
+        file_, rev = None, file_
+    elif rev is None:
+        raise error.CommandError('perfbdiff', 'invalid arguments')
+
+    textpairs = []
+
+    r = cmdutil.openrevlog(repo, 'perfbdiff', file_, opts)
+
+    startrev = r.rev(r.lookup(rev))
+    for rev in range(startrev, min(startrev + count, len(r) - 1)):
+        if opts['alldata']:
+            # Load revisions associated with changeset.
+            ctx = repo[rev]
+            mtext = repo.manifest.revision(ctx.manifestnode())
+            for pctx in ctx.parents():
+                pman = repo.manifest.revision(pctx.manifestnode())
+                textpairs.append((pman, mtext))
+
+            # Load filelog revisions by iterating manifest delta.
+            man = ctx.manifest()
+            pman = ctx.p1().manifest()
+            for filename, change in pman.diff(man).items():
+                fctx = repo.file(filename)
+                f1 = fctx.revision(change[0][0] or -1)
+                f2 = fctx.revision(change[1][0] or -1)
+                textpairs.append((f1, f2))
+        else:
+            dp = r.deltaparent(rev)
+            textpairs.append((r.revision(dp), r.revision(rev)))
+
+    def d():
+        for pair in textpairs:
+            bdiff.bdiff(*pair)
+
+    timer, fm = gettimer(ui, opts)
+    timer(d)
+    fm.end()
+
 @command('perfdiffwd', formatteropts)
 def perfdiffwd(ui, repo, **opts):
     """Profile diff of working directory changes"""
--- a/contrib/vim/patchreview.vim	Sun Nov 13 06:12:22 2016 +0900
+++ b/contrib/vim/patchreview.vim	Wed Nov 16 23:29:28 2016 -0500
@@ -720,7 +720,7 @@
     let s:origtabpagenr = tabpagenr()
     silent! exe 'tabedit ' . StrippedRelativeFilePath
     if exists('patchcmd')
-      " modelines in loaded files mess with diff comparision
+      " modelines in loaded files mess with diff comparison
       let s:keep_modeline=&modeline
       let &modeline=0
       silent! exe 'vert diffsplit ' . tmpname . '.file'
--- a/hgext/chgserver.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/chgserver.py	Wed Nov 16 23:29:28 2016 -0500
@@ -629,7 +629,7 @@
 
 def chgunixservice(ui, repo, opts):
     if repo:
-        # one chgserver can serve multiple repos. drop repo infomation
+        # one chgserver can serve multiple repos. drop repo information
         ui.setconfig('bundle', 'mainreporoot', '', 'repo')
     h = chgunixservicehandler(ui)
     return commandserver.unixforkingservice(ui, repo=None, opts=opts, handler=h)
--- a/hgext/color.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/color.py	Wed Nov 16 23:29:28 2016 -0500
@@ -275,8 +275,8 @@
 
     def modewarn():
         # only warn if color.mode was explicitly set and we're in
-        # an interactive terminal
-        if mode == realmode and ui.interactive():
+        # a formatted terminal
+        if mode == realmode and ui.formatted():
             ui.warn(_('warning: failed to set color mode to %s\n') % mode)
 
     if realmode == 'win32':
@@ -502,8 +502,8 @@
                 effects.append(l)
         effects = ' '.join(effects)
         if effects:
-            return '\n'.join([render_effects(s, effects)
-                              for s in msg.split('\n')])
+            return '\n'.join([render_effects(line, effects)
+                              for line in msg.split('\n')])
         return msg
 
 def uisetup(ui):
@@ -536,22 +536,50 @@
          _("when to colorize (boolean, always, auto, never, or debug)"),
          _('TYPE')))
 
-@command('debugcolor', [], 'hg debugcolor')
+@command('debugcolor',
+        [('', 'style', None, _('show all configured styles'))],
+        'hg debugcolor')
 def debugcolor(ui, repo, **opts):
+    """show available color, effects or style"""
+    ui.write(('color mode: %s\n') % ui._colormode)
+    if opts.get('style'):
+        return _debugdisplaystyle(ui)
+    else:
+        return _debugdisplaycolor(ui)
+
+def _debugdisplaycolor(ui):
     global _styles
-    _styles = {}
-    for effect in _effects.keys():
-        _styles[effect] = effect
-    if _terminfo_params:
-        for k, v in ui.configitems('color'):
-            if k.startswith('color.'):
-                _styles[k] = k[6:]
-            elif k.startswith('terminfo.'):
-                _styles[k] = k[9:]
-    ui.write(('color mode: %s\n') % ui._colormode)
-    ui.write(_('available colors:\n'))
-    for colorname, label in _styles.items():
-        ui.write(('%s\n') % colorname, label=label)
+    oldstyle = _styles
+    try:
+        _styles = {}
+        for effect in _effects.keys():
+            _styles[effect] = effect
+        if _terminfo_params:
+            for k, v in ui.configitems('color'):
+                if k.startswith('color.'):
+                    _styles[k] = k[6:]
+                elif k.startswith('terminfo.'):
+                    _styles[k] = k[9:]
+        ui.write(_('available colors:\n'))
+        # sort label with a '_' after the other to group '_background' entry.
+        items = sorted(_styles.items(),
+                       key=lambda i: ('_' in i[0], i[0], i[1]))
+        for colorname, label in items:
+            ui.write(('%s\n') % colorname, label=label)
+    finally:
+        _styles = oldstyle
+
+def _debugdisplaystyle(ui):
+    ui.write(_('available style:\n'))
+    width = max(len(s) for s in _styles)
+    for label, effects in sorted(_styles.items()):
+        ui.write('%s' % label, label=label)
+        if effects:
+            # 50
+            ui.write(': ')
+            ui.write(' ' * (max(0, width - len(label))))
+            ui.write(', '.join(ui.label(e, e) for e in effects.split()))
+        ui.write('\n')
 
 if os.name != 'nt':
     w32effects = None
--- a/hgext/convert/common.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/convert/common.py	Wed Nov 16 23:29:28 2016 -0500
@@ -454,7 +454,7 @@
             if err.errno != errno.ENOENT:
                 raise
             return
-        for i, line in enumerate(fp):
+        for i, line in enumerate(util.iterfile(fp)):
             line = line.splitlines()[0].rstrip()
             if not line:
                 # Ignore blank lines
--- a/hgext/convert/convcmd.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/convert/convcmd.py	Wed Nov 16 23:29:28 2016 -0500
@@ -201,7 +201,7 @@
         m = {}
         try:
             fp = open(path, 'r')
-            for i, line in enumerate(fp):
+            for i, line in enumerate(util.iterfile(fp)):
                 line = line.splitlines()[0].rstrip()
                 if not line:
                     # Ignore blank lines
--- a/hgext/convert/hg.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/convert/hg.py	Wed Nov 16 23:29:28 2016 -0500
@@ -352,7 +352,7 @@
             p2 = node
 
         if self.filemapmode and nparents == 1:
-            man = self.repo.manifest
+            man = self.repo.manifestlog._revlog
             mnode = self.repo.changelog.read(nodemod.bin(p2))[0]
             closed = 'close' in commit.extra
             if not closed and not man.cmp(m1node, man.revision(mnode)):
--- a/hgext/convert/subversion.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/convert/subversion.py	Wed Nov 16 23:29:28 2016 -0500
@@ -5,7 +5,6 @@
 
 import os
 import re
-import sys
 import tempfile
 import xml.dom.minidom
 
@@ -164,10 +163,8 @@
         raise error.Abort(_('debugsvnlog could not load Subversion python '
                            'bindings'))
 
-    util.setbinary(sys.stdin)
-    util.setbinary(sys.stdout)
-    args = decodeargs(sys.stdin.read())
-    get_log_child(sys.stdout, *args)
+    args = decodeargs(ui.fin.read())
+    get_log_child(ui.fout, *args)
 
 class logstream(object):
     """Interruptible revision log iterator."""
--- a/hgext/fsmonitor/__init__.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/fsmonitor/__init__.py	Wed Nov 16 23:29:28 2016 -0500
@@ -563,7 +563,7 @@
             pass
 
 class state_update(object):
-    ''' This context mananger is responsible for dispatching the state-enter
+    ''' This context manager is responsible for dispatching the state-enter
         and state-leave signals to the watchman service '''
 
     def __init__(self, repo, node, distance, partial):
--- a/hgext/histedit.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/histedit.py	Wed Nov 16 23:29:28 2016 -0500
@@ -173,7 +173,6 @@
 
 import errno
 import os
-import sys
 
 from mercurial.i18n import _
 from mercurial import (
@@ -991,9 +990,9 @@
         return goaleditplan
     return goalnew
 
-def _readfile(path):
+def _readfile(ui, path):
     if path == '-':
-        return sys.stdin.read()
+        return ui.fin.read()
     else:
         with open(path, 'rb') as f:
             return f.read()
@@ -1191,7 +1190,7 @@
                                  node.short(state.topmost))
         rules = ruleeditor(repo, ui, state.actions, comment)
     else:
-        rules = _readfile(rules)
+        rules = _readfile(ui, rules)
     actions = parserules(rules, state)
     ctxs = [repo[act.node] \
             for act in state.actions if act.node]
@@ -1232,7 +1231,7 @@
         actions = [pick(state, r) for r in revs]
         rules = ruleeditor(repo, ui, actions, comment)
     else:
-        rules = _readfile(rules)
+        rules = _readfile(ui, rules)
     actions = parserules(rules, state)
     warnverifyactions(ui, repo, actions, state, ctxs)
 
@@ -1406,12 +1405,12 @@
                        % node.short(missing[0]))
 
 def adjustreplacementsfrommarkers(repo, oldreplacements):
-    """Adjust replacements from obsolescense markers
+    """Adjust replacements from obsolescence markers
 
     Replacements structure is originally generated based on
     histedit's state and does not account for changes that are
     not recorded there. This function fixes that by adding
-    data read from obsolescense markers"""
+    data read from obsolescence markers"""
     if not obsolete.isenabled(repo, obsolete.createmarkersopt):
         return oldreplacements
 
--- a/hgext/keyword.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/keyword.py	Wed Nov 16 23:29:28 2016 -0500
@@ -737,6 +737,8 @@
             return ret
 
     def kwfilectx_cmp(orig, self, fctx):
+        if fctx._customcmp:
+            return fctx.cmp(self)
         # keyword affects data size, comparing wdir and filelog size does
         # not make sense
         if (fctx._filenode is None and
--- a/hgext/largefiles/lfcommands.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/largefiles/lfcommands.py	Wed Nov 16 23:29:28 2016 -0500
@@ -510,18 +510,21 @@
                 lfdirstate.normal(lfile)
                 update1 = 1
 
-            # copy the state of largefile standin from the repository's
+            # copy the exec mode of largefile standin from the repository's
             # dirstate to its state in the lfdirstate.
             rellfile = lfile
             relstandin = lfutil.standin(lfile)
             if wvfs.exists(relstandin):
+                # exec is decided by the users permissions using mask 0o100
                 standinexec = wvfs.stat(relstandin).st_mode & 0o100
-                st = wvfs.stat(rellfile).st_mode
-                if standinexec != st & 0o100:
-                    st &= ~0o111
+                st = wvfs.stat(rellfile)
+                mode = st.st_mode
+                if standinexec != mode & 0o100:
+                    # first remove all X bits, then shift all R bits to X
+                    mode &= ~0o111
                     if standinexec:
-                        st |= (st >> 2) & 0o111 & ~util.umask
-                    wvfs.chmod(rellfile, st)
+                        mode |= (mode >> 2) & 0o111 & ~util.umask
+                    wvfs.chmod(rellfile, mode)
                     update1 = 1
 
             updated += update1
--- a/hgext/logtoprocess.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/logtoprocess.py	Wed Nov 16 23:29:28 2016 -0500
@@ -27,7 +27,7 @@
 
 would log the warning message and traceback of any failed command dispatch.
 
-Scripts are run asychronously as detached daemon processes; mercurial will
+Scripts are run asynchronously as detached daemon processes; mercurial will
 not ensure that they exit cleanly.
 
 """
--- a/hgext/mq.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/mq.py	Wed Nov 16 23:29:28 2016 -0500
@@ -1660,7 +1660,7 @@
             # caching against the next repo.status call
             mm, aa, dd = repo.status(patchparent, top)[:3]
             changes = repo.changelog.read(top)
-            man = repo.manifest.read(changes[0])
+            man = repo.manifestlog[changes[0]].read()
             aaa = aa[:]
             matchfn = scmutil.match(repo[None], pats, opts)
             # in short mode, we only diff the files included in the
--- a/hgext/patchbomb.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/patchbomb.py	Wed Nov 16 23:29:28 2016 -0500
@@ -166,7 +166,7 @@
         while patchlines and not patchlines[0].strip():
             patchlines.pop(0)
 
-    ds = patch.diffstat(patchlines, git=opts.get('git'))
+    ds = patch.diffstat(patchlines)
     if opts.get('diffstat'):
         body += ds + '\n\n'
 
--- a/hgext/rebase.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/rebase.py	Wed Nov 16 23:29:28 2016 -0500
@@ -36,7 +36,7 @@
     extensions,
     hg,
     lock,
-    merge,
+    merge as mergemod,
     obsolete,
     patch,
     phases,
@@ -661,6 +661,9 @@
                     _('abort and continue do not allow specifying revisions'))
             if abortf and opts.get('tool', False):
                 ui.warn(_('tool option will be ignored\n'))
+            if contf:
+                ms = mergemod.mergestate.read(repo)
+                cmdutil.checkunresolved(ms)
 
             retcode = rbsrt._prepareabortorcontinue(abortf)
             if retcode is not None:
@@ -823,7 +826,7 @@
     # Update to target and merge it with local
     if repo['.'].rev() != p1:
         repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
-        merge.update(repo, p1, False, True)
+        mergemod.update(repo, p1, False, True)
     else:
         repo.ui.debug(" already in target\n")
     repo.dirstate.write(repo.currenttransaction())
@@ -832,8 +835,8 @@
         repo.ui.debug("   detach base %d:%s\n" % (base, repo[base]))
     # When collapsing in-place, the parent is the common ancestor, we
     # have to allow merging with it.
-    stats = merge.update(repo, rev, True, True, base, collapse,
-                        labels=['dest', 'source'])
+    stats = mergemod.update(repo, rev, True, True, base, collapse,
+                            labels=['dest', 'source'])
     if collapse:
         copies.duplicatecopies(repo, rev, target)
     else:
@@ -1150,7 +1153,7 @@
 
             # Update away from the rebase if necessary
             if shouldupdate or needupdate(repo, state):
-                merge.update(repo, originalwd, False, True)
+                mergemod.update(repo, originalwd, False, True)
 
             # Strip from the first rebased revision
             if rebased:
@@ -1382,7 +1385,7 @@
     """return a mapping obsolete => successor for all obsolete nodes to be
     rebased that have a successors in the destination
 
-    obsolete => None entries in the mapping indicate nodes with no succesor"""
+    obsolete => None entries in the mapping indicate nodes with no successor"""
     obsoletenotrebased = {}
 
     # Build a mapping successor => obsolete nodes for the obsolete
--- a/hgext/shelve.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/hgext/shelve.py	Wed Nov 16 23:29:28 2016 -0500
@@ -62,6 +62,11 @@
 
 backupdir = 'shelve-backup'
 shelvedir = 'shelved'
+shelvefileextensions = ['hg', 'patch']
+
+# we never need the user, so we use a
+# generic user for all shelve operations
+shelveuser = 'shelve@localhost'
 
 class shelvedfile(object):
     """Helper for the file storing a single shelve
@@ -221,7 +226,7 @@
             # keep it, because timestamp can't decide exact order of backups
             continue
         base = f[:-3]
-        for ext in 'hg patch'.split():
+        for ext in shelvefileextensions:
             try:
                 vfs.unlink(base + '.' + ext)
             except OSError as err:
@@ -242,24 +247,105 @@
         cmdutil.checkunfinished(repo)
         return _docreatecmd(ui, repo, pats, opts)
 
-def _docreatecmd(ui, repo, pats, opts):
-    def mutableancestors(ctx):
-        """return all mutable ancestors for ctx (included)
+def getshelvename(repo, parent, opts):
+    """Decide on the name this shelve is going to have"""
+    def gennames():
+        yield label
+        for i in xrange(1, 100):
+            yield '%s-%02d' % (label, i)
+    name = opts.get('name')
+    label = repo._activebookmark or parent.branch() or 'default'
+    # slashes aren't allowed in filenames, therefore we rename it
+    label = label.replace('/', '_')
+
+    if name:
+        if shelvedfile(repo, name, 'hg').exists():
+            e = _("a shelved change named '%s' already exists") % name
+            raise error.Abort(e)
+    else:
+        for n in gennames():
+            if not shelvedfile(repo, n, 'hg').exists():
+                name = n
+                break
+        else:
+            raise error.Abort(_("too many shelved changes named '%s'") % label)
+
+    # ensure we are not creating a subdirectory or a hidden file
+    if '/' in name or '\\' in name:
+        raise error.Abort(_('shelved change names may not contain slashes'))
+    if name.startswith('.'):
+        raise error.Abort(_("shelved change names may not start with '.'"))
+    return name
+
+def mutableancestors(ctx):
+    """return all mutable ancestors for ctx (included)
+
+    Much faster than the revset ancestors(ctx) & draft()"""
+    seen = set([nodemod.nullrev])
+    visit = collections.deque()
+    visit.append(ctx)
+    while visit:
+        ctx = visit.popleft()
+        yield ctx.node()
+        for parent in ctx.parents():
+            rev = parent.rev()
+            if rev not in seen:
+                seen.add(rev)
+                if parent.mutable():
+                    visit.append(parent)
 
-        Much faster than the revset ancestors(ctx) & draft()"""
-        seen = set([nodemod.nullrev])
-        visit = collections.deque()
-        visit.append(ctx)
-        while visit:
-            ctx = visit.popleft()
-            yield ctx.node()
-            for parent in ctx.parents():
-                rev = parent.rev()
-                if rev not in seen:
-                    seen.add(rev)
-                    if parent.mutable():
-                        visit.append(parent)
+def getcommitfunc(extra, interactive, editor=False):
+    def commitfunc(ui, repo, message, match, opts):
+        hasmq = util.safehasattr(repo, 'mq')
+        if hasmq:
+            saved, repo.mq.checkapplied = repo.mq.checkapplied, False
+        backup = repo.ui.backupconfig('phases', 'new-commit')
+        try:
+            repo.ui.setconfig('phases', 'new-commit', phases.secret)
+            editor_ = False
+            if editor:
+                editor_ = cmdutil.getcommiteditor(editform='shelve.shelve',
+                                                  **opts)
+            return repo.commit(message, shelveuser, opts.get('date'), match,
+                               editor=editor_, extra=extra)
+        finally:
+            repo.ui.restoreconfig(backup)
+            if hasmq:
+                repo.mq.checkapplied = saved
+
+    def interactivecommitfunc(ui, repo, *pats, **opts):
+        match = scmutil.match(repo['.'], pats, {})
+        message = opts['message']
+        return commitfunc(ui, repo, message, match, opts)
+
+    return interactivecommitfunc if interactive else commitfunc
 
+def _nothingtoshelvemessaging(ui, repo, pats, opts):
+    stat = repo.status(match=scmutil.match(repo[None], pats, opts))
+    if stat.deleted:
+        ui.status(_("nothing changed (%d missing files, see "
+                    "'hg status')\n") % len(stat.deleted))
+    else:
+        ui.status(_("nothing changed\n"))
+
+def _shelvecreatedcommit(repo, node, name):
+    bases = list(mutableancestors(repo[node]))
+    shelvedfile(repo, name, 'hg').writebundle(bases, node)
+    cmdutil.export(repo, [node],
+                   fp=shelvedfile(repo, name, 'patch').opener('wb'),
+                   opts=mdiff.diffopts(git=True))
+
+def _includeunknownfiles(repo, pats, opts, extra):
+    s = repo.status(match=scmutil.match(repo[None], pats, opts),
+                    unknown=True)
+    if s.unknown:
+        extra['shelve_unknown'] = '\0'.join(s.unknown)
+        repo[None].add(s.unknown)
+
+def _finishshelve(repo):
+    _aborttransaction(repo)
+
+def _docreatecmd(ui, repo, pats, opts):
     wctx = repo[None]
     parents = wctx.parents()
     if len(parents) > 1:
@@ -267,18 +353,6 @@
     parent = parents[0]
     origbranch = wctx.branch()
 
-    # we never need the user, so we use a generic user for all shelve operations
-    user = 'shelve@localhost'
-    label = repo._activebookmark or parent.branch() or 'default'
-
-    # slashes aren't allowed in filenames, therefore we rename it
-    label = label.replace('/', '_')
-
-    def gennames():
-        yield label
-        for i in xrange(1, 100):
-            yield '%s-%02d' % (label, i)
-
     if parent.node() != nodemod.nullid:
         desc = "changes to: %s" % parent.description().split('\n', 1)[0]
     else:
@@ -287,8 +361,6 @@
     if not opts.get('message'):
         opts['message'] = desc
 
-    name = opts.get('name')
-
     lock = tr = None
     try:
         lock = repo.lock()
@@ -297,81 +369,31 @@
         # pull races. ensure we don't print the abort message to stderr.
         tr = repo.transaction('commit', report=lambda x: None)
 
-        if name:
-            if shelvedfile(repo, name, 'hg').exists():
-                raise error.Abort(_("a shelved change named '%s' already exists"
-                                   ) % name)
-        else:
-            for n in gennames():
-                if not shelvedfile(repo, n, 'hg').exists():
-                    name = n
-                    break
-            else:
-                raise error.Abort(_("too many shelved changes named '%s'") %
-                                 label)
-
-        # ensure we are not creating a subdirectory or a hidden file
-        if '/' in name or '\\' in name:
-            raise error.Abort(_('shelved change names may not contain slashes'))
-        if name.startswith('.'):
-            raise error.Abort(_("shelved change names may not start with '.'"))
         interactive = opts.get('interactive', False)
         includeunknown = (opts.get('unknown', False) and
                           not opts.get('addremove', False))
 
-        extra={}
+        name = getshelvename(repo, parent, opts)
+        extra = {}
         if includeunknown:
-            s = repo.status(match=scmutil.match(repo[None], pats, opts),
-                            unknown=True)
-            if s.unknown:
-                extra['shelve_unknown'] = '\0'.join(s.unknown)
-                repo[None].add(s.unknown)
+            _includeunknownfiles(repo, pats, opts, extra)
 
         if _iswctxonnewbranch(repo) and not _isbareshelve(pats, opts):
             # In non-bare shelve we don't store newly created branch
             # at bundled commit
             repo.dirstate.setbranch(repo['.'].branch())
 
-        def commitfunc(ui, repo, message, match, opts):
-            hasmq = util.safehasattr(repo, 'mq')
-            if hasmq:
-                saved, repo.mq.checkapplied = repo.mq.checkapplied, False
-            backup = repo.ui.backupconfig('phases', 'new-commit')
-            try:
-                repo.ui. setconfig('phases', 'new-commit', phases.secret)
-                editor = cmdutil.getcommiteditor(editform='shelve.shelve',
-                                                 **opts)
-                return repo.commit(message, user, opts.get('date'), match,
-                                   editor=editor, extra=extra)
-            finally:
-                repo.ui.restoreconfig(backup)
-                if hasmq:
-                    repo.mq.checkapplied = saved
-
-        def interactivecommitfunc(ui, repo, *pats, **opts):
-            match = scmutil.match(repo['.'], pats, {})
-            message = opts['message']
-            return commitfunc(ui, repo, message, match, opts)
+        commitfunc = getcommitfunc(extra, interactive, editor=True)
         if not interactive:
             node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
         else:
-            node = cmdutil.dorecord(ui, repo, interactivecommitfunc, None,
+            node = cmdutil.dorecord(ui, repo, commitfunc, None,
                                     False, cmdutil.recordfilter, *pats, **opts)
         if not node:
-            stat = repo.status(match=scmutil.match(repo[None], pats, opts))
-            if stat.deleted:
-                ui.status(_("nothing changed (%d missing files, see "
-                            "'hg status')\n") % len(stat.deleted))
-            else:
-                ui.status(_("nothing changed\n"))
+            _nothingtoshelvemessaging(ui, repo, pats, opts)
             return 1
 
-        bases = list(mutableancestors(repo[node]))
-        shelvedfile(repo, name, 'hg').writebundle(bases, node)
-        cmdutil.export(repo, [node],
-                       fp=shelvedfile(repo, name, 'patch').opener('wb'),
-                       opts=mdiff.diffopts(git=True))
-
+        _shelvecreatedcommit(repo, node, name)
 
         if ui.formatted():
             desc = util.ellipsis(desc, ui.termwidth())
@@ -380,7 +402,7 @@
         if origbranch != repo['.'].branch() and not _isbareshelve(pats, opts):
             repo.dirstate.setbranch(origbranch)
 
-        _aborttransaction(repo)
+        _finishshelve(repo)
     finally:
         lockmod.release(tr, lock)
 
@@ -399,7 +421,7 @@
     with repo.wlock():
         for (name, _type) in repo.vfs.readdir(shelvedir):
             suffix = name.rsplit('.', 1)[-1]
-            if suffix in ('hg', 'patch'):
+            if suffix in shelvefileextensions:
                 shelvedfile(repo, name).movetobackup()
             cleanupoldbackups(repo)
 
@@ -410,8 +432,15 @@
     with repo.wlock():
         try:
             for name in pats:
-                for suffix in 'hg patch'.split():
-                    shelvedfile(repo, name, suffix).movetobackup()
+                for suffix in shelvefileextensions:
+                    shfile = shelvedfile(repo, name, suffix)
+                    # patch file is necessary, as it should
+                    # be present for any kind of shelve,
+                    # but the .hg file is optional as in future we
+                    # will add obsolete shelve with does not create a
+                    # bundle
+                    if shfile.exists() or suffix == 'patch':
+                        shfile.movetobackup()
             cleanupoldbackups(repo)
         except OSError as err:
             if err.errno != errno.ENOENT:
@@ -476,8 +505,7 @@
                 for chunk, label in patch.difflabel(iter, difflines):
                     ui.write(chunk, label=label)
             if opts['stat']:
-                for chunk, label in patch.diffstatui(difflines, width=width,
-                                                     git=True):
+                for chunk, label in patch.diffstatui(difflines, width=width):
                     ui.write(chunk, label=label)
 
 def singlepatchcmds(ui, repo, pats, opts, subcommand):
@@ -557,8 +585,10 @@
 def unshelvecleanup(ui, repo, name, opts):
     """remove related files after an unshelve"""
     if not opts.get('keep'):
-        for filetype in 'hg patch'.split():
-            shelvedfile(repo, name, filetype).movetobackup()
+        for filetype in shelvefileextensions:
+            shfile = shelvedfile(repo, name, filetype)
+            if shfile.exists():
+                shfile.movetobackup()
         cleanupoldbackups(repo)
 
 def unshelvecontinue(ui, repo, state, opts):
@@ -729,21 +759,8 @@
         if s.modified or s.added or s.removed or s.deleted:
             ui.status(_("temporarily committing pending changes "
                         "(restore with 'hg unshelve --abort')\n"))
-            def commitfunc(ui, repo, message, match, opts):
-                hasmq = util.safehasattr(repo, 'mq')
-                if hasmq:
-                    saved, repo.mq.checkapplied = repo.mq.checkapplied, False
-
-                backup = repo.ui.backupconfig('phases', 'new-commit')
-                try:
-                    repo.ui.setconfig('phases', 'new-commit', phases.secret)
-                    return repo.commit(message, 'shelve@localhost',
-                                       opts.get('date'), match)
-                finally:
-                    repo.ui.restoreconfig(backup)
-                    if hasmq:
-                        repo.mq.checkapplied = saved
-
+            commitfunc = getcommitfunc(extra=None, interactive=False,
+                                       editor=False)
             tempopts = {}
             tempopts['message'] = "pending changes temporary commit"
             tempopts['date'] = opts.get('date')
--- a/i18n/ja.po	Sun Nov 13 06:12:22 2016 +0900
+++ b/i18n/ja.po	Wed Nov 16 23:29:28 2016 -0500
@@ -6747,7 +6747,7 @@
 msgstr ""
 
 msgid ""
-"Scripts are run asychronously as detached daemon processes; mercurial will\n"
+"Scripts are run asynchronously as detached daemon processes; mercurial will\n"
 "not ensure that they exit cleanly."
 msgstr ""
 
@@ -10366,7 +10366,7 @@
 msgstr "shelve 状態管理ファイルが破損しています"
 
 msgid "please run hg unshelve --abort to abort unshelve operation"
-msgstr "'hg unshelve --abort' を実施して unshleve 操作を中断してください"
+msgstr "'hg unshelve --abort' を実施して unshelve 操作を中断してください"
 
 msgid ""
 "could not read shelved state file, your working copy may be in an unexpected "
@@ -14200,7 +14200,7 @@
 msgstr "トランザクション実施途中は廃止マーカを破棄できません"
 
 #, python-format
-msgid "deleted %i obsolescense markers\n"
+msgid "deleted %i obsolescence markers\n"
 msgstr "%i 個の廃止マーカを破棄\n"
 
 #, python-format
@@ -32665,8 +32665,8 @@
 msgid "revset expects one or more arguments"
 msgstr "revset の引数は1個以上です"
 
-msgid ":rstdoc(text, style): Format ReStructuredText."
-msgstr ":rstdoc(text, style): 出力を ReStructuredText として整形します。"
+msgid ":rstdoc(text, style): Format reStructuredText."
+msgstr ":rstdoc(text, style): 出力を reStructuredText として整形します。"
 
 #. i18n: "rstdoc" is a keyword
 msgid "rstdoc expects two arguments"
--- a/i18n/pt_BR.po	Sun Nov 13 06:12:22 2016 +0900
+++ b/i18n/pt_BR.po	Wed Nov 16 23:29:28 2016 -0500
@@ -6761,7 +6761,7 @@
 "falhasse."
 
 msgid ""
-"Scripts are run asychronously as detached daemon processes; mercurial will\n"
+"Scripts are run asynchronously as detached daemon processes; mercurial will\n"
 "not ensure that they exit cleanly."
 msgstr ""
 "Os scripts são executados assincronamente como processos desanexados;\n"
@@ -14438,7 +14438,7 @@
 "não é possível apagar marcações de obsolescência durante uma transação."
 
 #, python-format
-msgid "deleted %i obsolescense markers\n"
+msgid "deleted %i obsolescence markers\n"
 msgstr "%i marcações de obsolescência apagadas\n"
 
 #, python-format
@@ -33523,8 +33523,8 @@
 msgid "revset expects one or more arguments"
 msgstr "revset espera um ou mais argumentos"
 
-msgid ":rstdoc(text, style): Format ReStructuredText."
-msgstr ":rstdoc(texto, estilo): Formata ReStructuredText."
+msgid ":rstdoc(text, style): Format reStructuredText."
+msgstr ":rstdoc(texto, estilo): Formata reStructuredText."
 
 #. i18n: "rstdoc" is a keyword
 msgid "rstdoc expects two arguments"
--- a/mercurial/bdiff.c	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/bdiff.c	Wed Nov 16 23:29:28 2016 -0500
@@ -17,6 +17,10 @@
 #include "bitmanipulation.h"
 #include "bdiff.h"
 
+/* Hash implementation from diffutils */
+#define ROL(v, n) ((v) << (n) | (v) >> (sizeof(v) * CHAR_BIT - (n)))
+#define HASH(h, c) ((c) + ROL(h ,7))
+
 struct pos {
 	int pos, len;
 };
@@ -31,9 +35,11 @@
 
 	/* count the lines */
 	i = 1; /* extra line for sentinel */
-	for (p = a; p < a + len; p++)
-		if (*p == '\n' || p == plast)
+	for (p = a; p < plast; p++)
+		if (*p == '\n')
 			i++;
+	if (p == plast)
+		i++;
 
 	*lr = l = (struct bdiff_line *)malloc(sizeof(struct bdiff_line) * i);
 	if (!l)
@@ -42,8 +48,7 @@
 	/* build the line array and calculate hashes */
 	hash = 0;
 	for (p = a; p < a + len; p++) {
-		/* Leonid Yuriev's hash */
-		hash = (hash * 1664525) + (unsigned char)*p + 1013904223;
+		hash = HASH(hash, *p);
 
 		if (*p == '\n' || p == plast) {
 			l->hash = hash;
--- a/mercurial/bundle2.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/bundle2.py	Wed Nov 16 23:29:28 2016 -0500
@@ -485,11 +485,11 @@
     return '\n'.join(chunks)
 
 bundletypes = {
-    "": ("", None),       # only when using unbundle on ssh and old http servers
+    "": ("", 'UN'),       # only when using unbundle on ssh and old http servers
                           # since the unification ssh accepts a header but there
                           # is no capability signaling it.
     "HG20": (), # special-cased below
-    "HG10UN": ("HG10UN", None),
+    "HG10UN": ("HG10UN", 'UN'),
     "HG10BZ": ("HG10", 'BZ'),
     "HG10GZ": ("HG10GZ", 'GZ'),
 }
@@ -511,7 +511,7 @@
         self._params = []
         self._parts = []
         self.capabilities = dict(capabilities)
-        self._compressor = util.compressors[None]()
+        self._compengine = util.compengines.forbundletype('UN')
 
     def setcompression(self, alg):
         """setup core part compression to <alg>"""
@@ -519,7 +519,7 @@
             return
         assert not any(n.lower() == 'Compression' for n, v in self._params)
         self.addparam('Compression', alg)
-        self._compressor = util.compressors[alg]()
+        self._compengine = util.compengines.forbundletype(alg)
 
     @property
     def nbparts(self):
@@ -571,12 +571,8 @@
         yield _pack(_fstreamparamsize, len(param))
         if param:
             yield param
-        # starting compression
-        for chunk in self._getcorechunk():
-            data = self._compressor.compress(chunk)
-            if data:
-                yield data
-        yield self._compressor.flush()
+        for chunk in self._compengine.compressstream(self._getcorechunk()):
+            yield chunk
 
     def _paramchunk(self):
         """return a encoded version of all stream parameters"""
@@ -680,7 +676,7 @@
     def __init__(self, ui, fp):
         """If header is specified, we do not read it out of the stream."""
         self.ui = ui
-        self._decompressor = util.decompressors[None]
+        self._compengine = util.compengines.forbundletype('UN')
         self._compressed = None
         super(unbundle20, self).__init__(fp)
 
@@ -754,9 +750,9 @@
             params = self._readexact(paramssize)
             self._processallparams(params)
             yield params
-            assert self._decompressor is util.decompressors[None]
+            assert self._compengine.bundletype == 'UN'
         # From there, payload might need to be decompressed
-        self._fp = self._decompressor(self._fp)
+        self._fp = self._compengine.decompressorreader(self._fp)
         emptycount = 0
         while emptycount < 2:
             # so we can brainlessly loop
@@ -780,7 +776,7 @@
         # make sure param have been loaded
         self.params
         # From there, payload need to be decompressed
-        self._fp = self._decompressor(self._fp)
+        self._fp = self._compengine.decompressorreader(self._fp)
         indebug(self.ui, 'start extraction of bundle2 parts')
         headerblock = self._readpartheader()
         while headerblock is not None:
@@ -822,10 +818,10 @@
 @b2streamparamhandler('compression')
 def processcompression(unbundler, param, value):
     """read compression parameter and install payload decompression"""
-    if value not in util.decompressors:
+    if value not in util.compengines.supportedbundletypes:
         raise error.BundleUnknownFeatureError(params=(param,),
                                               values=(value,))
-    unbundler._decompressor = util.decompressors[value]
+    unbundler._compengine = util.compengines.forbundletype(value)
     if value is not None:
         unbundler._compressed = True
 
@@ -1318,18 +1314,14 @@
             raise error.Abort(_('old bundle types only supports v1 '
                                 'changegroups'))
         header, comp = bundletypes[bundletype]
-        if comp not in util.compressors:
+        if comp not in util.compengines.supportedbundletypes:
             raise error.Abort(_('unknown stream compression type: %s')
                               % comp)
-        z = util.compressors[comp]()
-        subchunkiter = cg.getchunks()
+        compengine = util.compengines.forbundletype(comp)
         def chunkiter():
             yield header
-            for chunk in subchunkiter:
-                data = z.compress(chunk)
-                if data:
-                    yield data
-            yield z.flush()
+            for chunk in compengine.compressstream(cg.getchunks()):
+                yield chunk
         chunkiter = chunkiter()
 
     # parse the changegroup data, otherwise we will block
--- a/mercurial/bundlerepo.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/bundlerepo.py	Wed Nov 16 23:29:28 2016 -0500
@@ -187,9 +187,9 @@
         finally:
             self.filteredrevs = oldfilter
 
-class bundlemanifest(bundlerevlog, manifest.manifest):
+class bundlemanifest(bundlerevlog, manifest.manifestrevlog):
     def __init__(self, opener, bundle, linkmapper, dirlogstarts=None, dir=''):
-        manifest.manifest.__init__(self, opener, dir=dir)
+        manifest.manifestrevlog.__init__(self, opener, dir=dir)
         bundlerevlog.__init__(self, opener, self.indexfile, bundle,
                               linkmapper)
         if dirlogstarts is None:
@@ -207,7 +207,7 @@
         if node in self.fulltextcache:
             result = self.fulltextcache[node].tostring()
         else:
-            result = manifest.manifest.revision(self, nodeorrev)
+            result = manifest.manifestrevlog.revision(self, nodeorrev)
         return result
 
     def dirlog(self, d):
@@ -359,7 +359,7 @@
 
     @localrepo.unfilteredpropertycache
     def filestart(self):
-        self.manifest
+        self.manifestlog
         return self.filestart
 
     def url(self):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/cffi/bdiff.py	Wed Nov 16 23:29:28 2016 -0500
@@ -0,0 +1,31 @@
+from __future__ import absolute_import
+
+import cffi
+import os
+
+ffi = cffi.FFI()
+ffi.set_source("_bdiff_cffi",
+    open(os.path.join(os.path.join(os.path.dirname(__file__), '..'),
+        'bdiff.c')).read(), include_dirs=['mercurial'])
+ffi.cdef("""
+struct bdiff_line {
+    int hash, n, e;
+    ssize_t len;
+    const char *l;
+};
+
+struct bdiff_hunk;
+struct bdiff_hunk {
+    int a1, a2, b1, b2;
+    struct bdiff_hunk *next;
+};
+
+int bdiff_splitlines(const char *a, ssize_t len, struct bdiff_line **lr);
+int bdiff_diff(struct bdiff_line *a, int an, struct bdiff_line *b, int bn,
+    struct bdiff_hunk *base);
+void bdiff_freehunks(struct bdiff_hunk *l);
+void free(void*);
+""")
+
+if __name__ == '__main__':
+    ffi.compile()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/cffi/mpatch.py	Wed Nov 16 23:29:28 2016 -0500
@@ -0,0 +1,35 @@
+from __future__ import absolute_import
+
+import cffi
+import os
+
+ffi = cffi.FFI()
+mpatch_c = os.path.join(os.path.join(os.path.dirname(__file__), '..',
+                                     'mpatch.c'))
+ffi.set_source("_mpatch_cffi", open(mpatch_c).read(),
+               include_dirs=["mercurial"])
+ffi.cdef("""
+
+struct mpatch_frag {
+       int start, end, len;
+       const char *data;
+};
+
+struct mpatch_flist {
+       struct mpatch_frag *base, *head, *tail;
+};
+
+extern "Python" struct mpatch_flist* cffi_get_next_item(void*, ssize_t);
+
+int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist** res);
+ssize_t mpatch_calcsize(size_t len, struct mpatch_flist *l);
+void mpatch_lfree(struct mpatch_flist *a);
+static int mpatch_apply(char *buf, const char *orig, size_t len,
+                        struct mpatch_flist *l);
+struct mpatch_flist *mpatch_fold(void *bins,
+                       struct mpatch_flist* (*get_next_item)(void*, ssize_t),
+                       ssize_t start, ssize_t end);
+""")
+
+if __name__ == '__main__':
+    ffi.compile()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/cffi/osutil.py	Wed Nov 16 23:29:28 2016 -0500
@@ -0,0 +1,102 @@
+from __future__ import absolute_import
+
+import cffi
+
+ffi = cffi.FFI()
+ffi.set_source("_osutil_cffi", """
+#include <sys/attr.h>
+#include <sys/vnode.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+typedef struct val_attrs {
+    uint32_t          length;
+    attribute_set_t   returned;
+    attrreference_t   name_info;
+    fsobj_type_t      obj_type;
+    struct timespec   mtime;
+    uint32_t          accessmask;
+    off_t             datalength;
+} __attribute__((aligned(4), packed)) val_attrs_t;
+""", include_dirs=['mercurial'])
+ffi.cdef('''
+
+typedef uint32_t attrgroup_t;
+
+typedef struct attrlist {
+    uint16_t     bitmapcount; /* number of attr. bit sets in list */
+    uint16_t   reserved;    /* (to maintain 4-byte alignment) */
+    attrgroup_t commonattr;  /* common attribute group */
+    attrgroup_t volattr;     /* volume attribute group */
+    attrgroup_t dirattr;     /* directory attribute group */
+    attrgroup_t fileattr;    /* file attribute group */
+    attrgroup_t forkattr;    /* fork attribute group */
+    ...;
+};
+
+typedef struct attribute_set {
+    ...;
+} attribute_set_t;
+
+typedef struct attrreference {
+    int attr_dataoffset;
+    int attr_length;
+    ...;
+} attrreference_t;
+
+typedef int ... off_t;
+
+typedef struct val_attrs {
+    uint32_t          length;
+    attribute_set_t   returned;
+    attrreference_t   name_info;
+    uint32_t          obj_type;
+    struct timespec   mtime;
+    uint32_t          accessmask;
+    off_t             datalength;
+    ...;
+} val_attrs_t;
+
+/* the exact layout of the above struct will be figured out during build time */
+
+typedef int ... time_t;
+
+typedef struct timespec {
+    time_t tv_sec;
+    ...;
+};
+
+int getattrlist(const char* path, struct attrlist * attrList, void * attrBuf,
+                size_t attrBufSize, unsigned int options);
+
+int getattrlistbulk(int dirfd, struct attrlist * attrList, void * attrBuf,
+                    size_t attrBufSize, uint64_t options);
+
+#define ATTR_BIT_MAP_COUNT ...
+#define ATTR_CMN_NAME ...
+#define ATTR_CMN_OBJTYPE ...
+#define ATTR_CMN_MODTIME ...
+#define ATTR_CMN_ACCESSMASK ...
+#define ATTR_CMN_ERROR ...
+#define ATTR_CMN_RETURNED_ATTRS ...
+#define ATTR_FILE_DATALENGTH ...
+
+#define VREG ...
+#define VDIR ...
+#define VLNK ...
+#define VBLK ...
+#define VCHR ...
+#define VFIFO ...
+#define VSOCK ...
+
+#define S_IFMT ...
+
+int open(const char *path, int oflag, int perm);
+int close(int);
+
+#define O_RDONLY ...
+''')
+
+if __name__ == '__main__':
+    ffi.compile()
--- a/mercurial/changegroup.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/changegroup.py	Wed Nov 16 23:29:28 2016 -0500
@@ -137,14 +137,16 @@
     _grouplistcount = 1 # One list of files after the manifests
 
     def __init__(self, fh, alg, extras=None):
-        if alg == 'UN':
-            alg = None # get more modern without breaking too much
-        if not alg in util.decompressors:
+        if alg is None:
+            alg = 'UN'
+        if alg not in util.compengines.supportedbundletypes:
             raise error.Abort(_('unknown stream compression type: %s')
                              % alg)
         if alg == 'BZ':
             alg = '_truncatedBZ'
-        self._stream = util.decompressors[alg](fh)
+
+        compengine = util.compengines.forbundletype(alg)
+        self._stream = compengine.decompressorreader(fh)
         self._type = alg
         self.extras = extras or {}
         self.callback = None
@@ -250,7 +252,7 @@
         # no new manifest will be created and the manifest group will
         # be empty during the pull
         self.manifestheader()
-        repo.manifest.addgroup(self, revmap, trp)
+        repo.manifestlog._revlog.addgroup(self, revmap, trp)
         repo.ui.progress(_('manifests'), None)
         self.callback = None
 
@@ -330,11 +332,12 @@
 
                 needfiles = {}
                 if repo.ui.configbool('server', 'validate', default=False):
+                    cl = repo.changelog
+                    ml = repo.manifestlog
                     # validate incoming csets have their manifests
                     for cset in xrange(clstart, clend):
-                        mfnode = repo.changelog.read(
-                            repo.changelog.node(cset))[0]
-                        mfest = repo.manifestlog[mfnode].readdelta()
+                        mfnode = cl.changelogrevision(cset).manifest
+                        mfest = ml[mfnode].readdelta()
                         # store file nodes we must see
                         for f, n in mfest.iteritems():
                             needfiles.setdefault(f, set()).add(n)
@@ -479,7 +482,7 @@
             # If we get here, there are directory manifests in the changegroup
             d = chunkdata["filename"]
             repo.ui.debug("adding %s revisions\n" % d)
-            dirlog = repo.manifest.dirlog(d)
+            dirlog = repo.manifestlog._revlog.dirlog(d)
             if not dirlog.addgroup(self, revmap, trp):
                 raise error.Abort(_("received dir revlog group is empty"))
 
@@ -587,7 +590,7 @@
     def _packmanifests(self, dir, mfnodes, lookuplinknode):
         """Pack flat manifests into a changegroup stream."""
         assert not dir
-        for chunk in self.group(mfnodes, self._repo.manifest,
+        for chunk in self.group(mfnodes, self._repo.manifestlog._revlog,
                                 lookuplinknode, units=_('manifests')):
             yield chunk
 
@@ -676,7 +679,8 @@
     def generatemanifests(self, commonrevs, clrevorder, fastpathlinkrev, mfs,
                           fnodes):
         repo = self._repo
-        dirlog = repo.manifest.dirlog
+        mfl = repo.manifestlog
+        dirlog = mfl._revlog.dirlog
         tmfnodes = {'': mfs}
 
         # Callback for the manifest, used to collect linkrevs for filelog
@@ -704,7 +708,7 @@
                 treemanifests to send.
                 """
                 clnode = tmfnodes[dir][x]
-                mdata = dirlog(dir).readshallowfast(x)
+                mdata = mfl.get(dir, x).readfast(shallow=True)
                 for p, n, fl in mdata.iterentries():
                     if fl == 't': # subdirectory manifest
                         subdir = dir + p + '/'
@@ -850,8 +854,10 @@
     def _packmanifests(self, dir, mfnodes, lookuplinknode):
         if dir:
             yield self.fileheader(dir)
-        for chunk in self.group(mfnodes, self._repo.manifest.dirlog(dir),
-                                lookuplinknode, units=_('manifests')):
+
+        dirlog = self._repo.manifestlog._revlog.dirlog(dir)
+        for chunk in self.group(mfnodes, dirlog, lookuplinknode,
+                                units=_('manifests')):
             yield chunk
 
     def _manifestsdone(self):
--- a/mercurial/cmdutil.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/cmdutil.py	Wed Nov 16 23:29:28 2016 -0500
@@ -555,11 +555,11 @@
             if 'treemanifest' not in repo.requirements:
                 raise error.Abort(_("--dir can only be used on repos with "
                                    "treemanifest enabled"))
-            dirlog = repo.manifest.dirlog(dir)
+            dirlog = repo.manifestlog._revlog.dirlog(dir)
             if len(dirlog):
                 r = dirlog
         elif mf:
-            r = repo.manifest
+            r = repo.manifestlog._revlog
         elif file_:
             filelog = repo.file(file_)
             if len(filelog):
@@ -1202,8 +1202,7 @@
         chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
                             prefix=prefix, relroot=relroot)
         for chunk, label in patch.diffstatui(util.iterlines(chunks),
-                                             width=width,
-                                             git=diffopts.git):
+                                             width=width):
             write(chunk, label=label)
     else:
         for chunk, label in patch.diffui(repo, node1, node2, match,
@@ -1324,7 +1323,8 @@
             mnode = ctx.manifestnode()
             # i18n: column positioning for "hg log"
             self.ui.write(_("manifest:    %d:%s\n") %
-                          (self.repo.manifest.rev(mnode), hex(mnode)),
+                          (self.repo.manifestlog._revlog.rev(mnode),
+                           hex(mnode)),
                           label='ui.debug log.manifest')
         # i18n: column positioning for "hg log"
         self.ui.write(_("user:        %s\n") % ctx.user(),
@@ -2566,11 +2566,14 @@
     # for performance to avoid the cost of parsing the manifest.
     if len(matcher.files()) == 1 and not matcher.anypats():
         file = matcher.files()[0]
-        mf = repo.manifest
+        mfl = repo.manifestlog
         mfnode = ctx.manifestnode()
-        if mfnode and mf.find(mfnode, file)[0]:
-            write(file)
-            return 0
+        try:
+            if mfnode and mfl[mfnode].find(file)[0]:
+                write(file)
+                return 0
+        except KeyError:
+            pass
 
     for abs in ctx.walk(matcher):
         write(abs)
@@ -3403,6 +3406,14 @@
 
     return cmd
 
+def checkunresolved(ms):
+    if list(ms.unresolved()):
+        raise error.Abort(_("unresolved merge conflicts "
+                            "(see 'hg help resolve')"))
+    if ms.mdstate() != 's' or list(ms.driverresolved()):
+        raise error.Abort(_('driver-resolved merge conflicts'),
+                          hint=_('run "hg resolve --all" to resolve'))
+
 # a list of (ui, repo, otherpeer, opts, missing) functions called by
 # commands.outgoing.  "missing" is "missing" of the result of
 # "findcommonoutgoing()"
@@ -3463,7 +3474,7 @@
     '''Check for an unfinished operation and return the command to finish
     it.
 
-    afterresolvedstates tupples define a .hg/{file} and the corresponding
+    afterresolvedstates tuples define a .hg/{file} and the corresponding
     command needed to finish it.
 
     Returns a (msg, warning) tuple. 'msg' is a string and 'warning' is
--- a/mercurial/commands.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/commands.py	Wed Nov 16 23:29:28 2016 -0500
@@ -35,7 +35,6 @@
     changegroup,
     cmdutil,
     commandserver,
-    context,
     copies,
     dagparser,
     dagutil,
@@ -61,12 +60,12 @@
     phases,
     policy,
     pvec,
+    pycompat,
     repair,
     revlog,
     revset,
     scmutil,
     setdiscovery,
-    simplemerge,
     sshserver,
     sslutil,
     streamclone,
@@ -1866,177 +1865,6 @@
     with repo.wlock(False):
         return cmdutil.copy(ui, repo, pats, opts)
 
-@command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
-def debugancestor(ui, repo, *args):
-    """find the ancestor revision of two revisions in a given index"""
-    if len(args) == 3:
-        index, rev1, rev2 = args
-        r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
-        lookup = r.lookup
-    elif len(args) == 2:
-        if not repo:
-            raise error.Abort(_("there is no Mercurial repository here "
-                               "(.hg not found)"))
-        rev1, rev2 = args
-        r = repo.changelog
-        lookup = repo.lookup
-    else:
-        raise error.Abort(_('either two or three arguments required'))
-    a = r.ancestor(lookup(rev1), lookup(rev2))
-    ui.write("%d:%s\n" % (r.rev(a), hex(a)))
-
-@command('debugbuilddag',
-    [('m', 'mergeable-file', None, _('add single file mergeable changes')),
-    ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
-    ('n', 'new-file', None, _('add new file at each rev'))],
-    _('[OPTION]... [TEXT]'))
-def debugbuilddag(ui, repo, text=None,
-                  mergeable_file=False,
-                  overwritten_file=False,
-                  new_file=False):
-    """builds a repo with a given DAG from scratch in the current empty repo
-
-    The description of the DAG is read from stdin if not given on the
-    command line.
-
-    Elements:
-
-     - "+n" is a linear run of n nodes based on the current default parent
-     - "." is a single node based on the current default parent
-     - "$" resets the default parent to null (implied at the start);
-           otherwise the default parent is always the last node created
-     - "<p" sets the default parent to the backref p
-     - "*p" is a fork at parent p, which is a backref
-     - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
-     - "/p2" is a merge of the preceding node and p2
-     - ":tag" defines a local tag for the preceding node
-     - "@branch" sets the named branch for subsequent nodes
-     - "#...\\n" is a comment up to the end of the line
-
-    Whitespace between the above elements is ignored.
-
-    A backref is either
-
-     - a number n, which references the node curr-n, where curr is the current
-       node, or
-     - the name of a local tag you placed earlier using ":tag", or
-     - empty to denote the default parent.
-
-    All string valued-elements are either strictly alphanumeric, or must
-    be enclosed in double quotes ("..."), with "\\" as escape character.
-    """
-
-    if text is None:
-        ui.status(_("reading DAG from stdin\n"))
-        text = ui.fin.read()
-
-    cl = repo.changelog
-    if len(cl) > 0:
-        raise error.Abort(_('repository is not empty'))
-
-    # determine number of revs in DAG
-    total = 0
-    for type, data in dagparser.parsedag(text):
-        if type == 'n':
-            total += 1
-
-    if mergeable_file:
-        linesperrev = 2
-        # make a file with k lines per rev
-        initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
-        initialmergedlines.append("")
-
-    tags = []
-
-    wlock = lock = tr = None
-    try:
-        wlock = repo.wlock()
-        lock = repo.lock()
-        tr = repo.transaction("builddag")
-
-        at = -1
-        atbranch = 'default'
-        nodeids = []
-        id = 0
-        ui.progress(_('building'), id, unit=_('revisions'), total=total)
-        for type, data in dagparser.parsedag(text):
-            if type == 'n':
-                ui.note(('node %s\n' % str(data)))
-                id, ps = data
-
-                files = []
-                fctxs = {}
-
-                p2 = None
-                if mergeable_file:
-                    fn = "mf"
-                    p1 = repo[ps[0]]
-                    if len(ps) > 1:
-                        p2 = repo[ps[1]]
-                        pa = p1.ancestor(p2)
-                        base, local, other = [x[fn].data() for x in (pa, p1,
-                                                                     p2)]
-                        m3 = simplemerge.Merge3Text(base, local, other)
-                        ml = [l.strip() for l in m3.merge_lines()]
-                        ml.append("")
-                    elif at > 0:
-                        ml = p1[fn].data().split("\n")
-                    else:
-                        ml = initialmergedlines
-                    ml[id * linesperrev] += " r%i" % id
-                    mergedtext = "\n".join(ml)
-                    files.append(fn)
-                    fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
-
-                if overwritten_file:
-                    fn = "of"
-                    files.append(fn)
-                    fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
-
-                if new_file:
-                    fn = "nf%i" % id
-                    files.append(fn)
-                    fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
-                    if len(ps) > 1:
-                        if not p2:
-                            p2 = repo[ps[1]]
-                        for fn in p2:
-                            if fn.startswith("nf"):
-                                files.append(fn)
-                                fctxs[fn] = p2[fn]
-
-                def fctxfn(repo, cx, path):
-                    return fctxs.get(path)
-
-                if len(ps) == 0 or ps[0] < 0:
-                    pars = [None, None]
-                elif len(ps) == 1:
-                    pars = [nodeids[ps[0]], None]
-                else:
-                    pars = [nodeids[p] for p in ps]
-                cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
-                                    date=(id, 0),
-                                    user="debugbuilddag",
-                                    extra={'branch': atbranch})
-                nodeid = repo.commitctx(cx)
-                nodeids.append(nodeid)
-                at = id
-            elif type == 'l':
-                id, name = data
-                ui.note(('tag %s\n' % name))
-                tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
-            elif type == 'a':
-                ui.note(('branch %s\n' % data))
-                atbranch = data
-            ui.progress(_('building'), id, unit=_('revisions'), total=total)
-        tr.close()
-
-        if tags:
-            repo.vfs.write("localtags", "".join(tags))
-    finally:
-        ui.progress(_('building'), None)
-        release(tr, lock, wlock)
-
 @command('debugbundle',
         [('a', 'all', None, _('show all details')),
          ('', 'spec', None, _('print the bundlespec of the bundle'))],
@@ -3067,7 +2895,7 @@
 
         with repo.lock():
             n = repair.deleteobsmarkers(repo.obsstore, indices)
-            ui.write(_('deleted %i obsolescense markers\n') % n)
+            ui.write(_('deleted %i obsolescence markers\n') % n)
 
         return
 
@@ -3160,7 +2988,7 @@
         if os.path.isdir(spec):
             spec += '/'
         spec = spec[len(rootdir):]
-        fixpaths = os.sep != '/'
+        fixpaths = pycompat.ossep != '/'
         if fixpaths:
             spec = spec.replace(os.sep, '/')
         speclen = len(spec)
@@ -3755,7 +3583,7 @@
     if not items:
         return
     f = lambda fn: fn
-    if ui.configbool('ui', 'slash') and os.sep != '/':
+    if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
         f = lambda fn: util.normpath(fn)
     fmt = 'f  %%-%ds  %%-%ds  %%s' % (
         max([len(abs) for abs in items]),
--- a/mercurial/commandserver.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/commandserver.py	Wed Nov 16 23:29:28 2016 -0500
@@ -54,8 +54,8 @@
     def write(self, data):
         if not data:
             return
-        self.out.write(struct.pack('>cI', self.channel, len(data)))
-        self.out.write(data)
+        # single write() to guarantee the same atomicity as the underlying file
+        self.out.write(struct.pack('>cI', self.channel, len(data)) + data)
         self.out.flush()
 
     def __getattr__(self, attr):
--- a/mercurial/config.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/config.py	Wed Nov 16 23:29:28 2016 -0500
@@ -90,13 +90,13 @@
             self._source.pop((section, item), None)
 
     def parse(self, src, data, sections=None, remap=None, include=None):
-        sectionre = util.re.compile(r'\[([^\[]+)\]')
-        itemre = util.re.compile(r'([^=\s][^=]*?)\s*=\s*(.*\S|)')
-        contre = util.re.compile(r'\s+(\S|\S.*\S)\s*$')
-        emptyre = util.re.compile(r'(;|#|\s*$)')
-        commentre = util.re.compile(r'(;|#)')
-        unsetre = util.re.compile(r'%unset\s+(\S+)')
-        includere = util.re.compile(r'%include\s+(\S|\S.*\S)\s*$')
+        sectionre = util.re.compile(br'\[([^\[]+)\]')
+        itemre = util.re.compile(br'([^=\s][^=]*?)\s*=\s*(.*\S|)')
+        contre = util.re.compile(br'\s+(\S|\S.*\S)\s*$')
+        emptyre = util.re.compile(br'(;|#|\s*$)')
+        commentre = util.re.compile(br'(;|#)')
+        unsetre = util.re.compile(br'%unset\s+(\S+)')
+        includere = util.re.compile(br'%include\s+(\S|\S.*\S)\s*$')
         section = ""
         item = None
         line = 0
--- a/mercurial/context.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/context.py	Wed Nov 16 23:29:28 2016 -0500
@@ -14,8 +14,11 @@
 
 from .i18n import _
 from .node import (
+    addednodeid,
     bin,
     hex,
+    modifiednodeid,
+    newnodeid,
     nullid,
     nullrev,
     short,
@@ -39,11 +42,6 @@
 
 propertycache = util.propertycache
 
-# Phony node value to stand-in for new files in some uses of
-# manifests. Manifests support 21-byte hashes for nodes which are
-# dirty in the working copy.
-_newnode = '!' * 21
-
 nonascii = re.compile(r'[^\x21-\x7f]').search
 
 class basectx(object):
@@ -142,7 +140,7 @@
                 removed.append(fn)
             elif flag1 != flag2:
                 modified.append(fn)
-            elif node2 != _newnode:
+            elif node2 != newnodeid:
                 # When comparing files between two commits, we save time by
                 # not comparing the file contents when the nodeids differ.
                 # Note that this means we incorrectly report a reverted change
@@ -178,6 +176,8 @@
         return hex(self.node())
     def manifest(self):
         return self._manifest
+    def manifestctx(self):
+        return self._manifestctx
     def repo(self):
         return self._repo
     def phasestr(self):
@@ -259,8 +259,10 @@
             if path in self._manifestdelta:
                 return (self._manifestdelta[path],
                         self._manifestdelta.flags(path))
-        node, flag = self._repo.manifest.find(self._changeset.manifest, path)
-        if not node:
+        mfl = self._repo.manifestlog
+        try:
+            node, flag = mfl[self._changeset.manifest].find(path)
+        except KeyError:
             raise error.ManifestLookupError(self._node, path,
                                             _('not found in manifest'))
 
@@ -528,12 +530,15 @@
 
     @propertycache
     def _manifest(self):
-        return self._repo.manifestlog[self._changeset.manifest].read()
+        return self._manifestctx.read()
+
+    @propertycache
+    def _manifestctx(self):
+        return self._repo.manifestlog[self._changeset.manifest]
 
     @propertycache
     def _manifestdelta(self):
-        mfnode = self._changeset.manifest
-        return self._repo.manifestlog[mfnode].readdelta()
+        return self._manifestctx.readdelta()
 
     @propertycache
     def _parents(self):
@@ -680,8 +685,7 @@
         elif '_descendantrev' in self.__dict__:
             # this file context was created from a revision with a known
             # descendant, we can (lazily) correct for linkrev aliases
-            return self._adjustlinkrev(self._path, self._filelog,
-                                       self._filenode, self._descendantrev)
+            return self._adjustlinkrev(self._descendantrev)
         else:
             return self._filelog.linkrev(self._filerev)
 
@@ -709,7 +713,10 @@
             return False
 
     def __str__(self):
-        return "%s@%s" % (self.path(), self._changectx)
+        try:
+            return "%s@%s" % (self.path(), self._changectx)
+        except error.LookupError:
+            return "%s@???" % self.path()
 
     def __repr__(self):
         return "<%s %s>" % (type(self).__name__, str(self))
@@ -808,17 +815,13 @@
 
         return True
 
-    def _adjustlinkrev(self, path, filelog, fnode, srcrev, inclusive=False):
+    def _adjustlinkrev(self, srcrev, inclusive=False):
         """return the first ancestor of <srcrev> introducing <fnode>
 
         If the linkrev of the file revision does not point to an ancestor of
         srcrev, we'll walk down the ancestors until we find one introducing
         this file revision.
 
-        :repo: a localrepository object (used to access changelog and manifest)
-        :path: the file path
-        :fnode: the nodeid of the file revision
-        :filelog: the filelog of this path
         :srcrev: the changeset revision we search ancestors from
         :inclusive: if true, the src revision will also be checked
         """
@@ -826,8 +829,7 @@
         cl = repo.unfiltered().changelog
         mfl = repo.manifestlog
         # fetch the linkrev
-        fr = filelog.rev(fnode)
-        lkr = filelog.linkrev(fr)
+        lkr = self.linkrev()
         # hack to reuse ancestor computation when searching for renames
         memberanc = getattr(self, '_ancestrycontext', None)
         iteranc = None
@@ -844,6 +846,8 @@
         if lkr not in memberanc:
             if iteranc is None:
                 iteranc = cl.ancestors(revs, lkr, inclusive=inclusive)
+            fnode = self._filenode
+            path = self._path
             for a in iteranc:
                 ac = cl.read(a) # get changeset data (we avoid object creation)
                 if path in ac[3]: # checking the 'files' field.
@@ -871,8 +875,7 @@
         noctx = not ('_changeid' in attrs or '_changectx' in attrs)
         if noctx or self.rev() == lkr:
             return self.linkrev()
-        return self._adjustlinkrev(self._path, self._filelog, self._filenode,
-                                   self.rev(), inclusive=True)
+        return self._adjustlinkrev(self.rev(), inclusive=True)
 
     def _parentfilectx(self, path, fileid, filelog):
         """create parent filectx keeping ancestry info for _adjustlinkrev()"""
@@ -1231,23 +1234,13 @@
         """
         parents = self.parents()
 
-        man1 = parents[0].manifest()
-        man = man1.copy()
-        if len(parents) > 1:
-            man2 = self.p2().manifest()
-            def getman(f):
-                if f in man1:
-                    return man1
-                return man2
-        else:
-            getman = lambda f: man1
+        man = parents[0].manifest().copy()
 
-        copied = self._repo.dirstate.copies()
         ff = self._flagfunc
-        for i, l in (("a", self._status.added), ("m", self._status.modified)):
+        for i, l in ((addednodeid, self._status.added),
+                     (modifiednodeid, self._status.modified)):
             for f in l:
-                orig = copied.get(f, f)
-                man[f] = getman(orig).get(orig, nullid) + i
+                man[f] = i
                 try:
                     man.setflag(f, ff(f))
                 except OSError:
@@ -1582,7 +1575,7 @@
         """
         mf = self._repo['.']._manifestmatches(match, s)
         for f in s.modified + s.added:
-            mf[f] = _newnode
+            mf[f] = newnodeid
             mf.setflag(f, self.flags(f))
         for f in s.removed:
             if f in mf:
--- a/mercurial/copies.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/copies.py	Wed Nov 16 23:29:28 2016 -0500
@@ -278,7 +278,7 @@
         ac = repo.changelog.ancestors(revs, inclusive=True)
         ctx._ancestrycontext = ac
     def makectx(f, n):
-        if len(n) != 20:  # in a working context?
+        if n in node.wdirnodes:  # in a working context?
             if ctx.rev() is None:
                 return ctx.filectx(f)
             return repo[None][f]
--- a/mercurial/crecord.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/crecord.py	Wed Nov 16 23:29:28 2016 -0500
@@ -14,14 +14,13 @@
 import os
 import re
 import signal
-import struct
-import sys
 
 from .i18n import _
 from . import (
     encoding,
     error,
     patch as patchmod,
+    scmutil,
     util,
 )
 stringio = util.stringio
@@ -52,11 +51,7 @@
 
 try:
     import curses
-    import fcntl
-    import termios
     curses.error
-    fcntl.ioctl
-    termios.TIOCGWINSZ
 except ImportError:
     # I have no idea if wcurses works with crecord...
     try:
@@ -75,8 +70,6 @@
     """
     return curses and ui.interface("chunkselector") == "curses"
 
-_origstdout = sys.__stdout__ # used by gethw()
-
 class patchnode(object):
     """abstract class for patch graph nodes
     (i.e. patchroot, header, hunk, hunkline)
@@ -473,18 +466,6 @@
 
     return (appliedhunklist, ret)
 
-def gethw():
-    """
-    magically get the current height and width of the window (without initscr)
-
-    this is a rip-off of a rip-off - taken from the bpython code.  it is
-    useful / necessary because otherwise curses.initscr() must be called,
-    which can leave the terminal in a nasty state after exiting.
-    """
-    h, w = struct.unpack(
-        "hhhh", fcntl.ioctl(_origstdout, termios.TIOCGWINSZ, "\000"*8))[0:2]
-    return h, w
-
 def chunkselector(ui, headerlist):
     """
     curses interface to get selection of chunks, and mark the applied flags
@@ -1259,7 +1240,7 @@
         "handle window resizing"
         try:
             curses.endwin()
-            self.yscreensize, self.xscreensize = gethw()
+            self.xscreensize, self.yscreensize = scmutil.termsize(self.ui)
             self.statuswin.resize(self.numstatuslines, self.xscreensize)
             self.numpadlines = self.getnumlinesdisplayed(ignorefolding=True) + 1
             self.chunkpad = curses.newpad(self.numpadlines, self.xscreensize)
@@ -1420,13 +1401,13 @@
                    "Press any key to continue.")
         elif opts.get('amend') is None:
             opts['amend'] = True
-            msg = ("Amend option is turned on -- commiting the currently "
+            msg = ("Amend option is turned on -- committing the currently "
                    "selected changes will not create a new changeset, but "
                    "instead update the most recently committed changeset.\n\n"
                    "Press any key to continue.")
         elif opts.get('amend') is True:
             opts['amend'] = None
-            msg = ("Amend option is turned off -- commiting the currently "
+            msg = ("Amend option is turned off -- committing the currently "
                    "selected changes will create a new changeset.\n\n"
                    "Press any key to continue.")
         if not test:
@@ -1629,7 +1610,7 @@
         except curses.error:
             self.initerr = _('this diff is too large to be displayed')
             return
-        # initialize selecteitemendline (initial start-line is 0)
+        # initialize selecteditemendline (initial start-line is 0)
         self.selecteditemendline = self.getnumlinesdisplayed(
             self.currentselecteditem, recursechildren=False)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/debugcommands.py	Wed Nov 16 23:29:28 2016 -0500
@@ -0,0 +1,203 @@
+# debugcommands.py - command processing for debug* commands
+#
+# Copyright 2005-2016 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from __future__ import absolute_import
+
+import os
+
+from .i18n import _
+from .node import (
+    hex,
+)
+from . import (
+    cmdutil,
+    commands,
+    context,
+    dagparser,
+    error,
+    lock as lockmod,
+    revlog,
+    scmutil,
+    simplemerge,
+)
+
+release = lockmod.release
+
+# We reuse the command table from commands because it is easier than
+# teaching dispatch about multiple tables.
+command = cmdutil.command(commands.table)
+
+@command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
+def debugancestor(ui, repo, *args):
+    """find the ancestor revision of two revisions in a given index"""
+    if len(args) == 3:
+        index, rev1, rev2 = args
+        r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
+        lookup = r.lookup
+    elif len(args) == 2:
+        if not repo:
+            raise error.Abort(_('there is no Mercurial repository here '
+                                '(.hg not found)'))
+        rev1, rev2 = args
+        r = repo.changelog
+        lookup = repo.lookup
+    else:
+        raise error.Abort(_('either two or three arguments required'))
+    a = r.ancestor(lookup(rev1), lookup(rev2))
+    ui.write('%d:%s\n' % (r.rev(a), hex(a)))
+
+@command('debugbuilddag',
+    [('m', 'mergeable-file', None, _('add single file mergeable changes')),
+    ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
+    ('n', 'new-file', None, _('add new file at each rev'))],
+    _('[OPTION]... [TEXT]'))
+def debugbuilddag(ui, repo, text=None,
+                  mergeable_file=False,
+                  overwritten_file=False,
+                  new_file=False):
+    """builds a repo with a given DAG from scratch in the current empty repo
+
+    The description of the DAG is read from stdin if not given on the
+    command line.
+
+    Elements:
+
+     - "+n" is a linear run of n nodes based on the current default parent
+     - "." is a single node based on the current default parent
+     - "$" resets the default parent to null (implied at the start);
+           otherwise the default parent is always the last node created
+     - "<p" sets the default parent to the backref p
+     - "*p" is a fork at parent p, which is a backref
+     - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
+     - "/p2" is a merge of the preceding node and p2
+     - ":tag" defines a local tag for the preceding node
+     - "@branch" sets the named branch for subsequent nodes
+     - "#...\\n" is a comment up to the end of the line
+
+    Whitespace between the above elements is ignored.
+
+    A backref is either
+
+     - a number n, which references the node curr-n, where curr is the current
+       node, or
+     - the name of a local tag you placed earlier using ":tag", or
+     - empty to denote the default parent.
+
+    All string valued-elements are either strictly alphanumeric, or must
+    be enclosed in double quotes ("..."), with "\\" as escape character.
+    """
+
+    if text is None:
+        ui.status(_("reading DAG from stdin\n"))
+        text = ui.fin.read()
+
+    cl = repo.changelog
+    if len(cl) > 0:
+        raise error.Abort(_('repository is not empty'))
+
+    # determine number of revs in DAG
+    total = 0
+    for type, data in dagparser.parsedag(text):
+        if type == 'n':
+            total += 1
+
+    if mergeable_file:
+        linesperrev = 2
+        # make a file with k lines per rev
+        initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
+        initialmergedlines.append("")
+
+    tags = []
+
+    wlock = lock = tr = None
+    try:
+        wlock = repo.wlock()
+        lock = repo.lock()
+        tr = repo.transaction("builddag")
+
+        at = -1
+        atbranch = 'default'
+        nodeids = []
+        id = 0
+        ui.progress(_('building'), id, unit=_('revisions'), total=total)
+        for type, data in dagparser.parsedag(text):
+            if type == 'n':
+                ui.note(('node %s\n' % str(data)))
+                id, ps = data
+
+                files = []
+                fctxs = {}
+
+                p2 = None
+                if mergeable_file:
+                    fn = "mf"
+                    p1 = repo[ps[0]]
+                    if len(ps) > 1:
+                        p2 = repo[ps[1]]
+                        pa = p1.ancestor(p2)
+                        base, local, other = [x[fn].data() for x in (pa, p1,
+                                                                     p2)]
+                        m3 = simplemerge.Merge3Text(base, local, other)
+                        ml = [l.strip() for l in m3.merge_lines()]
+                        ml.append("")
+                    elif at > 0:
+                        ml = p1[fn].data().split("\n")
+                    else:
+                        ml = initialmergedlines
+                    ml[id * linesperrev] += " r%i" % id
+                    mergedtext = "\n".join(ml)
+                    files.append(fn)
+                    fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
+
+                if overwritten_file:
+                    fn = "of"
+                    files.append(fn)
+                    fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
+
+                if new_file:
+                    fn = "nf%i" % id
+                    files.append(fn)
+                    fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
+                    if len(ps) > 1:
+                        if not p2:
+                            p2 = repo[ps[1]]
+                        for fn in p2:
+                            if fn.startswith("nf"):
+                                files.append(fn)
+                                fctxs[fn] = p2[fn]
+
+                def fctxfn(repo, cx, path):
+                    return fctxs.get(path)
+
+                if len(ps) == 0 or ps[0] < 0:
+                    pars = [None, None]
+                elif len(ps) == 1:
+                    pars = [nodeids[ps[0]], None]
+                else:
+                    pars = [nodeids[p] for p in ps]
+                cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
+                                    date=(id, 0),
+                                    user="debugbuilddag",
+                                    extra={'branch': atbranch})
+                nodeid = repo.commitctx(cx)
+                nodeids.append(nodeid)
+                at = id
+            elif type == 'l':
+                id, name = data
+                ui.note(('tag %s\n' % name))
+                tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
+            elif type == 'a':
+                ui.note(('branch %s\n' % data))
+                atbranch = data
+            ui.progress(_('building'), id, unit=_('revisions'), total=total)
+        tr.close()
+
+        if tags:
+            repo.vfs.write("localtags", "".join(tags))
+    finally:
+        ui.progress(_('building'), None)
+        release(tr, lock, wlock)
--- a/mercurial/destutil.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/destutil.py	Wed Nov 16 23:29:28 2016 -0500
@@ -133,7 +133,7 @@
         assert node is not None, "'tip' exists even in empty repository"
     return node, movemark, None
 
-# order in which each step should be evalutated
+# order in which each step should be evaluated
 # steps are run until one finds a destination
 destupdatesteps = ['evolution', 'bookmark', 'branch', 'branchfallback']
 # mapping to ease extension overriding steps.
--- a/mercurial/dirstate.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/dirstate.py	Wed Nov 16 23:29:28 2016 -0500
@@ -21,6 +21,7 @@
     osutil,
     parsers,
     pathutil,
+    pycompat,
     scmutil,
     util,
 )
@@ -215,7 +216,7 @@
 
     @propertycache
     def _slash(self):
-        return self._ui.configbool('ui', 'slash') and os.sep != '/'
+        return self._ui.configbool('ui', 'slash') and pycompat.ossep != '/'
 
     @propertycache
     def _checklink(self):
--- a/mercurial/dispatch.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/dispatch.py	Wed Nov 16 23:29:28 2016 -0500
@@ -26,6 +26,7 @@
 from . import (
     cmdutil,
     commands,
+    debugcommands,
     demandimport,
     encoding,
     error,
@@ -768,6 +769,10 @@
 
     # (reposetup is handled in hg.repository)
 
+    # Side-effect of accessing is debugcommands module is guaranteed to be
+    # imported and commands.table is populated.
+    debugcommands.command
+
     addaliases(lui, commands.table)
 
     # All aliases and commands are completely defined, now.
--- a/mercurial/error.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/error.py	Wed Nov 16 23:29:28 2016 -0500
@@ -84,7 +84,7 @@
     """Raised when an update is aborted because there is nothing to merge"""
 
 class ManyMergeDestAbort(MergeDestAbort):
-    """Raised when an update is aborted because destination is ambigious"""
+    """Raised when an update is aborted because destination is ambiguous"""
 
 class ResponseExpected(Abort):
     """Raised when an EOF is received for a prompt"""
--- a/mercurial/exchange.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/exchange.py	Wed Nov 16 23:29:28 2016 -0500
@@ -64,7 +64,7 @@
 
     Where <compression> is one of the supported compression formats
     and <type> is (currently) a version string. A ";" can follow the type and
-    all text afterwards is interpretted as URI encoded, ";" delimited key=value
+    all text afterwards is interpreted as URI encoded, ";" delimited key=value
     pairs.
 
     If ``strict`` is True (the default) <compression> is required. Otherwise,
@@ -282,7 +282,7 @@
     This function is used to allow testing of the older bundle version"""
     ui = op.repo.ui
     forcebundle1 = False
-    # The goal is this config is to allow developper to choose the bundle
+    # The goal is this config is to allow developer to choose the bundle
     # version used during exchanged. This is especially handy during test.
     # Value is a list of bundle version to be picked from, highest version
     # should be used.
@@ -1425,7 +1425,7 @@
     pullop.stepsdone.add('phases')
     publishing = bool(remotephases.get('publishing', False))
     if remotephases and not publishing:
-        # remote is new and unpublishing
+        # remote is new and non-publishing
         pheads, _dr = phases.analyzeremotephases(pullop.repo,
                                                  pullop.pulledsubset,
                                                  remotephases)
--- a/mercurial/extensions.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/extensions.py	Wed Nov 16 23:29:28 2016 -0500
@@ -426,7 +426,7 @@
         file.close()
 
     if doc: # extracting localized synopsis
-        return gettext(doc).splitlines()[0]
+        return gettext(doc)
     else:
         return _('(no help text available)')
 
@@ -448,7 +448,7 @@
     for name, path in paths.iteritems():
         doc = _disabledhelp(path)
         if doc:
-            exts[name] = doc
+            exts[name] = doc.splitlines()[0]
 
     return exts
 
--- a/mercurial/filemerge.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/filemerge.py	Wed Nov 16 23:29:28 2016 -0500
@@ -189,7 +189,8 @@
         if _toolbool(ui, t, "disabled", False):
             disabled.add(t)
     names = tools.keys()
-    tools = sorted([(-p, t) for t, p in tools.items() if t not in disabled])
+    tools = sorted([(-p, tool) for tool, p in tools.items()
+                    if tool not in disabled])
     uimerge = ui.config("ui", "merge")
     if uimerge:
         # external tools defined in uimerge won't be able to handle
--- a/mercurial/hbisect.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/hbisect.py	Wed Nov 16 23:29:28 2016 -0500
@@ -98,7 +98,7 @@
     tot = len(candidates)
     unskipped = [c for c in candidates if (c not in skip) and (c != badrev)]
     if tot == 1 or not unskipped:
-        return ([changelog.node(rev) for rev in candidates], 0, good)
+        return ([changelog.node(c) for c in candidates], 0, good)
     perfect = tot // 2
 
     # find the best node to test
--- a/mercurial/help/config.txt	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/help/config.txt	Wed Nov 16 23:29:28 2016 -0500
@@ -1401,7 +1401,7 @@
 
 ``type``
     The type of profiler to use.
-    (default: ls)
+    (default: stat)
 
     ``ls``
       Use Python's built-in instrumenting profiler. This profiler
@@ -1409,9 +1409,9 @@
       first line of a function. This restriction makes it difficult to
       identify the expensive parts of a non-trivial function.
     ``stat``
-      Use a third-party statistical profiler, statprof. This profiler
-      currently runs only on Unix systems, and is most useful for
-      profiling commands that run for longer than about 0.1 seconds.
+      Use a statistical profiler, statprof. This profiler is most
+      useful for profiling commands that run for longer than about 0.1
+      seconds.
 
 ``format``
     Profiling format.  Specific to the ``ls`` instrumenting profiler.
@@ -1426,6 +1426,20 @@
       file, the generated file can directly be loaded into
       kcachegrind.
 
+``statformat``
+    Profiling format for the ``stat`` profiler.
+    (default: hotpath)
+
+    ``hotpath``
+      Show a tree-based display containing the hot path of execution (where
+      most time was spent).
+    ``bymethod``
+      Show a table of methods ordered by how frequently they are active.
+    ``byline``
+      Show a table of lines in files ordered by how frequently they are active.
+    ``json``
+      Render profiling data as JSON.
+
 ``frequency``
     Sampling frequency.  Specific to the ``stat`` sampling profiler.
     (default: 1000)
--- a/mercurial/hgweb/protocol.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/hgweb/protocol.py	Wed Nov 16 23:29:28 2016 -0500
@@ -8,7 +8,6 @@
 from __future__ import absolute_import
 
 import cgi
-import zlib
 
 from .common import (
     HTTP_OK,
@@ -88,14 +87,8 @@
         # Don't allow untrusted settings because disabling compression or
         # setting a very high compression level could lead to flooding
         # the server's network or CPU.
-        z = zlib.compressobj(self.ui.configint('server', 'zliblevel', -1))
-        for chunk in chunks:
-            data = z.compress(chunk)
-            # Not all calls to compress() emit data. It is cheaper to inspect
-            # that here than to send it via the generator.
-            if data:
-                yield data
-        yield z.flush()
+        opts = {'level': self.ui.configint('server', 'zliblevel', -1)}
+        return util.compengines['zlib'].compressstream(chunks, opts)
 
     def _client(self):
         return 'remote:%s:%s:%s' % (
--- a/mercurial/hgweb/server.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/hgweb/server.py	Wed Nov 16 23:29:28 2016 -0500
@@ -281,8 +281,8 @@
             prefix = '/' + prefix.strip('/')
         self.prefix = prefix
 
-        alog = openlog(ui.config('web', 'accesslog', '-'), sys.stdout)
-        elog = openlog(ui.config('web', 'errorlog', '-'), sys.stderr)
+        alog = openlog(ui.config('web', 'accesslog', '-'), ui.fout)
+        elog = openlog(ui.config('web', 'errorlog', '-'), ui.ferr)
         self.accesslog = alog
         self.errorlog = elog
 
--- a/mercurial/hgweb/webutil.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/hgweb/webutil.py	Wed Nov 16 23:29:28 2016 -0500
@@ -269,7 +269,7 @@
     try:
         ctx = repo[changeid]
     except error.RepoError:
-        man = repo.manifest
+        man = repo.manifestlog._revlog
         ctx = repo[man.linkrev(man.rev(man.lookup(changeid)))]
 
     return ctx
--- a/mercurial/hook.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/hook.py	Wed Nov 16 23:29:28 2016 -0500
@@ -90,12 +90,6 @@
     starttime = time.time()
 
     try:
-        # redirect IO descriptors to the ui descriptors so hooks
-        # that write directly to these don't mess up the command
-        # protocol when running through the command server
-        old = sys.stdout, sys.stderr, sys.stdin
-        sys.stdout, sys.stderr, sys.stdin = ui.fout, ui.ferr, ui.fin
-
         r = obj(ui=ui, repo=repo, hooktype=name, **args)
     except Exception as exc:
         if isinstance(exc, error.Abort):
@@ -111,7 +105,6 @@
         ui.traceback()
         return True, True
     finally:
-        sys.stdout, sys.stderr, sys.stdin = old
         duration = time.time() - starttime
         ui.log('pythonhook', 'pythonhook-%s: %s finished in %0.2f seconds\n',
                name, funcname, duration)
@@ -216,11 +209,11 @@
         for hname, cmd in hooks:
             if oldstdout == -1 and _redirect:
                 try:
-                    stdoutno = sys.__stdout__.fileno()
-                    stderrno = sys.__stderr__.fileno()
+                    stdoutno = sys.stdout.fileno()
+                    stderrno = sys.stderr.fileno()
                     # temporarily redirect stdout to stderr, if possible
                     if stdoutno >= 0 and stderrno >= 0:
-                        sys.__stdout__.flush()
+                        sys.stdout.flush()
                         oldstdout = os.dup(stdoutno)
                         os.dup2(stderrno, stdoutno)
                 except (OSError, AttributeError):
@@ -265,6 +258,7 @@
             sys.stderr.flush()
     finally:
         if _redirect and oldstdout >= 0:
+            sys.stdout.flush()  # write hook output to stderr fd
             os.dup2(oldstdout, stdoutno)
             os.close(oldstdout)
 
--- a/mercurial/i18n.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/i18n.py	Wed Nov 16 23:29:28 2016 -0500
@@ -49,6 +49,7 @@
 _ugettext = None
 
 def setdatapath(datapath):
+    datapath = pycompat.fsdecode(datapath)
     localedir = os.path.join(datapath, pycompat.sysstr('locale'))
     t = gettextmod.translation('hg', localedir, _languages, fallback=True)
     global _ugettext
--- a/mercurial/localrepo.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/localrepo.py	Wed Nov 16 23:29:28 2016 -0500
@@ -504,15 +504,11 @@
                 c.readpending('00changelog.i.a')
         return c
 
-    @property
-    def manifest(self):
-        return self.manifestlog._oldmanifest
-
     def _constructmanifest(self):
         # This is a temporary function while we migrate from manifest to
         # manifestlog. It allows bundlerepo and unionrepo to intercept the
         # manifest creation.
-        return manifest.manifest(self.svfs)
+        return manifest.manifestrevlog(self.svfs)
 
     @storecache('00manifest.i')
     def manifestlog(self):
@@ -1502,7 +1498,7 @@
         return fparent1
 
     def checkcommitpatterns(self, wctx, vdirs, match, status, fail):
-        """check for commit arguments that aren't commitable"""
+        """check for commit arguments that aren't committable"""
         if match.isexact() or match.prefix():
             matched = set(status.modified + status.added + status.removed)
 
@@ -1633,13 +1629,7 @@
                 raise error.Abort(_("cannot commit merge with missing files"))
 
             ms = mergemod.mergestate.read(self)
-
-            if list(ms.unresolved()):
-                raise error.Abort(_("unresolved merge conflicts "
-                                    "(see 'hg help resolve')"))
-            if ms.mdstate() != 's' or list(ms.driverresolved()):
-                raise error.Abort(_('driver-resolved merge conflicts'),
-                                  hint=_('run "hg resolve --all" to resolve'))
+            cmdutil.checkunresolved(ms)
 
             if editor:
                 cctx._text = editor(self, cctx, subs)
@@ -1706,9 +1696,13 @@
             trp = weakref.proxy(tr)
 
             if ctx.files():
-                m1 = p1.manifest()
-                m2 = p2.manifest()
-                m = m1.copy()
+                m1ctx = p1.manifestctx()
+                m2ctx = p2.manifestctx()
+                mctx = m1ctx.copy()
+
+                m = mctx.read()
+                m1 = m1ctx.read()
+                m2 = m2ctx.read()
 
                 # check in files
                 added = []
@@ -1742,9 +1736,9 @@
                 drop = [f for f in removed if f in m]
                 for f in drop:
                     del m[f]
-                mn = self.manifestlog.add(m, trp, linkrev,
-                                          p1.manifestnode(), p2.manifestnode(),
-                                          added, drop)
+                mn = mctx.write(trp, linkrev,
+                                p1.manifestnode(), p2.manifestnode(),
+                                added, drop)
                 files = changed + removed
             else:
                 mn = p1.manifestnode()
--- a/mercurial/mail.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/mail.py	Wed Nov 16 23:29:28 2016 -0500
@@ -5,7 +5,7 @@
 # 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, print_function
+from __future__ import absolute_import
 
 import email
 import email.charset
@@ -14,7 +14,6 @@
 import quopri
 import smtplib
 import socket
-import sys
 import time
 
 from .i18n import _
@@ -87,7 +86,7 @@
 
     def _get_socket(self, host, port, timeout):
         if self.debuglevel > 0:
-            print('connect:', (host, port), file=sys.stderr)
+            self._ui.debug('connect: %r\n' % (host, port))
         new_socket = socket.create_connection((host, port), timeout)
         new_socket = sslutil.wrapsocket(new_socket,
                                         self.keyfile, self.certfile,
--- a/mercurial/manifest.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/manifest.py	Wed Nov 16 23:29:28 2016 -0500
@@ -422,6 +422,11 @@
     def __len__(self):
         return len(self._lm)
 
+    def __nonzero__(self):
+        # nonzero is covered by the __len__ function, but implementing it here
+        # makes it easier for extensions to override.
+        return len(self._lm) != 0
+
     def __setitem__(self, key, node):
         self._lm[key] = node, self.flags(key, '')
 
@@ -1178,7 +1183,7 @@
                                                     self._dirlogcache)
         return self._dirlogcache[dir]
 
-    def add(self, m, transaction, link, p1, p2, added, removed):
+    def add(self, m, transaction, link, p1, p2, added, removed, readtree=None):
         if (p1 in self.fulltextcache and util.safehasattr(m, 'fastdelta')
             and not self._usemanifestv2):
             # If our first parent is in the manifest cache, we can
@@ -1201,9 +1206,10 @@
             # through to the revlog layer, and let it handle the delta
             # process.
             if self._treeondisk:
-                m1 = self.read(p1)
-                m2 = self.read(p2)
-                n = self._addtree(m, transaction, link, m1, m2)
+                assert readtree, "readtree must be set for treemanifest writes"
+                m1 = readtree(self._dir, p1)
+                m2 = readtree(self._dir, p2)
+                n = self._addtree(m, transaction, link, m1, m2, readtree)
                 arraytext = None
             else:
                 text = m.text(self._usemanifestv2)
@@ -1215,14 +1221,15 @@
 
         return n
 
-    def _addtree(self, m, transaction, link, m1, m2):
+    def _addtree(self, m, transaction, link, m1, m2, readtree):
         # If the manifest is unchanged compared to one parent,
         # don't write a new revision
         if m.unmodifiedsince(m1) or m.unmodifiedsince(m2):
             return m.node()
         def writesubtree(subm, subp1, subp2):
             sublog = self.dirlog(subm.dir())
-            sublog.add(subm, transaction, link, subp1, subp2, None, None)
+            sublog.add(subm, transaction, link, subp1, subp2, None, None,
+                       readtree=readtree)
         m.writesubtrees(m1, m2, writesubtree)
         text = m.dirtext(self._usemanifestv2)
         # Double-check whether contents are unchanged to one parent
@@ -1248,41 +1255,100 @@
         self._repo = repo
 
         usetreemanifest = False
+        cachesize = 4
 
         opts = getattr(opener, 'options', None)
         if opts is not None:
             usetreemanifest = opts.get('treemanifest', usetreemanifest)
+            cachesize = opts.get('manifestcachesize', cachesize)
         self._treeinmem = usetreemanifest
 
         self._oldmanifest = repo._constructmanifest()
         self._revlog = self._oldmanifest
 
-        # We'll separate this into it's own cache once oldmanifest is no longer
-        # used
-        self._mancache = self._oldmanifest._mancache
+        # A cache of the manifestctx or treemanifestctx for each directory
+        self._dirmancache = {}
+        self._dirmancache[''] = util.lrucachedict(cachesize)
+
+        self.cachesize = cachesize
 
     def __getitem__(self, node):
-        """Retrieves the manifest instance for the given node. Throws a KeyError
-        if not found.
+        """Retrieves the manifest instance for the given node. Throws a
+        LookupError if not found.
         """
-        if node in self._mancache:
-            cachemf = self._mancache[node]
-            # The old manifest may put non-ctx manifests in the cache, so skip
-            # those since they don't implement the full api.
+        return self.get('', node)
+
+    def get(self, dir, node, verify=True):
+        """Retrieves the manifest instance for the given node. Throws a
+        LookupError if not found.
+
+        `verify` - if True an exception will be thrown if the node is not in
+                   the revlog
+        """
+        if node in self._dirmancache.get(dir, ()):
+            cachemf = self._dirmancache[dir][node]
+            # The old manifest may put non-ctx manifests in the cache, so
+            # skip those since they don't implement the full api.
             if (isinstance(cachemf, manifestctx) or
                 isinstance(cachemf, treemanifestctx)):
                 return cachemf
 
-        if self._treeinmem:
-            m = treemanifestctx(self._repo, '', node)
+        if dir:
+            if self._revlog._treeondisk:
+                if verify:
+                    dirlog = self._revlog.dirlog(dir)
+                    if node not in dirlog.nodemap:
+                        raise LookupError(node, dirlog.indexfile,
+                                          _('no node'))
+                m = treemanifestctx(self._repo, dir, node)
+            else:
+                raise error.Abort(
+                        _("cannot ask for manifest directory '%s' in a flat "
+                          "manifest") % dir)
         else:
-            m = manifestctx(self._repo, node)
+            if verify:
+                if node not in self._revlog.nodemap:
+                    raise LookupError(node, self._revlog.indexfile,
+                                      _('no node'))
+            if self._treeinmem:
+                m = treemanifestctx(self._repo, '', node)
+            else:
+                m = manifestctx(self._repo, node)
+
         if node != revlog.nullid:
-            self._mancache[node] = m
+            mancache = self._dirmancache.get(dir)
+            if not mancache:
+                mancache = util.lrucachedict(self.cachesize)
+                self._dirmancache[dir] = mancache
+            mancache[node] = m
         return m
 
-    def add(self, m, transaction, link, p1, p2, added, removed):
-        return self._revlog.add(m, transaction, link, p1, p2, added, removed)
+    def clearcaches(self):
+        self._dirmancache.clear()
+        self._revlog.clearcaches()
+
+class memmanifestctx(object):
+    def __init__(self, repo):
+        self._repo = repo
+        self._manifestdict = manifestdict()
+
+    def _revlog(self):
+        return self._repo.manifestlog._revlog
+
+    def new(self):
+        return memmanifestctx(self._repo)
+
+    def copy(self):
+        memmf = memmanifestctx(self._repo)
+        memmf._manifestdict = self.read().copy()
+        return memmf
+
+    def read(self):
+        return self._manifestdict
+
+    def write(self, transaction, link, p1, p2, added, removed):
+        return self._revlog().add(self._manifestdict, transaction, link, p1, p2,
+                                  added, removed)
 
 class manifestctx(object):
     """A class representing a single revision of a manifest, including its
@@ -1301,31 +1367,54 @@
         #rev = revlog.rev(node)
         #self.linkrev = revlog.linkrev(rev)
 
+    def _revlog(self):
+        return self._repo.manifestlog._revlog
+
     def node(self):
         return self._node
 
+    def new(self):
+        return memmanifestctx(self._repo)
+
+    def copy(self):
+        memmf = memmanifestctx(self._repo)
+        memmf._manifestdict = self.read().copy()
+        return memmf
+
     def read(self):
         if not self._data:
             if self._node == revlog.nullid:
                 self._data = manifestdict()
             else:
-                rl = self._repo.manifestlog._revlog
+                rl = self._revlog()
                 text = rl.revision(self._node)
                 arraytext = array.array('c', text)
                 rl._fulltextcache[self._node] = arraytext
                 self._data = manifestdict(text)
         return self._data
 
-    def readfast(self):
-        rl = self._repo.manifestlog._revlog
+    def readfast(self, shallow=False):
+        '''Calls either readdelta or read, based on which would be less work.
+        readdelta is called if the delta is against the p1, and therefore can be
+        read quickly.
+
+        If `shallow` is True, nothing changes since this is a flat manifest.
+        '''
+        rl = self._revlog()
         r = rl.rev(self._node)
         deltaparent = rl.deltaparent(r)
         if deltaparent != revlog.nullrev and deltaparent in rl.parentrevs(r):
             return self.readdelta()
         return self.read()
 
-    def readdelta(self):
-        revlog = self._repo.manifestlog._revlog
+    def readdelta(self, shallow=False):
+        '''Returns a manifest containing just the entries that are present
+        in this manifest, but not in its p1 manifest. This is efficient to read
+        if the revlog delta is already p1.
+
+        Changing the value of `shallow` has no effect on flat manifests.
+        '''
+        revlog = self._revlog()
         if revlog._usemanifestv2:
             # Need to perform a slow delta
             r0 = revlog.deltaparent(revlog.rev(self._node))
@@ -1343,6 +1432,35 @@
         d = mdiff.patchtext(revlog.revdiff(revlog.deltaparent(r), r))
         return manifestdict(d)
 
+    def find(self, key):
+        return self.read().find(key)
+
+class memtreemanifestctx(object):
+    def __init__(self, repo, dir=''):
+        self._repo = repo
+        self._dir = dir
+        self._treemanifest = treemanifest()
+
+    def _revlog(self):
+        return self._repo.manifestlog._revlog
+
+    def new(self, dir=''):
+        return memtreemanifestctx(self._repo, dir=dir)
+
+    def copy(self):
+        memmf = memtreemanifestctx(self._repo, dir=self._dir)
+        memmf._treemanifest = self._treemanifest.copy()
+        return memmf
+
+    def read(self):
+        return self._treemanifest
+
+    def write(self, transaction, link, p1, p2, added, removed):
+        def readtree(dir, node):
+            return self._repo.manifestlog.get(dir, node).read()
+        return self._revlog().add(self._treemanifest, transaction, link, p1, p2,
+                                  added, removed, readtree=readtree)
+
 class treemanifestctx(object):
     def __init__(self, repo, dir, node):
         self._repo = repo
@@ -1371,12 +1489,15 @@
                 def gettext():
                     return rl.revision(self._node)
                 def readsubtree(dir, subm):
-                    return treemanifestctx(self._repo, dir, subm).read()
+                    # Set verify to False since we need to be able to create
+                    # subtrees for trees that don't exist on disk.
+                    return self._repo.manifestlog.get(dir, subm,
+                                                      verify=False).read()
                 m.read(gettext, readsubtree)
                 m.setnode(self._node)
                 self._data = m
             else:
-                text = revlog.revision(self._node)
+                text = rl.revision(self._node)
                 arraytext = array.array('c', text)
                 rl.fulltextcache[self._node] = arraytext
                 self._data = treemanifest(dir=self._dir, text=text)
@@ -1386,150 +1507,62 @@
     def node(self):
         return self._node
 
-    def readdelta(self):
-        # Need to perform a slow delta
+    def new(self, dir=''):
+        return memtreemanifestctx(self._repo, dir=dir)
+
+    def copy(self):
+        memmf = memtreemanifestctx(self._repo, dir=self._dir)
+        memmf._treemanifest = self.read().copy()
+        return memmf
+
+    def readdelta(self, shallow=False):
+        '''Returns a manifest containing just the entries that are present
+        in this manifest, but not in its p1 manifest. This is efficient to read
+        if the revlog delta is already p1.
+
+        If `shallow` is True, this will read the delta for this directory,
+        without recursively reading subdirectory manifests. Instead, any
+        subdirectory entry will be reported as it appears in the manifest, i.e.
+        the subdirectory will be reported among files and distinguished only by
+        its 't' flag.
+        '''
         revlog = self._revlog()
-        r0 = revlog.deltaparent(revlog.rev(self._node))
-        m0 = treemanifestctx(self._repo, self._dir, revlog.node(r0)).read()
-        m1 = self.read()
-        md = treemanifest(dir=self._dir)
-        for f, ((n0, fl0), (n1, fl1)) in m0.diff(m1).iteritems():
-            if n1:
-                md[f] = n1
-                if fl1:
-                    md.setflag(f, fl1)
-        return md
+        if shallow and not revlog._usemanifestv2:
+            r = revlog.rev(self._node)
+            d = mdiff.patchtext(revlog.revdiff(revlog.deltaparent(r), r))
+            return manifestdict(d)
+        else:
+            # Need to perform a slow delta
+            r0 = revlog.deltaparent(revlog.rev(self._node))
+            m0 = self._repo.manifestlog.get(self._dir, revlog.node(r0)).read()
+            m1 = self.read()
+            md = treemanifest(dir=self._dir)
+            for f, ((n0, fl0), (n1, fl1)) in m0.diff(m1).iteritems():
+                if n1:
+                    md[f] = n1
+                    if fl1:
+                        md.setflag(f, fl1)
+            return md
 
-    def readfast(self):
+    def readfast(self, shallow=False):
+        '''Calls either readdelta or read, based on which would be less work.
+        readdelta is called if the delta is against the p1, and therefore can be
+        read quickly.
+
+        If `shallow` is True, it only returns the entries from this manifest,
+        and not any submanifests.
+        '''
         rl = self._revlog()
         r = rl.rev(self._node)
         deltaparent = rl.deltaparent(r)
-        if deltaparent != revlog.nullrev and deltaparent in rl.parentrevs(r):
-            return self.readdelta()
-        return self.read()
-
-class manifest(manifestrevlog):
-    def __init__(self, opener, dir='', dirlogcache=None):
-        '''The 'dir' and 'dirlogcache' arguments are for internal use by
-        manifest.manifest only. External users should create a root manifest
-        log with manifest.manifest(opener) and call dirlog() on it.
-        '''
-        # During normal operations, we expect to deal with not more than four
-        # revs at a time (such as during commit --amend). When rebasing large
-        # stacks of commits, the number can go up, hence the config knob below.
-        cachesize = 4
-        usetreemanifest = False
-        opts = getattr(opener, 'options', None)
-        if opts is not None:
-            cachesize = opts.get('manifestcachesize', cachesize)
-            usetreemanifest = opts.get('treemanifest', usetreemanifest)
-        self._mancache = util.lrucachedict(cachesize)
-        self._treeinmem = usetreemanifest
-        super(manifest, self).__init__(opener, dir=dir, dirlogcache=dirlogcache)
-
-    def _newmanifest(self, data=''):
-        if self._treeinmem:
-            return treemanifest(self._dir, data)
-        return manifestdict(data)
-
-    def dirlog(self, dir):
-        """This overrides the base revlog implementation to allow construction
-        'manifest' types instead of manifestrevlog types. This is only needed
-        until we migrate off the 'manifest' type."""
-        if dir:
-            assert self._treeondisk
-        if dir not in self._dirlogcache:
-            self._dirlogcache[dir] = manifest(self.opener, dir,
-                                              self._dirlogcache)
-        return self._dirlogcache[dir]
-
-    def _slowreaddelta(self, node):
-        r0 = self.deltaparent(self.rev(node))
-        m0 = self.read(self.node(r0))
-        m1 = self.read(node)
-        md = self._newmanifest()
-        for f, ((n0, fl0), (n1, fl1)) in m0.diff(m1).iteritems():
-            if n1:
-                md[f] = n1
-                if fl1:
-                    md.setflag(f, fl1)
-        return md
-
-    def readdelta(self, node):
-        if self._usemanifestv2 or self._treeondisk:
-            return self._slowreaddelta(node)
-        r = self.rev(node)
-        d = mdiff.patchtext(self.revdiff(self.deltaparent(r), r))
-        return self._newmanifest(d)
+        if (deltaparent != revlog.nullrev and
+            deltaparent in rl.parentrevs(r)):
+            return self.readdelta(shallow=shallow)
 
-    def readshallowdelta(self, node):
-        '''For flat manifests, this is the same as readdelta(). For
-        treemanifests, this will read the delta for this revlog's directory,
-        without recursively reading subdirectory manifests. Instead, any
-        subdirectory entry will be reported as it appears in the manifests, i.e.
-        the subdirectory will be reported among files and distinguished only by
-        its 't' flag.'''
-        if not self._treeondisk:
-            return self.readdelta(node)
-        if self._usemanifestv2:
-            raise error.Abort(
-                _("readshallowdelta() not implemented for manifestv2"))
-        r = self.rev(node)
-        d = mdiff.patchtext(self.revdiff(self.deltaparent(r), r))
-        return manifestdict(d)
-
-    def readshallowfast(self, node):
-        '''like readfast(), but calls readshallowdelta() instead of readdelta()
-        '''
-        r = self.rev(node)
-        deltaparent = self.deltaparent(r)
-        if deltaparent != revlog.nullrev and deltaparent in self.parentrevs(r):
-            return self.readshallowdelta(node)
-        return self.readshallow(node)
+        if shallow:
+            return manifestdict(rl.revision(self._node))
+        else:
+            return self.read()
 
-    def read(self, node):
-        if node == revlog.nullid:
-            return self._newmanifest() # don't upset local cache
-        if node in self._mancache:
-            cached = self._mancache[node]
-            if (isinstance(cached, manifestctx) or
-                isinstance(cached, treemanifestctx)):
-                cached = cached.read()
-            return cached
-        if self._treeondisk:
-            def gettext():
-                return self.revision(node)
-            def readsubtree(dir, subm):
-                return self.dirlog(dir).read(subm)
-            m = self._newmanifest()
-            m.read(gettext, readsubtree)
-            m.setnode(node)
-            arraytext = None
-        else:
-            text = self.revision(node)
-            m = self._newmanifest(text)
-            arraytext = array.array('c', text)
-        self._mancache[node] = m
-        if arraytext is not None:
-            self.fulltextcache[node] = arraytext
-        return m
-
-    def readshallow(self, node):
-        '''Reads the manifest in this directory. When using flat manifests,
-        this manifest will generally have files in subdirectories in it. Does
-        not cache the manifest as the callers generally do not read the same
-        version twice.'''
-        return manifestdict(self.revision(node))
-
-    def find(self, node, f):
-        '''look up entry for a single file efficiently.
-        return (node, flags) pair if found, (None, None) if not.'''
-        m = self.read(node)
-        try:
-            return m.find(f)
-        except KeyError:
-            return None, None
-
-    def clearcaches(self):
-        super(manifest, self).clearcaches()
-        self._mancache.clear()
+    def find(self, key):
+        return self.read().find(key)
--- a/mercurial/match.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/match.py	Wed Nov 16 23:29:28 2016 -0500
@@ -669,7 +669,7 @@
     patterns = []
 
     fp = open(filepath)
-    for lineno, line in enumerate(fp, start=1):
+    for lineno, line in enumerate(util.iterfile(fp), start=1):
         if "#" in line:
             global _commentre
             if not _commentre:
--- a/mercurial/merge.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/merge.py	Wed Nov 16 23:29:28 2016 -0500
@@ -15,8 +15,10 @@
 
 from .i18n import _
 from .node import (
+    addednodeid,
     bin,
     hex,
+    modifiednodeid,
     nullhex,
     nullid,
     nullrev,
@@ -66,7 +68,7 @@
        (experimental)
     m: the external merge driver defined for this merge plus its run state
        (experimental)
-    f: a (filename, dictonary) tuple of optional values for a given file
+    f: a (filename, dictionary) tuple of optional values for a given file
     X: unsupported mandatory record type (used in tests)
     x: unsupported advisory record type (used in tests)
     l: the labels for the parts of the merge.
@@ -814,7 +816,7 @@
     if '.hgsubstate' in m1:
         # check whether sub state is modified
         if any(wctx.sub(s).dirty() for s in wctx.substate):
-            m1['.hgsubstate'] += '+'
+            m1['.hgsubstate'] = modifiednodeid
 
     # Compare manifests
     if matcher is not None:
@@ -873,7 +875,7 @@
                     else:
                         actions[f] = ('cd', (f, None, f, False, pa.node()),
                                       "prompt changed/deleted")
-                elif n1[20:] == 'a':
+                elif n1 == addednodeid:
                     # This extra 'a' is added by working copy manifest to mark
                     # the file as locally added. We should forget it instead of
                     # deleting it.
--- a/mercurial/minirst.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/minirst.py	Wed Nov 16 23:29:28 2016 -0500
@@ -697,7 +697,7 @@
         if collapse:
             synthetic.reverse()
             for s in synthetic:
-                path = [blocks[i]['lines'][0] for i in s]
+                path = [blocks[syn]['lines'][0] for syn in s]
                 real = s[-1] + 2
                 realline = blocks[real]['lines']
                 realline[0] = ('"%s"' %
--- a/mercurial/node.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/node.py	Wed Nov 16 23:29:28 2016 -0500
@@ -17,6 +17,14 @@
 nullid = b"\0" * 20
 nullhex = hex(nullid)
 
+# Phony node value to stand-in for new files in some uses of
+# manifests.
+newnodeid = '!' * 20
+addednodeid = ('0' * 15) + 'added'
+modifiednodeid = ('0' * 12) + 'modified'
+
+wdirnodes = set((newnodeid, addednodeid, modifiednodeid))
+
 # pseudo identifiers for working directory
 # (they are experimental, so don't add too many dependencies on them)
 wdirrev = 0x7fffffff
--- a/mercurial/osutil.c	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/osutil.c	Wed Nov 16 23:29:28 2016 -0500
@@ -727,6 +727,63 @@
 }
 
 #endif /* CMSG_LEN */
+
+#if defined(HAVE_SETPROCTITLE)
+/* setproctitle is the first choice - available in FreeBSD */
+#define SETPROCNAME_USE_SETPROCTITLE
+#elif (defined(__linux__) || defined(__APPLE__)) && PY_MAJOR_VERSION == 2
+/* rewrite the argv buffer in place - works in Linux and OS X. Py_GetArgcArgv
+ * in Python 3 returns the copied wchar_t **argv, thus unsupported. */
+#define SETPROCNAME_USE_ARGVREWRITE
+#else
+#define SETPROCNAME_USE_NONE
+#endif
+
+#ifndef SETPROCNAME_USE_NONE
+static PyObject *setprocname(PyObject *self, PyObject *args)
+{
+	const char *name = NULL;
+	if (!PyArg_ParseTuple(args, "s", &name))
+		return NULL;
+
+#if defined(SETPROCNAME_USE_SETPROCTITLE)
+	setproctitle("%s", name);
+#elif defined(SETPROCNAME_USE_ARGVREWRITE)
+	{
+		static char *argvstart = NULL;
+		static size_t argvsize = 0;
+		if (argvstart == NULL) {
+			int argc = 0, i;
+			char **argv = NULL;
+			char *argvend;
+			extern void Py_GetArgcArgv(int *argc, char ***argv);
+			Py_GetArgcArgv(&argc, &argv);
+
+			/* Check the memory we can use. Typically, argv[i] and
+			 * argv[i + 1] are continuous. */
+			argvend = argvstart = argv[0];
+			for (i = 0; i < argc; ++i) {
+				if (argv[i] > argvend || argv[i] < argvstart)
+					break; /* not continuous */
+				size_t len = strlen(argv[i]);
+				argvend = argv[i] + len + 1 /* '\0' */;
+			}
+			if (argvend > argvstart) /* sanity check */
+				argvsize = argvend - argvstart;
+		}
+
+		if (argvstart && argvsize > 1) {
+			int n = snprintf(argvstart, argvsize, "%s", name);
+			if (n >= 0 && (size_t)n < argvsize)
+				memset(argvstart + n, 0, argvsize - n);
+		}
+	}
+#endif
+
+	Py_RETURN_NONE;
+}
+#endif /* ndef SETPROCNAME_USE_NONE */
+
 #endif /* ndef _WIN32 */
 
 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
@@ -899,7 +956,11 @@
 	{"recvfds", (PyCFunction)recvfds, METH_VARARGS,
 	 "receive list of file descriptors via socket\n"},
 #endif
+#ifndef SETPROCNAME_USE_NONE
+	{"setprocname", (PyCFunction)setprocname, METH_VARARGS,
+	 "set process title (best-effort)\n"},
 #endif
+#endif /* ndef _WIN32 */
 #ifdef __APPLE__
 	{
 		"isgui", (PyCFunction)isgui, METH_NOARGS,
--- a/mercurial/parser.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/parser.py	Wed Nov 16 23:29:28 2016 -0500
@@ -248,7 +248,7 @@
     This is a helper for fileset/revset/template aliases. A concrete rule set
     should be made by sub-classing this and implementing class/static methods.
 
-    It supports alias expansion of symbol and funciton-call styles::
+    It supports alias expansion of symbol and function-call styles::
 
         # decl = defn
         h = heads(default)
--- a/mercurial/patch.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/patch.py	Wed Nov 16 23:29:28 2016 -0500
@@ -1069,7 +1069,7 @@
                     # Remove comment lines
                     patchfp = open(patchfn)
                     ncpatchfp = stringio()
-                    for line in patchfp:
+                    for line in util.iterfile(patchfp):
                         if not line.startswith('#'):
                             ncpatchfp.write(line)
                     patchfp.close()
@@ -2012,7 +2012,7 @@
     fp = util.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
                                        util.shellquote(patchname)))
     try:
-        for line in fp:
+        for line in util.iterfile(fp):
             line = line.rstrip()
             ui.note(line + '\n')
             if line.startswith('patching file '):
@@ -2550,7 +2550,7 @@
     addresult()
     return results
 
-def diffstat(lines, width=80, git=False):
+def diffstat(lines, width=80):
     output = []
     stats = diffstatdata(lines)
     maxname, maxtotal, totaladds, totalremoves, hasbinary = diffstatsum(stats)
--- a/mercurial/pathutil.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/pathutil.py	Wed Nov 16 23:29:28 2016 -0500
@@ -84,7 +84,7 @@
         normparts.pop()
         prefixes = []
         # It's important that we check the path parts starting from the root.
-        # This means we won't accidentaly traverse a symlink into some other
+        # This means we won't accidentally traverse a symlink into some other
         # filesystem (which is potentially expensive to access).
         for i in range(len(parts)):
             prefix = os.sep.join(parts[:i + 1])
--- a/mercurial/posix.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/posix.py	Wed Nov 16 23:29:28 2016 -0500
@@ -463,36 +463,6 @@
 def gethgcmd():
     return sys.argv[:1]
 
-def termwidth():
-    try:
-        import array
-        import termios
-        for dev in (sys.stderr, sys.stdout, sys.stdin):
-            try:
-                try:
-                    fd = dev.fileno()
-                except AttributeError:
-                    continue
-                if not os.isatty(fd):
-                    continue
-                try:
-                    arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
-                    width = array.array('h', arri)[1]
-                    if width > 0:
-                        return width
-                except AttributeError:
-                    pass
-            except ValueError:
-                pass
-            except IOError as e:
-                if e[0] == errno.EINVAL:
-                    pass
-                else:
-                    raise
-    except ImportError:
-        pass
-    return 80
-
 def makedir(path, notindexed):
     os.mkdir(path)
 
--- a/mercurial/profiling.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/profiling.py	Wed Nov 16 23:29:28 2016 -0500
@@ -9,7 +9,6 @@
 
 import contextlib
 import os
-import sys
 import time
 
 from .i18n import _
@@ -80,11 +79,7 @@
 
 @contextlib.contextmanager
 def statprofile(ui, fp):
-    try:
-        import statprof
-    except ImportError:
-        raise error.Abort(_(
-            'statprof not available - install using "easy_install statprof"'))
+    from . import statprof
 
     freq = ui.configint('profiling', 'freq', default=1000)
     if freq > 0:
@@ -94,12 +89,29 @@
     else:
         ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
 
-    statprof.start()
+    statprof.start(mechanism='thread')
+
     try:
         yield
     finally:
-        statprof.stop()
-        statprof.display(fp)
+        data = statprof.stop()
+
+        profformat = ui.config('profiling', 'statformat', 'hotpath')
+
+        formats = {
+            'byline': statprof.DisplayFormats.ByLine,
+            'bymethod': statprof.DisplayFormats.ByMethod,
+            'hotpath': statprof.DisplayFormats.Hotpath,
+            'json': statprof.DisplayFormats.Json,
+        }
+
+        if profformat in formats:
+            displayformat = formats[profformat]
+        else:
+            ui.warn(_('unknown profiler output format: %s\n') % profformat)
+            displayformat = statprof.DisplayFormats.Hotpath
+
+        statprof.display(fp, data=data, format=displayformat)
 
 @contextlib.contextmanager
 def profile(ui):
@@ -110,10 +122,10 @@
     """
     profiler = os.getenv('HGPROF')
     if profiler is None:
-        profiler = ui.config('profiling', 'type', default='ls')
+        profiler = ui.config('profiling', 'type', default='stat')
     if profiler not in ('ls', 'stat', 'flame'):
         ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
-        profiler = 'ls'
+        profiler = 'stat'
 
     output = ui.config('profiling', 'output')
 
@@ -123,7 +135,7 @@
         path = ui.expandpath(output)
         fp = open(path, 'wb')
     else:
-        fp = sys.stderr
+        fp = ui.ferr
 
     try:
         if profiler == 'ls':
--- a/mercurial/progress.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/progress.py	Wed Nov 16 23:29:28 2016 -0500
@@ -7,7 +7,6 @@
 
 from __future__ import absolute_import
 
-import sys
 import threading
 import time
 
@@ -19,7 +18,7 @@
 
 def shouldprint(ui):
     return not (ui.quiet or ui.plain('progress')) and (
-        ui._isatty(sys.stderr) or ui.configbool('progress', 'assume-tty'))
+        ui._isatty(ui.ferr) or ui.configbool('progress', 'assume-tty'))
 
 def fmtremaining(seconds):
     """format a number of remaining seconds in human readable way
@@ -158,14 +157,14 @@
             out = spacejoin(head, prog, tail)
         else:
             out = spacejoin(head, tail)
-        sys.stderr.write('\r' + encoding.trim(out, termwidth))
+        self.ui.ferr.write('\r' + encoding.trim(out, termwidth))
         self.lasttopic = topic
-        sys.stderr.flush()
+        self.ui.ferr.flush()
 
     def clear(self):
         if not self.printed or not self.lastprint or not shouldprint(self.ui):
             return
-        sys.stderr.write('\r%s\r' % (' ' * self.width()))
+        self.ui.ferr.write('\r%s\r' % (' ' * self.width()))
         if self.printed:
             # force immediate re-paint of progress bar
             self.lastprint = 0
@@ -176,8 +175,8 @@
         if self.ui.configbool('progress', 'clear-complete', default=True):
             self.clear()
         else:
-            sys.stderr.write('\n')
-        sys.stderr.flush()
+            self.ui.ferr.write('\n')
+        self.ui.ferr.flush()
 
     def width(self):
         tw = self.ui.termwidth()
--- a/mercurial/pure/osutil.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/pure/osutil.py	Wed Nov 16 23:29:28 2016 -0500
@@ -14,7 +14,11 @@
 import stat as statmod
 import sys
 
-from . import policy
+from . import (
+    policy,
+    pycompat,
+)
+
 modulepolicy = policy.policy
 policynocffi = policy.policynocffi
 
@@ -51,8 +55,8 @@
     '''
     result = []
     prefix = path
-    if not prefix.endswith(os.sep):
-        prefix += os.sep
+    if not prefix.endswith(pycompat.ossep):
+        prefix += pycompat.ossep
     names = os.listdir(path)
     names.sort()
     for fn in names:
--- a/mercurial/pycompat.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/pycompat.py	Wed Nov 16 23:29:28 2016 -0500
@@ -10,6 +10,7 @@
 
 from __future__ import absolute_import
 
+import os
 import sys
 
 ispy3 = (sys.version_info[0] >= 3)
@@ -21,6 +22,7 @@
     import Queue as _queue
     import SocketServer as socketserver
     import urlparse
+    urlunquote = urlparse.unquote
     import xmlrpclib
 else:
     import http.client as httplib
@@ -29,13 +31,27 @@
     import queue as _queue
     import socketserver
     import urllib.parse as urlparse
+    urlunquote = urlparse.unquote_to_bytes
     import xmlrpc.client as xmlrpclib
 
 if ispy3:
     import builtins
     import functools
-    import os
     fsencode = os.fsencode
+    fsdecode = os.fsdecode
+    # A bytes version of os.name.
+    osname = os.name.encode('ascii')
+    ospathsep = os.pathsep.encode('ascii')
+    ossep = os.sep.encode('ascii')
+
+    # Since Python 3 converts argv to wchar_t type by Py_DecodeLocale() on Unix,
+    # we can use os.fsencode() to get back bytes argv.
+    #
+    # https://hg.python.org/cpython/file/v3.5.1/Programs/python.c#l55
+    #
+    # TODO: On Windows, the native argv is wchar_t, so we'll need a different
+    # workaround to simulate the Python 2 (i.e. ANSI Win32 API) behavior.
+    sysargv = list(map(os.fsencode, sys.argv))
 
     def sysstr(s):
         """Return a keyword str to be passed to Python functions such as
@@ -76,6 +92,16 @@
             raise TypeError(
                 "expect str, not %s" % type(filename).__name__)
 
+    # In Python 2, fsdecode() has a very chance to receive bytes. So it's
+    # better not to touch Python 2 part as it's already working fine.
+    def fsdecode(filename):
+        return filename
+
+    osname = os.name
+    ospathsep = os.pathsep
+    ossep = os.sep
+    sysargv = sys.argv
+
 stringio = io.StringIO
 empty = _queue.Empty
 queue = _queue.Queue
--- a/mercurial/registrar.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/registrar.py	Wed Nov 16 23:29:28 2016 -0500
@@ -13,7 +13,7 @@
 )
 
 class _funcregistrarbase(object):
-    """Base of decorator to register a fuction for specific purpose
+    """Base of decorator to register a function for specific purpose
 
     This decorator stores decorated functions into own dict 'table'.
 
@@ -177,7 +177,7 @@
 
     Usage::
 
-        templaetkeyword = registrar.templatekeyword()
+        templatekeyword = registrar.templatekeyword()
 
         @templatekeyword('mykeyword')
         def mykeywordfunc(repo, ctx, templ, cache, revcache, **args):
--- a/mercurial/repair.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/repair.py	Wed Nov 16 23:29:28 2016 -0500
@@ -67,7 +67,7 @@
         _, brokenset = revlog.getstrippoint(striprev)
         s.update([revlog.linkrev(r) for r in brokenset])
 
-    collectone(repo.manifest)
+    collectone(repo.manifestlog._revlog)
     for fname in files:
         collectone(repo.file(fname))
 
@@ -153,7 +153,7 @@
         tmpbundlefile = _bundle(repo, savebases, saveheads, node, 'temp',
                             compress=False)
 
-    mfst = repo.manifest
+    mfst = repo.manifestlog._revlog
 
     curtr = repo.currenttransaction()
     if curtr is not None:
@@ -174,7 +174,7 @@
                     if (unencoded.startswith('meta/') and
                         unencoded.endswith('00manifest.i')):
                         dir = unencoded[5:-12]
-                        repo.manifest.dirlog(dir).strip(striprev, tr)
+                        repo.manifestlog._revlog.dirlog(dir).strip(striprev, tr)
             for fn in files:
                 repo.file(fn).strip(striprev, tr)
             tr.endgroup()
@@ -244,6 +244,9 @@
             vfs.unlink(tmpbundlefile)
 
     repo.destroyed()
+    # return the backup file path (or None if 'backup' was False) so
+    # extensions can use it
+    return backupfile
 
 def rebuildfncache(ui, repo):
     """Rebuilds the fncache file from repo history.
--- a/mercurial/revlog.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/revlog.py	Wed Nov 16 23:29:28 2016 -0500
@@ -380,22 +380,29 @@
                     return r
             raise LookupError(node, self.indexfile, _('no node'))
 
-    def node(self, rev):
-        return self.index[rev][7]
-    def linkrev(self, rev):
-        return self.index[rev][4]
-    def parents(self, node):
-        i = self.index
-        d = i[self.rev(node)]
-        return i[d[5]][7], i[d[6]][7] # map revisions to nodes inline
-    def parentrevs(self, rev):
-        return self.index[rev][5:7]
+    # Accessors for index entries.
+
+    # First tuple entry is 8 bytes. First 6 bytes are offset. Last 2 bytes
+    # are flags.
     def start(self, rev):
         return int(self.index[rev][0] >> 16)
-    def end(self, rev):
-        return self.start(rev) + self.length(rev)
+
+    def flags(self, rev):
+        return self.index[rev][0] & 0xFFFF
+
     def length(self, rev):
         return self.index[rev][1]
+
+    def rawsize(self, rev):
+        """return the length of the uncompressed text for a given revision"""
+        l = self.index[rev][2]
+        if l >= 0:
+            return l
+
+        t = self.revision(self.node(rev))
+        return len(t)
+    size = rawsize
+
     def chainbase(self, rev):
         base = self._chainbasecache.get(rev)
         if base is not None:
@@ -409,6 +416,26 @@
 
         self._chainbasecache[rev] = base
         return base
+
+    def linkrev(self, rev):
+        return self.index[rev][4]
+
+    def parentrevs(self, rev):
+        return self.index[rev][5:7]
+
+    def node(self, rev):
+        return self.index[rev][7]
+
+    # Derived from index values.
+
+    def end(self, rev):
+        return self.start(rev) + self.length(rev)
+
+    def parents(self, node):
+        i = self.index
+        d = i[self.rev(node)]
+        return i[d[5]][7], i[d[6]][7] # map revisions to nodes inline
+
     def chainlen(self, rev):
         return self._chaininfo(rev)[0]
 
@@ -478,18 +505,6 @@
         chain.reverse()
         return chain, stopped
 
-    def flags(self, rev):
-        return self.index[rev][0] & 0xFFFF
-    def rawsize(self, rev):
-        """return the length of the uncompressed text for a given revision"""
-        l = self.index[rev][2]
-        if l >= 0:
-            return l
-
-        t = self.revision(self.node(rev))
-        return len(t)
-    size = rawsize
-
     def ancestors(self, revs, stoprev=0, inclusive=False):
         """Generate the ancestors of 'revs' in reverse topological order.
         Does not generate revs lower than stoprev.
@@ -582,7 +597,7 @@
                         visit.append(p)
         missing = list(missing)
         missing.sort()
-        return has, [self.node(r) for r in missing]
+        return has, [self.node(miss) for miss in missing]
 
     def incrementalmissingrevs(self, common=None):
         """Return an object that can be used to incrementally compute the
@@ -734,10 +749,10 @@
                 # include roots that aren't ancestors.
 
                 # Filter out roots that aren't ancestors of heads
-                roots = [n for n in roots if n in ancestors]
+                roots = [root for root in roots if root in ancestors]
                 # Recompute the lowest revision
                 if roots:
-                    lowestrev = min([self.rev(n) for n in roots])
+                    lowestrev = min([self.rev(root) for root in roots])
                 else:
                     # No more roots?  Return empty list
                     return nonodes
@@ -796,7 +811,7 @@
                     # But, obviously its parents aren't.
                     for p in self.parents(n):
                         heads.pop(p, None)
-        heads = [n for n, flag in heads.iteritems() if flag]
+        heads = [head for head, flag in heads.iteritems() if flag]
         roots = list(roots)
         assert orderedout
         assert roots
@@ -948,9 +963,9 @@
 
     def _partialmatch(self, id):
         try:
-            n = self.index.partialmatch(id)
-            if n and self.hasnode(n):
-                return n
+            partial = self.index.partialmatch(id)
+            if partial and self.hasnode(partial):
+                return partial
             return None
         except RevlogError:
             # parsers.c radix tree lookup gave multiple matches
@@ -1094,8 +1109,17 @@
         Callers will need to call ``self.start(rev)`` and ``self.length(rev)``
         to determine where each revision's data begins and ends.
         """
-        start = self.start(startrev)
-        end = self.end(endrev)
+        # Inlined self.start(startrev) & self.end(endrev) for perf reasons
+        # (functions are expensive).
+        index = self.index
+        istart = index[startrev]
+        start = int(istart[0] >> 16)
+        if startrev == endrev:
+            end = start + istart[1]
+        else:
+            iend = index[endrev]
+            end = int(iend[0] >> 16) + iend[1]
+
         if self._inline:
             start += (startrev + 1) * self._io.size
             end += (endrev + 1) * self._io.size
--- a/mercurial/revset.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/revset.py	Wed Nov 16 23:29:28 2016 -0500
@@ -437,10 +437,10 @@
 def func(repo, subset, a, b, order):
     f = getsymbol(a)
     if f in symbols:
-        fn = symbols[f]
-        if getattr(fn, '_takeorder', False):
-            return fn(repo, subset, b, order)
-        return fn(repo, subset, b)
+        func = symbols[f]
+        if getattr(func, '_takeorder', False):
+            return func(repo, subset, b, order)
+        return func(repo, subset, b)
 
     keep = lambda fn: getattr(fn, '__doc__', None) is not None
 
@@ -1443,7 +1443,7 @@
 
     results = set(cl.findmissingrevs(common=exclude, heads=include))
     # XXX we should turn this into a baseset instead of a set, smartset may do
-    # some optimisations from the fact this is a baseset.
+    # some optimizations from the fact this is a baseset.
     return subset & results
 
 @predicate('origin([set])', safe=True)
@@ -1475,7 +1475,7 @@
     o = set([_firstsrc(r) for r in dests])
     o -= set([None])
     # XXX we should turn this into a baseset instead of a set, smartset may do
-    # some optimisations from the fact this is a baseset.
+    # some optimizations from the fact this is a baseset.
     return subset & o
 
 @predicate('outgoing([path])', safe=True)
@@ -1521,7 +1521,7 @@
         ps.add(cl.parentrevs(r)[0])
     ps -= set([node.nullrev])
     # XXX we should turn this into a baseset instead of a set, smartset may do
-    # some optimisations from the fact this is a baseset.
+    # some optimizations from the fact this is a baseset.
     return subset & ps
 
 @predicate('p2([set])', safe=True)
@@ -1544,7 +1544,7 @@
         ps.add(cl.parentrevs(r)[1])
     ps -= set([node.nullrev])
     # XXX we should turn this into a baseset instead of a set, smartset may do
-    # some optimisations from the fact this is a baseset.
+    # some optimizations from the fact this is a baseset.
     return subset & ps
 
 def parentpost(repo, subset, x, order):
@@ -3198,7 +3198,7 @@
     def __len__(self):
         # Basic implementation to be changed in future patches.
         # until this gets improved, we use generator expression
-        # here, since list compr is free to call __len__ again
+        # here, since list comprehensions are free to call __len__ again
         # causing infinite recursion
         l = baseset(r for r in self)
         return len(l)
--- a/mercurial/scmposix.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/scmposix.py	Wed Nov 16 23:29:28 2016 -0500
@@ -1,9 +1,13 @@
 from __future__ import absolute_import
 
+import array
+import errno
+import fcntl
 import os
 import sys
 
 from . import (
+    encoding,
     osutil,
 )
 
@@ -34,6 +38,34 @@
 
 def userrcpath():
     if sys.platform == 'plan9':
-        return [os.environ['home'] + '/lib/hgrc']
+        return [encoding.environ['home'] + '/lib/hgrc']
     else:
         return [os.path.expanduser('~/.hgrc')]
+
+def termsize(ui):
+    try:
+        import termios
+        TIOCGWINSZ = termios.TIOCGWINSZ  # unavailable on IRIX (issue3449)
+    except (AttributeError, ImportError):
+        return 80, 24
+
+    for dev in (ui.ferr, ui.fout, ui.fin):
+        try:
+            try:
+                fd = dev.fileno()
+            except AttributeError:
+                continue
+            if not os.isatty(fd):
+                continue
+            arri = fcntl.ioctl(fd, TIOCGWINSZ, '\0' * 8)
+            height, width = array.array('h', arri)[:2]
+            if width > 0 and height > 0:
+                return width, height
+        except ValueError:
+            pass
+        except IOError as e:
+            if e[0] == errno.EINVAL:
+                pass
+            else:
+                raise
+    return 80, 24
--- a/mercurial/scmutil.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/scmutil.py	Wed Nov 16 23:29:28 2016 -0500
@@ -27,6 +27,7 @@
     osutil,
     pathutil,
     phases,
+    pycompat,
     revset,
     similar,
     util,
@@ -39,6 +40,7 @@
 
 systemrcpath = scmplatform.systemrcpath
 userrcpath = scmplatform.userrcpath
+termsize = scmplatform.termsize
 
 class status(tuple):
     '''Named tuple with a list of files per status. The 'deleted', 'unknown'
@@ -754,7 +756,7 @@
     if _rcpath is None:
         if 'HGRCPATH' in encoding.environ:
             _rcpath = []
-            for p in os.environ['HGRCPATH'].split(os.pathsep):
+            for p in encoding.environ['HGRCPATH'].split(pycompat.ospathsep):
                 if not p:
                     continue
                 p = util.expandpath(p)
--- a/mercurial/scmwindows.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/scmwindows.py	Wed Nov 16 23:29:28 2016 -0500
@@ -5,6 +5,7 @@
 from . import (
     osutil,
     util,
+    win32,
 )
 
 try:
@@ -51,3 +52,6 @@
         path.append(os.path.join(userprofile, 'mercurial.ini'))
         path.append(os.path.join(userprofile, '.hgrc'))
     return path
+
+def termsize(ui):
+    return win32.termsize()
--- a/mercurial/simplemerge.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/simplemerge.py	Wed Nov 16 23:29:28 2016 -0500
@@ -19,7 +19,6 @@
 from __future__ import absolute_import
 
 import os
-import sys
 
 from .i18n import _
 from . import (
@@ -275,7 +274,7 @@
     def minimize(self, merge_regions):
         """Trim conflict regions of lines where A and B sides match.
 
-        Lines where both A and B have made the same changes at the begining
+        Lines where both A and B have made the same changes at the beginning
         or the end of each merge region are eliminated from the conflict
         region and are instead considered the same.
         """
@@ -441,7 +440,7 @@
         opener = scmutil.opener(os.path.dirname(local))
         out = opener(os.path.basename(local), "w", atomictemp=True)
     else:
-        out = sys.stdout
+        out = ui.fout
 
     m3 = Merge3Text(basetext, localtext, othertext)
     extrakwargs = {
--- a/mercurial/sslutil.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/sslutil.py	Wed Nov 16 23:29:28 2016 -0500
@@ -638,7 +638,7 @@
                 # According to RFC 2818 the most specific Common Name must
                 # be used.
                 if key == 'commonName':
-                    # 'subject' entries are unicide.
+                    # 'subject' entries are unicode.
                     try:
                         value = value.encode('ascii')
                     except UnicodeEncodeError:
@@ -764,7 +764,7 @@
     return None
 
 def validatesocket(sock):
-    """Validate a socket meets security requiremnets.
+    """Validate a socket meets security requirements.
 
     The passed socket must have been created with ``wrapsocket()``.
     """
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/statprof.py	Wed Nov 16 23:29:28 2016 -0500
@@ -0,0 +1,805 @@
+#!/usr/bin/env python
+## statprof.py
+## Copyright (C) 2012 Bryan O'Sullivan <bos@serpentine.com>
+## Copyright (C) 2011 Alex Fraser <alex at phatcore dot com>
+## Copyright (C) 2004,2005 Andy Wingo <wingo at pobox dot com>
+## Copyright (C) 2001 Rob Browning <rlb at defaultvalue dot org>
+
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this program; if not, contact:
+##
+## Free Software Foundation           Voice:  +1-617-542-5942
+## 59 Temple Place - Suite 330        Fax:    +1-617-542-2652
+## Boston, MA  02111-1307,  USA       gnu@gnu.org
+
+"""
+statprof is intended to be a fairly simple statistical profiler for
+python. It was ported directly from a statistical profiler for guile,
+also named statprof, available from guile-lib [0].
+
+[0] http://wingolog.org/software/guile-lib/statprof/
+
+To start profiling, call statprof.start():
+>>> start()
+
+Then run whatever it is that you want to profile, for example:
+>>> import test.pystone; test.pystone.pystones()
+
+Then stop the profiling and print out the results:
+>>> stop()
+>>> display()
+  %   cumulative      self
+ time    seconds   seconds  name
+ 26.72      1.40      0.37  pystone.py:79:Proc0
+ 13.79      0.56      0.19  pystone.py:133:Proc1
+ 13.79      0.19      0.19  pystone.py:208:Proc8
+ 10.34      0.16      0.14  pystone.py:229:Func2
+  6.90      0.10      0.10  pystone.py:45:__init__
+  4.31      0.16      0.06  pystone.py:53:copy
+    ...
+
+All of the numerical data is statistically approximate. In the
+following column descriptions, and in all of statprof, "time" refers
+to execution time (both user and system), not wall clock time.
+
+% time
+    The percent of the time spent inside the procedure itself (not
+    counting children).
+
+cumulative seconds
+    The total number of seconds spent in the procedure, including
+    children.
+
+self seconds
+    The total number of seconds spent in the procedure itself (not
+    counting children).
+
+name
+    The name of the procedure.
+
+By default statprof keeps the data collected from previous runs. If you
+want to clear the collected data, call reset():
+>>> reset()
+
+reset() can also be used to change the sampling frequency from the
+default of 1000 Hz. For example, to tell statprof to sample 50 times a
+second:
+>>> reset(50)
+
+This means that statprof will sample the call stack after every 1/50 of
+a second of user + system time spent running on behalf of the python
+process. When your process is idle (for example, blocking in a read(),
+as is the case at the listener), the clock does not advance. For this
+reason statprof is not currently not suitable for profiling io-bound
+operations.
+
+The profiler uses the hash of the code object itself to identify the
+procedures, so it won't confuse different procedures with the same name.
+They will show up as two different rows in the output.
+
+Right now the profiler is quite simplistic.  I cannot provide
+call-graphs or other higher level information.  What you see in the
+table is pretty much all there is. Patches are welcome :-)
+
+
+Threading
+---------
+
+Because signals only get delivered to the main thread in Python,
+statprof only profiles the main thread. However because the time
+reporting function uses per-process timers, the results can be
+significantly off if other threads' work patterns are not similar to the
+main thread's work patterns.
+"""
+# no-check-code
+from __future__ import absolute_import, division, print_function
+
+import collections
+import contextlib
+import getopt
+import inspect
+import json
+import os
+import signal
+import sys
+import tempfile
+import threading
+import time
+
+defaultdict = collections.defaultdict
+contextmanager = contextlib.contextmanager
+
+__all__ = ['start', 'stop', 'reset', 'display', 'profile']
+
+skips = set(["util.py:check", "extensions.py:closure",
+             "color.py:colorcmd", "dispatch.py:checkargs",
+             "dispatch.py:<lambda>", "dispatch.py:_runcatch",
+             "dispatch.py:_dispatch", "dispatch.py:_runcommand",
+             "pager.py:pagecmd", "dispatch.py:run",
+             "dispatch.py:dispatch", "dispatch.py:runcommand",
+             "hg.py:<module>", "evolve.py:warnobserrors",
+         ])
+
+###########################################################################
+## Utils
+
+def clock():
+    times = os.times()
+    return times[0] + times[1]
+
+
+###########################################################################
+## Collection data structures
+
+class ProfileState(object):
+    def __init__(self, frequency=None):
+        self.reset(frequency)
+
+    def reset(self, frequency=None):
+        # total so far
+        self.accumulated_time = 0.0
+        # start_time when timer is active
+        self.last_start_time = None
+        # a float
+        if frequency:
+            self.sample_interval = 1.0 / frequency
+        elif not hasattr(self, 'sample_interval'):
+            # default to 1000 Hz
+            self.sample_interval = 1.0 / 1000.0
+        else:
+            # leave the frequency as it was
+            pass
+        self.remaining_prof_time = None
+        # for user start/stop nesting
+        self.profile_level = 0
+
+        self.samples = []
+
+    def accumulate_time(self, stop_time):
+        self.accumulated_time += stop_time - self.last_start_time
+
+    def seconds_per_sample(self):
+        return self.accumulated_time / len(self.samples)
+
+state = ProfileState()
+
+
+class CodeSite(object):
+    cache = {}
+
+    __slots__ = ('path', 'lineno', 'function', 'source')
+
+    def __init__(self, path, lineno, function):
+        self.path = path
+        self.lineno = lineno
+        self.function = function
+        self.source = None
+
+    def __eq__(self, other):
+        try:
+            return (self.lineno == other.lineno and
+                    self.path == other.path)
+        except:
+            return False
+
+    def __hash__(self):
+        return hash((self.lineno, self.path))
+
+    @classmethod
+    def get(cls, path, lineno, function):
+        k = (path, lineno)
+        try:
+            return cls.cache[k]
+        except KeyError:
+            v = cls(path, lineno, function)
+            cls.cache[k] = v
+            return v
+
+    def getsource(self, length):
+        if self.source is None:
+            lineno = self.lineno - 1
+            fp = None
+            try:
+                fp = open(self.path)
+                for i, line in enumerate(fp):
+                    if i == lineno:
+                        self.source = line.strip()
+                        break
+            except:
+                pass
+            finally:
+                if fp:
+                    fp.close()
+            if self.source is None:
+                self.source = ''
+
+        source = self.source
+        if len(source) > length:
+            source = source[:(length - 3)] + "..."
+        return source
+
+    def filename(self):
+        return os.path.basename(self.path)
+
+class Sample(object):
+    __slots__ = ('stack', 'time')
+
+    def __init__(self, stack, time):
+        self.stack = stack
+        self.time = time
+
+    @classmethod
+    def from_frame(cls, frame, time):
+        stack = []
+
+        while frame:
+            stack.append(CodeSite.get(frame.f_code.co_filename, frame.f_lineno,
+                                      frame.f_code.co_name))
+            frame = frame.f_back
+
+        return Sample(stack, time)
+
+###########################################################################
+## SIGPROF handler
+
+def profile_signal_handler(signum, frame):
+    if state.profile_level > 0:
+        now = clock()
+        state.accumulate_time(now)
+
+        state.samples.append(Sample.from_frame(frame, state.accumulated_time))
+
+        signal.setitimer(signal.ITIMER_PROF,
+            state.sample_interval, 0.0)
+        state.last_start_time = now
+
+stopthread = threading.Event()
+def samplerthread(tid):
+    while not stopthread.is_set():
+        now = clock()
+        state.accumulate_time(now)
+
+        frame = sys._current_frames()[tid]
+        state.samples.append(Sample.from_frame(frame, state.accumulated_time))
+
+        state.last_start_time = now
+        time.sleep(state.sample_interval)
+
+    stopthread.clear()
+
+###########################################################################
+## Profiling API
+
+def is_active():
+    return state.profile_level > 0
+
+lastmechanism = None
+def start(mechanism='thread'):
+    '''Install the profiling signal handler, and start profiling.'''
+    state.profile_level += 1
+    if state.profile_level == 1:
+        state.last_start_time = clock()
+        rpt = state.remaining_prof_time
+        state.remaining_prof_time = None
+
+        global lastmechanism
+        lastmechanism = mechanism
+
+        if mechanism == 'signal':
+            signal.signal(signal.SIGPROF, profile_signal_handler)
+            signal.setitimer(signal.ITIMER_PROF,
+                rpt or state.sample_interval, 0.0)
+        elif mechanism == 'thread':
+            frame = inspect.currentframe()
+            tid = [k for k, f in sys._current_frames().items() if f == frame][0]
+            state.thread = threading.Thread(target=samplerthread,
+                                 args=(tid,), name="samplerthread")
+            state.thread.start()
+
+def stop():
+    '''Stop profiling, and uninstall the profiling signal handler.'''
+    state.profile_level -= 1
+    if state.profile_level == 0:
+        if lastmechanism == 'signal':
+            rpt = signal.setitimer(signal.ITIMER_PROF, 0.0, 0.0)
+            signal.signal(signal.SIGPROF, signal.SIG_IGN)
+            state.remaining_prof_time = rpt[0]
+        elif lastmechanism == 'thread':
+            stopthread.set()
+            state.thread.join()
+
+        state.accumulate_time(clock())
+        state.last_start_time = None
+        statprofpath = os.environ.get('STATPROF_DEST')
+        if statprofpath:
+            save_data(statprofpath)
+
+    return state
+
+def save_data(path):
+    with open(path, 'w+') as file:
+        file.write(str(state.accumulated_time) + '\n')
+        for sample in state.samples:
+            time = str(sample.time)
+            stack = sample.stack
+            sites = ['\1'.join([s.path, str(s.lineno), s.function])
+                     for s in stack]
+            file.write(time + '\0' + '\0'.join(sites) + '\n')
+
+def load_data(path):
+    lines = open(path, 'r').read().splitlines()
+
+    state.accumulated_time = float(lines[0])
+    state.samples = []
+    for line in lines[1:]:
+        parts = line.split('\0')
+        time = float(parts[0])
+        rawsites = parts[1:]
+        sites = []
+        for rawsite in rawsites:
+            siteparts = rawsite.split('\1')
+            sites.append(CodeSite.get(siteparts[0], int(siteparts[1]),
+                        siteparts[2]))
+
+        state.samples.append(Sample(sites, time))
+
+
+
+def reset(frequency=None):
+    '''Clear out the state of the profiler.  Do not call while the
+    profiler is running.
+
+    The optional frequency argument specifies the number of samples to
+    collect per second.'''
+    assert state.profile_level == 0, "Can't reset() while statprof is running"
+    CodeSite.cache.clear()
+    state.reset(frequency)
+
+
+@contextmanager
+def profile():
+    start()
+    try:
+        yield
+    finally:
+        stop()
+        display()
+
+
+###########################################################################
+## Reporting API
+
+class SiteStats(object):
+    def __init__(self, site):
+        self.site = site
+        self.selfcount = 0
+        self.totalcount = 0
+
+    def addself(self):
+        self.selfcount += 1
+
+    def addtotal(self):
+        self.totalcount += 1
+
+    def selfpercent(self):
+        return self.selfcount / len(state.samples) * 100
+
+    def totalpercent(self):
+        return self.totalcount / len(state.samples) * 100
+
+    def selfseconds(self):
+        return self.selfcount * state.seconds_per_sample()
+
+    def totalseconds(self):
+        return self.totalcount * state.seconds_per_sample()
+
+    @classmethod
+    def buildstats(cls, samples):
+        stats = {}
+
+        for sample in samples:
+            for i, site in enumerate(sample.stack):
+                sitestat = stats.get(site)
+                if not sitestat:
+                    sitestat = SiteStats(site)
+                    stats[site] = sitestat
+
+                sitestat.addtotal()
+
+                if i == 0:
+                    sitestat.addself()
+
+        return [s for s in stats.itervalues()]
+
+class DisplayFormats:
+    ByLine = 0
+    ByMethod = 1
+    AboutMethod = 2
+    Hotpath = 3
+    FlameGraph = 4
+    Json = 5
+
+def display(fp=None, format=3, data=None, **kwargs):
+    '''Print statistics, either to stdout or the given file object.'''
+    data = data or state
+
+    if fp is None:
+        import sys
+        fp = sys.stdout
+    if len(data.samples) == 0:
+        print('No samples recorded.', file=fp)
+        return
+
+    if format == DisplayFormats.ByLine:
+        display_by_line(data, fp)
+    elif format == DisplayFormats.ByMethod:
+        display_by_method(data, fp)
+    elif format == DisplayFormats.AboutMethod:
+        display_about_method(data, fp, **kwargs)
+    elif format == DisplayFormats.Hotpath:
+        display_hotpath(data, fp, **kwargs)
+    elif format == DisplayFormats.FlameGraph:
+        write_to_flame(data, fp, **kwargs)
+    elif format == DisplayFormats.Json:
+        write_to_json(data, fp)
+    else:
+        raise Exception("Invalid display format")
+
+    if format != DisplayFormats.Json:
+        print('---', file=fp)
+        print('Sample count: %d' % len(data.samples), file=fp)
+        print('Total time: %f seconds' % data.accumulated_time, file=fp)
+
+def display_by_line(data, fp):
+    '''Print the profiler data with each sample line represented
+    as one row in a table.  Sorted by self-time per line.'''
+    stats = SiteStats.buildstats(data.samples)
+    stats.sort(reverse=True, key=lambda x: x.selfseconds())
+
+    print('%5.5s %10.10s   %7.7s  %-8.8s' %
+          ('%  ', 'cumulative', 'self', ''), file=fp)
+    print('%5.5s  %9.9s  %8.8s  %-8.8s' %
+          ("time", "seconds", "seconds", "name"), file=fp)
+
+    for stat in stats:
+        site = stat.site
+        sitelabel = '%s:%d:%s' % (site.filename(), site.lineno, site.function)
+        print('%6.2f %9.2f %9.2f  %s' % (stat.selfpercent(),
+                                         stat.totalseconds(),
+                                         stat.selfseconds(),
+                                         sitelabel),
+              file=fp)
+
+def display_by_method(data, fp):
+    '''Print the profiler data with each sample function represented
+    as one row in a table.  Important lines within that function are
+    output as nested rows.  Sorted by self-time per line.'''
+    print('%5.5s %10.10s   %7.7s  %-8.8s' %
+          ('%  ', 'cumulative', 'self', ''), file=fp)
+    print('%5.5s  %9.9s  %8.8s  %-8.8s' %
+          ("time", "seconds", "seconds", "name"), file=fp)
+
+    stats = SiteStats.buildstats(data.samples)
+
+    grouped = defaultdict(list)
+    for stat in stats:
+        grouped[stat.site.filename() + ":" + stat.site.function].append(stat)
+
+    # compute sums for each function
+    functiondata = []
+    for fname, sitestats in grouped.iteritems():
+        total_cum_sec = 0
+        total_self_sec = 0
+        total_percent = 0
+        for stat in sitestats:
+            total_cum_sec += stat.totalseconds()
+            total_self_sec += stat.selfseconds()
+            total_percent += stat.selfpercent()
+
+        functiondata.append((fname,
+                             total_cum_sec,
+                             total_self_sec,
+                             total_percent,
+                             sitestats))
+
+    # sort by total self sec
+    functiondata.sort(reverse=True, key=lambda x: x[2])
+
+    for function in functiondata:
+        if function[3] < 0.05:
+            continue
+        print('%6.2f %9.2f %9.2f  %s' % (function[3], # total percent
+                                         function[1], # total cum sec
+                                         function[2], # total self sec
+                                         function[0]), # file:function
+              file=fp)
+        function[4].sort(reverse=True, key=lambda i: i.selfseconds())
+        for stat in function[4]:
+            # only show line numbers for significant locations (>1% time spent)
+            if stat.selfpercent() > 1:
+                source = stat.site.getsource(25)
+                stattuple = (stat.selfpercent(), stat.selfseconds(),
+                             stat.site.lineno, source)
+
+                print('%33.0f%% %6.2f   line %s: %s' % (stattuple), file=fp)
+
+def display_about_method(data, fp, function=None, **kwargs):
+    if function is None:
+        raise Exception("Invalid function")
+
+    filename = None
+    if ':' in function:
+        filename, function = function.split(':')
+
+    relevant_samples = 0
+    parents = {}
+    children = {}
+
+    for sample in data.samples:
+        for i, site in enumerate(sample.stack):
+            if site.function == function and (not filename
+                or site.filename() == filename):
+                relevant_samples += 1
+                if i != len(sample.stack) - 1:
+                    parent = sample.stack[i + 1]
+                    if parent in parents:
+                        parents[parent] = parents[parent] + 1
+                    else:
+                        parents[parent] = 1
+
+                if site in children:
+                    children[site] = children[site] + 1
+                else:
+                    children[site] = 1
+
+    parents = [(parent, count) for parent, count in parents.iteritems()]
+    parents.sort(reverse=True, key=lambda x: x[1])
+    for parent, count in parents:
+        print('%6.2f%%   %s:%s   line %s: %s' %
+            (count / relevant_samples * 100, parent.filename(),
+            parent.function, parent.lineno, parent.getsource(50)), file=fp)
+
+    stats = SiteStats.buildstats(data.samples)
+    stats = [s for s in stats
+               if s.site.function == function and
+               (not filename or s.site.filename() == filename)]
+
+    total_cum_sec = 0
+    total_self_sec = 0
+    total_self_percent = 0
+    total_cum_percent = 0
+    for stat in stats:
+        total_cum_sec += stat.totalseconds()
+        total_self_sec += stat.selfseconds()
+        total_self_percent += stat.selfpercent()
+        total_cum_percent += stat.totalpercent()
+
+    print(
+        '\n    %s:%s    Total: %0.2fs (%0.2f%%)    Self: %0.2fs (%0.2f%%)\n' %
+        (
+        filename or '___',
+        function,
+        total_cum_sec,
+        total_cum_percent,
+        total_self_sec,
+        total_self_percent
+        ), file=fp)
+
+    children = [(child, count) for child, count in children.iteritems()]
+    children.sort(reverse=True, key=lambda x: x[1])
+    for child, count in children:
+        print('        %6.2f%%   line %s: %s' %
+              (count / relevant_samples * 100, child.lineno,
+               child.getsource(50)), file=fp)
+
+def display_hotpath(data, fp, limit=0.05, **kwargs):
+    class HotNode(object):
+        def __init__(self, site):
+            self.site = site
+            self.count = 0
+            self.children = {}
+
+        def add(self, stack, time):
+            self.count += time
+            site = stack[0]
+            child = self.children.get(site)
+            if not child:
+                child = HotNode(site)
+                self.children[site] = child
+
+            if len(stack) > 1:
+                i = 1
+                # Skip boiler plate parts of the stack
+                while i < len(stack) and '%s:%s' % (stack[i].filename(), stack[i].function) in skips:
+                    i += 1
+                if i < len(stack):
+                    child.add(stack[i:], time)
+
+    root = HotNode(None)
+    lasttime = data.samples[0].time
+    for sample in data.samples:
+        root.add(sample.stack[::-1], sample.time - lasttime)
+        lasttime = sample.time
+
+    def _write(node, depth, multiple_siblings):
+        site = node.site
+        visiblechildren = [c for c in node.children.itervalues()
+                             if c.count >= (limit * root.count)]
+        if site:
+            indent = depth * 2 - 1
+            filename = ''
+            function = ''
+            if len(node.children) > 0:
+                childsite = list(node.children.itervalues())[0].site
+                filename = (childsite.filename() + ':').ljust(15)
+                function = childsite.function
+
+            # lots of string formatting
+            listpattern = ''.ljust(indent) +\
+                          ('\\' if multiple_siblings else '|') +\
+                          ' %4.1f%%  %s %s'
+            liststring = listpattern % (node.count / root.count * 100,
+                                        filename, function)
+            codepattern = '%' + str(55 - len(liststring)) + 's %s:  %s'
+            codestring = codepattern % ('line', site.lineno, site.getsource(30))
+
+            finalstring = liststring + codestring
+            childrensamples = sum([c.count for c in node.children.itervalues()])
+            # Make frames that performed more than 10% of the operation red
+            if node.count - childrensamples > (0.1 * root.count):
+                finalstring = '\033[91m' + finalstring + '\033[0m'
+            # Make frames that didn't actually perform work dark grey
+            elif node.count - childrensamples == 0:
+                finalstring = '\033[90m' + finalstring + '\033[0m'
+            print(finalstring, file=fp)
+
+        newdepth = depth
+        if len(visiblechildren) > 1 or multiple_siblings:
+            newdepth += 1
+
+        visiblechildren.sort(reverse=True, key=lambda x: x.count)
+        for child in visiblechildren:
+            _write(child, newdepth, len(visiblechildren) > 1)
+
+    if root.count > 0:
+        _write(root, 0, False)
+
+def write_to_flame(data, fp, scriptpath=None, outputfile=None, **kwargs):
+    if scriptpath is None:
+        scriptpath = os.environ['HOME'] + '/flamegraph.pl'
+    if not os.path.exists(scriptpath):
+        print("error: missing %s" % scriptpath, file=fp)
+        print("get it here: https://github.com/brendangregg/FlameGraph",
+              file=fp)
+        return
+
+    fd, path = tempfile.mkstemp()
+
+    file = open(path, "w+")
+
+    lines = {}
+    for sample in data.samples:
+        sites = [s.function for s in sample.stack]
+        sites.reverse()
+        line = ';'.join(sites)
+        if line in lines:
+            lines[line] = lines[line] + 1
+        else:
+            lines[line] = 1
+
+    for line, count in lines.iteritems():
+        file.write("%s %s\n" % (line, count))
+
+    file.close()
+
+    if outputfile is None:
+        outputfile = '~/flamegraph.svg'
+
+    os.system("perl ~/flamegraph.pl %s > %s" % (path, outputfile))
+    print("Written to %s" % outputfile, file=fp)
+
+def write_to_json(data, fp):
+    samples = []
+
+    for sample in data.samples:
+        stack = []
+
+        for frame in sample.stack:
+            stack.append((frame.path, frame.lineno, frame.function))
+
+        samples.append((sample.time, stack))
+
+    print(json.dumps(samples), file=fp)
+
+def printusage():
+    print("""
+The statprof command line allows you to inspect the last profile's results in
+the following forms:
+
+usage:
+    hotpath [-l --limit percent]
+        Shows a graph of calls with the percent of time each takes.
+        Red calls take over 10%% of the total time themselves.
+    lines
+        Shows the actual sampled lines.
+    functions
+        Shows the samples grouped by function.
+    function [filename:]functionname
+        Shows the callers and callees of a particular function.
+    flame [-s --script-path] [-o --output-file path]
+        Writes out a flamegraph to output-file (defaults to ~/flamegraph.svg)
+        Requires that ~/flamegraph.pl exist.
+        (Specify alternate script path with --script-path.)""")
+
+def main(argv=None):
+    if argv is None:
+        argv = sys.argv
+
+    if len(argv) == 1:
+        printusage()
+        return 0
+
+    displayargs = {}
+
+    optstart = 2
+    displayargs['function'] = None
+    if argv[1] == 'hotpath':
+        displayargs['format'] = DisplayFormats.Hotpath
+    elif argv[1] == 'lines':
+        displayargs['format'] = DisplayFormats.ByLine
+    elif argv[1] == 'functions':
+        displayargs['format'] = DisplayFormats.ByMethod
+    elif argv[1] == 'function':
+        displayargs['format'] = DisplayFormats.AboutMethod
+        displayargs['function'] = argv[2]
+        optstart = 3
+    elif argv[1] == 'flame':
+        displayargs['format'] = DisplayFormats.FlameGraph
+    else:
+        printusage()
+        return 0
+
+    # process options
+    try:
+        opts, args = getopt.getopt(sys.argv[optstart:], "hl:f:o:p:",
+                                   ["help", "limit=", "file=", "output-file=", "script-path="])
+    except getopt.error as msg:
+        print(msg)
+        printusage()
+        return 2
+
+    displayargs['limit'] = 0.05
+    path = None
+    for o, value in opts:
+        if o in ("-l", "--limit"):
+            displayargs['limit'] = float(value)
+        elif o in ("-f", "--file"):
+            path = value
+        elif o in ("-o", "--output-file"):
+            displayargs['outputfile'] = value
+        elif o in ("-p", "--script-path"):
+            displayargs['scriptpath'] = value
+        elif o in ("-h", "help"):
+            printusage()
+            return 0
+        else:
+            assert False, "unhandled option %s" % o
+
+    load_data(path=path)
+
+    display(**displayargs)
+
+    return 0
+
+if __name__ == "__main__":
+    sys.exit(main())
--- a/mercurial/store.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/store.py	Wed Nov 16 23:29:28 2016 -0500
@@ -436,7 +436,7 @@
         self.entries = set(decodedir(fp.read()).splitlines())
         if '' in self.entries:
             fp.seek(0)
-            for n, line in enumerate(fp):
+            for n, line in enumerate(util.iterfile(fp)):
                 if not line.rstrip('\n'):
                     t = _('invalid entry in fncache, line %d') % (n + 1)
                     raise error.Abort(t)
--- a/mercurial/streamclone.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/streamclone.py	Wed Nov 16 23:29:28 2016 -0500
@@ -286,11 +286,11 @@
 def consumev1(repo, fp, filecount, bytecount):
     """Apply the contents from version 1 of a streaming clone file handle.
 
-    This takes the output from "streamout" and applies it to the specified
+    This takes the output from "stream_out" and applies it to the specified
     repository.
 
-    Like "streamout," the status line added by the wire protocol is not handled
-    by this function.
+    Like "stream_out," the status line added by the wire protocol is not
+    handled by this function.
     """
     with repo.lock():
         repo.ui.status(_('%d files to transfer, %s of data\n') %
--- a/mercurial/templatekw.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/templatekw.py	Wed Nov 16 23:29:28 2016 -0500
@@ -458,7 +458,8 @@
         # just avoid crash, we might want to use the 'ff...' hash in future
         return
     args = args.copy()
-    args.update({'rev': repo.manifest.rev(mnode), 'node': hex(mnode)})
+    args.update({'rev': repo.manifestlog._revlog.rev(mnode),
+                 'node': hex(mnode)})
     return templ('manifest', **args)
 
 def shownames(namespace, **args):
--- a/mercurial/templater.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/templater.py	Wed Nov 16 23:29:28 2016 -0500
@@ -792,7 +792,7 @@
 
 @templatefunc('rstdoc(text, style)')
 def rstdoc(context, mapping, args):
-    """Format ReStructuredText."""
+    """Format reStructuredText."""
     if len(args) != 2:
         # i18n: "rstdoc" is a keyword
         raise error.ParseError(_("rstdoc expects two arguments"))
--- a/mercurial/ui.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/ui.py	Wed Nov 16 23:29:28 2016 -0500
@@ -22,6 +22,7 @@
 
 from . import (
     config,
+    encoding,
     error,
     formatter,
     progress,
@@ -175,7 +176,7 @@
     def readconfig(self, filename, root=None, trust=False,
                    sections=None, remap=None):
         try:
-            fp = open(filename)
+            fp = open(filename, u'rb')
         except IOError:
             if not sections: # ignore unless we were looking for something
                 return
@@ -569,9 +570,11 @@
         - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
         - True otherwise
         '''
-        if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
+        if ('HGPLAIN' not in encoding.environ and
+                'HGPLAINEXCEPT' not in encoding.environ):
             return False
-        exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
+        exceptions = encoding.environ.get('HGPLAINEXCEPT',
+                '').strip().split(',')
         if feature and exceptions:
             return feature not in exceptions
         return True
@@ -584,13 +587,13 @@
         If not found and ui.askusername is True, ask the user, else use
         ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
         """
-        user = os.environ.get("HGUSER")
+        user = encoding.environ.get("HGUSER")
         if user is None:
             user = self.config("ui", ["username", "user"])
             if user is not None:
                 user = os.path.expandvars(user)
         if user is None:
-            user = os.environ.get("EMAIL")
+            user = encoding.environ.get("EMAIL")
         if user is None and self.configbool("ui", "askusername"):
             user = self.prompt(_("enter a commit username:"), default=None)
         if user is None and not self.interactive():
@@ -733,7 +736,7 @@
         is curses, the interface for histedit is text and the interface for
         selecting chunk is crecord (the best curses interface available).
 
-        Consider the following exemple:
+        Consider the following example:
         ui.interface = curses
         ui.interface.histedit = text
 
@@ -814,12 +817,12 @@
     def termwidth(self):
         '''how wide is the terminal in columns?
         '''
-        if 'COLUMNS' in os.environ:
+        if 'COLUMNS' in encoding.environ:
             try:
-                return int(os.environ['COLUMNS'])
+                return int(encoding.environ['COLUMNS'])
             except ValueError:
                 pass
-        return util.termwidth()
+        return scmutil.termsize(self)[0]
 
     def formatted(self):
         '''should formatted output be used?
@@ -1075,10 +1078,10 @@
             editor = 'E'
         else:
             editor = 'vi'
-        return (os.environ.get("HGEDITOR") or
+        return (encoding.environ.get("HGEDITOR") or
                 self.config("ui", "editor") or
-                os.environ.get("VISUAL") or
-                os.environ.get("EDITOR", editor))
+                encoding.environ.get("VISUAL") or
+                encoding.environ.get("EDITOR", editor))
 
     @util.propertycache
     def _progbar(self):
--- a/mercurial/unionrepo.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/unionrepo.py	Wed Nov 16 23:29:28 2016 -0500
@@ -152,18 +152,18 @@
     def baserevdiff(self, rev1, rev2):
         return changelog.changelog.revdiff(self, rev1, rev2)
 
-class unionmanifest(unionrevlog, manifest.manifest):
+class unionmanifest(unionrevlog, manifest.manifestrevlog):
     def __init__(self, opener, opener2, linkmapper):
-        manifest.manifest.__init__(self, opener)
-        manifest2 = manifest.manifest(opener2)
+        manifest.manifestrevlog.__init__(self, opener)
+        manifest2 = manifest.manifestrevlog(opener2)
         unionrevlog.__init__(self, opener, self.indexfile, manifest2,
                              linkmapper)
 
     def baserevision(self, nodeorrev):
-        return manifest.manifest.revision(self, nodeorrev)
+        return manifest.manifestrevlog.revision(self, nodeorrev)
 
     def baserevdiff(self, rev1, rev2):
-        return manifest.manifest.revdiff(self, rev1, rev2)
+        return manifest.manifestrevlog.revdiff(self, rev1, rev2)
 
 class unionfilelog(unionrevlog, filelog.filelog):
     def __init__(self, opener, path, opener2, linkmapper, repo):
--- a/mercurial/util.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/util.py	Wed Nov 16 23:29:28 2016 -0500
@@ -122,7 +122,6 @@
 statfiles = getattr(osutil, 'statfiles', platform.statfiles)
 statisexec = platform.statisexec
 statislink = platform.statislink
-termwidth = platform.termwidth
 testpid = platform.testpid
 umask = platform.umask
 unlink = platform.unlink
@@ -938,6 +937,9 @@
 else:
     datapath = os.path.dirname(__file__)
 
+if not isinstance(datapath, bytes):
+    datapath = pycompat.fsencode(datapath)
+
 i18n.setdatapath(datapath)
 
 _hgexecutable = None
@@ -1454,7 +1456,7 @@
     def __eq__(self, old):
         try:
             # if ambiguity between stat of new and old file is
-            # avoided, comparision of size, ctime and mtime is enough
+            # avoided, comparison of size, ctime and mtime is enough
             # to exactly detect change of a file regardless of platform
             return (self.stat.st_size == old.stat.st_size and
                     self.stat.st_ctime == old.stat.st_ctime and
@@ -2206,6 +2208,11 @@
                             subsequent_indent=hangindent)
     return wrapper.fill(line).encode(encoding.encoding)
 
+def iterfile(fp):
+    """like fp.__iter__ but does not have issues with EINTR. Python 2.7.12 is
+    known to have such issues."""
+    return iter(fp.readline, '')
+
 def iterlines(iterator):
     for chunk in iterator:
         for line in chunk.splitlines():
@@ -2396,7 +2403,7 @@
 
     _safechars = "!~*'()+"
     _safepchars = "/!~*'()+:\\"
-    _matchscheme = remod.compile(r'^[a-zA-Z0-9+.\-]+:').match
+    _matchscheme = remod.compile('^[a-zA-Z0-9+.\\-]+:').match
 
     def __init__(self, path, parsequery=True, parsefragment=True):
         # We slowly chomp away at path until we have only the path left
@@ -2410,7 +2417,7 @@
             path, self.fragment = path.split('#', 1)
 
         # special case for Windows drive letters and UNC paths
-        if hasdriveletter(path) or path.startswith(r'\\'):
+        if hasdriveletter(path) or path.startswith('\\\\'):
             self.path = path
             return
 
@@ -2488,7 +2495,7 @@
                   'path', 'fragment'):
             v = getattr(self, a)
             if v is not None:
-                setattr(self, a, pycompat.urlparse.unquote(v))
+                setattr(self, a, pycompat.urlunquote(v))
 
     def __repr__(self):
         attrs = []
@@ -2812,32 +2819,6 @@
         yield path[:pos]
         pos = path.rfind('/', 0, pos)
 
-# compression utility
-
-class nocompress(object):
-    def compress(self, x):
-        return x
-    def flush(self):
-        return ""
-
-compressors = {
-    None: nocompress,
-    # lambda to prevent early import
-    'BZ': lambda: bz2.BZ2Compressor(),
-    'GZ': lambda: zlib.compressobj(),
-    }
-# also support the old form by courtesies
-compressors['UN'] = compressors[None]
-
-def _makedecompressor(decompcls):
-    def generator(f):
-        d = decompcls()
-        for chunk in filechunkiter(f):
-            yield d.decompress(chunk)
-    def func(fh):
-        return chunkbuffer(generator(fh))
-    return func
-
 class ctxmanager(object):
     '''A context manager for use in 'with' blocks to allow multiple
     contexts to be entered at once.  This is both safer and more
@@ -2898,20 +2879,233 @@
             raise exc_val
         return received and suppressed
 
-def _bz2():
-    d = bz2.BZ2Decompressor()
-    # Bzip2 stream start with BZ, but we stripped it.
-    # we put it back for good measure.
-    d.decompress('BZ')
-    return d
-
-decompressors = {None: lambda fh: fh,
-                 '_truncatedBZ': _makedecompressor(_bz2),
-                 'BZ': _makedecompressor(lambda: bz2.BZ2Decompressor()),
-                 'GZ': _makedecompressor(lambda: zlib.decompressobj()),
-                 }
-# also support the old form by courtesies
-decompressors['UN'] = decompressors[None]
+# compression code
+
+class compressormanager(object):
+    """Holds registrations of various compression engines.
+
+    This class essentially abstracts the differences between compression
+    engines to allow new compression formats to be added easily, possibly from
+    extensions.
+
+    Compressors are registered against the global instance by calling its
+    ``register()`` method.
+    """
+    def __init__(self):
+        self._engines = {}
+        # Bundle spec human name to engine name.
+        self._bundlenames = {}
+        # Internal bundle identifier to engine name.
+        self._bundletypes = {}
+
+    def __getitem__(self, key):
+        return self._engines[key]
+
+    def __contains__(self, key):
+        return key in self._engines
+
+    def __iter__(self):
+        return iter(self._engines.keys())
+
+    def register(self, engine):
+        """Register a compression engine with the manager.
+
+        The argument must be a ``compressionengine`` instance.
+        """
+        if not isinstance(engine, compressionengine):
+            raise ValueError(_('argument must be a compressionengine'))
+
+        name = engine.name()
+
+        if name in self._engines:
+            raise error.Abort(_('compression engine %s already registered') %
+                              name)
+
+        bundleinfo = engine.bundletype()
+        if bundleinfo:
+            bundlename, bundletype = bundleinfo
+
+            if bundlename in self._bundlenames:
+                raise error.Abort(_('bundle name %s already registered') %
+                                  bundlename)
+            if bundletype in self._bundletypes:
+                raise error.Abort(_('bundle type %s already registered by %s') %
+                                  (bundletype, self._bundletypes[bundletype]))
+
+            # No external facing name declared.
+            if bundlename:
+                self._bundlenames[bundlename] = name
+
+            self._bundletypes[bundletype] = name
+
+        self._engines[name] = engine
+
+    @property
+    def supportedbundlenames(self):
+        return set(self._bundlenames.keys())
+
+    @property
+    def supportedbundletypes(self):
+        return set(self._bundletypes.keys())
+
+    def forbundlename(self, bundlename):
+        """Obtain a compression engine registered to a bundle name.
+
+        Will raise KeyError if the bundle type isn't registered.
+        """
+        return self._engines[self._bundlenames[bundlename]]
+
+    def forbundletype(self, bundletype):
+        """Obtain a compression engine registered to a bundle type.
+
+        Will raise KeyError if the bundle type isn't registered.
+        """
+        return self._engines[self._bundletypes[bundletype]]
+
+compengines = compressormanager()
+
+class compressionengine(object):
+    """Base class for compression engines.
+
+    Compression engines must implement the interface defined by this class.
+    """
+    def name(self):
+        """Returns the name of the compression engine.
+
+        This is the key the engine is registered under.
+
+        This method must be implemented.
+        """
+        raise NotImplementedError()
+
+    def bundletype(self):
+        """Describes bundle identifiers for this engine.
+
+        If this compression engine isn't supported for bundles, returns None.
+
+        If this engine can be used for bundles, returns a 2-tuple of strings of
+        the user-facing "bundle spec" compression name and an internal
+        identifier used to denote the compression format within bundles. To
+        exclude the name from external usage, set the first element to ``None``.
+
+        If bundle compression is supported, the class must also implement
+        ``compressstream`` and `decompressorreader``.
+        """
+        return None
+
+    def compressstream(self, it, opts=None):
+        """Compress an iterator of chunks.
+
+        The method receives an iterator (ideally a generator) of chunks of
+        bytes to be compressed. It returns an iterator (ideally a generator)
+        of bytes of chunks representing the compressed output.
+
+        Optionally accepts an argument defining how to perform compression.
+        Each engine treats this argument differently.
+        """
+        raise NotImplementedError()
+
+    def decompressorreader(self, fh):
+        """Perform decompression on a file object.
+
+        Argument is an object with a ``read(size)`` method that returns
+        compressed data. Return value is an object with a ``read(size)`` that
+        returns uncompressed data.
+        """
+        raise NotImplementedError()
+
+class _zlibengine(compressionengine):
+    def name(self):
+        return 'zlib'
+
+    def bundletype(self):
+        return 'gzip', 'GZ'
+
+    def compressstream(self, it, opts=None):
+        opts = opts or {}
+
+        z = zlib.compressobj(opts.get('level', -1))
+        for chunk in it:
+            data = z.compress(chunk)
+            # Not all calls to compress emit data. It is cheaper to inspect
+            # here than to feed empty chunks through generator.
+            if data:
+                yield data
+
+        yield z.flush()
+
+    def decompressorreader(self, fh):
+        def gen():
+            d = zlib.decompressobj()
+            for chunk in filechunkiter(fh):
+                yield d.decompress(chunk)
+
+        return chunkbuffer(gen())
+
+compengines.register(_zlibengine())
+
+class _bz2engine(compressionengine):
+    def name(self):
+        return 'bz2'
+
+    def bundletype(self):
+        return 'bzip2', 'BZ'
+
+    def compressstream(self, it, opts=None):
+        opts = opts or {}
+        z = bz2.BZ2Compressor(opts.get('level', 9))
+        for chunk in it:
+            data = z.compress(chunk)
+            if data:
+                yield data
+
+        yield z.flush()
+
+    def decompressorreader(self, fh):
+        def gen():
+            d = bz2.BZ2Decompressor()
+            for chunk in filechunkiter(fh):
+                yield d.decompress(chunk)
+
+        return chunkbuffer(gen())
+
+compengines.register(_bz2engine())
+
+class _truncatedbz2engine(compressionengine):
+    def name(self):
+        return 'bz2truncated'
+
+    def bundletype(self):
+        return None, '_truncatedBZ'
+
+    # We don't implement compressstream because it is hackily handled elsewhere.
+
+    def decompressorreader(self, fh):
+        def gen():
+            # The input stream doesn't have the 'BZ' header. So add it back.
+            d = bz2.BZ2Decompressor()
+            d.decompress('BZ')
+            for chunk in filechunkiter(fh):
+                yield d.decompress(chunk)
+
+        return chunkbuffer(gen())
+
+compengines.register(_truncatedbz2engine())
+
+class _noopengine(compressionengine):
+    def name(self):
+        return 'none'
+
+    def bundletype(self):
+        return 'none', 'UN'
+
+    def compressstream(self, it, opts=None):
+        return it
+
+    def decompressorreader(self, fh):
+        return fh
+
+compengines.register(_noopengine())
 
 # convenient shortcut
 dst = debugstacktrace
--- a/mercurial/verify.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/verify.py	Wed Nov 16 23:29:28 2016 -0500
@@ -51,7 +51,7 @@
         self.errors = 0
         self.warnings = 0
         self.havecl = len(repo.changelog) > 0
-        self.havemf = len(repo.manifest) > 0
+        self.havemf = len(repo.manifestlog._revlog) > 0
         self.revlogv1 = repo.changelog.version != revlog.REVLOGV0
         self.lrugetctx = util.lrucachefunc(repo.changectx)
         self.refersmf = False
@@ -201,7 +201,8 @@
                         progress=None):
         repo = self.repo
         ui = self.ui
-        mf = self.repo.manifest.dirlog(dir)
+        mfl = self.repo.manifestlog
+        mf = mfl._revlog.dirlog(dir)
 
         if not dir:
             self.ui.status(_("checking manifests\n"))
@@ -235,7 +236,8 @@
                 self.err(lr, _("%s not in changesets") % short(n), label)
 
             try:
-                for f, fn, fl in mf.readshallowdelta(n).iterentries():
+                mfdelta = mfl.get(dir, n).readdelta(shallow=True)
+                for f, fn, fl in mfdelta.iterentries():
                     if not f:
                         self.err(lr, _("entry without name in manifest"))
                     elif f == "/dev/null":  # ignore this in very old repos
@@ -423,7 +425,7 @@
 
             # cross-check
             if f in filenodes:
-                fns = [(lr, n) for n, lr in filenodes[f].iteritems()]
+                fns = [(v, k) for k, v in filenodes[f].iteritems()]
                 for lr, node in sorted(fns):
                     self.err(lr, _("manifest refers to unknown revision %s") %
                              short(node), f)
--- a/mercurial/win32.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/win32.py	Wed Nov 16 23:29:28 2016 -0500
@@ -347,23 +347,25 @@
     pid = _kernel32.GetCurrentProcessId()
     _user32.EnumWindows(_WNDENUMPROC(callback), pid)
 
-def termwidth():
+def termsize():
     # cmd.exe does not handle CR like a unix console, the CR is
     # counted in the line length. On 80 columns consoles, if 80
     # characters are written, the following CR won't apply on the
     # current line but on the new one. Keep room for it.
-    width = 79
+    width = 80 - 1
+    height = 25
     # Query stderr to avoid problems with redirections
     screenbuf = _kernel32.GetStdHandle(
                   _STD_ERROR_HANDLE) # don't close the handle returned
     if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
-        return width
+        return width, height
     csbi = _CONSOLE_SCREEN_BUFFER_INFO()
     if not _kernel32.GetConsoleScreenBufferInfo(
                         screenbuf, ctypes.byref(csbi)):
-        return width
-    width = csbi.srWindow.Right - csbi.srWindow.Left
-    return width
+        return width, height
+    width = csbi.srWindow.Right - csbi.srWindow.Left  # don't '+ 1'
+    height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1
+    return width, height
 
 def _1stchild(pid):
     '''return the 1st found child of the given pid
--- a/mercurial/windows.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/windows.py	Wed Nov 16 23:29:28 2016 -0500
@@ -38,7 +38,6 @@
 setsignalhandler = win32.setsignalhandler
 spawndetached = win32.spawndetached
 split = os.path.split
-termwidth = win32.termwidth
 testpid = win32.testpid
 unlink = win32.unlink
 
--- a/mercurial/worker.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/mercurial/worker.py	Wed Nov 16 23:29:28 2016 -0500
@@ -11,10 +11,12 @@
 import os
 import signal
 import sys
-import threading
 
 from .i18n import _
-from . import error
+from . import (
+    error,
+    util,
+)
 
 def countcpus():
     '''try to count the number of CPUs on the system'''
@@ -85,11 +87,44 @@
     workers = _numworkers(ui)
     oldhandler = signal.getsignal(signal.SIGINT)
     signal.signal(signal.SIGINT, signal.SIG_IGN)
-    pids, problem = [], [0]
+    pids, problem = set(), [0]
+    def killworkers():
+        # if one worker bails, there's no good reason to wait for the rest
+        for p in pids:
+            try:
+                os.kill(p, signal.SIGTERM)
+            except OSError as err:
+                if err.errno != errno.ESRCH:
+                    raise
+    def waitforworkers(blocking=True):
+        for pid in pids.copy():
+            p = st = 0
+            while True:
+                try:
+                    p, st = os.waitpid(pid, (0 if blocking else os.WNOHANG))
+                except OSError as e:
+                    if e.errno == errno.EINTR:
+                        continue
+                    elif e.errno == errno.ECHILD:
+                        break # ignore ECHILD
+                    else:
+                        raise
+            if p:
+                pids.remove(p)
+                st = _exitstatus(st)
+            if st and not problem[0]:
+                problem[0] = st
+                # unregister SIGCHLD handler as all children will be killed
+                signal.signal(signal.SIGCHLD, oldchldhandler)
+                killworkers()
+    def sigchldhandler(signum, frame):
+        waitforworkers(blocking=False)
+    oldchldhandler = signal.signal(signal.SIGCHLD, sigchldhandler)
     for pargs in partition(args, workers):
         pid = os.fork()
         if pid == 0:
             signal.signal(signal.SIGINT, oldhandler)
+            signal.signal(signal.SIGCHLD, oldchldhandler)
             try:
                 os.close(rfd)
                 for i, item in func(*(staticargs + (pargs,))):
@@ -99,36 +134,20 @@
                 os._exit(255)
                 # other exceptions are allowed to propagate, we rely
                 # on lock.py's pid checks to avoid release callbacks
-        pids.append(pid)
-    pids.reverse()
+        pids.add(pid)
     os.close(wfd)
     fp = os.fdopen(rfd, 'rb', 0)
-    def killworkers():
-        # if one worker bails, there's no good reason to wait for the rest
-        for p in pids:
-            try:
-                os.kill(p, signal.SIGTERM)
-            except OSError as err:
-                if err.errno != errno.ESRCH:
-                    raise
-    def waitforworkers():
-        for _pid in pids:
-            st = _exitstatus(os.wait()[1])
-            if st and not problem[0]:
-                problem[0] = st
-                killworkers()
-    t = threading.Thread(target=waitforworkers)
-    t.start()
     def cleanup():
         signal.signal(signal.SIGINT, oldhandler)
-        t.join()
+        waitforworkers()
+        signal.signal(signal.SIGCHLD, oldchldhandler)
         status = problem[0]
         if status:
             if status < 0:
                 os.kill(os.getpid(), -status)
             sys.exit(status)
     try:
-        for line in fp:
+        for line in util.iterfile(fp):
             l = line.split(' ', 1)
             yield int(l[0]), l[1][:-1]
     except: # re-raises
--- a/setup.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/setup.py	Wed Nov 16 23:29:28 2016 -0500
@@ -67,6 +67,7 @@
     from setuptools import setup
 else:
     from distutils.core import setup
+from distutils.ccompiler import new_compiler
 from distutils.core import Command, Extension
 from distutils.dist import Distribution
 from distutils.command.build import build
@@ -318,14 +319,16 @@
         if self.distribution.pure:
             self.distribution.ext_modules = []
         elif self.distribution.cffi:
-            import setup_mpatch_cffi
-            import setup_bdiff_cffi
-            exts = [setup_mpatch_cffi.ffi.distutils_extension(),
-                    setup_bdiff_cffi.ffi.distutils_extension()]
+            from mercurial.cffi import (
+                bdiff,
+                mpatch,
+            )
+            exts = [mpatch.ffi.distutils_extension(),
+                    bdiff.ffi.distutils_extension()]
             # cffi modules go here
             if sys.platform == 'darwin':
-                import setup_osutil_cffi
-                exts.append(setup_osutil_cffi.ffi.distutils_extension())
+                from mercurial.cffi import osutil
+                exts.append(osutil.ffi.distutils_extension())
             self.distribution.ext_modules = exts
         else:
             h = os.path.join(get_python_inc(), 'Python.h')
@@ -551,8 +554,14 @@
                   'mercurial/compat.h',
                   'mercurial/util.h']
 
+osutil_cflags = []
 osutil_ldflags = []
 
+# platform specific macros: HAVE_SETPROCTITLE
+for plat, func in [(re.compile('freebsd'), 'setproctitle')]:
+    if plat.search(sys.platform) and hasfunction(new_compiler(), func):
+        osutil_cflags.append('-DHAVE_%s' % func.upper())
+
 if sys.platform == 'darwin':
     osutil_ldflags += ['-framework', 'ApplicationServices']
 
@@ -573,6 +582,7 @@
                                     'mercurial/pathencode.c'],
               depends=common_depends),
     Extension('mercurial.osutil', ['mercurial/osutil.c'],
+              extra_compile_args=osutil_cflags,
               extra_link_args=osutil_ldflags,
               depends=common_depends),
     Extension('hgext.fsmonitor.pywatchman.bser',
--- a/setup_bdiff_cffi.py	Sun Nov 13 06:12:22 2016 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-from __future__ import absolute_import
-
-import cffi
-import os
-
-ffi = cffi.FFI()
-ffi.set_source("_bdiff_cffi",
-    open(os.path.join(os.path.join(os.path.dirname(__file__), 'mercurial'),
-        'bdiff.c')).read(), include_dirs=['mercurial'])
-ffi.cdef("""
-struct bdiff_line {
-    int hash, n, e;
-    ssize_t len;
-    const char *l;
-};
-
-struct bdiff_hunk;
-struct bdiff_hunk {
-    int a1, a2, b1, b2;
-    struct bdiff_hunk *next;
-};
-
-int bdiff_splitlines(const char *a, ssize_t len, struct bdiff_line **lr);
-int bdiff_diff(struct bdiff_line *a, int an, struct bdiff_line *b, int bn,
-    struct bdiff_hunk *base);
-void bdiff_freehunks(struct bdiff_hunk *l);
-void free(void*);
-""")
-
-if __name__ == '__main__':
-    ffi.compile()
--- a/setup_mpatch_cffi.py	Sun Nov 13 06:12:22 2016 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-from __future__ import absolute_import
-
-import cffi
-import os
-
-ffi = cffi.FFI()
-mpatch_c = os.path.join(os.path.join(os.path.dirname(__file__), 'mercurial',
-                                     'mpatch.c'))
-ffi.set_source("_mpatch_cffi", open(mpatch_c).read(),
-               include_dirs=["mercurial"])
-ffi.cdef("""
-
-struct mpatch_frag {
-       int start, end, len;
-       const char *data;
-};
-
-struct mpatch_flist {
-       struct mpatch_frag *base, *head, *tail;
-};
-
-extern "Python" struct mpatch_flist* cffi_get_next_item(void*, ssize_t);
-
-int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist** res);
-ssize_t mpatch_calcsize(size_t len, struct mpatch_flist *l);
-void mpatch_lfree(struct mpatch_flist *a);
-static int mpatch_apply(char *buf, const char *orig, size_t len,
-                        struct mpatch_flist *l);
-struct mpatch_flist *mpatch_fold(void *bins,
-                       struct mpatch_flist* (*get_next_item)(void*, ssize_t),
-                       ssize_t start, ssize_t end);
-""")
-
-if __name__ == '__main__':
-    ffi.compile()
--- a/setup_osutil_cffi.py	Sun Nov 13 06:12:22 2016 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-from __future__ import absolute_import
-
-import cffi
-
-ffi = cffi.FFI()
-ffi.set_source("_osutil_cffi", """
-#include <sys/attr.h>
-#include <sys/vnode.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-
-typedef struct val_attrs {
-    uint32_t          length;
-    attribute_set_t   returned;
-    attrreference_t   name_info;
-    fsobj_type_t      obj_type;
-    struct timespec   mtime;
-    uint32_t          accessmask;
-    off_t             datalength;
-} __attribute__((aligned(4), packed)) val_attrs_t;
-""", include_dirs=['mercurial'])
-ffi.cdef('''
-
-typedef uint32_t attrgroup_t;
-
-typedef struct attrlist {
-    uint16_t     bitmapcount; /* number of attr. bit sets in list */
-    uint16_t   reserved;    /* (to maintain 4-byte alignment) */
-    attrgroup_t commonattr;  /* common attribute group */
-    attrgroup_t volattr;     /* volume attribute group */
-    attrgroup_t dirattr;     /* directory attribute group */
-    attrgroup_t fileattr;    /* file attribute group */
-    attrgroup_t forkattr;    /* fork attribute group */
-    ...;
-};
-
-typedef struct attribute_set {
-    ...;
-} attribute_set_t;
-
-typedef struct attrreference {
-    int attr_dataoffset;
-    int attr_length;
-    ...;
-} attrreference_t;
-
-typedef int ... off_t;
-
-typedef struct val_attrs {
-    uint32_t          length;
-    attribute_set_t   returned;
-    attrreference_t   name_info;
-    uint32_t          obj_type;
-    struct timespec   mtime;
-    uint32_t          accessmask;
-    off_t             datalength;
-    ...;
-} val_attrs_t;
-
-/* the exact layout of the above struct will be figured out during build time */
-
-typedef int ... time_t;
-
-typedef struct timespec {
-    time_t tv_sec;
-    ...;
-};
-
-int getattrlist(const char* path, struct attrlist * attrList, void * attrBuf,
-                size_t attrBufSize, unsigned int options);
-
-int getattrlistbulk(int dirfd, struct attrlist * attrList, void * attrBuf,
-                    size_t attrBufSize, uint64_t options);
-
-#define ATTR_BIT_MAP_COUNT ...
-#define ATTR_CMN_NAME ...
-#define ATTR_CMN_OBJTYPE ...
-#define ATTR_CMN_MODTIME ...
-#define ATTR_CMN_ACCESSMASK ...
-#define ATTR_CMN_ERROR ...
-#define ATTR_CMN_RETURNED_ATTRS ...
-#define ATTR_FILE_DATALENGTH ...
-
-#define VREG ...
-#define VDIR ...
-#define VLNK ...
-#define VBLK ...
-#define VCHR ...
-#define VFIFO ...
-#define VSOCK ...
-
-#define S_IFMT ...
-
-int open(const char *path, int oflag, int perm);
-int close(int);
-
-#define O_RDONLY ...
-''')
-
-if __name__ == '__main__':
-    ffi.compile()
--- a/tests/failfilemerge.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/failfilemerge.py	Wed Nov 16 23:29:28 2016 -0500
@@ -1,4 +1,4 @@
-# extension to emulate interupting filemerge._filemerge
+# extension to emulate interrupting filemerge._filemerge
 
 from __future__ import absolute_import
 
--- a/tests/filterpyflakes.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/filterpyflakes.py	Wed Nov 16 23:29:28 2016 -0500
@@ -36,7 +36,8 @@
             (r"local variable '.*' is assigned to but never used", None),
             (r"unable to detect undefined names", None),
             (r"undefined name '.*'",
-             r"undefined name '(WindowsError|memoryview)'")
+             r"undefined name '(WindowsError|memoryview)'"),
+            ("list comprehension", None),
            ]
 
     for msgtype, (pat, excl) in enumerate(pats):
--- a/tests/hghave.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/hghave.py	Wed Nov 16 23:29:28 2016 -0500
@@ -150,7 +150,7 @@
 
 @check("darcs", "darcs client")
 def has_darcs():
-    return matchoutput('darcs --version', br'2\.[2-9]', True)
+    return matchoutput('darcs --version', br'\b2\.([2-9]|\d{2})', True)
 
 @check("mtn", "monotone client (>= 1.0)")
 def has_mtn():
--- a/tests/test-ancestor.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-ancestor.py	Wed Nov 16 23:29:28 2016 -0500
@@ -11,7 +11,7 @@
 from mercurial.node import nullrev
 from mercurial import (
     ancestor,
-    commands,
+    debugcommands,
     hg,
     ui as uimod,
     util,
@@ -226,7 +226,7 @@
             # C version not available
             return
 
-        commands.debugbuilddag(u, repo, dag)
+        debugcommands.debugbuilddag(u, repo, dag)
         # Compare the results of the Python and C versions. This does not
         # include choosing a winner when more than one gca exists -- we make
         # sure both return exactly the same set of gcas.
--- a/tests/test-atomictempfile.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-atomictempfile.py	Wed Nov 16 23:29:28 2016 -0500
@@ -68,7 +68,7 @@
             repetition = 3
 
             # repeat atomic write with checkambig=True, to examine
-            # whether st_mtime is advanced multiple times as expecetd
+            # whether st_mtime is advanced multiple times as expected
             for j in xrange(repetition):
                 atomicwrite(True)
             newstat = os.stat(self._filename)
@@ -77,7 +77,7 @@
                 continue
 
             # st_mtime should be advanced "repetition" times, because
-            # all atomicwrite() occured at same time (in sec)
+            # all atomicwrite() occurred at same time (in sec)
             self.assertTrue(newstat.st_mtime ==
                             ((oldstat.st_mtime + repetition) & 0x7fffffff))
             # no more examination is needed, if assumption above is true
--- a/tests/test-backout.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-backout.t	Wed Nov 16 23:29:28 2016 -0500
@@ -272,7 +272,7 @@
 
 (1) update to REV1 (REV2 => REV1)
 (2) revert by REV1^1
-(3) commit backnig out revision (REV3)
+(3) commit backing out revision (REV3)
 (4) update to REV2 (REV3 => REV2)
 (5) merge with REV3 (REV2 => REV2, REV3)
 
@@ -287,7 +287,7 @@
   > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
   > EOF
 
-("-m" is needed to avoid writing dirstte changes out at other than
+("-m" is needed to avoid writing dirstate changes out at other than
 invocation of the hook to be examined)
 
   $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
--- a/tests/test-bookmarks-pushpull.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-bookmarks-pushpull.t	Wed Nov 16 23:29:28 2016 -0500
@@ -550,7 +550,7 @@
 
   $ cd ..
 
-Test to show result of bookmarks comparision
+Test to show result of bookmarks comparison
 
   $ mkdir bmcomparison
   $ cd bmcomparison
--- a/tests/test-bookmarks.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-bookmarks.t	Wed Nov 16 23:29:28 2016 -0500
@@ -734,7 +734,7 @@
      summary:     0
   
 
-no-op update doesn't deactive bookmarks
+no-op update doesn't deactivate bookmarks
 
   $ hg bookmarks
    * four                      3:9ba5f110a0b3
--- a/tests/test-check-code.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-check-code.t	Wed Nov 16 23:29:28 2016 -0500
@@ -17,3 +17,4 @@
   Skipping i18n/polib.py it has no-che?k-code (glob)
   Skipping mercurial/httpclient/__init__.py it has no-che?k-code (glob)
   Skipping mercurial/httpclient/_readers.py it has no-che?k-code (glob)
+  Skipping mercurial/statprof.py it has no-che?k-code (glob)
--- a/tests/test-check-py3-commands.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-check-py3-commands.t	Wed Nov 16 23:29:28 2016 -0500
@@ -9,6 +9,6 @@
   >   $PYTHON3 `which hg` $cmd 2>&1 2>&1 | tail -1
   > done
   version
-  TypeError: str expected, not bytes
+  NameError: name 'basestring' is not defined
   debuginstall
-  TypeError: str expected, not bytes
+  NameError: name 'basestring' is not defined
--- a/tests/test-check-py3-compat.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-check-py3-compat.t	Wed Nov 16 23:29:28 2016 -0500
@@ -21,7 +21,8 @@
   hgext/fsmonitor/pywatchman/pybser.py: error importing: <ImportError> No module named 'pybser' (error at __init__.py:*)
   hgext/fsmonitor/watchmanclient.py: error importing: <ImportError> No module named 'pybser' (error at __init__.py:*)
   hgext/mq.py: error importing: <TypeError> __import__() argument 1 must be str, not bytes (error at extensions.py:*)
-  mercurial/scmwindows.py: error importing: <ImportError> No module named 'winreg' (error at scmwindows.py:*)
+  mercurial/scmwindows.py: error importing: <ImportError> No module named 'msvcrt' (error at win32.py:*)
+  mercurial/statprof.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at statprof.py:*)
   mercurial/win32.py: error importing: <ImportError> No module named 'msvcrt' (error at win32.py:*)
   mercurial/windows.py: error importing: <ImportError> No module named 'msvcrt' (error at windows.py:*)
 
--- a/tests/test-check-pyflakes.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-check-pyflakes.t	Wed Nov 16 23:29:28 2016 -0500
@@ -10,6 +10,6 @@
   > -X mercurial/pycompat.py \
   > 2>/dev/null \
   > | xargs pyflakes 2>/dev/null | "$TESTDIR/filterpyflakes.py"
-  tests/filterpyflakes.py:61: undefined name 'undefinedname'
+  tests/filterpyflakes.py:62: undefined name 'undefinedname'
   
 
--- a/tests/test-commandserver.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-commandserver.t	Wed Nov 16 23:29:28 2016 -0500
@@ -135,6 +135,19 @@
   summary:     1
   
 
+check that "histedit --commands=-" can read rules from the input channel:
+
+  >>> import cStringIO
+  >>> from hgclient import readchannel, runcommand, check
+  >>> @check
+  ... def serverinput(server):
+  ...     readchannel(server)
+  ...     rules = 'pick eff892de26ec\n'
+  ...     runcommand(server, ['histedit', '0', '--commands=-',
+  ...                         '--config', 'extensions.histedit='],
+  ...                input=cStringIO.StringIO(rules))
+  *** runcommand histedit 0 --commands=- --config extensions.histedit=
+
 check that --cwd doesn't persist between requests:
 
   $ mkdir foo
@@ -223,8 +236,6 @@
   ...                         'id'],
   ...                input=stringio('some input'))
   *** runcommand --config hooks.pre-identify=python:hook.hook id
-  hook talking
-  now try to read something: 'some input'
   eff892de26ec tip
 
   $ rm hook.py*
@@ -804,7 +815,7 @@
   $ echo foo > foo
   $ hg add foo
 
-(failuer before finalization)
+(failure before finalization)
 
   >>> from hgclient import readchannel, runcommand, check
   >>> @check
@@ -823,7 +834,7 @@
   *** runcommand log
   *** runcommand verify -q
 
-(failuer after finalization)
+(failure after finalization)
 
   >>> from hgclient import readchannel, runcommand, check
   >>> @check
--- a/tests/test-contrib-perf.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-contrib-perf.t	Wed Nov 16 23:29:28 2016 -0500
@@ -50,6 +50,7 @@
    perfancestorset
                  (no help text available)
    perfannotate  (no help text available)
+   perfbdiff     benchmark a bdiff between revisions
    perfbranchmap
                  benchmark the update of a branchmap
    perfcca       (no help text available)
@@ -112,6 +113,7 @@
   $ hg perfancestors
   $ hg perfancestorset 2
   $ hg perfannotate a
+  $ hg perfbdiff -c 1
   $ hg perfbranchmap
   $ hg perfcca
   $ hg perfchangegroupchangelog
--- a/tests/test-convert-darcs.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-convert-darcs.t	Wed Nov 16 23:29:28 2016 -0500
@@ -8,7 +8,7 @@
 
   $ mkdir darcs-repo
   $ cd darcs-repo
-  $ darcs init
+  $ darcs init -q
   $ echo a > a
   $ darcs record -a -l -m p0
   Finished recording patch 'p0'
@@ -43,6 +43,7 @@
   Backing up ./a(*) (glob)
   We have conflicts in the following files:
   ./a
+   (?)
   $ sleep 1
   $ echo e > a
   $ echo f > f
@@ -54,13 +55,13 @@
 
 test file and directory move
 
-  $ darcs mv f ff
+  $ darcs mv -q f ff
 
 Test remove + move
 
-  $ darcs remove dir/d2
+  $ darcs remove -q dir/d2
   $ rm dir/d2
-  $ darcs mv dir dir2
+  $ darcs mv -q dir dir2
   $ darcs record -a -l -m p3
   Finished recording patch 'p3'
 
--- a/tests/test-extension.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-extension.t	Wed Nov 16 23:29:28 2016 -0500
@@ -251,10 +251,10 @@
 
 #if demandimport absimport
 
-Examine whether module loading is delayed until actual refering, even
+Examine whether module loading is delayed until actual referring, even
 though module is imported with "absolute_import" feature.
 
-Files below in each packages are used for descirbed purpose:
+Files below in each packages are used for described purpose:
 
 - "called": examine whether "from MODULE import ATTR" works correctly
 - "unused": examine whether loading is delayed correctly
@@ -1045,6 +1045,61 @@
   $ hg help patchbomb
   patchbomb extension - command to send changesets as (a series of) patch emails
   
+  The series is started off with a "[PATCH 0 of N]" introduction, which
+  describes the series as a whole.
+  
+  Each patch email has a Subject line of "[PATCH M of N] ...", using the first
+  line of the changeset description as the subject text. The message contains
+  two or three body parts:
+  
+  - The changeset description.
+  - [Optional] The result of running diffstat on the patch.
+  - The patch itself, as generated by 'hg export'.
+  
+  Each message refers to the first in the series using the In-Reply-To and
+  References headers, so they will show up as a sequence in threaded mail and
+  news readers, and in mail archives.
+  
+  To configure other defaults, add a section like this to your configuration
+  file:
+  
+    [email]
+    from = My Name <my@email>
+    to = recipient1, recipient2, ...
+    cc = cc1, cc2, ...
+    bcc = bcc1, bcc2, ...
+    reply-to = address1, address2, ...
+  
+  Use "[patchbomb]" as configuration section name if you need to override global
+  "[email]" address settings.
+  
+  Then you can use the 'hg email' command to mail a series of changesets as a
+  patchbomb.
+  
+  You can also either configure the method option in the email section to be a
+  sendmail compatible mailer or fill out the [smtp] section so that the
+  patchbomb extension can automatically send patchbombs directly from the
+  commandline. See the [email] and [smtp] sections in hgrc(5) for details.
+  
+  By default, 'hg email' will prompt for a "To" or "CC" header if you do not
+  supply one via configuration or the command line.  You can override this to
+  never prompt by configuring an empty value:
+  
+    [email]
+    cc =
+  
+  You can control the default inclusion of an introduction message with the
+  "patchbomb.intro" configuration option. The configuration is always
+  overwritten by command line flags like --intro and --desc:
+  
+    [patchbomb]
+    intro=auto   # include introduction message if more than 1 patch (default)
+    intro=never  # never include an introduction message
+    intro=always # always include an introduction message
+  
+  You can set patchbomb to always ask for confirmation by setting
+  "patchbomb.confirm" to true.
+  
   (use 'hg help extensions' for information on enabling extensions)
 
 
--- a/tests/test-filecache.py	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-filecache.py	Wed Nov 16 23:29:28 2016 -0500
@@ -197,7 +197,7 @@
         repetition = 3
 
         # repeat changing via checkambigatclosing, to examine whether
-        # st_mtime is advanced multiple times as expecetd
+        # st_mtime is advanced multiple times as expected
         for i in xrange(repetition):
             # explicit closing
             fp = scmutil.checkambigatclosing(open(filename, 'a'))
@@ -214,7 +214,7 @@
             continue
 
         # st_mtime should be advanced "repetition * 2" times, because
-        # all changes occured at same time (in sec)
+        # all changes occurred at same time (in sec)
         expected = (oldstat.st_mtime + repetition * 2) & 0x7fffffff
         if newstat.st_mtime != expected:
             print("'newstat.st_mtime %s is not %s (as %s + %s * 2)" %
--- a/tests/test-generaldelta.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-generaldelta.t	Wed Nov 16 23:29:28 2016 -0500
@@ -74,7 +74,7 @@
   $ cd ..
 
 Test "usegeneraldelta" config
-(repo are general delta, but incoming bundle are not re-deltified)
+(repo are general delta, but incoming bundle are not re-deltafied)
 
 delta coming from the server base delta server are not recompressed.
 (also include the aggressive version for comparison)
--- a/tests/test-https.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-https.t	Wed Nov 16 23:29:28 2016 -0500
@@ -379,7 +379,7 @@
 
 Fingerprints
 
-- works without cacerts (hostkeyfingerprints)
+- works without cacerts (hostfingerprints)
   $ hg -R copy-pull id https://localhost:$HGPORT/ --insecure --config hostfingerprints.localhost=ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03
   warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
   5fed3813f7f5
--- a/tests/test-import.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-import.t	Wed Nov 16 23:29:28 2016 -0500
@@ -431,10 +431,10 @@
   parent: 0
 
 Test that "hg rollback" doesn't restore dirstate to one at the
-beginning of the rollbacked transaction in not-"parent-gone" case.
+beginning of the rolled back transaction in not-"parent-gone" case.
 
 invoking pretxncommit hook will cause marking '.hg/dirstate' as a file
-to be restored at rollbacking, after DirstateTransactionPlan (see wiki
+to be restored when rolling back, after DirstateTransactionPlan (see wiki
 page for detail).
 
   $ hg --cwd b branch -q foobar
@@ -451,7 +451,7 @@
   $ hg --cwd b update -q -C 0
   $ hg --cwd b --config extensions.strip= strip -q 1
 
-Test visibility of in-memory distate changes inside transaction to
+Test visibility of in-memory dirstate changes inside transaction to
 external process
 
   $ echo foo > a/foo
--- a/tests/test-largefiles-wireproto.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-largefiles-wireproto.t	Wed Nov 16 23:29:28 2016 -0500
@@ -388,7 +388,7 @@
 
   $ killdaemons.py
 
-largefiles should not ask for password again after succesfull authorization
+largefiles should not ask for password again after successful authorization
 
   $ hg init credentialmain
   $ cd credentialmain
--- a/tests/test-mq-qrefresh-replace-log-message.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-mq-qrefresh-replace-log-message.t	Wed Nov 16 23:29:28 2016 -0500
@@ -199,7 +199,7 @@
   
   test saving last-message.txt
 
-Test visibility of in-memory distate changes outside transaction to
+Test visibility of in-memory dirstate changes outside transaction to
 external process
 
   $ cat > $TESTTMP/checkvisibility.sh <<EOF
--- a/tests/test-obsolete.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-obsolete.t	Wed Nov 16 23:29:28 2016 -0500
@@ -1211,7 +1211,7 @@
   2 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 \(.*\) {'user': 'test'} (re)
   3 4715cf767440ed891755448016c2b8cf70760c30 7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d 0 \(.*\) {'user': 'test'} (re)
   $ hg debugobsolete --delete 1 --delete 3
-  deleted 2 obsolescense markers
+  deleted 2 obsolescence markers
   $ hg debugobsolete
   cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 \(.*\) {'user': 'test'} (re)
   1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 \(.*\) {'user': 'test'} (re)
--- a/tests/test-profile.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-profile.t	Wed Nov 16 23:29:28 2016 -0500
@@ -8,25 +8,27 @@
 
 test --profile
 
-  $ hg --profile st 2>../out
+  $ prof='hg --config profiling.type=ls --profile'
+
+  $ $prof st 2>../out
   $ grep CallCount ../out > /dev/null || cat ../out
 
-  $ hg --profile --config profiling.output=../out st
+  $ $prof --config profiling.output=../out st
   $ grep CallCount ../out > /dev/null || cat ../out
 
-  $ hg --profile --config profiling.output=blackbox --config extensions.blackbox= st
+  $ $prof --config profiling.output=blackbox --config extensions.blackbox= st
   $ grep CallCount .hg/blackbox.log > /dev/null || cat .hg/blackbox.log
 
-  $ hg --profile --config profiling.format=text st 2>../out
+  $ $prof --config profiling.format=text st 2>../out
   $ grep CallCount ../out > /dev/null || cat ../out
 
   $ echo "[profiling]" >> $HGRCPATH
   $ echo "format=kcachegrind" >> $HGRCPATH
 
-  $ hg --profile st 2>../out
+  $ $prof st 2>../out
   $ grep 'events: Ticks' ../out > /dev/null || cat ../out
 
-  $ hg --profile --config profiling.output=../out st
+  $ $prof --config profiling.output=../out st
   $ grep 'events: Ticks' ../out > /dev/null || cat ../out
 
 #endif
@@ -35,7 +37,7 @@
 
 Profiling of HTTP requests works
 
-  $ hg --profile --config profiling.format=text --config profiling.output=../profile.log serve -d -p $HGPORT --pid-file ../hg.pid -A ../access.log
+  $ $prof --config profiling.format=text --config profiling.output=../profile.log serve -d -p $HGPORT --pid-file ../hg.pid -A ../access.log
   $ cat ../hg.pid >> $DAEMON_PIDS
   $ hg -q clone -U http://localhost:$HGPORT ../clone
 
@@ -45,4 +47,49 @@
 
 #endif
 
+Install an extension that can sleep and guarantee a profiler has time to run
+
+  $ cat >> sleepext.py << EOF
+  > import time
+  > from mercurial import cmdutil, commands
+  > cmdtable = {}
+  > command = cmdutil.command(cmdtable)
+  > @command('sleep', [], 'hg sleep')
+  > def sleep(ui, *args, **kwargs):
+  >     time.sleep(0.1)
+  > EOF
+
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > sleep = `pwd`/sleepext.py
+  > EOF
+
+statistical profiler works
+
+  $ hg --profile sleep 2>../out
+  $ grep Sample ../out
+  Sample count: \d+ (re)
+
+Various statprof formatters work
+
+  $ hg --profile --config profiling.statformat=byline sleep 2>../out
+  $ head -n 1 ../out
+    %   cumulative      self          
+  $ grep Sample ../out
+  Sample count: \d+ (re)
+
+  $ hg --profile --config profiling.statformat=bymethod sleep 2>../out
+  $ head -n 1 ../out
+    %   cumulative      self          
+  $ grep Sample ../out
+  Sample count: \d+ (re)
+
+  $ hg --profile --config profiling.statformat=hotpath sleep 2>../out
+  $ grep Sample ../out
+  Sample count: \d+ (re)
+
+  $ hg --profile --config profiling.statformat=json sleep 2>../out
+  $ cat ../out
+  \[\[\d+.* (re)
+
   $ cd ..
--- a/tests/test-pull-update.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-pull-update.t	Wed Nov 16 23:29:28 2016 -0500
@@ -130,7 +130,7 @@
 
 Test that updating deactivates current active bookmark, if the
 destination of the update is explicitly specified, and it doesn't
-match with the name of any exsiting bookmarks.
+match with the name of any existing bookmarks.
 
   $ cd ../t
   $ hg bookmark -d active-after-pull
--- a/tests/test-push-hook-lock.t	Sun Nov 13 06:12:22 2016 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-  $ hg init 1
-
-  $ echo '[ui]' >> 1/.hg/hgrc
-  $ echo 'timeout = 10' >> 1/.hg/hgrc
-
-  $ echo foo > 1/foo
-  $ hg --cwd 1 ci -A -m foo
-  adding foo
-
-  $ hg clone 1 2
-  updating to branch default
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-
-  $ hg clone 2 3
-  updating to branch default
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-
-  $ cat <<EOF > $TESTTMP/debuglocks-pretxn-hook.sh
-  > hg debuglocks
-  > true
-  > EOF
-  $ echo '[hooks]' >> 2/.hg/hgrc
-  $ echo "pretxnchangegroup.a = sh $TESTTMP/debuglocks-pretxn-hook.sh" >> 2/.hg/hgrc
-  $ echo 'changegroup.push = hg push -qf ../1' >> 2/.hg/hgrc
-
-  $ echo bar >> 3/foo
-  $ hg --cwd 3 ci -m bar
-
-  $ hg --cwd 3 push ../2 --config devel.legacy.exchange=bundle1
-  pushing to ../2
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 1 changesets with 1 changes to 1 files
-  lock:  user *, process * (*s) (glob)
-  wlock: free
-
-  $ hg --cwd 1 --config extensions.strip= strip tip -q
-  $ hg --cwd 2 --config extensions.strip= strip tip -q
-  $ hg --cwd 3 push ../2 # bundle2+
-  pushing to ../2
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 1 changesets with 1 changes to 1 files
-  lock:  user *, process * (*s) (glob)
-  wlock: user *, process * (*s) (glob)
-
--- a/tests/test-push-r.t	Sun Nov 13 06:12:22 2016 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +0,0 @@
-  $ hg init test
-  $ cd test
-  $ hg unbundle "$TESTDIR/bundles/remote.hg"
-  adding changesets
-  adding manifests
-  adding file changes
-  added 9 changesets with 7 changes to 4 files (+1 heads)
-  (run 'hg heads' to see heads, 'hg merge' to merge)
-  $ hg up tip
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ cd ..
-
-  $ for i in 0 1 2 3 4 5 6 7 8; do
-  >    echo
-  >    mkdir test-"$i"
-  >    hg --cwd test-"$i" init
-  >    hg -R test push -r "$i" test-"$i"
-  >    cd test-"$i"
-  >    hg verify
-  >    cd ..
-  > done
-  
-  pushing to test-0
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 1 changesets with 1 changes to 1 files
-  checking changesets
-  checking manifests
-  crosschecking files in changesets and manifests
-  checking files
-  1 files, 1 changesets, 1 total revisions
-  
-  pushing to test-1
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 2 changesets with 2 changes to 1 files
-  checking changesets
-  checking manifests
-  crosschecking files in changesets and manifests
-  checking files
-  1 files, 2 changesets, 2 total revisions
-  
-  pushing to test-2
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 3 changesets with 3 changes to 1 files
-  checking changesets
-  checking manifests
-  crosschecking files in changesets and manifests
-  checking files
-  1 files, 3 changesets, 3 total revisions
-  
-  pushing to test-3
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 4 changesets with 4 changes to 1 files
-  checking changesets
-  checking manifests
-  crosschecking files in changesets and manifests
-  checking files
-  1 files, 4 changesets, 4 total revisions
-  
-  pushing to test-4
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 2 changesets with 2 changes to 1 files
-  checking changesets
-  checking manifests
-  crosschecking files in changesets and manifests
-  checking files
-  1 files, 2 changesets, 2 total revisions
-  
-  pushing to test-5
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 3 changesets with 3 changes to 1 files
-  checking changesets
-  checking manifests
-  crosschecking files in changesets and manifests
-  checking files
-  1 files, 3 changesets, 3 total revisions
-  
-  pushing to test-6
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 4 changesets with 5 changes to 2 files
-  checking changesets
-  checking manifests
-  crosschecking files in changesets and manifests
-  checking files
-  2 files, 4 changesets, 5 total revisions
-  
-  pushing to test-7
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 5 changesets with 6 changes to 3 files
-  checking changesets
-  checking manifests
-  crosschecking files in changesets and manifests
-  checking files
-  3 files, 5 changesets, 6 total revisions
-  
-  pushing to test-8
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 5 changesets with 5 changes to 2 files
-  checking changesets
-  checking manifests
-  crosschecking files in changesets and manifests
-  checking files
-  2 files, 5 changesets, 5 total revisions
-
-  $ cd test-8
-
-  $ hg pull ../test-7
-  pulling from ../test-7
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 4 changesets with 2 changes to 3 files (+1 heads)
-  (run 'hg heads' to see heads, 'hg merge' to merge)
-
-  $ hg verify
-  checking changesets
-  checking manifests
-  crosschecking files in changesets and manifests
-  checking files
-  4 files, 9 changesets, 7 total revisions
-
-  $ cd ..
--- a/tests/test-push-validation.t	Sun Nov 13 06:12:22 2016 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-  $ hg init test
-  $ cd test
-
-  $ cat > .hg/hgrc <<EOF
-  > [server]
-  > validate=1
-  > EOF
-
-  $ echo alpha > alpha
-  $ echo beta > beta
-  $ hg addr
-  adding alpha
-  adding beta
-  $ hg ci -m 1
-
-  $ cd ..
-  $ hg clone test test-clone
-  updating to branch default
-  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-
-Test spurious filelog entries:
-
-  $ cd test-clone
-  $ echo blah >> beta
-  $ cp .hg/store/data/beta.i tmp1
-  $ hg ci -m 2
-  $ cp .hg/store/data/beta.i tmp2
-  $ hg -q rollback
-  $ mv tmp2 .hg/store/data/beta.i
-  $ echo blah >> beta
-  $ hg ci -m '2 (corrupt)'
-
-Expected to fail:
-
-  $ hg verify
-  checking changesets
-  checking manifests
-  crosschecking files in changesets and manifests
-  checking files
-   beta@1: dddc47b3ba30 not in manifests
-  2 files, 2 changesets, 4 total revisions
-  1 integrity errors encountered!
-  (first damaged changeset appears to be 1)
-  [1]
-
-  $ hg push
-  pushing to $TESTTMP/test (glob)
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  transaction abort!
-  rollback completed
-  abort: received spurious file revlog entry
-  [255]
-
-  $ hg -q rollback
-  $ mv tmp1 .hg/store/data/beta.i
-  $ echo beta > beta
-
-Test missing filelog entries:
-
-  $ cp .hg/store/data/beta.i tmp
-  $ echo blah >> beta
-  $ hg ci -m '2 (corrupt)'
-  $ mv tmp .hg/store/data/beta.i
-
-Expected to fail:
-
-  $ hg verify
-  checking changesets
-  checking manifests
-  crosschecking files in changesets and manifests
-  checking files
-   beta@1: manifest refers to unknown revision dddc47b3ba30
-  2 files, 2 changesets, 2 total revisions
-  1 integrity errors encountered!
-  (first damaged changeset appears to be 1)
-  [1]
-
-  $ hg push
-  pushing to $TESTTMP/test (glob)
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  transaction abort!
-  rollback completed
-  abort: missing file data for beta:dddc47b3ba30e54484720ce0f4f768a0f4b6efb9 - run hg verify
-  [255]
-
-  $ cd ..
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-push.t	Wed Nov 16 23:29:28 2016 -0500
@@ -0,0 +1,299 @@
+==================================
+Basic testing for the push command
+==================================
+
+Testing of the '--rev' flag
+===========================
+
+  $ hg init test-revflag
+  $ hg -R test-revflag unbundle "$TESTDIR/bundles/remote.hg"
+  adding changesets
+  adding manifests
+  adding file changes
+  added 9 changesets with 7 changes to 4 files (+1 heads)
+  (run 'hg heads' to see heads, 'hg merge' to merge)
+
+  $ for i in 0 1 2 3 4 5 6 7 8; do
+  >    echo
+  >    hg init test-revflag-"$i"
+  >    hg -R test-revflag push -r "$i" test-revflag-"$i"
+  >    hg -R test-revflag-"$i" verify
+  > done
+  
+  pushing to test-revflag-0
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  1 files, 1 changesets, 1 total revisions
+  
+  pushing to test-revflag-1
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 1 files
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  1 files, 2 changesets, 2 total revisions
+  
+  pushing to test-revflag-2
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 3 changesets with 3 changes to 1 files
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  1 files, 3 changesets, 3 total revisions
+  
+  pushing to test-revflag-3
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 4 changesets with 4 changes to 1 files
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  1 files, 4 changesets, 4 total revisions
+  
+  pushing to test-revflag-4
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 1 files
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  1 files, 2 changesets, 2 total revisions
+  
+  pushing to test-revflag-5
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 3 changesets with 3 changes to 1 files
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  1 files, 3 changesets, 3 total revisions
+  
+  pushing to test-revflag-6
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 4 changesets with 5 changes to 2 files
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  2 files, 4 changesets, 5 total revisions
+  
+  pushing to test-revflag-7
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 5 changesets with 6 changes to 3 files
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  3 files, 5 changesets, 6 total revisions
+  
+  pushing to test-revflag-8
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 5 changesets with 5 changes to 2 files
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  2 files, 5 changesets, 5 total revisions
+
+  $ cd test-revflag-8
+
+  $ hg pull ../test-revflag-7
+  pulling from ../test-revflag-7
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 4 changesets with 2 changes to 3 files (+1 heads)
+  (run 'hg heads' to see heads, 'hg merge' to merge)
+
+  $ hg verify
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  4 files, 9 changesets, 7 total revisions
+
+  $ cd ..
+
+Test server side validation during push
+=======================================
+
+  $ hg init test-validation
+  $ cd test-validation
+
+  $ cat > .hg/hgrc <<EOF
+  > [server]
+  > validate=1
+  > EOF
+
+  $ echo alpha > alpha
+  $ echo beta > beta
+  $ hg addr
+  adding alpha
+  adding beta
+  $ hg ci -m 1
+
+  $ cd ..
+  $ hg clone test-validation test-validation-clone
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Test spurious filelog entries:
+
+  $ cd test-validation-clone
+  $ echo blah >> beta
+  $ cp .hg/store/data/beta.i tmp1
+  $ hg ci -m 2
+  $ cp .hg/store/data/beta.i tmp2
+  $ hg -q rollback
+  $ mv tmp2 .hg/store/data/beta.i
+  $ echo blah >> beta
+  $ hg ci -m '2 (corrupt)'
+
+Expected to fail:
+
+  $ hg verify
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+   beta@1: dddc47b3ba30 not in manifests
+  2 files, 2 changesets, 4 total revisions
+  1 integrity errors encountered!
+  (first damaged changeset appears to be 1)
+  [1]
+
+  $ hg push
+  pushing to $TESTTMP/test-validation (glob)
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  transaction abort!
+  rollback completed
+  abort: received spurious file revlog entry
+  [255]
+
+  $ hg -q rollback
+  $ mv tmp1 .hg/store/data/beta.i
+  $ echo beta > beta
+
+Test missing filelog entries:
+
+  $ cp .hg/store/data/beta.i tmp
+  $ echo blah >> beta
+  $ hg ci -m '2 (corrupt)'
+  $ mv tmp .hg/store/data/beta.i
+
+Expected to fail:
+
+  $ hg verify
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+   beta@1: manifest refers to unknown revision dddc47b3ba30
+  2 files, 2 changesets, 2 total revisions
+  1 integrity errors encountered!
+  (first damaged changeset appears to be 1)
+  [1]
+
+  $ hg push
+  pushing to $TESTTMP/test-validation (glob)
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  transaction abort!
+  rollback completed
+  abort: missing file data for beta:dddc47b3ba30e54484720ce0f4f768a0f4b6efb9 - run hg verify
+  [255]
+
+  $ cd ..
+
+Test push hook locking
+=====================
+
+  $ hg init 1
+
+  $ echo '[ui]' >> 1/.hg/hgrc
+  $ echo 'timeout = 10' >> 1/.hg/hgrc
+
+  $ echo foo > 1/foo
+  $ hg --cwd 1 ci -A -m foo
+  adding foo
+
+  $ hg clone 1 2
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ hg clone 2 3
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ cat <<EOF > $TESTTMP/debuglocks-pretxn-hook.sh
+  > hg debuglocks
+  > true
+  > EOF
+  $ echo '[hooks]' >> 2/.hg/hgrc
+  $ echo "pretxnchangegroup.a = sh $TESTTMP/debuglocks-pretxn-hook.sh" >> 2/.hg/hgrc
+  $ echo 'changegroup.push = hg push -qf ../1' >> 2/.hg/hgrc
+
+  $ echo bar >> 3/foo
+  $ hg --cwd 3 ci -m bar
+
+  $ hg --cwd 3 push ../2 --config devel.legacy.exchange=bundle1
+  pushing to ../2
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  lock:  user *, process * (*s) (glob)
+  wlock: free
+
+  $ hg --cwd 1 --config extensions.strip= strip tip -q
+  $ hg --cwd 2 --config extensions.strip= strip tip -q
+  $ hg --cwd 3 push ../2 # bundle2+
+  pushing to ../2
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  lock:  user *, process * (*s) (glob)
+  wlock: user *, process * (*s) (glob)
+
--- a/tests/test-qrecord.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-qrecord.t	Wed Nov 16 23:29:28 2016 -0500
@@ -9,6 +9,9 @@
   record extension - commands to interactively select changes for
   commit/qrefresh (DEPRECATED)
   
+  The feature provided by this extension has been moved into core Mercurial as
+  'hg commit --interactive'.
+  
   (use 'hg help extensions' for information on enabling extensions)
 
 help qrecord (no record)
--- a/tests/test-rebase-conflicts.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-rebase-conflicts.t	Wed Nov 16 23:29:28 2016 -0500
@@ -73,8 +73,6 @@
 Try to continue without solving the conflict:
 
   $ hg rebase --continue
-  already rebased 3:3163e20567cc "L1" as 3e046f2ecedb
-  rebasing 4:46f0b057b5c0 "L2"
   abort: unresolved merge conflicts (see 'hg help resolve')
   [255]
 
--- a/tests/test-rebase-scenario-global.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-rebase-scenario-global.t	Wed Nov 16 23:29:28 2016 -0500
@@ -838,7 +838,7 @@
 
   $ cd ..
 
-Make the repo a bit more interresting
+Make the repo a bit more interesting
 
   $ hg up 1
   0 files updated, 0 files merged, 2 files removed, 0 files unresolved
--- a/tests/test-revert-interactive.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-revert-interactive.t	Wed Nov 16 23:29:28 2016 -0500
@@ -137,7 +137,7 @@
   $ ls folder1/
   g
 
-Test that a noop revert doesn't do an unecessary backup
+Test that a noop revert doesn't do an unnecessary backup
   $ (echo y; echo n) | hg revert -i -r 2 folder1/g
   diff --git a/folder1/g b/folder1/g
   1 hunks, 1 lines changed
--- a/tests/test-revset.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-revset.t	Wed Nov 16 23:29:28 2016 -0500
@@ -1079,7 +1079,7 @@
   8
   9
 
-Test opreand of '%' is optimized recursively (issue4670)
+Test operand of '%' is optimized recursively (issue4670)
 
   $ try --optimize '8:9-8%'
   (onlypost
@@ -3085,7 +3085,7 @@
   [255]
 
 test scope of alias expansion: 'universe' is expanded prior to 'shadowall(0)',
-but 'all()' should never be substituded to '0()'.
+but 'all()' should never be substituted to '0()'.
 
   $ echo 'universe = all()' >> .hg/hgrc
   $ echo 'shadowall(all) = all and universe' >> .hg/hgrc
--- a/tests/test-shelve.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-shelve.t	Wed Nov 16 23:29:28 2016 -0500
@@ -1493,7 +1493,7 @@
 When i unshelve resulting in merge conflicts and makes saved
 file shelvedstate looks like in previous versions in
 mercurial(without restore branch information in 7th line) i
-expect that after resolving conflicts and succesfully
+expect that after resolving conflicts and successfully
 running 'shelve --continue' the branch information won't be
 restored and branch will be unchanged.
 
@@ -1587,7 +1587,7 @@
   default
   $ cd ..
 
-Prepare unshleve with a corrupted shelvedstate
+Prepare unshelve with a corrupted shelvedstate
   $ hg init r1 && cd r1
   $ echo text1 > file && hg add file
   $ hg shelve
--- a/tests/test-ssh.t	Sun Nov 13 06:12:22 2016 +0900
+++ b/tests/test-ssh.t	Wed Nov 16 23:29:28 2016 -0500
@@ -265,8 +265,17 @@
   > sys.stdout.write("KABOOM\n")
   > EOF
 
-  $ echo '[hooks]' >> ../remote/.hg/hgrc
-  $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
+  $ cat <<EOF > $TESTTMP/badpyhook.py
+  > import sys
+  > def hook(ui, repo, hooktype, **kwargs):
+  >     sys.stdout.write("KABOOM IN PROCESS\n")
+  > EOF
+
+  $ cat <<EOF >> ../remote/.hg/hgrc
+  > [hooks]
+  > changegroup.stdout = python $TESTTMP/badhook
+  > changegroup.pystdout = python:$TESTTMP/badpyhook.py:hook
+  > EOF
   $ echo r > r
   $ hg ci -A -m z r
 
@@ -281,6 +290,7 @@
   remote: adding file changes
   remote: added 1 changesets with 1 changes to 1 files
   remote: KABOOM
+  remote: KABOOM IN PROCESS
   $ hg -R ../remote heads
   changeset:   5:1383141674ec
   tag:         tip
@@ -447,6 +457,7 @@
   remote: adding file changes
   remote: added 1 changesets with 1 changes to 1 files
   remote: KABOOM
+  remote: KABOOM IN PROCESS
   local stdout
 
 debug output