posix: implement readpipe using non-blocking I/O (issue4336)

On Linux, fstat().st_size of a pipe always returns 0, even if the
pipe has data available for reading. This meant that reading from
and subsequently printing the stderr pipe content after wireproto
commands over SSH meant that available data wasn't being printed.

We now implement pipe reading on POSIX by doing a non-blocking
read for all available data.
This commit is contained in:
Gregory Szorc 2014-08-16 10:28:59 -07:00
parent db57d5e9d6
commit 6799e4f38a

View File

@ -8,6 +8,7 @@
from i18n import _
import encoding
import os, sys, errno, stat, getpass, pwd, grp, socket, tempfile, unicodedata
import fcntl
posixfile = open
normpath = os.path.normpath
@ -432,7 +433,7 @@ def gethgcmd():
def termwidth():
try:
import termios, array, fcntl
import termios, array
for dev in (sys.stderr, sys.stdout, sys.stdin):
try:
try:
@ -570,13 +571,24 @@ def statisexec(st):
def readpipe(pipe):
"""Read all available data from a pipe."""
chunks = []
while True:
size = os.fstat(pipe.fileno()).st_size
if not size:
break
# We can't fstat() a pipe because Linux will always report 0.
# So, we set the pipe to non-blocking mode and read everything
# that's available.
flags = fcntl.fcntl(pipe, fcntl.F_GETFL)
flags |= os.O_NONBLOCK
oldflags = fcntl.fcntl(pipe, fcntl.F_SETFL, flags)
s = pipe.read(size)
if not s:
break
chunks.append(s)
try:
chunks = []
while True:
try:
s = pipe.read()
if not s:
break
chunks.append(s)
except IOError:
break
return ''.join(chunks)
finally:
fcntl.fcntl(pipe, fcntl.F_SETFL, oldflags)