Permalink
Browse files

drpm: fallback to .rpm download on drpm rebuild error. (RhBug:1071501)

  • Loading branch information...
1 parent dd0e16e commit a2e7f7b9722f259f73655939030b337b435465cd Ales Kozumplik committed Mar 10, 2014
Showing with 74 additions and 25 deletions.
  1. +19 −1 dnf/base.py
  2. +5 −2 dnf/exceptions.py
  3. +31 −14 dnf/repo.py
  4. +3 −0 tests/support.py
  5. +16 −8 tests/test_repo.py
View
@@ -908,9 +908,27 @@ def download_packages(self, pkglist, progress=None, callback_total=None):
remote_size = sum(pload.download_size for pload in payloads)
progress.start(len(payloads), remote_size)
errors = dnf.repo.download_payloads(payloads, drpm)
- if errors:
+ if errors.irrecoverable:
raise dnf.exceptions.DownloadError(errors)
+ if errors.recoverable:
+ msg = dnf.exceptions.DownloadError.errmap2str(errors.recoverable)
+ self.logger.info(msg)
+
+ remaining_pkgs = [pkg for pkg in errors.recoverable]
+ payloads = [dnf.repo.pkg2payload(pkg, progress, dnf.repo.RPMPayload)
+ for pkg in remaining_pkgs]
+ remaining_size = sum(pload.download_size for pload in payloads)
+ progress.start(len(payloads), remaining_size)
+
+ errors = dnf.repo.download_payloads(payloads, drpm)
+ assert(not errors.recoverable)
+ if errors.irrecoverable:
+ raise dnf.exceptions.DownloadErrors(errors)
+
+ remote_pkgs.extend(remaining_pkgs)
+ remote_size += remaining_size
+
if callback_total is not None:
callback_total(remote_pkgs, remote_size, beg_download)
View
@@ -78,15 +78,18 @@ class DownloadError(Error):
def __init__(self, errmap):
self.errmap = errmap
- def __str__(self):
- errmap = self.errmap
+ @staticmethod
+ def errmap2str(errmap):
errstrings = []
for key in errmap:
for error in errmap[key]:
msg = '%s: %s' % (key, error) if key else '%s' % error
errstrings.append(msg)
return '\n'.join(errstrings)
+ def __str__(self):
+ return self.errmap2str(self.errmap)
+
def __unicode__(self):
return to_unicode(str(self))
View
@@ -69,35 +69,52 @@ def pkg2payload(pkg, progress, *factories):
return pload
raise ValueError('no matching payload factory for %s' % pkg)
+class _DownloadErrors(object):
+ def __init__(self):
+ self.fatal = None
+ self._irrecoverable = {}
+ self._recoverable = {}
+
+ @property
+ def irrecoverable(self):
+ if self._irrecoverable:
+ return self._irrecoverable
+ if self.fatal:
+ return {'': [self.fatal]}
+ return {}
+
+ @property
+ def recoverable(self):
+ return self._recoverable
+
+ @recoverable.setter
+ def recoverable(self, new_dct):
+ self._recoverable = new_dct
+
def download_payloads(payloads, drpm):
# download packages
+ drpm.err.clear()
targets = [pload.librepo_target() for pload in payloads]
- fatal = None
+ errs = _DownloadErrors()
try:
librepo.download_packages(targets, failfast=True)
except librepo.LibrepoException as e:
- fatal = e.args[1] or '<unspecified librepo error>'
+ errs.fatal = e.args[1] or '<unspecified librepo error>'
drpm.wait()
# process downloading errors
- errors = drpm.err.copy()
+ errs.recoverable = drpm.err.copy()
for tgt in targets:
err = tgt.err
- payload = tgt.cbdata
- pkg = payload.pkg
if err is None:
continue
if err == 'Already downloaded' or err.startswith('Not finished'):
- err = None
- if err:
- errors[pkg] = [err]
-
- if errors:
- return errors
- if fatal:
- return {'' : [fatal]}
+ continue
+ payload = tgt.cbdata
+ pkg = payload.pkg
+ errs.irrecoverable[pkg] = [err]
- return {}
+ return errs
class _Handle(librepo.Handle):
def __init__(self, gpgcheck, max_mirror_tries):
View
@@ -433,6 +433,9 @@ def assertItemsEqual(self, item1, item2):
super().assertCountEqual(item1, item2)
class TestCase(PycompTestCase):
+ def assertEmpty(self, collection):
+ return self.assertEqual(len(collection), 0)
+
def assertFile(self, path):
"""Assert the given path is a file."""
return self.assertTrue(os.path.isfile(path))
View
@@ -343,23 +343,30 @@ def test_reviving_404(self, new_remote_m):
class DownloadPayloadsTest(RepoTestMixin, support.TestCase):
def test_drpm_error(self):
+ def wait(self):
+ self.err['step'] = ['right']
+
drpm = dnf.drpm.DeltaInfo(None, None)
- drpm.err = {'step' : ['right']}
- self.assertEqual(dnf.repo.download_payloads([], drpm),
- {'step' : ['right']})
+ with mock.patch('dnf.drpm.DeltaInfo.wait', wait):
+ errs = dnf.repo.download_payloads([], drpm)
+ self.assertEqual(errs.recoverable, {'step' : ['right']})
+ self.assertEmpty(errs.irrecoverable)
def test_empty_transaction(self):
drpm = dnf.drpm.DeltaInfo(None, None)
- self.assertEqual(dnf.repo.download_payloads([], drpm), {})
+ errs = dnf.repo.download_payloads([], drpm)
+ self.assertEmpty(errs.recoverable)
+ self.assertEmpty(errs.irrecoverable)
def test_fatal_error(self):
def raiser(targets, failfast):
raise librepo.LibrepoException(10, 'hit', 'before')
drpm = dnf.drpm.DeltaInfo(None, None)
with mock.patch('librepo.download_packages', side_effect=raiser):
- errors = dnf.repo.download_payloads([], drpm)
- self.assertEqual(errors, {'' : ['hit']})
+ errs = dnf.repo.download_payloads([], drpm)
+ self.assertEqual(errs.irrecoverable, {'' : ['hit']})
+ self.assertEmpty(errs.recoverable)
# twist Repo to think it's remote:
@mock.patch('dnf.repo.Repo.local', False)
@@ -372,8 +379,9 @@ def test_remote_download(self):
pload = dnf.repo.RPMPayload(pkg, progress)
drpm = dnf.drpm.DeltaInfo(None, None)
- errors = dnf.repo.download_payloads([pload], drpm)
- self.assertLength(errors, 0)
+ errs = dnf.repo.download_payloads([pload], drpm)
+ self.assertEmpty(errs.recoverable)
+ self.assertEmpty(errs.irrecoverable)
path = os.path.join(self.TMP_CACHEDIR, 'r/packages/tour-4-4.noarch.rpm')
self.assertFile(path)

0 comments on commit a2e7f7b

Please sign in to comment.