mercurial/progress.py
changeset 32049 ed42e00a5c4e
parent 32048 c3ef33fd0058
child 33249 391da1416038
--- a/mercurial/progress.py	Thu Apr 13 22:27:25 2017 +0900
+++ b/mercurial/progress.py	Thu Apr 13 22:31:17 2017 +0900
@@ -7,6 +7,7 @@
 
 from __future__ import absolute_import
 
+import errno
 import threading
 import time
 
@@ -60,6 +61,24 @@
     # 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 @@
         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()