|
Packit Service |
21c75c |
# repo.py
|
|
Packit Service |
21c75c |
# DNF Repository objects.
|
|
Packit Service |
21c75c |
#
|
|
Packit Service |
21c75c |
# Copyright (C) 2013-2016 Red Hat, Inc.
|
|
Packit Service |
21c75c |
#
|
|
Packit Service |
21c75c |
# This copyrighted material is made available to anyone wishing to use,
|
|
Packit Service |
21c75c |
# modify, copy, or redistribute it subject to the terms and conditions of
|
|
Packit Service |
21c75c |
# the GNU General Public License v.2, or (at your option) any later version.
|
|
Packit Service |
21c75c |
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
Packit Service |
21c75c |
# ANY WARRANTY expressed or implied, including the implied warranties of
|
|
Packit Service |
21c75c |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|
Packit Service |
21c75c |
# Public License for more details. You should have received a copy of the
|
|
Packit Service |
21c75c |
# GNU General Public License along with this program; if not, write to the
|
|
Packit Service |
21c75c |
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
21c75c |
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
|
|
Packit Service |
21c75c |
# source code or documentation are not subject to the GNU General Public
|
|
Packit Service |
21c75c |
# License and may only be used or replicated with the express permission of
|
|
Packit Service |
21c75c |
# Red Hat, Inc.
|
|
Packit Service |
21c75c |
#
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
from __future__ import absolute_import
|
|
Packit Service |
21c75c |
from __future__ import unicode_literals
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
from dnf.i18n import ucd, _
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
import dnf.callback
|
|
Packit Service |
21c75c |
import dnf.conf
|
|
Packit Service |
21c75c |
import dnf.conf.substitutions
|
|
Packit Service |
21c75c |
import dnf.const
|
|
Packit Service |
21c75c |
import dnf.crypto
|
|
Packit Service |
21c75c |
import dnf.exceptions
|
|
Packit Service |
21c75c |
import dnf.logging
|
|
Packit Service |
21c75c |
import dnf.pycomp
|
|
Packit Service |
21c75c |
import dnf.util
|
|
Packit Service |
21c75c |
import dnf.yum.misc
|
|
Packit Service |
21c75c |
import libdnf.error
|
|
Packit Service |
21c75c |
import libdnf.repo
|
|
Packit Service |
21c75c |
import functools
|
|
Packit Service |
21c75c |
import hashlib
|
|
Packit Service |
21c75c |
import hawkey
|
|
Packit Service |
21c75c |
import logging
|
|
Packit Service |
21c75c |
import operator
|
|
Packit Service |
21c75c |
import os
|
|
Packit Service |
21c75c |
import re
|
|
Packit Service |
21c75c |
import shutil
|
|
Packit Service |
21c75c |
import string
|
|
Packit Service |
21c75c |
import sys
|
|
Packit Service |
21c75c |
import time
|
|
Packit Service |
21c75c |
import traceback
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
_PACKAGES_RELATIVE_DIR = "packages"
|
|
Packit Service |
21c75c |
_MIRRORLIST_FILENAME = "mirrorlist"
|
|
Packit Service |
21c75c |
# Chars allowed in a repo ID
|
|
Packit Service |
21c75c |
_REPOID_CHARS = string.ascii_letters + string.digits + '-_.:'
|
|
Packit Service |
21c75c |
# Regex pattern that matches a repo cachedir and captures the repo ID
|
|
Packit Service |
21c75c |
_CACHEDIR_RE = r'(?P<repoid>[%s]+)\-[%s]{16}' % (re.escape(_REPOID_CHARS),
|
|
Packit Service |
21c75c |
string.hexdigits)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
# Regex patterns matching any filename that is repo-specific cache data of a
|
|
Packit Service |
21c75c |
# particular type. The filename is expected to not contain the base cachedir
|
|
Packit Service |
21c75c |
# path components.
|
|
Packit Service |
21c75c |
CACHE_FILES = {
|
|
Packit Service |
21c75c |
'metadata': r'^%s\/.*((xml|yaml)(\.gz|\.xz|\.bz2|.zck)?|asc|cachecookie|%s)$' %
|
|
Packit Service |
21c75c |
(_CACHEDIR_RE, _MIRRORLIST_FILENAME),
|
|
Packit Service |
21c75c |
'packages': r'^%s\/%s\/.+rpm$' % (_CACHEDIR_RE, _PACKAGES_RELATIVE_DIR),
|
|
Packit Service |
21c75c |
'dbcache': r'^.+(solv|solvx)$',
|
|
Packit Service |
21c75c |
}
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
logger = logging.getLogger("dnf")
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def repo_id_invalid(repo_id):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
"""Return index of an invalid character in the repo ID (if present)."""
|
|
Packit Service |
21c75c |
first_invalid = libdnf.repo.Repo.verifyId(repo_id)
|
|
Packit Service |
21c75c |
return None if first_invalid < 0 else first_invalid
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _pkg2payload(pkg, progress, *factories):
|
|
Packit Service |
21c75c |
for fn in factories:
|
|
Packit Service |
21c75c |
pload = fn(pkg, progress)
|
|
Packit Service |
21c75c |
if pload is not None:
|
|
Packit Service |
21c75c |
return pload
|
|
Packit Service |
21c75c |
raise ValueError(_('no matching payload factory for %s') % pkg)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _download_payloads(payloads, drpm):
|
|
Packit Service |
21c75c |
# download packages
|
|
Packit Service |
21c75c |
def _download_sort_key(payload):
|
|
Packit Service |
21c75c |
return not hasattr(payload, 'delta')
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
drpm.err.clear()
|
|
Packit Service |
21c75c |
targets = [pload._librepo_target()
|
|
Packit Service |
21c75c |
for pload in sorted(payloads, key=_download_sort_key)]
|
|
Packit Service |
21c75c |
errs = _DownloadErrors()
|
|
Packit Service |
21c75c |
try:
|
|
Packit Service |
21c75c |
libdnf.repo.PackageTarget.downloadPackages(libdnf.repo.VectorPPackageTarget(targets), True)
|
|
Packit Service |
21c75c |
except RuntimeError as e:
|
|
Packit Service |
21c75c |
errs._fatal = str(e)
|
|
Packit Service |
21c75c |
drpm.wait()
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
# process downloading errors
|
|
Packit Service |
21c75c |
errs._recoverable = drpm.err.copy()
|
|
Packit Service |
21c75c |
for tgt in targets:
|
|
Packit Service |
21c75c |
err = tgt.getErr()
|
|
Packit Service |
21c75c |
if err is None or err.startswith('Not finished'):
|
|
Packit Service |
21c75c |
continue
|
|
Packit Service |
21c75c |
callbacks = tgt.getCallbacks()
|
|
Packit Service |
21c75c |
payload = callbacks.package_pload
|
|
Packit Service |
21c75c |
pkg = payload.pkg
|
|
Packit Service |
21c75c |
if err == _('Already downloaded'):
|
|
Packit Service |
21c75c |
errs._skipped.add(pkg)
|
|
Packit Service |
21c75c |
continue
|
|
Packit Service |
21c75c |
pkg.repo._repo.expire()
|
|
Packit Service |
21c75c |
errs._irrecoverable[pkg] = [err]
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
return errs
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _update_saving(saving, payloads, errs):
|
|
Packit Service |
21c75c |
real, full = saving
|
|
Packit Service |
21c75c |
for pload in payloads:
|
|
Packit Service |
21c75c |
pkg = pload.pkg
|
|
Packit Service |
21c75c |
if pkg in errs:
|
|
Packit Service |
21c75c |
real += pload.download_size
|
|
Packit Service |
21c75c |
continue
|
|
Packit Service |
21c75c |
real += pload.download_size
|
|
Packit Service |
21c75c |
full += pload._full_size
|
|
Packit Service |
21c75c |
return real, full
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
class _DownloadErrors(object):
|
|
Packit Service |
21c75c |
def __init__(self):
|
|
Packit Service |
21c75c |
self._val_irrecoverable = {}
|
|
Packit Service |
21c75c |
self._val_recoverable = {}
|
|
Packit Service |
21c75c |
self._fatal = None
|
|
Packit Service |
21c75c |
self._skipped = set()
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@property
|
|
Packit Service |
21c75c |
def _irrecoverable(self):
|
|
Packit Service |
21c75c |
if self._val_irrecoverable:
|
|
Packit Service |
21c75c |
return self._val_irrecoverable
|
|
Packit Service |
21c75c |
if self._fatal:
|
|
Packit Service |
21c75c |
return {'': [self._fatal]}
|
|
Packit Service |
21c75c |
return {}
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@property
|
|
Packit Service |
21c75c |
def _recoverable(self):
|
|
Packit Service |
21c75c |
return self._val_recoverable
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@_recoverable.setter
|
|
Packit Service |
21c75c |
def _recoverable(self, new_dct):
|
|
Packit Service |
21c75c |
self._val_recoverable = new_dct
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _bandwidth_used(self, pload):
|
|
Packit Service |
21c75c |
if pload.pkg in self._skipped:
|
|
Packit Service |
21c75c |
return 0
|
|
Packit Service |
21c75c |
return pload.download_size
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
class _DetailedLibrepoError(Exception):
|
|
Packit Service |
21c75c |
def __init__(self, librepo_err, source_url):
|
|
Packit Service |
21c75c |
Exception.__init__(self)
|
|
Packit Service |
21c75c |
self.librepo_code = librepo_err.args[0]
|
|
Packit Service |
21c75c |
self.librepo_msg = librepo_err.args[1]
|
|
Packit Service |
21c75c |
self.source_url = source_url
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
class _NullKeyImport(dnf.callback.KeyImport):
|
|
Packit Service |
21c75c |
def _confirm(self, id, userid, fingerprint, url, timestamp):
|
|
Packit Service |
21c75c |
return True
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
class Metadata(object):
|
|
Packit Service |
21c75c |
def __init__(self, repo):
|
|
Packit Service |
21c75c |
self._repo = repo
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@property
|
|
Packit Service |
21c75c |
def fresh(self):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
return self._repo.fresh()
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
class PackageTargetCallbacks(libdnf.repo.PackageTargetCB):
|
|
Packit Service |
21c75c |
def __init__(self, package_pload):
|
|
Packit Service |
21c75c |
super(PackageTargetCallbacks, self).__init__()
|
|
Packit Service |
21c75c |
self.package_pload = package_pload
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def end(self, status, msg):
|
|
Packit Service |
21c75c |
self.package_pload._end_cb(None, status, msg)
|
|
Packit Service |
21c75c |
return 0
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def progress(self, totalToDownload, downloaded):
|
|
Packit Service |
21c75c |
self.package_pload._progress_cb(None, totalToDownload, downloaded)
|
|
Packit Service |
21c75c |
return 0
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def mirrorFailure(self, msg, url):
|
|
Packit Service |
21c75c |
self.package_pload._mirrorfail_cb(None, msg, url)
|
|
Packit Service |
21c75c |
return 0
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
class PackagePayload(dnf.callback.Payload):
|
|
Packit Service |
21c75c |
def __init__(self, pkg, progress):
|
|
Packit Service |
21c75c |
super(PackagePayload, self).__init__(progress)
|
|
Packit Service |
21c75c |
self.callbacks = PackageTargetCallbacks(self)
|
|
Packit Service |
21c75c |
self.pkg = pkg
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _end_cb(self, cbdata, lr_status, msg):
|
|
Packit Service |
21c75c |
"""End callback to librepo operation."""
|
|
Packit Service |
21c75c |
status = dnf.callback.STATUS_FAILED
|
|
Packit Service |
21c75c |
if msg is None:
|
|
Packit Service |
21c75c |
status = dnf.callback.STATUS_OK
|
|
Packit Service |
21c75c |
elif msg.startswith('Not finished'):
|
|
Packit Service |
21c75c |
return
|
|
Packit Service |
21c75c |
elif lr_status == libdnf.repo.PackageTargetCB.TransferStatus_ALREADYEXISTS:
|
|
Packit Service |
21c75c |
status = dnf.callback.STATUS_ALREADY_EXISTS
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
self.progress.end(self, status, msg)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _mirrorfail_cb(self, cbdata, err, url):
|
|
Packit Service |
21c75c |
self.progress.end(self, dnf.callback.STATUS_MIRROR, err)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _progress_cb(self, cbdata, total, done):
|
|
Packit Service |
21c75c |
try:
|
|
Packit Service |
21c75c |
self.progress.progress(self, done)
|
|
Packit Service |
21c75c |
except Exception:
|
|
Packit Service |
21c75c |
exc_type, exc_value, exc_traceback = sys.exc_info()
|
|
Packit Service |
21c75c |
except_list = traceback.format_exception(exc_type, exc_value, exc_traceback)
|
|
Packit Service |
21c75c |
logger.critical(''.join(except_list))
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@property
|
|
Packit Service |
21c75c |
def _full_size(self):
|
|
Packit Service |
21c75c |
return self.download_size
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _librepo_target(self):
|
|
Packit Service |
21c75c |
pkg = self.pkg
|
|
Packit Service |
21c75c |
pkgdir = pkg.pkgdir
|
|
Packit Service |
21c75c |
dnf.util.ensure_dir(pkgdir)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
target_dct = {
|
|
Packit Service |
21c75c |
'dest': pkgdir,
|
|
Packit Service |
21c75c |
'resume': True,
|
|
Packit Service |
21c75c |
'cbdata': self,
|
|
Packit Service |
21c75c |
'progresscb': self._progress_cb,
|
|
Packit Service |
21c75c |
'endcb': self._end_cb,
|
|
Packit Service |
21c75c |
'mirrorfailurecb': self._mirrorfail_cb,
|
|
Packit Service |
21c75c |
}
|
|
Packit Service |
21c75c |
target_dct.update(self._target_params())
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
return libdnf.repo.PackageTarget(
|
|
Packit Service |
21c75c |
pkg.repo._repo,
|
|
Packit Service |
21c75c |
target_dct['relative_url'],
|
|
Packit Service |
21c75c |
target_dct['dest'], target_dct['checksum_type'], target_dct['checksum'],
|
|
Packit Service |
21c75c |
target_dct['expectedsize'], target_dct['base_url'], target_dct['resume'],
|
|
Packit Service |
21c75c |
0, 0, self.callbacks)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
class RPMPayload(PackagePayload):
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def __str__(self):
|
|
Packit Service |
21c75c |
return os.path.basename(self.pkg.location)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _target_params(self):
|
|
Packit Service |
21c75c |
pkg = self.pkg
|
|
Packit Service |
21c75c |
ctype, csum = pkg.returnIdSum()
|
|
Packit Service |
21c75c |
ctype_code = libdnf.repo.PackageTarget.checksumType(ctype)
|
|
Packit Service |
21c75c |
if ctype_code == libdnf.repo.PackageTarget.ChecksumType_UNKNOWN:
|
|
Packit Service |
21c75c |
logger.warning(_("unsupported checksum type: %s"), ctype)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
return {
|
|
Packit Service |
21c75c |
'relative_url': pkg.location,
|
|
Packit Service |
21c75c |
'checksum_type': ctype_code,
|
|
Packit Service |
21c75c |
'checksum': csum,
|
|
Packit Service |
21c75c |
'expectedsize': pkg.downloadsize,
|
|
Packit Service |
21c75c |
'base_url': pkg.baseurl,
|
|
Packit Service |
21c75c |
}
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@property
|
|
Packit Service |
21c75c |
def download_size(self):
|
|
Packit Service |
21c75c |
"""Total size of the download."""
|
|
Packit Service |
21c75c |
return self.pkg.downloadsize
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
class RemoteRPMPayload(PackagePayload):
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def __init__(self, remote_location, conf, progress):
|
|
Packit Service |
21c75c |
super(RemoteRPMPayload, self).__init__("unused_object", progress)
|
|
Packit Service |
21c75c |
self.remote_location = remote_location
|
|
Packit Service |
21c75c |
self.remote_size = 0
|
|
Packit Service |
21c75c |
self.conf = conf
|
|
Packit Service |
21c75c |
s = (self.conf.releasever or "") + self.conf.substitutions.get('basearch')
|
|
Packit Service |
21c75c |
digest = hashlib.sha256(s.encode('utf8')).hexdigest()[:16]
|
|
Packit Service |
21c75c |
repodir = "commandline-" + digest
|
|
Packit Service |
21c75c |
self.pkgdir = os.path.join(self.conf.cachedir, repodir, "packages")
|
|
Packit Service |
21c75c |
dnf.util.ensure_dir(self.pkgdir)
|
|
Packit Service |
21c75c |
self.local_path = os.path.join(self.pkgdir, self.__str__().lstrip("/"))
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def __str__(self):
|
|
Packit Service |
21c75c |
return os.path.basename(self.remote_location)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _progress_cb(self, cbdata, total, done):
|
|
Packit Service |
21c75c |
self.remote_size = total
|
|
Packit Service |
21c75c |
try:
|
|
Packit Service |
21c75c |
self.progress.progress(self, done)
|
|
Packit Service |
21c75c |
except Exception:
|
|
Packit Service |
21c75c |
exc_type, exc_value, exc_traceback = sys.exc_info()
|
|
Packit Service |
21c75c |
except_list = traceback.format_exception(exc_type, exc_value, exc_traceback)
|
|
Packit Service |
21c75c |
logger.critical(''.join(except_list))
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _librepo_target(self):
|
|
Packit Service |
21c75c |
return libdnf.repo.PackageTarget(
|
|
Packit Service |
21c75c |
self.conf._config, os.path.basename(self.remote_location),
|
|
Packit Service |
21c75c |
self.pkgdir, 0, None, 0, os.path.dirname(self.remote_location),
|
|
Packit Service |
21c75c |
True, 0, 0, self.callbacks)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@property
|
|
Packit Service |
21c75c |
def download_size(self):
|
|
Packit Service |
21c75c |
"""Total size of the download."""
|
|
Packit Service |
21c75c |
return self.remote_size
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
class MDPayload(dnf.callback.Payload):
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def __init__(self, progress):
|
|
Packit Service |
21c75c |
super(MDPayload, self).__init__(progress)
|
|
Packit Service |
21c75c |
self._text = ""
|
|
Packit Service |
21c75c |
self._download_size = 0
|
|
Packit Service |
21c75c |
self.fastest_mirror_running = False
|
|
Packit Service |
21c75c |
self.mirror_failures = set()
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def __str__(self):
|
|
Packit Service |
21c75c |
if dnf.pycomp.PY3:
|
|
Packit Service |
21c75c |
return self._text
|
|
Packit Service |
21c75c |
else:
|
|
Packit Service |
21c75c |
return self._text.encode('utf-8')
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def __unicode__(self):
|
|
Packit Service |
21c75c |
return self._text
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _progress_cb(self, cbdata, total, done):
|
|
Packit Service |
21c75c |
self._download_size = total
|
|
Packit Service |
21c75c |
self.progress.progress(self, done)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _fastestmirror_cb(self, cbdata, stage, data):
|
|
Packit Service |
21c75c |
if stage == libdnf.repo.RepoCB.FastestMirrorStage_DETECTION:
|
|
Packit Service |
21c75c |
# pinging mirrors, this might take a while
|
|
Packit Service |
21c75c |
msg = _('determining the fastest mirror (%s hosts).. ') % data
|
|
Packit Service |
21c75c |
self.fastest_mirror_running = True
|
|
Packit Service |
21c75c |
elif stage == libdnf.repo.RepoCB.FastestMirrorStage_STATUS and self.fastest_mirror_running:
|
|
Packit Service |
21c75c |
# done.. report but ignore any errors
|
|
Packit Service |
21c75c |
msg = 'error: %s\n' % data if data else 'done.\n'
|
|
Packit Service |
21c75c |
else:
|
|
Packit Service |
21c75c |
return
|
|
Packit Service |
21c75c |
self.progress.message(msg)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _mirror_failure_cb(self, cbdata, msg, url, metadata):
|
|
Packit Service |
21c75c |
self.mirror_failures.add(msg)
|
|
Packit Service |
21c75c |
msg = 'error: %s (%s).' % (msg, url)
|
|
Packit Service |
21c75c |
logger.debug(msg)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@property
|
|
Packit Service |
21c75c |
def download_size(self):
|
|
Packit Service |
21c75c |
return self._download_size
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@property
|
|
Packit Service |
21c75c |
def progress(self):
|
|
Packit Service |
21c75c |
return self._progress
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@progress.setter
|
|
Packit Service |
21c75c |
def progress(self, progress):
|
|
Packit Service |
21c75c |
if progress is None:
|
|
Packit Service |
21c75c |
progress = dnf.callback.NullDownloadProgress()
|
|
Packit Service |
21c75c |
self._progress = progress
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def start(self, text):
|
|
Packit Service |
21c75c |
self._text = text
|
|
Packit Service |
21c75c |
self.progress.start(1, 0)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def end(self):
|
|
Packit Service |
21c75c |
self._download_size = 0
|
|
Packit Service |
21c75c |
self.progress.end(self, None, None)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
# use the local cache even if it's expired. download if there's no cache.
|
|
Packit Service |
21c75c |
SYNC_LAZY = libdnf.repo.Repo.SyncStrategy_LAZY
|
|
Packit Service |
21c75c |
# use the local cache, even if it's expired, never download.
|
|
Packit Service |
21c75c |
SYNC_ONLY_CACHE = libdnf.repo.Repo.SyncStrategy_ONLY_CACHE
|
|
Packit Service |
21c75c |
# try the cache, if it is expired download new md.
|
|
Packit Service |
21c75c |
SYNC_TRY_CACHE = libdnf.repo.Repo.SyncStrategy_TRY_CACHE
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
class RepoCallbacks(libdnf.repo.RepoCB):
|
|
Packit Service |
21c75c |
def __init__(self, repo):
|
|
Packit Service |
21c75c |
super(RepoCallbacks, self).__init__()
|
|
Packit Service |
21c75c |
self._repo = repo
|
|
Packit Service |
21c75c |
self._md_pload = repo._md_pload
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def start(self, what):
|
|
Packit Service |
21c75c |
self._md_pload.start(what)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def end(self):
|
|
Packit Service |
21c75c |
self._md_pload.end()
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def progress(self, totalToDownload, downloaded):
|
|
Packit Service |
21c75c |
self._md_pload._progress_cb(None, totalToDownload, downloaded)
|
|
Packit Service |
21c75c |
return 0
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def fastestMirror(self, stage, ptr):
|
|
Packit Service |
21c75c |
self._md_pload._fastestmirror_cb(None, stage, ptr)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def handleMirrorFailure(self, msg, url, metadata):
|
|
Packit Service |
21c75c |
self._md_pload._mirror_failure_cb(None, msg, url, metadata)
|
|
Packit Service |
21c75c |
return 0
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def repokeyImport(self, id, userid, fingerprint, url, timestamp):
|
|
Packit Service |
21c75c |
return self._repo._key_import._confirm(id, userid, fingerprint, url, timestamp)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
class Repo(dnf.conf.RepoConf):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
DEFAULT_SYNC = SYNC_TRY_CACHE
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def __init__(self, name=None, parent_conf=None):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
super(Repo, self).__init__(section=name, parent=parent_conf)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
self._config.this.disown() # _repo will be the owner of _config
|
|
Packit Service |
21c75c |
self._repo = libdnf.repo.Repo(name if name else "", self._config)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
self._md_pload = MDPayload(dnf.callback.NullDownloadProgress())
|
|
Packit Service |
21c75c |
self._callbacks = RepoCallbacks(self)
|
|
Packit Service |
21c75c |
self._callbacks.this.disown() # _repo will be the owner of callbacks
|
|
Packit Service |
21c75c |
self._repo.setCallbacks(self._callbacks)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
self._pkgdir = None
|
|
Packit Service |
21c75c |
self._key_import = _NullKeyImport()
|
|
Packit Service |
21c75c |
self.metadata = None # :api
|
|
Packit Service |
21c75c |
self._repo.setSyncStrategy(self.DEFAULT_SYNC)
|
|
Packit Service |
21c75c |
if parent_conf:
|
|
Packit Service |
21c75c |
self._repo.setSubstitutions(parent_conf.substitutions)
|
|
Packit Service |
21c75c |
self._substitutions = dnf.conf.substitutions.Substitutions()
|
|
Packit Service |
21c75c |
self._check_config_file_age = parent_conf.check_config_file_age \
|
|
Packit Service |
21c75c |
if parent_conf is not None else True
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@property
|
|
Packit Service |
21c75c |
def id(self):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
return self._repo.getId()
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@property
|
|
Packit Service |
21c75c |
def repofile(self):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
return self._repo.getRepoFilePath()
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@repofile.setter
|
|
Packit Service |
21c75c |
def repofile(self, value):
|
|
Packit Service |
21c75c |
self._repo.setRepoFilePath(value)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@property
|
|
Packit Service |
21c75c |
def pkgdir(self):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
if self._repo.isLocal():
|
|
Packit Service |
21c75c |
return self._repo.getLocalBaseurl()
|
|
Packit Service |
21c75c |
return self.cache_pkgdir()
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def cache_pkgdir(self):
|
|
Packit Service |
21c75c |
if self._pkgdir is not None:
|
|
Packit Service |
21c75c |
return self._pkgdir
|
|
Packit Service |
21c75c |
return os.path.join(self._repo.getCachedir(), _PACKAGES_RELATIVE_DIR)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@pkgdir.setter
|
|
Packit Service |
21c75c |
def pkgdir(self, val):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
self._pkgdir = val
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@property
|
|
Packit Service |
21c75c |
def _pubring_dir(self):
|
|
Packit Service |
21c75c |
return os.path.join(self._repo.getCachedir(), 'pubring')
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@property
|
|
Packit Service |
21c75c |
def load_metadata_other(self):
|
|
Packit Service |
21c75c |
return self._repo.getLoadMetadataOther()
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
@load_metadata_other.setter
|
|
Packit Service |
21c75c |
def load_metadata_other(self, val):
|
|
Packit Service |
21c75c |
self._repo.setLoadMetadataOther(val)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def __lt__(self, other):
|
|
Packit Service |
21c75c |
return self.id < other.id
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def __repr__(self):
|
|
Packit Service |
21c75c |
return "<%s %s>" % (self.__class__.__name__, self.id)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def __setattr__(self, name, value):
|
|
Packit Service |
21c75c |
super(Repo, self).__setattr__(name, value)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def disable(self):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
self._repo.disable()
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def enable(self):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
self._repo.enable()
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def add_metadata_type_to_download(self, metadata_type):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
"""Ask for additional repository metadata type to download.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Given metadata_type is appended to the default metadata set when
|
|
Packit Service |
21c75c |
repository is downloaded.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Parameters
|
|
Packit Service |
21c75c |
----------
|
|
Packit Service |
21c75c |
metadata_type: string
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Example: add_metadata_type_to_download("productid")
|
|
Packit Service |
21c75c |
"""
|
|
Packit Service |
21c75c |
self._repo.addMetadataTypeToDownload(metadata_type)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def remove_metadata_type_from_download(self, metadata_type):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
"""Stop asking for this additional repository metadata type
|
|
Packit Service |
21c75c |
in download.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Given metadata_type is no longer downloaded by default
|
|
Packit Service |
21c75c |
when this repository is downloaded.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Parameters
|
|
Packit Service |
21c75c |
----------
|
|
Packit Service |
21c75c |
metadata_type: string
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Example: remove_metadata_type_from_download("productid")
|
|
Packit Service |
21c75c |
"""
|
|
Packit Service |
21c75c |
self._repo.removeMetadataTypeFromDownload(metadata_type)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def get_metadata_path(self, metadata_type):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
"""Return path to the file with downloaded repository metadata of given type.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Parameters
|
|
Packit Service |
21c75c |
----------
|
|
Packit Service |
21c75c |
metadata_type: string
|
|
Packit Service |
21c75c |
"""
|
|
Packit Service |
21c75c |
return self._repo.getMetadataPath(metadata_type)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def get_metadata_content(self, metadata_type):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
"""Return content of the file with downloaded repository metadata of given type.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Content of compressed metadata file is returned uncompressed.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Parameters
|
|
Packit Service |
21c75c |
----------
|
|
Packit Service |
21c75c |
metadata_type: string
|
|
Packit Service |
21c75c |
"""
|
|
Packit Service |
21c75c |
return self._repo.getMetadataContent(metadata_type)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def load(self):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
"""Load the metadata for this repo.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Depending on the configuration and the age and consistence of data
|
|
Packit Service |
21c75c |
available on the disk cache, either loads the metadata from the cache or
|
|
Packit Service |
21c75c |
downloads them from the mirror, baseurl or metalink.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
This method will by default not try to refresh already loaded data if
|
|
Packit Service |
21c75c |
called repeatedly.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Returns True if this call to load() caused a fresh metadata download.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
"""
|
|
Packit Service |
21c75c |
ret = False
|
|
Packit Service |
21c75c |
try:
|
|
Packit Service |
21c75c |
ret = self._repo.load()
|
|
Packit Service |
21c75c |
except (libdnf.error.Error, RuntimeError) as e:
|
|
Packit Service |
21c75c |
if self._md_pload.mirror_failures:
|
|
Packit Service |
21c75c |
msg = "Errors during downloading metadata for repository '%s':" % self.id
|
|
Packit Service |
21c75c |
for failure in self._md_pload.mirror_failures:
|
|
Packit Service |
21c75c |
msg += "\n - %s" % failure
|
|
Packit Service |
21c75c |
logger.warning(msg)
|
|
Packit Service |
21c75c |
raise dnf.exceptions.RepoError(str(e))
|
|
Packit Service |
21c75c |
finally:
|
|
Packit Service |
21c75c |
self._md_pload.mirror_failures = set()
|
|
Packit Service |
21c75c |
self.metadata = Metadata(self._repo)
|
|
Packit Service |
21c75c |
return ret
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _metadata_expire_in(self):
|
|
Packit Service |
21c75c |
"""Get the number of seconds after which the cached metadata will expire.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Returns a tuple, boolean whether there even is cached metadata and the
|
|
Packit Service |
21c75c |
number of seconds it will expire in. Negative number means the metadata
|
|
Packit Service |
21c75c |
has expired already, None that it never expires.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
"""
|
|
Packit Service |
21c75c |
if not self.metadata:
|
|
Packit Service |
21c75c |
self._repo.loadCache(False)
|
|
Packit Service |
21c75c |
if self.metadata:
|
|
Packit Service |
21c75c |
if self.metadata_expire == -1:
|
|
Packit Service |
21c75c |
return True, None
|
|
Packit Service |
21c75c |
expiration = self._repo.getExpiresIn()
|
|
Packit Service |
21c75c |
if self._repo.isExpired():
|
|
Packit Service |
21c75c |
expiration = min(0, expiration)
|
|
Packit Service |
21c75c |
return True, expiration
|
|
Packit Service |
21c75c |
return False, 0
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def _set_key_import(self, key_import):
|
|
Packit Service |
21c75c |
self._key_import = key_import
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def set_progress_bar(self, progress):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
self._md_pload.progress = progress
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def get_http_headers(self):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
"""Returns user defined http headers.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Returns
|
|
Packit Service |
21c75c |
-------
|
|
Packit Service |
21c75c |
headers : tuple of strings
|
|
Packit Service |
21c75c |
"""
|
|
Packit Service |
21c75c |
return self._repo.getHttpHeaders()
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def set_http_headers(self, headers):
|
|
Packit Service |
21c75c |
# :api
|
|
Packit Service |
21c75c |
"""Sets http headers.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Sets new http headers and rewrites existing ones.
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
Parameters
|
|
Packit Service |
21c75c |
----------
|
|
Packit Service |
21c75c |
headers : tuple or list of strings
|
|
Packit Service |
21c75c |
Example: set_http_headers(["User-Agent: Agent007", "MyFieldName: MyFieldValue"])
|
|
Packit Service |
21c75c |
"""
|
|
Packit Service |
21c75c |
self._repo.setHttpHeaders(headers)
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
def remote_location(self, location, schemes=('http', 'ftp', 'file', 'https')):
|
|
Packit Service |
21c75c |
"""
|
|
Packit Service |
21c75c |
:param location: relative location inside the repo
|
|
Packit Service |
21c75c |
:param schemes: list of allowed protocols. Default is ('http', 'ftp', 'file', 'https')
|
|
Packit Service |
21c75c |
:return: absolute url (string) or None
|
|
Packit Service |
21c75c |
"""
|
|
Packit Service |
21c75c |
def schemes_filter(url_list):
|
|
Packit Service |
21c75c |
for url in url_list:
|
|
Packit Service |
21c75c |
if schemes:
|
|
Packit Service |
21c75c |
s = dnf.pycomp.urlparse.urlparse(url)[0]
|
|
Packit Service |
21c75c |
if s in schemes:
|
|
Packit Service |
21c75c |
return os.path.join(url, location.lstrip('/'))
|
|
Packit Service |
21c75c |
else:
|
|
Packit Service |
21c75c |
return os.path.join(url, location.lstrip('/'))
|
|
Packit Service |
21c75c |
return None
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
if not location:
|
|
Packit Service |
21c75c |
return None
|
|
Packit Service |
21c75c |
|
|
Packit Service |
21c75c |
mirrors = self._repo.getMirrors()
|
|
Packit Service |
21c75c |
if mirrors:
|
|
Packit Service |
21c75c |
return schemes_filter(mirrors)
|
|
Packit Service |
21c75c |
elif self.baseurl:
|
|
Packit Service |
21c75c |
return schemes_filter(self.baseurl)
|