diff --git a/mercurial/progress.py b/mercurial/progress.py --- a/mercurial/progress.py +++ b/mercurial/progress.py @@ -7,6 +7,7 @@ from __future__ import absolute_import +import errno import threading import time @@ -60,6 +61,24 @@ def fmtremaining(seconds): # i18n: format X years and YY weeks as "XyYYw" return _("%dy%02dw") % (years, weeks) +# file_write() and file_flush() of Python 2 do not restart on EINTR if +# the file is attached to a "slow" device (e.g. a terminal) and raise +# IOError. We cannot know how many bytes would be written by file_write(), +# but a progress text is known to be short enough to be written by a +# single write() syscall, so we can just retry file_write() with the whole +# text. (issue5532) +# +# This should be a short-term workaround. We'll need to fix every occurrence +# of write() to a terminal or pipe. +def _eintrretry(func, *args): + while True: + try: + return func(*args) + except IOError as err: + if err.errno == errno.EINTR: + continue + raise + class progbar(object): def __init__(self, ui): self.ui = ui @@ -179,10 +198,10 @@ class progbar(object): self._flusherr() def _flusherr(self): - self.ui.ferr.flush() + _eintrretry(self.ui.ferr.flush) def _writeerr(self, msg): - self.ui.ferr.write(msg) + _eintrretry(self.ui.ferr.write, msg) def width(self): tw = self.ui.termwidth()