Patchwork [2,of,5] procutil: move protectio/restoreio from commandserver

login
register
mail settings
Submitter Yuya Nishihara
Date March 25, 2018, 12:54 p.m.
Message ID <d3c212ea1f34ecff5ae1.1521982453@mimosa>
Download mbox | patch
Permalink /patch/29850/
State Accepted
Headers show

Comments

Yuya Nishihara - March 25, 2018, 12:54 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1521945630 -32400
#      Sun Mar 25 11:40:30 2018 +0900
# Node ID d3c212ea1f34ecff5ae12beceea0f61c6302416f
# Parent  a32a2b99f0627a6acdee3e6e9ff5b677a1cac18d
procutil: move protectio/restoreio from commandserver

Some variants of this will be useful for stdio-based servers such as
sshserver.

Patch

diff --git a/mercurial/commandserver.py b/mercurial/commandserver.py
--- a/mercurial/commandserver.py
+++ b/mercurial/commandserver.py
@@ -306,35 +306,6 @@  class server(object):
 
         return 0
 
-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 [(uin, procutil.stdin, r'rb'),
-                          (uout, procutil.stdout, r'wb')]:
-        if f is sysf:
-            newfd = os.dup(f.fileno())
-            os.dup2(nullfd, f.fileno())
-            f = os.fdopen(newfd, mode)
-        newfiles.append(f)
-    os.close(nullfd)
-    return tuple(newfiles)
-
-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()
-
 class pipeservice(object):
     def __init__(self, ui, repo, opts):
         self.ui = ui
@@ -347,13 +318,13 @@  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 = _protectio(ui.fin, ui.fout)
+        fin, fout = procutil.protectstdio(ui.fin, ui.fout)
         try:
             sv = server(ui, self.repo, fin, fout)
             return sv.serve()
         finally:
             sv.cleanup()
-            _restoreio(ui.fin, ui.fout, fin, fout)
+            procutil.restorestdio(ui.fin, ui.fout, fin, fout)
 
 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
@@ -211,6 +211,35 @@  def isstdin(f):
 def isstdout(f):
     return _testfileno(f, sys.__stdout__)
 
+def protectstdio(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 [(uin, stdin, r'rb'),
+                          (uout, stdout, r'wb')]:
+        if f is sysf:
+            newfd = os.dup(f.fileno())
+            os.dup2(nullfd, f.fileno())
+            f = os.fdopen(newfd, mode)
+        newfiles.append(f)
+    os.close(nullfd)
+    return tuple(newfiles)
+
+def restorestdio(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()
+
 def shellenviron(environ=None):
     """return environ with optional override, useful for shelling out"""
     def py2shell(val):