# HG changeset patch # User Martin von Zweigbergk # Date 2021-06-18 22:48:51 # Node ID 7a430116f6396332ffb0ec41cc00471635156136 # Parent 6ecd0980d7f988580cf06db653d975f7d8f7b012 ui: add a context manager for silencing the ui (pushbuffer+popbuffer) We often silence the ui by calling `ui.pushbuffer()` followed (a later in the code) by `ui.popbuffer()`. These places can be identified by the fact that they ignore the output returned from `ui.popbuffer()`. Let's create a context manager for these cases, to avoid repetition, and to avoid accidentally leaving the ui silent on exceptions. I deliberately called the new function `silent()` instead of `buffered()`, because it's just an implementation detail that it uses `pushbuffer()` and `popbuffer()`. We could later optimize it to not buffer the output. Differential Revision: https://phab.mercurial-scm.org/D10884 diff --git a/contrib/benchmarks/__init__.py b/contrib/benchmarks/__init__.py --- a/contrib/benchmarks/__init__.py +++ b/contrib/benchmarks/__init__.py @@ -76,9 +76,8 @@ def runperfcommand(reponame, command, *a ui, 'perfext', os.path.join(basedir, 'contrib', 'perf.py') ) cmd = getattr(perfext, command) - ui.pushbuffer() - cmd(ui, repo, *args, **kwargs) - output = ui.popbuffer() + with ui.silent(): + cmd(ui, repo, *args, **kwargs) match = outputre.search(output) if not match: raise ValueError("Invalid output {}".format(output)) diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -575,9 +575,8 @@ class histeditaction(object): parentctx, but does not commit them.""" repo = self.repo rulectx = repo[self.node] - repo.ui.pushbuffer() - hg.update(repo, self.state.parentctxnode, quietempty=True) - repo.ui.popbuffer() + with repo.ui.silent(): + hg.update(repo, self.state.parentctxnode, quietempty=True) stats = applychanges(repo.ui, repo, rulectx, {}) repo.dirstate.setbranch(rulectx.branch()) if stats.unresolvedcount: @@ -654,10 +653,9 @@ def applychanges(ui, repo, ctx, opts): if ctx.p1().node() == repo.dirstate.p1(): # edits are "in place" we do not need to make any merge, # just applies changes on parent for editing - ui.pushbuffer() - cmdutil.revert(ui, repo, ctx, all=True) - stats = mergemod.updateresult(0, 0, 0, 0) - ui.popbuffer() + with ui.silent(): + cmdutil.revert(ui, repo, ctx, all=True) + stats = mergemod.updateresult(0, 0, 0, 0) else: try: # ui.forcemerge is an internal variable, do not document diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -7241,9 +7241,8 @@ def summary(ui, repo, **opts): if revs: revs = [other.lookup(rev) for rev in revs] ui.debug(b'comparing with %s\n' % urlutil.hidepassword(source)) - repo.ui.pushbuffer() - commoninc = discovery.findcommonincoming(repo, other, heads=revs) - repo.ui.popbuffer() + with repo.ui.silent(): + commoninc = discovery.findcommonincoming(repo, other, heads=revs) return source, sbranch, other, commoninc, commoninc[1] if needsincoming: @@ -7287,11 +7286,10 @@ def summary(ui, repo, **opts): common = commoninc if revs: revs = [repo.lookup(rev) for rev in revs] - repo.ui.pushbuffer() - outgoing = discovery.findcommonoutgoing( - repo, dother, onlyheads=revs, commoninc=common - ) - repo.ui.popbuffer() + with repo.ui.silent(): + outgoing = discovery.findcommonoutgoing( + repo, dother, onlyheads=revs, commoninc=common + ) return dest, dbranch, dother, outgoing if needsoutgoing: diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py --- a/mercurial/debugcommands.py +++ b/mercurial/debugcommands.py @@ -2754,9 +2754,9 @@ def debugpickmergetool(ui, repo, *pats, changedelete = opts[b'changedelete'] for path in ctx.walk(m): fctx = ctx[path] - try: - if not ui.debugflag: - ui.pushbuffer(error=True) + with ui.silent( + error=True + ) if not ui.debugflag else util.nullcontextmanager(): tool, toolpath = filemerge._picktool( repo, ui, @@ -2765,9 +2765,6 @@ def debugpickmergetool(ui, repo, *pats, b'l' in fctx.flags(), changedelete, ) - finally: - if not ui.debugflag: - ui.popbuffer() ui.write(b'%s = %s\n' % (path, tool)) @@ -4580,17 +4577,16 @@ def debugwireproto(ui, repo, path=None, ui.write(_(b'creating http peer for wire protocol version 2\n')) # We go through makepeer() because we need an API descriptor for # the peer instance to be useful. - with ui.configoverride( + maybe_silent = ( + ui.silent() + if opts[b'nologhandshake'] + else util.nullcontextmanager() + ) + with maybe_silent, ui.configoverride( {(b'experimental', b'httppeer.advertise-v2'): True} ): - if opts[b'nologhandshake']: - ui.pushbuffer() - peer = httppeer.makepeer(ui, path, opener=opener) - if opts[b'nologhandshake']: - ui.popbuffer() - if not isinstance(peer, httppeer.httpv2peer): raise error.Abort( _( diff --git a/mercurial/logcmdutil.py b/mercurial/logcmdutil.py --- a/mercurial/logcmdutil.py +++ b/mercurial/logcmdutil.py @@ -93,9 +93,8 @@ def diff_parent(ctx): }, b"merge-diff", ): - repo.ui.pushbuffer() - merge.merge(ctx.p2(), wc=wctx) - repo.ui.popbuffer() + with repo.ui.silent(): + merge.merge(ctx.p2(), wc=wctx) return wctx else: return ctx.p1() diff --git a/mercurial/repair.py b/mercurial/repair.py --- a/mercurial/repair.py +++ b/mercurial/repair.py @@ -28,6 +28,7 @@ from . import ( pycompat, requirements, scmutil, + util, ) from .utils import ( hashutil, @@ -239,19 +240,23 @@ def strip(ui, repo, nodelist, backup=Tru ui.note(_(b"adding branch\n")) f = vfs.open(tmpbundlefile, b"rb") gen = exchange.readbundle(ui, f, tmpbundlefile, vfs) - if not repo.ui.verbose: - # silence internal shuffling chatter - repo.ui.pushbuffer() - tmpbundleurl = b'bundle:' + vfs.join(tmpbundlefile) - txnname = b'strip' - if not isinstance(gen, bundle2.unbundle20): - txnname = b"strip\n%s" % urlutil.hidepassword(tmpbundleurl) - with repo.transaction(txnname) as tr: - bundle2.applybundle( - repo, gen, tr, source=b'strip', url=tmpbundleurl - ) - if not repo.ui.verbose: - repo.ui.popbuffer() + # silence internal shuffling chatter + maybe_silent = ( + repo.ui.silent() + if not repo.ui.verbose + else util.nullcontextmanager() + ) + with maybe_silent: + tmpbundleurl = b'bundle:' + vfs.join(tmpbundlefile) + txnname = b'strip' + if not isinstance(gen, bundle2.unbundle20): + txnname = b"strip\n%s" % urlutil.hidepassword( + tmpbundleurl + ) + with repo.transaction(txnname) as tr: + bundle2.applybundle( + repo, gen, tr, source=b'strip', url=tmpbundleurl + ) f.close() with repo.transaction(b'repair') as tr: diff --git a/mercurial/revset.py b/mercurial/revset.py --- a/mercurial/revset.py +++ b/mercurial/revset.py @@ -1872,9 +1872,10 @@ def outgoing(repo, subset, x): revs = [repo.lookup(rev) for rev in revs] other = hg.peer(repo, {}, dest) try: - repo.ui.pushbuffer() - outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs) - repo.ui.popbuffer() + with repo.ui.silent(): + outgoing = discovery.findcommonoutgoing( + repo, other, onlyheads=revs + ) finally: other.close() missing.update(outgoing.missing) diff --git a/mercurial/ui.py b/mercurial/ui.py --- a/mercurial/ui.py +++ b/mercurial/ui.py @@ -1146,6 +1146,14 @@ class ui(object): self._fmsg = f self._fmsgout, self._fmsgerr = _selectmsgdests(self) + @contextlib.contextmanager + def silent(self, error=False, subproc=False, labeled=False): + self.pushbuffer(error=error, subproc=subproc, labeled=labeled) + try: + yield + finally: + self.popbuffer() + def pushbuffer(self, error=False, subproc=False, labeled=False): """install a buffer to capture standard output of the ui object diff --git a/tests/bruterebase.py b/tests/bruterebase.py --- a/tests/bruterebase.py +++ b/tests/bruterebase.py @@ -48,26 +48,25 @@ def debugbruterebase(ui, repo, source, d tr = repo.transaction(b'rebase') tr._report = lambda x: 0 # hide "transaction abort" - ui.pushbuffer() - try: - rebase.rebase(ui, repo, dest=dest, rev=[spec]) - except error.Abort as ex: - summary = b'ABORT: %s' % ex.message - except Exception as ex: - summary = b'CRASH: %s' % ex - else: - # short summary about new nodes - cl = repo.changelog - descs = [] - for rev in xrange(repolen, len(repo)): - desc = b'%s:' % getdesc(rev) - for prev in cl.parentrevs(rev): - if prev > -1: - desc += getdesc(prev) - descs.append(desc) - descs.sort() - summary = b' '.join(descs) - ui.popbuffer() + with ui.silent(): + try: + rebase.rebase(ui, repo, dest=dest, rev=[spec]) + except error.Abort as ex: + summary = b'ABORT: %s' % ex.message + except Exception as ex: + summary = b'CRASH: %s' % ex + else: + # short summary about new nodes + cl = repo.changelog + descs = [] + for rev in xrange(repolen, len(repo)): + desc = b'%s:' % getdesc(rev) + for prev in cl.parentrevs(rev): + if prev > -1: + desc += getdesc(prev) + descs.append(desc) + descs.sort() + summary = b' '.join(descs) repo.vfs.tryunlink(b'rebasestate') subsetdesc = b''.join(getdesc(rev) for rev in subset)