diff --git a/mercurial/commandserver.py b/mercurial/commandserver.py --- a/mercurial/commandserver.py +++ b/mercurial/commandserver.py @@ -318,13 +318,12 @@ class pipeservice(object): ui = self.ui # redirect stdio to null device so that broken extensions or in-process # hooks will never cause corruption of channel protocol. - fin, fout = procutil.protectstdio(ui.fin, ui.fout) - try: - sv = server(ui, self.repo, fin, fout) - return sv.serve() - finally: - sv.cleanup() - procutil.restorestdio(ui.fin, ui.fout, fin, fout) + with procutil.protectedstdio(ui.fin, ui.fout) as (fin, fout): + try: + sv = server(ui, self.repo, fin, fout) + return sv.serve() + finally: + sv.cleanup() def _initworkerprocess(): # use a different process group from the master process, in order to: diff --git a/mercurial/utils/procutil.py b/mercurial/utils/procutil.py --- a/mercurial/utils/procutil.py +++ b/mercurial/utils/procutil.py @@ -9,6 +9,7 @@ from __future__ import absolute_import +import contextlib import imp import io import os @@ -240,6 +241,15 @@ def restorestdio(uin, uout, fin, fout): os.dup2(f.fileno(), uif.fileno()) f.close() +@contextlib.contextmanager +def protectedstdio(uin, uout): + """Run code block with protected standard streams""" + fin, fout = protectstdio(uin, uout) + try: + yield fin, fout + finally: + restorestdio(uin, uout, fin, fout) + def shellenviron(environ=None): """return environ with optional override, useful for shelling out""" def py2shell(val):