Patchwork [2,of,2,RESEND] procutil: redirect ui.fout to stderr while stdio is protected

login
register
mail settings
Submitter Yuya Nishihara
Date March 31, 2018, 1:48 a.m.
Message ID <81951fe000108850cd19.1522460927@mimosa>
Download mbox | patch
Permalink /patch/30037/
State Accepted
Headers show

Comments

Yuya Nishihara - March 31, 2018, 1:48 a.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1521947733 -32400
#      Sun Mar 25 12:15:33 2018 +0900
# Node ID 81951fe000108850cd19f4f1185f803e20778d1b
# Parent  6fdab0e7824cd95ea5edd4511d5063823ba423d5
procutil: redirect ui.fout to stderr while stdio is protected

The new behavior seems slightly nicer as we can at least read the output.
And this is similar to what the sshserver is doing, so we can probably
reuse protectstdio() instead of the weird hook.redirect(True) hack.
Augie Fackler - March 31, 2018, 3:25 p.m.
On Sat, Mar 31, 2018 at 10:48:47AM +0900, Yuya Nishihara wrote:
> # HG changeset patch
> # User Yuya Nishihara <yuya@tcha.org>
> # Date 1521947733 -32400
> #      Sun Mar 25 12:15:33 2018 +0900
> # Node ID 81951fe000108850cd19f4f1185f803e20778d1b
> # Parent  6fdab0e7824cd95ea5edd4511d5063823ba423d5
> procutil: redirect ui.fout to stderr while stdio is protected

queued, thanks

Patch

diff --git a/mercurial/utils/procutil.py b/mercurial/utils/procutil.py
--- a/mercurial/utils/procutil.py
+++ b/mercurial/utils/procutil.py
@@ -213,25 +213,27 @@  def isstdout(f):
     return _testfileno(f, sys.__stdout__)
 
 def protectstdio(uin, uout):
-    """Duplicate streams and redirect original to null if (uin, uout) are
-    stdio
+    """Duplicate streams and redirect original if (uin, uout) are stdio
+
+    If uin is stdin, it's redirected to /dev/null. If uout is stdout, it's
+    redirected to stderr so the output is still readable.
 
     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()
-    nullfd = os.open(os.devnull, os.O_RDWR)
     fin, fout = uin, uout
     if uin is stdin:
         newfd = os.dup(uin.fileno())
+        nullfd = os.open(os.devnull, os.O_RDONLY)
         os.dup2(nullfd, uin.fileno())
+        os.close(nullfd)
         fin = os.fdopen(newfd, r'rb')
     if uout is stdout:
         newfd = os.dup(uout.fileno())
-        os.dup2(nullfd, uout.fileno())
+        os.dup2(stderr.fileno(), uout.fileno())
         fout = os.fdopen(newfd, r'wb')
-    os.close(nullfd)
     return fin, fout
 
 def restorestdio(uin, uout, fin, fout):
diff --git a/tests/test-commandserver.t b/tests/test-commandserver.t
--- a/tests/test-commandserver.t
+++ b/tests/test-commandserver.t
@@ -249,6 +249,8 @@  check that local configs for the cached 
   ...                input=stringio('some input'))
   *** runcommand --config hooks.pre-identify=python:hook.hook id
   eff892de26ec tip
+  hook talking
+  now try to read something: ''
 
 Clean hook cached version
   $ rm hook.py*
@@ -619,7 +621,7 @@  changelog and manifest would have invali
   > @command(b"debugwritestdout", norepo=True)
   > def debugwritestdout(ui):
   >     os.write(1, "low-level stdout fd and\n")
-  >     sys.stdout.write("stdout should be redirected to /dev/null\n")
+  >     sys.stdout.write("stdout should be redirected to stderr\n")
   >     sys.stdout.flush()
   > EOF
   $ cat <<EOF >> .hg/hgrc
@@ -657,6 +659,8 @@  changelog and manifest would have invali
   *** runcommand debugreadstdin
   read: ''
   *** runcommand debugwritestdout
+  low-level stdout fd and
+  stdout should be redirected to stderr
 
 
 run commandserver in commandserver, which is silly but should work: