# HG changeset patch # User Gregory Szorc # Date 1408210139 25200 # Node ID 331cbf088c4cc553f23df25d4a520b79bc7ec291 # Parent 234e4c24b9802cce7a9f28c0a7c8a89d25cf5c5d 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. diff -r 234e4c24b980 -r 331cbf088c4c mercurial/posix.py --- a/mercurial/posix.py Fri Aug 15 20:02:18 2014 -0700 +++ b/mercurial/posix.py Sat Aug 16 10:28:59 2014 -0700 @@ -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 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 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)