Mercurial > hg-stable
changeset 44654:3cbbfd0bfc17
hook: move stdio redirection to context manager
The old code was checking stdio redirection in a loop.
This didn't make sense. The pattern is better expressed
as a context manager IMO, so this commit refactors it
to be one.
Differential Revision: https://phab.mercurial-scm.org/D8338
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Sun, 29 Mar 2020 11:58:50 -0700 |
parents | 00e0c5c06ed5 |
children | 02fa5392bab6 |
files | mercurial/hook.py |
diffstat | 1 files changed, 35 insertions(+), 25 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/hook.py Sat Mar 28 12:18:58 2020 -0700 +++ b/mercurial/hook.py Sun Mar 29 11:58:50 2020 -0700 @@ -7,6 +7,7 @@ from __future__ import absolute_import +import contextlib import os import sys @@ -259,26 +260,45 @@ return r +@contextlib.contextmanager +def redirect_stdio(): + """Redirects stdout to stderr, if possible.""" + + oldstdout = -1 + try: + if _redirect: + try: + stdoutno = procutil.stdout.fileno() + stderrno = procutil.stderr.fileno() + # temporarily redirect stdout to stderr, if possible + if stdoutno >= 0 and stderrno >= 0: + procutil.stdout.flush() + oldstdout = os.dup(stdoutno) + os.dup2(stderrno, stdoutno) + except (OSError, AttributeError): + # files seem to be bogus, give up on redirecting (WSGI, etc) + pass + + yield + + finally: + # The stderr is fully buffered on Windows when connected to a pipe. + # A forcible flush is required to make small stderr data in the + # remote side available to the client immediately. + procutil.stderr.flush() + + if _redirect and oldstdout >= 0: + procutil.stdout.flush() # write hook output to stderr fd + os.dup2(oldstdout, stdoutno) + os.close(oldstdout) + + def runhooks(ui, repo, htype, hooks, throw=False, **args): args = pycompat.byteskwargs(args) res = {} - oldstdout = -1 - try: + with redirect_stdio(): for hname, cmd in hooks: - if oldstdout == -1 and _redirect: - try: - stdoutno = procutil.stdout.fileno() - stderrno = procutil.stderr.fileno() - # temporarily redirect stdout to stderr, if possible - if stdoutno >= 0 and stderrno >= 0: - procutil.stdout.flush() - oldstdout = os.dup(stdoutno) - os.dup2(stderrno, stdoutno) - except (OSError, AttributeError): - # files seem to be bogus, give up on redirecting (WSGI, etc) - pass - if cmd is _fromuntrusted: if throw: raise error.HookAbort( @@ -312,15 +332,5 @@ raised = False res[hname] = r, raised - finally: - # The stderr is fully buffered on Windows when connected to a pipe. - # A forcible flush is required to make small stderr data in the - # remote side available to the client immediately. - procutil.stderr.flush() - - if _redirect and oldstdout >= 0: - procutil.stdout.flush() # write hook output to stderr fd - os.dup2(oldstdout, stdoutno) - os.close(oldstdout) return res