procutil: assign pseudo file object if sys.stdout/stderr is missing
This basically simulates the Python 2 behavior. If libc stdio were used,
these file objects would be available and raise EBADF. There is subtle
difference between py2 and py3, but I think py3 behavior (i.e. exit 255)
is more correct.
"if" conditions are adjust so that they look similar to
dispatch.initstdio().
--- a/mercurial/utils/procutil.py Sat Dec 19 11:10:18 2020 +0900
+++ b/mercurial/utils/procutil.py Fri Dec 18 20:09:11 2020 +0900
@@ -131,17 +131,25 @@
if pycompat.ispy3:
- # Python 3 implements its own I/O streams.
+ # Python 3 implements its own I/O streams. Unlike stdio of C library,
+ # sys.stdin/stdout/stderr may be None if underlying fd is closed.
+
# TODO: .buffer might not exist if std streams were replaced; we'll need
# a silly wrapper to make a bytes stream backed by a unicode one.
- # sys.stdin can be None
- if sys.stdin:
+ if sys.stdin is None:
+ stdin = BadFile()
+ else:
stdin = sys.stdin.buffer
+ if sys.stdout is None:
+ stdout = BadFile()
else:
- stdin = BadFile()
- stdout = _make_write_all(sys.stdout.buffer)
- stderr = _make_write_all(sys.stderr.buffer)
+ stdout = _make_write_all(sys.stdout.buffer)
+ if sys.stderr is None:
+ stderr = BadFile()
+ else:
+ stderr = _make_write_all(sys.stderr.buffer)
+
if pycompat.iswindows:
# Work around Windows bugs.
stdout = platform.winstdout(stdout)
--- a/tests/test-basic.t Sat Dec 19 11:10:18 2020 +0900
+++ b/tests/test-basic.t Fri Dec 18 20:09:11 2020 +0900
@@ -49,6 +49,31 @@
[255]
#endif
+On Python 3, stdio may be None:
+
+ $ hg debuguiprompt --config ui.interactive=true 0<&-
+ abort: Bad file descriptor
+ [255]
+ $ hg version -q 0<&-
+ Mercurial Distributed SCM * (glob)
+
+#if py3
+ $ hg version -q 1>&-
+ abort: Bad file descriptor
+ [255]
+#else
+ $ hg version -q 1>&-
+#endif
+ $ hg unknown -q 1>&-
+ hg: unknown command 'unknown'
+ (did you mean debugknown?)
+ [255]
+
+ $ hg version -q 2>&-
+ Mercurial Distributed SCM * (glob)
+ $ hg unknown -q 2>&-
+ [255]
+
$ hg commit -m test
This command is ancient: