| |
@@ -13,6 +13,7 @@
|
| |
|
| |
import errno
|
| |
import fnmatch
|
| |
+ import functools
|
| |
import getpass
|
| |
import glob
|
| |
import io
|
| |
@@ -1632,7 +1633,7 @@
|
| |
self.log.debug('Cloning into: %s', target)
|
| |
cmd.append(target)
|
| |
|
| |
- self._run_command(cmd, cwd=path)
|
| |
+ self.retry_clone()(self._run_command)(cmd, cwd=path, return_text=True, return_stderr=True)
|
| |
|
| |
# Set configuration
|
| |
base_repo = self.get_base_repo(repo)
|
| |
@@ -1647,6 +1648,51 @@
|
| |
|
| |
return
|
| |
|
| |
+ def retry_clone(self, attempts=None, delay_between_attempts=None, raises=None):
|
| |
+ """A decorator that allows to retry a section of code until success or counter elapses
|
| |
+ """
|
| |
+
|
| |
+ def wrapper(function):
|
| |
+ @functools.wraps(function)
|
| |
+ def inner(*args, **kwargs):
|
| |
+
|
| |
+ attempts_all = attempts or self.lookaside_attempts
|
| |
+ attempts_left = attempts_all
|
| |
+ delay = delay_between_attempts or self.lookaside_delay
|
| |
+ stop_patterns = [
|
| |
+ r"destination path.+already exists",
|
| |
+ r"No such repository",
|
| |
+ ]
|
| |
+
|
| |
+ while attempts_left > 0:
|
| |
+ code, _, stderr = function(*args, **kwargs)
|
| |
+ # delayed print - this error was originally suppressed within
|
| |
+ # the function. Display it now.
|
| |
+ self.log.error(stderr)
|
| |
+ if code and stop_patterns:
|
| |
+ for pattern in stop_patterns:
|
| |
+ if re.search(pattern, stderr, flags=re.IGNORECASE):
|
| |
+ raise rpkgError('Failed to execute command.')
|
| |
+ else:
|
| |
+ return
|
| |
+ attempts_left -= 1
|
| |
+ self.log.debug("Attempt %d/%d has failed."
|
| |
+ % (attempts_all - attempts_left, attempts_all))
|
| |
+ if attempts_left:
|
| |
+ self.log.info("The operation will be retried in %ds." % (delay))
|
| |
+ time.sleep(delay)
|
| |
+ delay *= 2
|
| |
+ self.log.info("Retrying ...")
|
| |
+ else:
|
| |
+ if raises is None:
|
| |
+ raise rpkgError('Failed to execute command.')
|
| |
+ else:
|
| |
+ raise raises(e)
|
| |
+
|
| |
+ return inner
|
| |
+
|
| |
+ return wrapper
|
| |
+
|
| |
def get_base_repo(self, repo):
|
| |
# Handle namespaced repositories
|
| |
# Example:
|
| |
JIRA: RHELCMP-12562
Signed-off-by: Ondřej Nosek onosek@redhat.com