407 # to see output immediately on pager, the mode stays unchanged |
407 # to see output immediately on pager, the mode stays unchanged |
408 # when client re-attached. ferr is unchanged because it should |
408 # when client re-attached. ferr is unchanged because it should |
409 # be unbuffered no matter if it is a tty or not. |
409 # be unbuffered no matter if it is a tty or not. |
410 if fn == b'ferr': |
410 if fn == b'ferr': |
411 newfp = fp |
411 newfp = fp |
|
412 elif pycompat.ispy3: |
|
413 # On Python 3, the standard library doesn't offer line-buffered |
|
414 # binary streams, so wrap/unwrap it. |
|
415 if fp.isatty(): |
|
416 newfp = procutil.make_line_buffered(fp) |
|
417 else: |
|
418 newfp = procutil.unwrap_line_buffered(fp) |
412 else: |
419 else: |
413 # make it line buffered explicitly because the default is |
420 # Python 2 uses the I/O streams provided by the C library, so |
414 # decided on first write(), where fout could be a pager. |
421 # make it line-buffered explicitly. Otherwise the default would |
|
422 # be decided on first write(), where fout could be a pager. |
415 if fp.isatty(): |
423 if fp.isatty(): |
416 bufsize = 1 # line buffered |
424 bufsize = 1 # line buffered |
417 else: |
425 else: |
418 bufsize = -1 # system default |
426 bufsize = -1 # system default |
419 newfp = os.fdopen(fp.fileno(), mode, bufsize) |
427 newfp = os.fdopen(fp.fileno(), mode, bufsize) |
|
428 if newfp is not fp: |
420 setattr(ui, fn, newfp) |
429 setattr(ui, fn, newfp) |
421 setattr(self, cn, newfp) |
430 setattr(self, cn, newfp) |
422 |
431 |
423 self._ioattached = True |
432 self._ioattached = True |
424 self.cresult.write(struct.pack(b'>i', len(clientfds))) |
433 self.cresult.write(struct.pack(b'>i', len(clientfds))) |
438 return |
447 return |
439 nullfd = os.open(os.devnull, os.O_WRONLY) |
448 nullfd = os.open(os.devnull, os.O_WRONLY) |
440 ui = self.ui |
449 ui = self.ui |
441 for (ch, fp, fd), (cn, fn, mode) in zip(self._oldios, _iochannels): |
450 for (ch, fp, fd), (cn, fn, mode) in zip(self._oldios, _iochannels): |
442 newfp = getattr(ui, fn) |
451 newfp = getattr(ui, fn) |
443 # close newfp while it's associated with client; otherwise it |
452 # On Python 2, newfp and fp may be separate file objects associated |
444 # would be closed when newfp is deleted |
453 # with the same fd, so we must close newfp while it's associated |
445 if newfp is not fp: |
454 # with the client. Otherwise the new associated fd would be closed |
|
455 # when newfp gets deleted. On Python 3, newfp is just a wrapper |
|
456 # around fp even if newfp is not fp, so deleting newfp is safe. |
|
457 if not (pycompat.ispy3 or newfp is fp): |
446 newfp.close() |
458 newfp.close() |
447 # restore original fd: fp is open again |
459 # restore original fd: fp is open again |
448 try: |
460 try: |
449 if newfp is fp and 'w' in mode: |
461 if (pycompat.ispy3 or newfp is fp) and 'w' in mode: |
450 # Discard buffered data which couldn't be flushed because |
462 # Discard buffered data which couldn't be flushed because |
451 # of EPIPE. The data should belong to the current session |
463 # of EPIPE. The data should belong to the current session |
452 # and should never persist. |
464 # and should never persist. |
453 os.dup2(nullfd, fp.fileno()) |
465 os.dup2(nullfd, fp.fileno()) |
454 fp.flush() |
466 fp.flush() |