changeset 37122:4f742c2cb837

commandserver: rewrite protectio/restoreio to not depend on ui Prepares for porting to utils.procutil, in which ui shouldn't be known. ui.flush() is replaced with ui.fout.flush() since ui.ferr wasn't involved.
author Yuya Nishihara <yuya@tcha.org>
date Sun, 25 Mar 2018 11:30:59 +0900
parents 24ab3381bf15
children 0216232f21ab
files mercurial/commandserver.py
diffstat 1 files changed, 17 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/commandserver.py	Sat Mar 24 14:54:15 2018 +0900
+++ b/mercurial/commandserver.py	Sun Mar 25 11:30:59 2018 +0900
@@ -306,13 +306,19 @@
 
         return 0
 
-def _protectio(ui):
-    """ duplicates streams and redirect original to null if ui uses stdio """
-    ui.flush()
+def _protectio(uin, uout):
+    """Duplicate streams and redirect original to null if (uin, uout) are
+    stdio
+
+    Returns (fin, fout) which point to the original (uin, uout) fds, but
+    may be copy of (uin, uout). The returned streams can be considered
+    "owned" in that print(), exec(), etc. never reach to them.
+    """
+    uout.flush()
     newfiles = []
     nullfd = os.open(os.devnull, os.O_RDWR)
-    for f, sysf, mode in [(ui.fin, procutil.stdin, r'rb'),
-                          (ui.fout, procutil.stdout, r'wb')]:
+    for f, sysf, mode in [(uin, procutil.stdin, r'rb'),
+                          (uout, procutil.stdout, r'wb')]:
         if f is sysf:
             newfd = os.dup(f.fileno())
             os.dup2(nullfd, f.fileno())
@@ -321,10 +327,10 @@
     os.close(nullfd)
     return tuple(newfiles)
 
-def _restoreio(ui, fin, fout):
-    """ restores streams from duplicated ones """
-    ui.flush()
-    for f, uif in [(fin, ui.fin), (fout, ui.fout)]:
+def _restoreio(uin, uout, fin, fout):
+    """Restore (uin, uout) streams from possibly duplicated (fin, fout)"""
+    uout.flush()
+    for f, uif in [(fin, uin), (fout, uout)]:
         if f is not uif:
             os.dup2(f.fileno(), uif.fileno())
             f.close()
@@ -341,13 +347,13 @@
         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 = _protectio(ui)
+        fin, fout = _protectio(ui.fin, ui.fout)
         try:
             sv = server(ui, self.repo, fin, fout)
             return sv.serve()
         finally:
             sv.cleanup()
-            _restoreio(ui, fin, fout)
+            _restoreio(ui.fin, ui.fout, fin, fout)
 
 def _initworkerprocess():
     # use a different process group from the master process, in order to: