mercurial/utils/procutil.py
changeset 37123 0216232f21ab
parent 37118 5be286db5fb5
child 37124 6715e8035b4f
--- a/mercurial/utils/procutil.py	Sun Mar 25 11:30:59 2018 +0900
+++ b/mercurial/utils/procutil.py	Sun Mar 25 11:40:30 2018 +0900
@@ -211,6 +211,35 @@
 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):