Index: gclient_utils.py |
diff --git a/gclient_utils.py b/gclient_utils.py |
index 80eb816b12dc1c540eb72c043c118e3d36dc5dc4..5044987afabcee71eb014ce83ea055fdd76ca013 100644 |
--- a/gclient_utils.py |
+++ b/gclient_utils.py |
@@ -21,6 +21,10 @@ import urlparse |
import subprocess2 |
+RETRY_MAX = 3 |
+RETRY_INITIAL_SLEEP = 0.5 |
+ |
+ |
class Error(Exception): |
"""gclient exception class.""" |
def __init__(self, msg, *args, **kwargs): |
@@ -407,7 +411,7 @@ class GClientChildren(object): |
def CheckCallAndFilter(args, stdout=None, filter_fn=None, |
print_stdout=None, call_filter_on_first_line=False, |
- **kwargs): |
+ retry=False, **kwargs): |
"""Runs a command and calls back a filter function if needed. |
Accepts all subprocess2.Popen() parameters plus: |
@@ -416,62 +420,74 @@ def CheckCallAndFilter(args, stdout=None, filter_fn=None, |
of the subprocess2's output. Each line has the trailing newline |
character trimmed. |
stdout: Can be any bufferable output. |
+ retry: If the process exits non-zero, sleep for a brief interval and try |
+ again, up to RETRY_MAX times. |
stderr is always redirected to stdout. |
""" |
assert print_stdout or filter_fn |
stdout = stdout or sys.stdout |
filter_fn = filter_fn or (lambda x: None) |
- kid = subprocess2.Popen( |
- args, bufsize=0, stdout=subprocess2.PIPE, stderr=subprocess2.STDOUT, |
- **kwargs) |
- GClientChildren.add(kid) |
+ sleep_interval = RETRY_INITIAL_SLEEP |
+ run_cwd = kwargs.get('cwd', os.getcwd()) |
+ for _ in xrange(RETRY_MAX + 1): |
+ kid = subprocess2.Popen( |
+ args, bufsize=0, stdout=subprocess2.PIPE, stderr=subprocess2.STDOUT, |
+ **kwargs) |
- # Do a flush of stdout before we begin reading from the subprocess2's stdout |
- stdout.flush() |
+ GClientChildren.add(kid) |
- # Also, we need to forward stdout to prevent weird re-ordering of output. |
- # This has to be done on a per byte basis to make sure it is not buffered: |
- # normally buffering is done for each line, but if svn requests input, no |
- # end-of-line character is output after the prompt and it would not show up. |
- try: |
- in_byte = kid.stdout.read(1) |
- if in_byte: |
- if call_filter_on_first_line: |
- filter_fn(None) |
- in_line = '' |
- while in_byte: |
- if in_byte != '\r': |
- if print_stdout: |
- stdout.write(in_byte) |
- if in_byte != '\n': |
- in_line += in_byte |
+ # Do a flush of stdout before we begin reading from the subprocess2's stdout |
+ stdout.flush() |
+ |
+ # Also, we need to forward stdout to prevent weird re-ordering of output. |
+ # This has to be done on a per byte basis to make sure it is not buffered: |
+ # normally buffering is done for each line, but if svn requests input, no |
+ # end-of-line character is output after the prompt and it would not show up. |
+ try: |
+ in_byte = kid.stdout.read(1) |
+ if in_byte: |
+ if call_filter_on_first_line: |
+ filter_fn(None) |
+ in_line = '' |
+ while in_byte: |
+ if in_byte != '\r': |
+ if print_stdout: |
+ stdout.write(in_byte) |
+ if in_byte != '\n': |
+ in_line += in_byte |
+ else: |
+ filter_fn(in_line) |
+ in_line = '' |
else: |
filter_fn(in_line) |
in_line = '' |
- else: |
+ in_byte = kid.stdout.read(1) |
+ # Flush the rest of buffered output. This is only an issue with |
+ # stdout/stderr not ending with a \n. |
+ if len(in_line): |
filter_fn(in_line) |
- in_line = '' |
- in_byte = kid.stdout.read(1) |
- # Flush the rest of buffered output. This is only an issue with |
- # stdout/stderr not ending with a \n. |
- if len(in_line): |
- filter_fn(in_line) |
- rv = kid.wait() |
- |
- # Don't put this in a 'finally,' since the child may still run if we get an |
- # exception. |
- GClientChildren.remove(kid) |
- |
- except KeyboardInterrupt: |
- print >> sys.stderr, 'Failed while running "%s"' % ' '.join(args) |
- raise |
- |
- if rv: |
- raise subprocess2.CalledProcessError( |
- rv, args, kwargs.get('cwd', None), None, None) |
- return 0 |
+ rv = kid.wait() |
+ |
+ # Don't put this in a 'finally,' since the child may still run if we get |
+ # an exception. |
+ GClientChildren.remove(kid) |
+ |
+ except KeyboardInterrupt: |
+ print >> sys.stderr, 'Failed while running "%s"' % ' '.join(args) |
+ raise |
+ |
+ if rv == 0: |
+ return 0 |
+ if not retry: |
+ break |
+ print ("WARNING: subprocess '%s' in %s failed; will retry after a short " |
+ 'nap...' % (' '.join('"%s"' % x for x in args), run_cwd)) |
+ sys.sleep(sleep_interval) |
+ sleep_interval *= 2 |
+ raise subprocess2.CalledProcessError( |
+ rv, args, kwargs.get('cwd', None), None, None) |
def FindGclientRoot(from_dir, filename='.gclient'): |