diff mercurial/ui.py @ 41285:cf8677cd7286

ui: proxy protect/restorestdio() calls to update internal flag It should be better to manage the redirection flag solely by the ui class.
author Yuya Nishihara <yuya@tcha.org>
date Wed, 26 Sep 2018 21:41:52 +0900
parents b0e3f2d7c143
children ff927ecb12f9
line wrap: on
line diff
--- a/mercurial/ui.py	Wed Sep 26 21:29:13 2018 +0900
+++ b/mercurial/ui.py	Wed Sep 26 21:41:52 2018 +0900
@@ -1080,14 +1080,38 @@
             return False
         return procutil.isatty(fh)
 
+    def protectfinout(self):
+        """Duplicate ui streams and redirect original if they are stdio
+
+        Returns (fin, fout) which point to the original ui fds, but may be
+        copy of them. The returned streams can be considered "owned" in that
+        print(), exec(), etc. never reach to them.
+        """
+        if self._finoutredirected:
+            # if already redirected, protectstdio() would just create another
+            # nullfd pair, which is equivalent to returning self._fin/_fout.
+            return self._fin, self._fout
+        fin, fout = procutil.protectstdio(self._fin, self._fout)
+        self._finoutredirected = (fin, fout) != (self._fin, self._fout)
+        return fin, fout
+
+    def restorefinout(self, fin, fout):
+        """Restore ui streams from possibly duplicated (fin, fout)"""
+        if (fin, fout) == (self._fin, self._fout):
+            return
+        procutil.restorestdio(self._fin, self._fout, fin, fout)
+        # protectfinout() won't create more than one duplicated streams,
+        # so we can just turn the redirection flag off.
+        self._finoutredirected = False
+
     @contextlib.contextmanager
     def protectedfinout(self):
         """Run code block with protected standard streams"""
-        fin, fout = procutil.protectstdio(self._fin, self._fout)
+        fin, fout = self.protectfinout()
         try:
             yield fin, fout
         finally:
-            procutil.restorestdio(self._fin, self._fout, fin, fout)
+            self.restorefinout(fin, fout)
 
     def disablepager(self):
         self._disablepager = True