Blame dnf/base.py

Packit 6f3914
# Copyright 2005 Duke University
Packit 6f3914
# Copyright (C) 2012-2018 Red Hat, Inc.
Packit 6f3914
#
Packit 6f3914
# This program is free software; you can redistribute it and/or modify
Packit 6f3914
# it under the terms of the GNU General Public License as published by
Packit 6f3914
# the Free Software Foundation; either version 2 of the License, or
Packit 6f3914
# (at your option) any later version.
Packit 6f3914
#
Packit 6f3914
# This program is distributed in the hope that it will be useful,
Packit 6f3914
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6f3914
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 6f3914
# GNU Library General Public License for more details.
Packit 6f3914
#
Packit 6f3914
# You should have received a copy of the GNU General Public License
Packit 6f3914
# along with this program; if not, write to the Free Software
Packit 6f3914
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 6f3914
Packit 6f3914
"""
Packit 6f3914
Supplies the Base class.
Packit 6f3914
"""
Packit 6f3914
Packit 6f3914
from __future__ import absolute_import
Packit 6f3914
from __future__ import division
Packit 6f3914
from __future__ import print_function
Packit 6f3914
from __future__ import unicode_literals
Packit 6f3914
Packit 6f3914
import argparse
Packit 6f3914
import dnf
Packit 6f3914
import libdnf.transaction
Packit 6f3914
Packit 6f3914
from dnf.comps import CompsQuery
Packit 6f3914
from dnf.i18n import _, P_, ucd
Packit 6f3914
from dnf.util import _parse_specs
Packit 6f3914
from dnf.db.history import SwdbInterface
Packit 6f3914
from dnf.yum import misc
Packit 6f3914
from functools import reduce
Packit 6f3914
try:
Packit 6f3914
    from collections.abc import Sequence
Packit 6f3914
except ImportError:
Packit 6f3914
    from collections import Sequence
Packit 6f3914
import datetime
Packit 6f3914
import dnf.callback
Packit 6f3914
import dnf.comps
Packit 6f3914
import dnf.conf
Packit 6f3914
import dnf.conf.read
Packit 6f3914
import dnf.crypto
Packit 6f3914
import dnf.dnssec
Packit 6f3914
import dnf.drpm
Packit 6f3914
import dnf.exceptions
Packit 6f3914
import dnf.goal
Packit 6f3914
import dnf.history
Packit 6f3914
import dnf.lock
Packit 6f3914
import dnf.logging
Packit 6f3914
# WITH_MODULES is used by ansible (lib/ansible/modules/packaging/os/dnf.py)
Packit 6f3914
try:
Packit 6f3914
    import dnf.module.module_base
Packit 6f3914
    WITH_MODULES = True
Packit 6f3914
except ImportError:
Packit 6f3914
    WITH_MODULES = False
Packit 6f3914
import dnf.persistor
Packit 6f3914
import dnf.plugin
Packit 6f3914
import dnf.query
Packit 6f3914
import dnf.repo
Packit 6f3914
import dnf.repodict
Packit 6f3914
import dnf.rpm.connection
Packit 6f3914
import dnf.rpm.miscutils
Packit 6f3914
import dnf.rpm.transaction
Packit 6f3914
import dnf.sack
Packit 6f3914
import dnf.selector
Packit 6f3914
import dnf.subject
Packit 6f3914
import dnf.transaction
Packit 6f3914
import dnf.util
Packit 6f3914
import dnf.yum.rpmtrans
Packit 6f3914
import functools
Packit 6f3914
import hawkey
Packit 6f3914
import itertools
Packit 6f3914
import logging
Packit 6f3914
import math
Packit 6f3914
import os
Packit 6f3914
import operator
Packit 6f3914
import re
Packit 6f3914
import rpm
Packit 6f3914
import time
Packit 6f3914
import shutil
Packit 6f3914
Packit 6f3914
Packit 6f3914
logger = logging.getLogger("dnf")
Packit 6f3914
Packit 6f3914
Packit 6f3914
class Base(object):
Packit 6f3914
Packit 6f3914
    def __init__(self, conf=None):
Packit 6f3914
        # :api
Packit 6f3914
        self._closed = False
Packit 6f3914
        self._conf = conf or self._setup_default_conf()
Packit 6f3914
        self._goal = None
Packit 6f3914
        self._repo_persistor = None
Packit 6f3914
        self._sack = None
Packit 6f3914
        self._transaction = None
Packit 6f3914
        self._priv_ts = None
Packit 6f3914
        self._comps = None
Packit 6f3914
        self._comps_trans = dnf.comps.TransactionBunch()
Packit 6f3914
        self._history = None
Packit 6f3914
        self._tempfiles = set()
Packit 6f3914
        self._trans_tempfiles = set()
Packit 6f3914
        self._ds_callback = dnf.callback.Depsolve()
Packit 6f3914
        self._logging = dnf.logging.Logging()
Packit 6f3914
        self._repos = dnf.repodict.RepoDict()
Packit 6f3914
        self._rpm_probfilter = set([rpm.RPMPROB_FILTER_OLDPACKAGE])
Packit 6f3914
        self._plugins = dnf.plugin.Plugins()
Packit 6f3914
        self._trans_success = False
Packit 6f3914
        self._trans_install_set = False
Packit 6f3914
        self._tempfile_persistor = None
Packit 6f3914
        self._update_security_filters = []
Packit 6f3914
        self._allow_erasing = False
Packit 6f3914
        self._repo_set_imported_gpg_keys = set()
Packit 6f3914
        self.output = None
Packit 6f3914
Packit 6f3914
    def __enter__(self):
Packit 6f3914
        return self
Packit 6f3914
Packit 6f3914
    def __exit__(self, *exc_args):
Packit 6f3914
        self.close()
Packit 6f3914
Packit 6f3914
    def __del__(self):
Packit 6f3914
        self.close()
Packit 6f3914
Packit 6f3914
    def _add_tempfiles(self, files):
Packit 6f3914
        if self._transaction:
Packit 6f3914
            self._trans_tempfiles.update(files)
Packit 6f3914
        elif self.conf.destdir:
Packit 6f3914
            pass
Packit 6f3914
        else:
Packit 6f3914
            self._tempfiles.update(files)
Packit 6f3914
Packit 6f3914
    def _add_repo_to_sack(self, repo):
Packit 6f3914
        repo.load()
Packit 6f3914
        mdload_flags = dict(load_filelists=True,
Packit 6f3914
                            load_presto=repo.deltarpm,
Packit 6f3914
                            load_updateinfo=True)
Packit 6f3914
        if repo.load_metadata_other:
Packit 6f3914
            mdload_flags["load_other"] = True
Packit 6f3914
        try:
Packit 6f3914
            self._sack.load_repo(repo._repo, build_cache=True, **mdload_flags)
Packit 6f3914
        except hawkey.Exception as e:
Packit 6f3914
            logger.debug(_("loading repo '{}' failure: {}").format(repo.id, e))
Packit 6f3914
            raise dnf.exceptions.RepoError(
Packit 6f3914
                _("Loading repository '{}' has failed").format(repo.id))
Packit 6f3914
Packit 6f3914
    @staticmethod
Packit 6f3914
    def _setup_default_conf():
Packit 6f3914
        conf = dnf.conf.Conf()
Packit 6f3914
        subst = conf.substitutions
Packit 6f3914
        if 'releasever' not in subst:
Packit 6f3914
            subst['releasever'] = \
Packit 6f3914
                dnf.rpm.detect_releasever(conf.installroot)
Packit 6f3914
        return conf
Packit 6f3914
Packit 6f3914
    def _setup_modular_excludes(self):
Packit 6f3914
        hot_fix_repos = [i.id for i in self.repos.iter_enabled() if i.module_hotfixes]
Packit 6f3914
        try:
Packit 6f3914
            solver_errors = self.sack.filter_modules(
Packit 6f3914
                self._moduleContainer, hot_fix_repos, self.conf.installroot,
Packit 6f3914
                self.conf.module_platform_id, update_only=False, debugsolver=self.conf.debug_solver)
Packit 6f3914
        except hawkey.Exception as e:
Packit 6f3914
            raise dnf.exceptions.Error(ucd(e))
Packit 6f3914
        if solver_errors:
Packit 6f3914
            logger.warning(
Packit 6f3914
                dnf.module.module_base.format_modular_solver_errors(solver_errors[0]))
Packit 6f3914
Packit 6f3914
    def _setup_excludes_includes(self, only_main=False):
Packit 6f3914
        disabled = set(self.conf.disable_excludes)
Packit 6f3914
        if 'all' in disabled and WITH_MODULES:
Packit 6f3914
            self._setup_modular_excludes()
Packit 6f3914
            return
Packit 6f3914
        repo_includes = []
Packit 6f3914
        repo_excludes = []
Packit 6f3914
        # first evaluate repo specific includes/excludes
Packit 6f3914
        if not only_main:
Packit 6f3914
            for r in self.repos.iter_enabled():
Packit 6f3914
                if r.id in disabled:
Packit 6f3914
                    continue
Packit 6f3914
                if len(r.includepkgs) > 0:
Packit 6f3914
                    incl_query = self.sack.query().filterm(empty=True)
Packit 6f3914
                    for incl in set(r.includepkgs):
Packit 6f3914
                        subj = dnf.subject.Subject(incl)
Packit 6f3914
                        incl_query = incl_query.union(subj.get_best_query(
Packit 6f3914
                            self.sack, with_nevra=True, with_provides=False, with_filenames=False))
Packit 6f3914
                    incl_query.filterm(reponame=r.id)
Packit 6f3914
                    repo_includes.append((incl_query.apply(), r.id))
Packit 6f3914
                excl_query = self.sack.query().filterm(empty=True)
Packit 6f3914
                for excl in set(r.excludepkgs):
Packit 6f3914
                    subj = dnf.subject.Subject(excl)
Packit 6f3914
                    excl_query = excl_query.union(subj.get_best_query(
Packit 6f3914
                        self.sack, with_nevra=True, with_provides=False, with_filenames=False))
Packit 6f3914
                excl_query.filterm(reponame=r.id)
Packit 6f3914
                if excl_query:
Packit 6f3914
                    repo_excludes.append((excl_query, r.id))
Packit 6f3914
Packit 6f3914
        # then main (global) includes/excludes because they can mask
Packit 6f3914
        # repo specific settings
Packit 6f3914
        if 'main' not in disabled:
Packit 6f3914
            include_query = self.sack.query().filterm(empty=True)
Packit 6f3914
            if len(self.conf.includepkgs) > 0:
Packit 6f3914
                for incl in set(self.conf.includepkgs):
Packit 6f3914
                    subj = dnf.subject.Subject(incl)
Packit 6f3914
                    include_query = include_query.union(subj.get_best_query(
Packit 6f3914
                        self.sack, with_nevra=True, with_provides=False, with_filenames=False))
Packit 6f3914
            exclude_query = self.sack.query().filterm(empty=True)
Packit 6f3914
            for excl in set(self.conf.excludepkgs):
Packit 6f3914
                subj = dnf.subject.Subject(excl)
Packit 6f3914
                exclude_query = exclude_query.union(subj.get_best_query(
Packit 6f3914
                    self.sack, with_nevra=True, with_provides=False, with_filenames=False))
Packit 6f3914
            if len(self.conf.includepkgs) > 0:
Packit 6f3914
                self.sack.add_includes(include_query)
Packit 6f3914
                self.sack.set_use_includes(True)
Packit 6f3914
            if exclude_query:
Packit 6f3914
                self.sack.add_excludes(exclude_query)
Packit 6f3914
Packit 6f3914
        if repo_includes:
Packit 6f3914
            for query, repoid in repo_includes:
Packit 6f3914
                self.sack.add_includes(query)
Packit 6f3914
                self.sack.set_use_includes(True, repoid)
Packit 6f3914
Packit 6f3914
        if repo_excludes:
Packit 6f3914
            for query, repoid in repo_excludes:
Packit 6f3914
                self.sack.add_excludes(query)
Packit 6f3914
Packit 6f3914
        if not only_main and WITH_MODULES:
Packit 6f3914
            self._setup_modular_excludes()
Packit 6f3914
Packit 6f3914
    def _store_persistent_data(self):
Packit 6f3914
        if self._repo_persistor and not self.conf.cacheonly:
Packit 6f3914
            expired = [r.id for r in self.repos.iter_enabled()
Packit 6f3914
                       if (r.metadata and r._repo.isExpired())]
Packit 6f3914
            self._repo_persistor.expired_to_add.update(expired)
Packit 6f3914
            self._repo_persistor.save()
Packit 6f3914
Packit 6f3914
        if self._tempfile_persistor:
Packit 6f3914
            self._tempfile_persistor.save()
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def comps(self):
Packit 6f3914
        # :api
Packit 6f3914
        return self._comps
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def conf(self):
Packit 6f3914
        # :api
Packit 6f3914
        return self._conf
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def repos(self):
Packit 6f3914
        # :api
Packit 6f3914
        return self._repos
Packit 6f3914
Packit 6f3914
    @repos.deleter
Packit 6f3914
    def repos(self):
Packit 6f3914
        # :api
Packit 6f3914
        self._repos = None
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    @dnf.util.lazyattr("_priv_rpmconn")
Packit 6f3914
    def _rpmconn(self):
Packit 6f3914
        return dnf.rpm.connection.RpmConnection(self.conf.installroot)
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def sack(self):
Packit 6f3914
        # :api
Packit 6f3914
        return self._sack
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def _moduleContainer(self):
Packit 6f3914
        if self.sack is None:
Packit 6f3914
            raise dnf.exceptions.Error("Sack was not initialized")
Packit 6f3914
        if self.sack._moduleContainer is None:
Packit 6f3914
            self.sack._moduleContainer = libdnf.module.ModulePackageContainer(
Packit 6f3914
                False, self.conf.installroot, self.conf.substitutions["arch"], self.conf.persistdir)
Packit 6f3914
        return self.sack._moduleContainer
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def transaction(self):
Packit 6f3914
        # :api
Packit 6f3914
        return self._transaction
Packit 6f3914
Packit 6f3914
    @transaction.setter
Packit 6f3914
    def transaction(self, value):
Packit 6f3914
        # :api
Packit 6f3914
        if self._transaction:
Packit 6f3914
            raise ValueError('transaction already set')
Packit 6f3914
        self._transaction = value
Packit 6f3914
Packit 6f3914
    def _activate_persistor(self):
Packit 6f3914
        self._repo_persistor = dnf.persistor.RepoPersistor(self.conf.cachedir)
Packit 6f3914
Packit 6f3914
    def init_plugins(self, disabled_glob=(), enable_plugins=(), cli=None):
Packit 6f3914
        # :api
Packit 6f3914
        """Load plugins and run their __init__()."""
Packit 6f3914
        if self.conf.plugins:
Packit 6f3914
            self._plugins._load(self.conf, disabled_glob, enable_plugins)
Packit 6f3914
        self._plugins._run_init(self, cli)
Packit 6f3914
Packit 6f3914
    def pre_configure_plugins(self):
Packit 6f3914
        # :api
Packit 6f3914
        """Run plugins pre_configure() method."""
Packit 6f3914
        self._plugins._run_pre_config()
Packit 6f3914
Packit 6f3914
    def configure_plugins(self):
Packit 6f3914
        # :api
Packit 6f3914
        """Run plugins configure() method."""
Packit 6f3914
        self._plugins._run_config()
Packit 6f3914
Packit 6f3914
    def update_cache(self, timer=False):
Packit 6f3914
        # :api
Packit 6f3914
Packit 6f3914
        period = self.conf.metadata_timer_sync
Packit 6f3914
        persistor = self._repo_persistor
Packit 6f3914
        if timer:
Packit 6f3914
            if dnf.util.on_metered_connection():
Packit 6f3914
                msg = _('Metadata timer caching disabled '
Packit 6f3914
                        'when running on metered connection.')
Packit 6f3914
                logger.info(msg)
Packit 6f3914
                return False
Packit 6f3914
            if dnf.util.on_ac_power() is False:
Packit 6f3914
                msg = _('Metadata timer caching disabled '
Packit 6f3914
                        'when running on a battery.')
Packit 6f3914
                logger.info(msg)
Packit 6f3914
                return False
Packit 6f3914
            if period <= 0:
Packit 6f3914
                msg = _('Metadata timer caching disabled.')
Packit 6f3914
                logger.info(msg)
Packit 6f3914
                return False
Packit 6f3914
            since_last_makecache = persistor.since_last_makecache()
Packit 6f3914
            if since_last_makecache is not None and since_last_makecache < period:
Packit 6f3914
                logger.info(_('Metadata cache refreshed recently.'))
Packit 6f3914
                return False
Packit 6f3914
            for repo in self.repos.values():
Packit 6f3914
                repo._repo.setMaxMirrorTries(1)
Packit 6f3914
Packit 6f3914
        if not self.repos._any_enabled():
Packit 6f3914
            logger.info(_('There are no enabled repositories in "{}".').format(
Packit 6f3914
                '", "'.join(self.conf.reposdir)))
Packit 6f3914
            return False
Packit 6f3914
Packit 6f3914
        for r in self.repos.iter_enabled():
Packit 6f3914
            (is_cache, expires_in) = r._metadata_expire_in()
Packit 6f3914
            if expires_in is None:
Packit 6f3914
                logger.info(_('%s: will never be expired and will not be refreshed.'), r.id)
Packit 6f3914
            elif not is_cache or expires_in <= 0:
Packit 6f3914
                logger.debug(_('%s: has expired and will be refreshed.'), r.id)
Packit 6f3914
                r._repo.expire()
Packit 6f3914
            elif timer and expires_in < period:
Packit 6f3914
                # expires within the checking period:
Packit 6f3914
                msg = _("%s: metadata will expire after %d seconds and will be refreshed now")
Packit 6f3914
                logger.debug(msg, r.id, expires_in)
Packit 6f3914
                r._repo.expire()
Packit 6f3914
            else:
Packit 6f3914
                logger.debug(_('%s: will expire after %d seconds.'), r.id,
Packit 6f3914
                             expires_in)
Packit 6f3914
Packit 6f3914
        if timer:
Packit 6f3914
            persistor.reset_last_makecache = True
Packit 6f3914
        self.fill_sack(load_system_repo=False, load_available_repos=True)  # performs the md sync
Packit 6f3914
        logger.info(_('Metadata cache created.'))
Packit 6f3914
        return True
Packit 6f3914
Packit 6f3914
    def fill_sack(self, load_system_repo=True, load_available_repos=True):
Packit 6f3914
        # :api
Packit 6f3914
        """Prepare the Sack and the Goal objects. """
Packit 6f3914
        timer = dnf.logging.Timer('sack setup')
Packit 6f3914
        self.reset(sack=True, goal=True)
Packit 6f3914
        self._sack = dnf.sack._build_sack(self)
Packit 6f3914
        lock = dnf.lock.build_metadata_lock(self.conf.cachedir, self.conf.exit_on_lock)
Packit 6f3914
        with lock:
Packit 6f3914
            if load_system_repo is not False:
Packit 6f3914
                try:
Packit 6f3914
                    # FIXME: If build_cache=True, @System.solv is incorrectly updated in install-
Packit 6f3914
                    # remove loops
Packit 6f3914
                    self._sack.load_system_repo(build_cache=False)
Packit 6f3914
                except IOError:
Packit 6f3914
                    if load_system_repo != 'auto':
Packit 6f3914
                        raise
Packit 6f3914
            if load_available_repos:
Packit 6f3914
                error_repos = []
Packit 6f3914
                mts = 0
Packit 6f3914
                age = time.time()
Packit 6f3914
                # Iterate over installed GPG keys and check their validity using DNSSEC
Packit 6f3914
                if self.conf.gpgkey_dns_verification:
Packit 6f3914
                    dnf.dnssec.RpmImportedKeys.check_imported_keys_validity()
Packit 6f3914
                for r in self.repos.iter_enabled():
Packit 6f3914
                    try:
Packit 6f3914
                        self._add_repo_to_sack(r)
Packit 6f3914
                        if r._repo.getTimestamp() > mts:
Packit 6f3914
                            mts = r._repo.getTimestamp()
Packit 6f3914
                        if r._repo.getAge() < age:
Packit 6f3914
                            age = r._repo.getAge()
Packit 6f3914
                        logger.debug(_("%s: using metadata from %s."), r.id,
Packit 6f3914
                                     dnf.util.normalize_time(
Packit 6f3914
                                         r._repo.getMaxTimestamp()))
Packit 6f3914
                    except dnf.exceptions.RepoError as e:
Packit 6f3914
                        r._repo.expire()
Packit 6f3914
                        if r.skip_if_unavailable is False:
Packit 6f3914
                            raise
Packit 6f3914
                        logger.warning("Error: %s", e)
Packit 6f3914
                        error_repos.append(r.id)
Packit 6f3914
                        r.disable()
Packit 6f3914
                if error_repos:
Packit 6f3914
                    logger.warning(
Packit 6f3914
                        _("Ignoring repositories: %s"), ', '.join(error_repos))
Packit 6f3914
                if self.repos._any_enabled():
Packit 6f3914
                    if age != 0 and mts != 0:
Packit 6f3914
                        logger.info(_("Last metadata expiration check: %s ago on %s."),
Packit 6f3914
                                    datetime.timedelta(seconds=int(age)),
Packit 6f3914
                                    dnf.util.normalize_time(mts))
Packit 6f3914
            else:
Packit 6f3914
                self.repos.all().disable()
Packit 6f3914
        conf = self.conf
Packit 6f3914
        self._sack._configure(conf.installonlypkgs, conf.installonly_limit)
Packit 6f3914
        self._setup_excludes_includes()
Packit 6f3914
        timer()
Packit 6f3914
        self._goal = dnf.goal.Goal(self._sack)
Packit 6f3914
        self._plugins.run_sack()
Packit 6f3914
        return self._sack
Packit 6f3914
Packit 6f3914
    def _finalize_base(self):
Packit 6f3914
        self._tempfile_persistor = dnf.persistor.TempfilePersistor(
Packit 6f3914
            self.conf.cachedir)
Packit 6f3914
Packit 6f3914
        if not self.conf.keepcache:
Packit 6f3914
            self._clean_packages(self._tempfiles)
Packit 6f3914
            if self._trans_success:
Packit 6f3914
                self._trans_tempfiles.update(
Packit 6f3914
                    self._tempfile_persistor.get_saved_tempfiles())
Packit 6f3914
                self._tempfile_persistor.empty()
Packit 6f3914
                if self._trans_install_set:
Packit 6f3914
                    self._clean_packages(self._trans_tempfiles)
Packit 6f3914
            else:
Packit 6f3914
                self._tempfile_persistor.tempfiles_to_add.update(
Packit 6f3914
                    self._trans_tempfiles)
Packit 6f3914
Packit 6f3914
        if self._tempfile_persistor.tempfiles_to_add:
Packit 6f3914
            logger.info(_("The downloaded packages were saved in cache "
Packit 6f3914
                          "until the next successful transaction."))
Packit 6f3914
            logger.info(_("You can remove cached packages by executing "
Packit 6f3914
                          "'%s'."), "{prog} clean packages".format(prog=dnf.util.MAIN_PROG))
Packit 6f3914
Packit 6f3914
        # Do not trigger the lazy creation:
Packit 6f3914
        if self._history is not None:
Packit 6f3914
            self.history.close()
Packit 6f3914
        self._store_persistent_data()
Packit 6f3914
        self._closeRpmDB()
Packit 6f3914
        self._trans_success = False
Packit 6f3914
Packit 6f3914
    def close(self):
Packit 6f3914
        # :api
Packit 6f3914
        """Close all potential handles and clean cache.
Packit 6f3914
Packit 6f3914
        Typically the handles are to data sources and sinks.
Packit 6f3914
Packit 6f3914
        """
Packit 6f3914
Packit 6f3914
        if self._closed:
Packit 6f3914
            return
Packit 6f3914
        logger.log(dnf.logging.DDEBUG, 'Cleaning up.')
Packit 6f3914
        self._closed = True
Packit 6f3914
        self._finalize_base()
Packit 6f3914
        self.reset(sack=True, repos=True, goal=True)
Packit 6f3914
Packit 6f3914
    def read_all_repos(self, opts=None):
Packit 6f3914
        # :api
Packit 6f3914
        """Read repositories from the main conf file and from .repo files."""
Packit 6f3914
Packit 6f3914
        reader = dnf.conf.read.RepoReader(self.conf, opts)
Packit 6f3914
        for repo in reader:
Packit 6f3914
            try:
Packit 6f3914
                self.repos.add(repo)
Packit 6f3914
            except dnf.exceptions.ConfigError as e:
Packit 6f3914
                logger.warning(e)
Packit 6f3914
Packit 6f3914
    def reset(self, sack=False, repos=False, goal=False):
Packit 6f3914
        # :api
Packit 6f3914
        """Make the Base object forget about various things."""
Packit 6f3914
        if sack:
Packit 6f3914
            self._sack = None
Packit 6f3914
        if repos:
Packit 6f3914
            self._repos = dnf.repodict.RepoDict()
Packit 6f3914
        if goal:
Packit 6f3914
            self._goal = None
Packit 6f3914
            if self._sack is not None:
Packit 6f3914
                self._goal = dnf.goal.Goal(self._sack)
Packit 6f3914
            if self._sack and self._moduleContainer:
Packit 6f3914
                # sack must be set to enable operations on moduleContainer
Packit 6f3914
                self._moduleContainer.rollback()
Packit 6f3914
            if self._history is not None:
Packit 6f3914
                self.history.close()
Packit 6f3914
            self._comps_trans = dnf.comps.TransactionBunch()
Packit 6f3914
            self._transaction = None
Packit 6f3914
Packit 6f3914
    def _closeRpmDB(self):
Packit 6f3914
        """Closes down the instances of rpmdb that could be open."""
Packit 6f3914
        del self._ts
Packit 6f3914
Packit 6f3914
    _TS_FLAGS_TO_RPM = {'noscripts': rpm.RPMTRANS_FLAG_NOSCRIPTS,
Packit 6f3914
                        'notriggers': rpm.RPMTRANS_FLAG_NOTRIGGERS,
Packit 6f3914
                        'nodocs': rpm.RPMTRANS_FLAG_NODOCS,
Packit 6f3914
                        'test': rpm.RPMTRANS_FLAG_TEST,
Packit 6f3914
                        'justdb': rpm.RPMTRANS_FLAG_JUSTDB,
Packit 6f3914
                        'nocontexts': rpm.RPMTRANS_FLAG_NOCONTEXTS,
Packit 6f3914
                        'nocrypto': rpm.RPMTRANS_FLAG_NOFILEDIGEST}
Packit 6f3914
    if hasattr(rpm, 'RPMTRANS_FLAG_NOCAPS'):
Packit 6f3914
        # Introduced in rpm-4.14
Packit 6f3914
        _TS_FLAGS_TO_RPM['nocaps'] = rpm.RPMTRANS_FLAG_NOCAPS
Packit 6f3914
Packit 6f3914
    _TS_VSFLAGS_TO_RPM = {'nocrypto': rpm._RPMVSF_NOSIGNATURES |
Packit 6f3914
                          rpm._RPMVSF_NODIGESTS}
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def goal(self):
Packit 6f3914
        return self._goal
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def _ts(self):
Packit 6f3914
        """Set up the RPM transaction set that will be used
Packit 6f3914
           for all the work."""
Packit 6f3914
        if self._priv_ts is not None:
Packit 6f3914
            return self._priv_ts
Packit 6f3914
        self._priv_ts = dnf.rpm.transaction.TransactionWrapper(
Packit 6f3914
            self.conf.installroot)
Packit 6f3914
        self._priv_ts.setFlags(0)  # reset everything.
Packit 6f3914
        for flag in self.conf.tsflags:
Packit 6f3914
            rpm_flag = self._TS_FLAGS_TO_RPM.get(flag)
Packit 6f3914
            if rpm_flag is None:
Packit 6f3914
                logger.critical(_('Invalid tsflag in config file: %s'), flag)
Packit 6f3914
                continue
Packit 6f3914
            self._priv_ts.addTsFlag(rpm_flag)
Packit 6f3914
            vs_flag = self._TS_VSFLAGS_TO_RPM.get(flag)
Packit 6f3914
            if vs_flag is not None:
Packit 6f3914
                self._priv_ts.pushVSFlags(vs_flag)
Packit 6f3914
Packit 6f3914
        if not self.conf.diskspacecheck:
Packit 6f3914
            self._rpm_probfilter.add(rpm.RPMPROB_FILTER_DISKSPACE)
Packit 6f3914
Packit 6f3914
        if self.conf.ignorearch:
Packit 6f3914
            self._rpm_probfilter.add(rpm.RPMPROB_FILTER_IGNOREARCH)
Packit 6f3914
Packit 6f3914
        probfilter = reduce(operator.or_, self._rpm_probfilter, 0)
Packit 6f3914
        self._priv_ts.setProbFilter(probfilter)
Packit 6f3914
        return self._priv_ts
Packit 6f3914
Packit 6f3914
    @_ts.deleter
Packit 6f3914
    def _ts(self):
Packit 6f3914
        """Releases the RPM transaction set. """
Packit 6f3914
        if self._priv_ts is None:
Packit 6f3914
            return
Packit 6f3914
        self._priv_ts.close()
Packit 6f3914
        del self._priv_ts
Packit 6f3914
        self._priv_ts = None
Packit 6f3914
Packit 6f3914
    def read_comps(self, arch_filter=False):
Packit 6f3914
        # :api
Packit 6f3914
        """Create the groups object to access the comps metadata."""
Packit 6f3914
        timer = dnf.logging.Timer('loading comps')
Packit 6f3914
        self._comps = dnf.comps.Comps()
Packit 6f3914
Packit 6f3914
        logger.log(dnf.logging.DDEBUG, 'Getting group metadata')
Packit 6f3914
        for repo in self.repos.iter_enabled():
Packit 6f3914
            if not repo.enablegroups:
Packit 6f3914
                continue
Packit 6f3914
            if not repo.metadata:
Packit 6f3914
                continue
Packit 6f3914
            comps_fn = repo._repo.getCompsFn()
Packit 6f3914
            if not comps_fn:
Packit 6f3914
                continue
Packit 6f3914
Packit 6f3914
            logger.log(dnf.logging.DDEBUG,
Packit 6f3914
                       'Adding group file from repository: %s', repo.id)
Packit 6f3914
            if repo._repo.getSyncStrategy() == dnf.repo.SYNC_ONLY_CACHE:
Packit 6f3914
                decompressed = misc.calculate_repo_gen_dest(comps_fn,
Packit 6f3914
                                                            'groups.xml')
Packit 6f3914
                if not os.path.exists(decompressed):
Packit 6f3914
                    # root privileges are needed for comps decompression
Packit 6f3914
                    continue
Packit 6f3914
            else:
Packit 6f3914
                decompressed = misc.repo_gen_decompress(comps_fn, 'groups.xml')
Packit 6f3914
Packit 6f3914
            try:
Packit 6f3914
                self._comps._add_from_xml_filename(decompressed)
Packit 6f3914
            except dnf.exceptions.CompsError as e:
Packit 6f3914
                msg = _('Failed to add groups file for repository: %s - %s')
Packit 6f3914
                logger.critical(msg, repo.id, e)
Packit 6f3914
Packit 6f3914
        if arch_filter:
Packit 6f3914
            self._comps._i.arch_filter(
Packit 6f3914
                [self._conf.substitutions['basearch']])
Packit 6f3914
        timer()
Packit 6f3914
        return self._comps
Packit 6f3914
Packit 6f3914
    def _getHistory(self):
Packit 6f3914
        """auto create the history object that to access/append the transaction
Packit 6f3914
           history information. """
Packit 6f3914
        if self._history is None:
Packit 6f3914
            releasever = self.conf.releasever
Packit 6f3914
            self._history = SwdbInterface(self.conf.persistdir, releasever=releasever)
Packit 6f3914
        return self._history
Packit 6f3914
Packit 6f3914
    history = property(fget=lambda self: self._getHistory(),
Packit 6f3914
                       fset=lambda self, value: setattr(
Packit 6f3914
                           self, "_history", value),
Packit 6f3914
                       fdel=lambda self: setattr(self, "_history", None),
Packit 6f3914
                       doc="DNF SWDB Interface Object")
Packit 6f3914
Packit 6f3914
    def _goal2transaction(self, goal):
Packit 6f3914
        ts = self.history.rpm
Packit 6f3914
        all_obsoleted = set(goal.list_obsoleted())
Packit 6f3914
        installonly_query = self._get_installonly_query()
Packit 6f3914
Packit 6f3914
        for pkg in goal.list_downgrades():
Packit 6f3914
            obs = goal.obsoleted_by_package(pkg)
Packit 6f3914
            downgraded = obs[0]
Packit 6f3914
            self._ds_callback.pkg_added(downgraded, 'dd')
Packit 6f3914
            self._ds_callback.pkg_added(pkg, 'd')
Packit 6f3914
            ts.add_downgrade(pkg, downgraded, obs[1:])
Packit 6f3914
        for pkg in goal.list_reinstalls():
Packit 6f3914
            self._ds_callback.pkg_added(pkg, 'r')
Packit 6f3914
            obs = goal.obsoleted_by_package(pkg)
Packit 6f3914
            nevra_pkg = str(pkg)
Packit 6f3914
            # reinstall could obsolete multiple packages with the same NEVRA or different NEVRA
Packit 6f3914
            # Set the package with the same NEVRA as reinstalled
Packit 6f3914
            obsoletes = []
Packit 6f3914
            for obs_pkg in obs:
Packit 6f3914
                if str(obs_pkg) == nevra_pkg:
Packit 6f3914
                    obsoletes.insert(0, obs_pkg)
Packit 6f3914
                else:
Packit 6f3914
                    obsoletes.append(obs_pkg)
Packit 6f3914
            reinstalled = obsoletes[0]
Packit 6f3914
            ts.add_reinstall(pkg, reinstalled, obsoletes[1:])
Packit 6f3914
        for pkg in goal.list_installs():
Packit 6f3914
            self._ds_callback.pkg_added(pkg, 'i')
Packit 6f3914
            obs = goal.obsoleted_by_package(pkg)
Packit 6f3914
            # Skip obsoleted packages that are not part of all_obsoleted,
Packit 6f3914
            # they are handled as upgrades/downgrades.
Packit 6f3914
            # Also keep RPMs with the same name - they're not always in all_obsoleted.
Packit 6f3914
            obs = [i for i in obs if i in all_obsoleted or i.name == pkg.name]
Packit 6f3914
Packit 6f3914
            reason = goal.get_reason(pkg)
Packit 6f3914
Packit 6f3914
            if pkg in installonly_query:
Packit 6f3914
                reason_installonly = ts.get_reason(pkg)
Packit 6f3914
                if libdnf.transaction.TransactionItemReasonCompare(
Packit 6f3914
                        reason, reason_installonly) == -1:
Packit 6f3914
                    reason = reason_installonly
Packit 6f3914
Packit 6f3914
            # inherit the best reason from obsoleted packages
Packit 6f3914
            for obsolete in obs:
Packit 6f3914
                reason_obsolete = ts.get_reason(obsolete)
Packit 6f3914
                if libdnf.transaction.TransactionItemReasonCompare(reason, reason_obsolete) == -1:
Packit 6f3914
                    reason = reason_obsolete
Packit 6f3914
Packit 6f3914
            ts.add_install(pkg, obs, reason)
Packit 6f3914
            cb = lambda pkg: self._ds_callback.pkg_added(pkg, 'od')
Packit 6f3914
            dnf.util.mapall(cb, obs)
Packit 6f3914
        for pkg in goal.list_upgrades():
Packit 6f3914
            obs = goal.obsoleted_by_package(pkg)
Packit 6f3914
            upgraded = None
Packit 6f3914
            for i in obs:
Packit 6f3914
                # try to find a package with matching name as the upgrade
Packit 6f3914
                if i.name == pkg.name:
Packit 6f3914
                    upgraded = i
Packit 6f3914
                    break
Packit 6f3914
            if upgraded is None:
Packit 6f3914
                # no matching name -> pick the first one
Packit 6f3914
                upgraded = obs.pop(0)
Packit 6f3914
            else:
Packit 6f3914
                obs.remove(upgraded)
Packit 6f3914
            # Skip obsoleted packages that are not part of all_obsoleted,
Packit 6f3914
            # they are handled as upgrades/downgrades.
Packit 6f3914
            # Also keep RPMs with the same name - they're not always in all_obsoleted.
Packit 6f3914
            obs = [i for i in obs if i in all_obsoleted or i.name == pkg.name]
Packit 6f3914
Packit 6f3914
            cb = lambda pkg: self._ds_callback.pkg_added(pkg, 'od')
Packit 6f3914
            dnf.util.mapall(cb, obs)
Packit 6f3914
            if pkg in installonly_query:
Packit 6f3914
                ts.add_install(pkg, obs)
Packit 6f3914
            else:
Packit 6f3914
                ts.add_upgrade(pkg, upgraded, obs)
Packit 6f3914
                self._ds_callback.pkg_added(upgraded, 'ud')
Packit 6f3914
            self._ds_callback.pkg_added(pkg, 'u')
Packit 6f3914
        for pkg in goal.list_erasures():
Packit 6f3914
            self._ds_callback.pkg_added(pkg, 'e')
Packit 6f3914
            reason = goal.get_reason(pkg)
Packit 6f3914
            ts.add_erase(pkg, reason)
Packit 6f3914
        return ts
Packit 6f3914
Packit 6f3914
    def _query_matches_installed(self, q):
Packit 6f3914
        """ See what packages in the query match packages (also in older
Packit 6f3914
            versions, but always same architecture) that are already installed.
Packit 6f3914
Packit 6f3914
            Unlike in case of _sltr_matches_installed(), it is practical here
Packit 6f3914
            to know even the packages in the original query that can still be
Packit 6f3914
            installed.
Packit 6f3914
        """
Packit 6f3914
        inst = q.installed()
Packit 6f3914
        inst_per_arch = inst._na_dict()
Packit 6f3914
        avail_per_arch = q.available()._na_dict()
Packit 6f3914
        avail_l = []
Packit 6f3914
        inst_l = []
Packit 6f3914
        for na in avail_per_arch:
Packit 6f3914
            if na in inst_per_arch:
Packit 6f3914
                inst_l.append(inst_per_arch[na][0])
Packit 6f3914
            else:
Packit 6f3914
                avail_l.append(avail_per_arch[na])
Packit 6f3914
        return inst_l, avail_l
Packit 6f3914
Packit 6f3914
    def _sltr_matches_installed(self, sltr):
Packit 6f3914
        """ See if sltr matches a patches that is (in older version or different
Packit 6f3914
            architecture perhaps) already installed.
Packit 6f3914
        """
Packit 6f3914
        inst = self.sack.query().installed().filterm(pkg=sltr.matches())
Packit 6f3914
        return list(inst)
Packit 6f3914
Packit 6f3914
    def iter_userinstalled(self):
Packit 6f3914
        """Get iterator over the packages installed by the user."""
Packit 6f3914
        return (pkg for pkg in self.sack.query().installed()
Packit 6f3914
                if self.history.user_installed(pkg))
Packit 6f3914
Packit 6f3914
    def _run_hawkey_goal(self, goal, allow_erasing):
Packit 6f3914
        ret = goal.run(
Packit 6f3914
            allow_uninstall=allow_erasing, force_best=self.conf.best,
Packit 6f3914
            ignore_weak_deps=(not self.conf.install_weak_deps))
Packit 6f3914
        if self.conf.debug_solver:
Packit 6f3914
            goal.write_debugdata('./debugdata/rpms')
Packit 6f3914
        return ret
Packit 6f3914
Packit 6f3914
    def resolve(self, allow_erasing=False):
Packit 6f3914
        # :api
Packit 6f3914
        """Build the transaction set."""
Packit 6f3914
        exc = None
Packit 6f3914
        self._finalize_comps_trans()
Packit 6f3914
Packit 6f3914
        timer = dnf.logging.Timer('depsolve')
Packit 6f3914
        self._ds_callback.start()
Packit 6f3914
        goal = self._goal
Packit 6f3914
        if goal.req_has_erase():
Packit 6f3914
            goal.push_userinstalled(self.sack.query().installed(),
Packit 6f3914
                                    self.history)
Packit 6f3914
        elif not self.conf.upgrade_group_objects_upgrade:
Packit 6f3914
            # exclude packages installed from groups
Packit 6f3914
            # these packages will be marked to installation
Packit 6f3914
            # which could prevent them from upgrade, downgrade
Packit 6f3914
            # to prevent "conflicting job" error it's not applied
Packit 6f3914
            # to "remove" and "reinstall" commands
Packit 6f3914
Packit 6f3914
            solver = self._build_comps_solver()
Packit 6f3914
            solver._exclude_packages_from_installed_groups(self)
Packit 6f3914
Packit 6f3914
        goal.add_protected(self.sack.query().filterm(
Packit 6f3914
            name=self.conf.protected_packages))
Packit 6f3914
        if not self._run_hawkey_goal(goal, allow_erasing):
Packit 6f3914
            if self.conf.debuglevel >= 6:
Packit 6f3914
                goal.log_decisions()
Packit 6f3914
            msg = dnf.util._format_resolve_problems(goal.problem_rules())
Packit 6f3914
            exc = dnf.exceptions.DepsolveError(msg)
Packit 6f3914
        else:
Packit 6f3914
            self._transaction = self._goal2transaction(goal)
Packit 6f3914
Packit 6f3914
        self._ds_callback.end()
Packit 6f3914
        timer()
Packit 6f3914
Packit 6f3914
        got_transaction = self._transaction is not None and \
Packit 6f3914
            len(self._transaction) > 0
Packit 6f3914
        if got_transaction:
Packit 6f3914
            msg = self._transaction._rpm_limitations()
Packit 6f3914
            if msg:
Packit 6f3914
                exc = dnf.exceptions.Error(msg)
Packit 6f3914
Packit 6f3914
        if exc is not None:
Packit 6f3914
            raise exc
Packit 6f3914
Packit 6f3914
        self._plugins.run_resolved()
Packit 6f3914
Packit 6f3914
        # auto-enable module streams based on installed RPMs
Packit 6f3914
        new_pkgs = self._goal.list_installs()
Packit 6f3914
        new_pkgs += self._goal.list_upgrades()
Packit 6f3914
        new_pkgs += self._goal.list_downgrades()
Packit 6f3914
        new_pkgs += self._goal.list_reinstalls()
Packit 6f3914
        self.sack.set_modules_enabled_by_pkgset(self._moduleContainer, new_pkgs)
Packit 6f3914
Packit 6f3914
        return got_transaction
Packit 6f3914
Packit 6f3914
    def do_transaction(self, display=()):
Packit 6f3914
        # :api
Packit 6f3914
        if not isinstance(display, Sequence):
Packit 6f3914
            display = [display]
Packit 6f3914
        display = \
Packit 6f3914
            [dnf.yum.rpmtrans.LoggingTransactionDisplay()] + list(display)
Packit 6f3914
Packit 6f3914
        if not self.transaction:
Packit 6f3914
            # packages are not changed, but comps and modules changes need to be committed
Packit 6f3914
            self._moduleContainer.save()
Packit 6f3914
            self._moduleContainer.updateFailSafeData()
Packit 6f3914
            if self._history and (self._history.group or self._history.env):
Packit 6f3914
                cmdline = None
Packit 6f3914
                if hasattr(self, 'args') and self.args:
Packit 6f3914
                    cmdline = ' '.join(self.args)
Packit 6f3914
                elif hasattr(self, 'cmds') and self.cmds:
Packit 6f3914
                    cmdline = ' '.join(self.cmds)
Packit 6f3914
                old = self.history.last()
Packit 6f3914
                if old is None:
Packit 6f3914
                    rpmdb_version = self.sack._rpmdb_version()
Packit 6f3914
                else:
Packit 6f3914
                    rpmdb_version = old.end_rpmdb_version
Packit 6f3914
Packit 6f3914
                self.history.beg(rpmdb_version, [], [], cmdline)
Packit 6f3914
                self.history.end(rpmdb_version)
Packit 6f3914
            self._plugins.run_pre_transaction()
Packit 6f3914
            self._plugins.run_transaction()
Packit 6f3914
            self._trans_success = True
Packit 6f3914
            return
Packit 6f3914
Packit 6f3914
        tid = None
Packit 6f3914
        logger.info(_('Running transaction check'))
Packit 6f3914
        lock = dnf.lock.build_rpmdb_lock(self.conf.persistdir,
Packit 6f3914
                                         self.conf.exit_on_lock)
Packit 6f3914
        with lock:
Packit 6f3914
            self.transaction._populate_rpm_ts(self._ts)
Packit 6f3914
Packit 6f3914
            msgs = self._run_rpm_check()
Packit 6f3914
            if msgs:
Packit 6f3914
                msg = _('Error: transaction check vs depsolve:')
Packit 6f3914
                logger.error(msg)
Packit 6f3914
                for msg in msgs:
Packit 6f3914
                    logger.error(msg)
Packit 6f3914
                raise dnf.exceptions.TransactionCheckError(msg)
Packit 6f3914
Packit 6f3914
            logger.info(_('Transaction check succeeded.'))
Packit 6f3914
Packit 6f3914
            timer = dnf.logging.Timer('transaction test')
Packit 6f3914
            logger.info(_('Running transaction test'))
Packit 6f3914
Packit 6f3914
            self._ts.order()  # order the transaction
Packit 6f3914
            self._ts.clean()  # release memory not needed beyond this point
Packit 6f3914
Packit 6f3914
            testcb = dnf.yum.rpmtrans.RPMTransaction(self, test=True)
Packit 6f3914
            tserrors = self._ts.test(testcb)
Packit 6f3914
Packit 6f3914
            if len(tserrors) > 0:
Packit 6f3914
                for msg in testcb.messages():
Packit 6f3914
                    logger.critical(_('RPM: {}').format(msg))
Packit 6f3914
                errstring = _('Transaction test error:') + '\n'
Packit 6f3914
                for descr in tserrors:
Packit 6f3914
                    errstring += '  %s\n' % ucd(descr)
Packit 6f3914
Packit 6f3914
                summary = self._trans_error_summary(errstring)
Packit 6f3914
                if summary:
Packit 6f3914
                    errstring += '\n' + summary
Packit 6f3914
Packit 6f3914
                raise dnf.exceptions.Error(errstring)
Packit 6f3914
            del testcb
Packit 6f3914
Packit 6f3914
            logger.info(_('Transaction test succeeded.'))
Packit 6f3914
            timer()
Packit 6f3914
Packit 6f3914
            # save module states on disk right before entering rpm transaction,
Packit 6f3914
            # because we want system in recoverable state if transaction gets interrupted
Packit 6f3914
            self._moduleContainer.save()
Packit 6f3914
            self._moduleContainer.updateFailSafeData()
Packit 6f3914
Packit 6f3914
            # unset the sigquit handler
Packit 6f3914
            timer = dnf.logging.Timer('transaction')
Packit 6f3914
            # setup our rpm ts callback
Packit 6f3914
            cb = dnf.yum.rpmtrans.RPMTransaction(self, displays=display)
Packit 6f3914
            if self.conf.debuglevel < 2:
Packit 6f3914
                for display_ in cb.displays:
Packit 6f3914
                    display_.output = False
Packit 6f3914
Packit 6f3914
            self._plugins.run_pre_transaction()
Packit 6f3914
Packit 6f3914
            logger.info(_('Running transaction'))
Packit 6f3914
            tid = self._run_transaction(cb=cb)
Packit 6f3914
        timer()
Packit 6f3914
        self._plugins.unload_removed_plugins(self.transaction)
Packit 6f3914
        self._plugins.run_transaction()
Packit 6f3914
Packit 6f3914
        return tid
Packit 6f3914
Packit 6f3914
    def _trans_error_summary(self, errstring):
Packit 6f3914
        """Parse the error string for 'interesting' errors which can
Packit 6f3914
        be grouped, such as disk space issues.
Packit 6f3914
Packit 6f3914
        :param errstring: the error string
Packit 6f3914
        :return: a string containing a summary of the errors
Packit 6f3914
        """
Packit 6f3914
        summary = ''
Packit 6f3914
        # do disk space report first
Packit 6f3914
        p = re.compile(r'needs (\d+)(K|M)B(?: more space)? on the (\S+) filesystem')
Packit 6f3914
        disk = {}
Packit 6f3914
        for m in p.finditer(errstring):
Packit 6f3914
            size_in_mb = int(m.group(1)) if m.group(2) == 'M' else math.ceil(
Packit 6f3914
                int(m.group(1)) / 1024.0)
Packit 6f3914
            if m.group(3) not in disk:
Packit 6f3914
                disk[m.group(3)] = size_in_mb
Packit 6f3914
            if disk[m.group(3)] < size_in_mb:
Packit 6f3914
                disk[m.group(3)] = size_in_mb
Packit 6f3914
Packit 6f3914
        if disk:
Packit 6f3914
            summary += _('Disk Requirements:') + "\n"
Packit 6f3914
            for k in disk:
Packit 6f3914
                summary += "   " + P_(
Packit 6f3914
                    'At least {0}MB more space needed on the {1} filesystem.',
Packit 6f3914
                    'At least {0}MB more space needed on the {1} filesystem.',
Packit 6f3914
                    disk[k]).format(disk[k], k) + '\n'
Packit 6f3914
Packit 6f3914
        if not summary:
Packit 6f3914
            return None
Packit 6f3914
Packit 6f3914
        summary = _('Error Summary') + '\n-------------\n' + summary
Packit 6f3914
Packit 6f3914
        return summary
Packit 6f3914
Packit 6f3914
    def _record_history(self):
Packit 6f3914
        return self.conf.history_record and \
Packit 6f3914
            not self._ts.isTsFlagSet(rpm.RPMTRANS_FLAG_TEST)
Packit 6f3914
Packit 6f3914
    def _run_transaction(self, cb):
Packit 6f3914
        """
Packit 6f3914
        Perform the RPM transaction.
Packit 6f3914
Packit 6f3914
        :return: history database transaction ID or None
Packit 6f3914
        """
Packit 6f3914
Packit 6f3914
        tid = None
Packit 6f3914
        if self._record_history():
Packit 6f3914
            using_pkgs_pats = list(self.conf.history_record_packages)
Packit 6f3914
            installed_query = self.sack.query().installed()
Packit 6f3914
            using_pkgs = installed_query.filter(name=using_pkgs_pats).run()
Packit 6f3914
            rpmdbv = self.sack._rpmdb_version()
Packit 6f3914
            lastdbv = self.history.last()
Packit 6f3914
            if lastdbv is not None:
Packit 6f3914
                lastdbv = lastdbv.end_rpmdb_version
Packit 6f3914
Packit 6f3914
            if lastdbv is None or rpmdbv != lastdbv:
Packit 6f3914
                logger.debug(_("RPMDB altered outside of {prog}.").format(
Packit 6f3914
                    prog=dnf.util.MAIN_PROG_UPPER))
Packit 6f3914
Packit 6f3914
            cmdline = None
Packit 6f3914
            if hasattr(self, 'args') and self.args:
Packit 6f3914
                cmdline = ' '.join(self.args)
Packit 6f3914
            elif hasattr(self, 'cmds') and self.cmds:
Packit 6f3914
                cmdline = ' '.join(self.cmds)
Packit 6f3914
Packit 6f3914
            tid = self.history.beg(rpmdbv, using_pkgs, [], cmdline)
Packit 6f3914
Packit 6f3914
            if self.conf.comment:
Packit 6f3914
                # write out user provided comment to history info
Packit 6f3914
                # TODO:
Packit 6f3914
                # self._store_comment_in_history(tid, self.conf.comment)
Packit 6f3914
                pass
Packit 6f3914
Packit 6f3914
        if self.conf.reset_nice:
Packit 6f3914
            onice = os.nice(0)
Packit 6f3914
            if onice:
Packit 6f3914
                try:
Packit 6f3914
                    os.nice(-onice)
Packit 6f3914
                except:
Packit 6f3914
                    onice = 0
Packit 6f3914
Packit 6f3914
        logger.log(dnf.logging.DDEBUG, 'RPM transaction start.')
Packit 6f3914
        errors = self._ts.run(cb.callback, '')
Packit 6f3914
        logger.log(dnf.logging.DDEBUG, 'RPM transaction over.')
Packit 6f3914
        # ts.run() exit codes are, hmm, "creative": None means all ok, empty
Packit 6f3914
        # list means some errors happened in the transaction and non-empty
Packit 6f3914
        # list that there were errors preventing the ts from starting...
Packit 6f3914
        if self.conf.reset_nice:
Packit 6f3914
            try:
Packit 6f3914
                os.nice(onice)
Packit 6f3914
            except:
Packit 6f3914
                pass
Packit 6f3914
        dnf.util._sync_rpm_trans_with_swdb(self._ts, self._transaction)
Packit 6f3914
Packit 6f3914
        if errors is None:
Packit 6f3914
            pass
Packit 6f3914
        elif len(errors) == 0:
Packit 6f3914
            # If there is no failing element it means that some "global" error
Packit 6f3914
            # occurred (like rpm failed to obtain the transaction lock). Just pass
Packit 6f3914
            # the rpm logs on to the user and raise an Error.
Packit 6f3914
            # If there are failing elements the problem is related to those
Packit 6f3914
            # elements and the Error is raised later, after saving the failure
Packit 6f3914
            # to the history and printing out the transaction table to user.
Packit 6f3914
            failed = [el for el in self._ts if el.Failed()]
Packit 6f3914
            if not failed:
Packit 6f3914
                for msg in cb.messages():
Packit 6f3914
                    logger.critical(_('RPM: {}').format(msg))
Packit 6f3914
                msg = _('Could not run transaction.')
Packit 6f3914
                raise dnf.exceptions.Error(msg)
Packit 6f3914
        else:
Packit 6f3914
            logger.critical(_("Transaction couldn't start:"))
Packit 6f3914
            for e in errors:
Packit 6f3914
                logger.critical(ucd(e[0]))
Packit 6f3914
            if self._record_history() and not self._ts.isTsFlagSet(rpm.RPMTRANS_FLAG_TEST):
Packit 6f3914
                self.history.end(rpmdbv)
Packit 6f3914
            msg = _("Could not run transaction.")
Packit 6f3914
            raise dnf.exceptions.Error(msg)
Packit 6f3914
Packit 6f3914
        for i in ('ts_all_fn', 'ts_done_fn'):
Packit 6f3914
            if hasattr(cb, i):
Packit 6f3914
                fn = getattr(cb, i)
Packit 6f3914
                try:
Packit 6f3914
                    misc.unlink_f(fn)
Packit 6f3914
                except (IOError, OSError):
Packit 6f3914
                    msg = _('Failed to remove transaction file %s')
Packit 6f3914
                    logger.critical(msg, fn)
Packit 6f3914
Packit 6f3914
        # keep install_set status because _verify_transaction will clean it
Packit 6f3914
        self._trans_install_set = bool(self._transaction.install_set)
Packit 6f3914
Packit 6f3914
        # sync up what just happened versus what is in the rpmdb
Packit 6f3914
        if not self._ts.isTsFlagSet(rpm.RPMTRANS_FLAG_TEST):
Packit 6f3914
            self._verify_transaction(cb.verify_tsi_package)
Packit 6f3914
Packit 6f3914
        return tid
Packit 6f3914
Packit 6f3914
    def _verify_transaction(self, verify_pkg_cb=None):
Packit 6f3914
        transaction_items = [
Packit 6f3914
            tsi for tsi in self.transaction
Packit 6f3914
            if tsi.action != libdnf.transaction.TransactionItemAction_REASON_CHANGE]
Packit 6f3914
        total = len(transaction_items)
Packit 6f3914
Packit 6f3914
        def display_banner(pkg, count):
Packit 6f3914
            count += 1
Packit 6f3914
            if verify_pkg_cb is not None:
Packit 6f3914
                verify_pkg_cb(pkg, count, total)
Packit 6f3914
            return count
Packit 6f3914
Packit 6f3914
        timer = dnf.logging.Timer('verify transaction')
Packit 6f3914
        count = 0
Packit 6f3914
Packit 6f3914
        rpmdb_sack = dnf.sack.rpmdb_sack(self)
Packit 6f3914
Packit 6f3914
        # mark group packages that are installed on the system as installed in the db
Packit 6f3914
        q = rpmdb_sack.query().installed()
Packit 6f3914
        names = set([i.name for i in q])
Packit 6f3914
        for ti in self.history.group:
Packit 6f3914
            g = ti.getCompsGroupItem()
Packit 6f3914
            for p in g.getPackages():
Packit 6f3914
                if p.getName() in names:
Packit 6f3914
                    p.setInstalled(True)
Packit 6f3914
                    p.save()
Packit 6f3914
Packit 6f3914
        # TODO: installed groups in environments
Packit 6f3914
Packit 6f3914
        # Post-transaction verification is no longer needed,
Packit 6f3914
        # because DNF trusts error codes returned by RPM.
Packit 6f3914
        # Verification banner is displayed to preserve UX.
Packit 6f3914
        # TODO: drop in future DNF
Packit 6f3914
        for tsi in transaction_items:
Packit 6f3914
            count = display_banner(tsi.pkg, count)
Packit 6f3914
Packit 6f3914
        rpmdbv = rpmdb_sack._rpmdb_version()
Packit 6f3914
        self.history.end(rpmdbv)
Packit 6f3914
Packit 6f3914
        timer()
Packit 6f3914
        self._trans_success = True
Packit 6f3914
Packit 6f3914
    def _download_remote_payloads(self, payloads, drpm, progress, callback_total):
Packit 6f3914
        lock = dnf.lock.build_download_lock(self.conf.cachedir, self.conf.exit_on_lock)
Packit 6f3914
        with lock:
Packit 6f3914
            beg_download = time.time()
Packit 6f3914
            est_remote_size = sum(pload.download_size for pload in payloads)
Packit 6f3914
            total_drpm = len(
Packit 6f3914
                [payload for payload in payloads if isinstance(payload, dnf.drpm.DeltaPayload)])
Packit 6f3914
            # compatibility part for tools that do not accept total_drpms keyword
Packit 6f3914
            if progress.start.__code__.co_argcount == 4:
Packit 6f3914
                progress.start(len(payloads), est_remote_size, total_drpms=total_drpm)
Packit 6f3914
            else:
Packit 6f3914
                progress.start(len(payloads), est_remote_size)
Packit 6f3914
            errors = dnf.repo._download_payloads(payloads, drpm)
Packit 6f3914
Packit 6f3914
            if errors._irrecoverable:
Packit 6f3914
                raise dnf.exceptions.DownloadError(errors._irrecoverable)
Packit 6f3914
Packit 6f3914
            remote_size = sum(errors._bandwidth_used(pload)
Packit 6f3914
                              for pload in payloads)
Packit 6f3914
            saving = dnf.repo._update_saving((0, 0), payloads,
Packit 6f3914
                                             errors._recoverable)
Packit 6f3914
Packit 6f3914
            retries = self.conf.retries
Packit 6f3914
            forever = retries == 0
Packit 6f3914
            while errors._recoverable and (forever or retries > 0):
Packit 6f3914
                if retries > 0:
Packit 6f3914
                    retries -= 1
Packit 6f3914
Packit 6f3914
                msg = _("Some packages were not downloaded. Retrying.")
Packit 6f3914
                logger.info(msg)
Packit 6f3914
Packit 6f3914
                remaining_pkgs = [pkg for pkg in errors._recoverable]
Packit 6f3914
                payloads = \
Packit 6f3914
                    [dnf.repo._pkg2payload(pkg, progress, dnf.repo.RPMPayload)
Packit 6f3914
                     for pkg in remaining_pkgs]
Packit 6f3914
                est_remote_size = sum(pload.download_size
Packit 6f3914
                                      for pload in payloads)
Packit 6f3914
                progress.start(len(payloads), est_remote_size)
Packit 6f3914
                errors = dnf.repo._download_payloads(payloads, drpm)
Packit 6f3914
Packit 6f3914
                if errors._irrecoverable:
Packit 6f3914
                    raise dnf.exceptions.DownloadError(errors._irrecoverable)
Packit 6f3914
Packit 6f3914
                remote_size += \
Packit 6f3914
                    sum(errors._bandwidth_used(pload) for pload in payloads)
Packit 6f3914
                saving = dnf.repo._update_saving(saving, payloads, {})
Packit 6f3914
Packit 6f3914
            if errors._recoverable:
Packit 6f3914
                msg = dnf.exceptions.DownloadError.errmap2str(
Packit 6f3914
                    errors._recoverable)
Packit 6f3914
                logger.info(msg)
Packit 6f3914
Packit 6f3914
        if callback_total is not None:
Packit 6f3914
            callback_total(remote_size, beg_download)
Packit 6f3914
Packit 6f3914
        (real, full) = saving
Packit 6f3914
        if real != full:
Packit 6f3914
            if real < full:
Packit 6f3914
                msg = _("Delta RPMs reduced %.1f MB of updates to %.1f MB "
Packit 6f3914
                        "(%d.1%% saved)")
Packit 6f3914
            elif real > full:
Packit 6f3914
                msg = _("Failed Delta RPMs increased %.1f MB of updates to %.1f MB "
Packit 6f3914
                        "(%d.1%% wasted)")
Packit 6f3914
            percent = 100 - real / full * 100
Packit 6f3914
            logger.info(msg, full / 1024 ** 2, real / 1024 ** 2, percent)
Packit 6f3914
Packit 6f3914
    def download_packages(self, pkglist, progress=None, callback_total=None):
Packit 6f3914
        # :api
Packit 6f3914
        """Download the packages specified by the given list of packages.
Packit 6f3914
Packit 6f3914
        `pkglist` is a list of packages to download, `progress` is an optional
Packit 6f3914
         DownloadProgress instance, `callback_total` an optional callback to
Packit 6f3914
         output messages about the download operation.
Packit 6f3914
Packit 6f3914
        """
Packit 6f3914
        remote_pkgs, local_pkgs = self._select_remote_pkgs(pkglist)
Packit 6f3914
        if remote_pkgs:
Packit 6f3914
            if progress is None:
Packit 6f3914
                progress = dnf.callback.NullDownloadProgress()
Packit 6f3914
            drpm = dnf.drpm.DeltaInfo(self.sack.query().installed(),
Packit 6f3914
                                      progress, self.conf.deltarpm_percentage)
Packit 6f3914
            self._add_tempfiles([pkg.localPkg() for pkg in remote_pkgs])
Packit 6f3914
            payloads = [dnf.repo._pkg2payload(pkg, progress, drpm.delta_factory,
Packit 6f3914
                                              dnf.repo.RPMPayload)
Packit 6f3914
                        for pkg in remote_pkgs]
Packit 6f3914
            self._download_remote_payloads(payloads, drpm, progress, callback_total)
Packit 6f3914
Packit 6f3914
        if self.conf.destdir:
Packit 6f3914
            for pkg in local_pkgs:
Packit 6f3914
                if pkg.baseurl:
Packit 6f3914
                    location = os.path.join(pkg.baseurl.replace("file://", ""),
Packit 6f3914
                                            pkg.location.lstrip("/"))
Packit 6f3914
                else:
Packit 6f3914
                    location = os.path.join(pkg.repo.pkgdir, pkg.location.lstrip("/"))
Packit 6f3914
                shutil.copy(location, self.conf.destdir)
Packit 6f3914
Packit 6f3914
    def add_remote_rpms(self, path_list, strict=True, progress=None):
Packit 6f3914
        # :api
Packit 6f3914
        pkgs = []
Packit 6f3914
        if not path_list:
Packit 6f3914
            return pkgs
Packit 6f3914
        pkgs_error = []
Packit 6f3914
        for path in path_list:
Packit 6f3914
            if not os.path.exists(path) and '://' in path:
Packit 6f3914
                # download remote rpm to a tempfile
Packit 6f3914
                path = dnf.util._urlopen_progress(path, self.conf, progress)
Packit 6f3914
                self._add_tempfiles([path])
Packit 6f3914
            try:
Packit 6f3914
                pkgs.append(self.sack.add_cmdline_package(path))
Packit 6f3914
            except IOError as e:
Packit 6f3914
                logger.warning(e)
Packit 6f3914
                pkgs_error.append(path)
Packit 6f3914
        self._setup_excludes_includes(only_main=True)
Packit 6f3914
        if pkgs_error and strict:
Packit 6f3914
            raise IOError(_("Could not open: {}").format(' '.join(pkgs_error)))
Packit 6f3914
        return pkgs
Packit 6f3914
Packit 6f3914
    def _sig_check_pkg(self, po):
Packit 6f3914
        """Verify the GPG signature of the given package object.
Packit 6f3914
Packit 6f3914
        :param po: the package object to verify the signature of
Packit 6f3914
        :return: (result, error_string)
Packit 6f3914
           where result is::
Packit 6f3914
Packit 6f3914
              0 = GPG signature verifies ok or verification is not required.
Packit 6f3914
              1 = GPG verification failed but installation of the right GPG key
Packit 6f3914
                    might help.
Packit 6f3914
              2 = Fatal GPG verification error, give up.
Packit 6f3914
        """
Packit 6f3914
        if po._from_cmdline:
Packit 6f3914
            check = self.conf.localpkg_gpgcheck
Packit 6f3914
            hasgpgkey = 0
Packit 6f3914
        else:
Packit 6f3914
            repo = self.repos[po.repoid]
Packit 6f3914
            check = repo.gpgcheck
Packit 6f3914
            hasgpgkey = not not repo.gpgkey
Packit 6f3914
Packit 6f3914
        if check:
Packit 6f3914
            root = self.conf.installroot
Packit 6f3914
            ts = dnf.rpm.transaction.initReadOnlyTransaction(root)
Packit 6f3914
            sigresult = dnf.rpm.miscutils.checkSig(ts, po.localPkg())
Packit 6f3914
            localfn = os.path.basename(po.localPkg())
Packit 6f3914
            del ts
Packit 6f3914
            if sigresult == 0:
Packit 6f3914
                result = 0
Packit 6f3914
                msg = ''
Packit 6f3914
Packit 6f3914
            elif sigresult == 1:
Packit 6f3914
                if hasgpgkey:
Packit 6f3914
                    result = 1
Packit 6f3914
                else:
Packit 6f3914
                    result = 2
Packit 6f3914
                msg = _('Public key for %s is not installed') % localfn
Packit 6f3914
Packit 6f3914
            elif sigresult == 2:
Packit 6f3914
                result = 2
Packit 6f3914
                msg = _('Problem opening package %s') % localfn
Packit 6f3914
Packit 6f3914
            elif sigresult == 3:
Packit 6f3914
                if hasgpgkey:
Packit 6f3914
                    result = 1
Packit 6f3914
                else:
Packit 6f3914
                    result = 2
Packit 6f3914
                result = 1
Packit 6f3914
                msg = _('Public key for %s is not trusted') % localfn
Packit 6f3914
Packit 6f3914
            elif sigresult == 4:
Packit 6f3914
                result = 2
Packit 6f3914
                msg = _('Package %s is not signed') % localfn
Packit 6f3914
Packit 6f3914
        else:
Packit 6f3914
            result = 0
Packit 6f3914
            msg = ''
Packit 6f3914
Packit 6f3914
        return result, msg
Packit 6f3914
Packit 6f3914
    def _clean_packages(self, packages):
Packit 6f3914
        for fn in packages:
Packit 6f3914
            if not os.path.exists(fn):
Packit 6f3914
                continue
Packit 6f3914
            try:
Packit 6f3914
                misc.unlink_f(fn)
Packit 6f3914
            except OSError:
Packit 6f3914
                logger.warning(_('Cannot remove %s'), fn)
Packit 6f3914
                continue
Packit 6f3914
            else:
Packit 6f3914
                logger.log(dnf.logging.DDEBUG,
Packit 6f3914
                           _('%s removed'), fn)
Packit 6f3914
Packit 6f3914
    def _do_package_lists(self, pkgnarrow='all', patterns=None, showdups=None,
Packit 6f3914
                       ignore_case=False, reponame=None):
Packit 6f3914
        """Return a :class:`misc.GenericHolder` containing
Packit 6f3914
        lists of package objects.  The contents of the lists are
Packit 6f3914
        specified in various ways by the arguments.
Packit 6f3914
Packit 6f3914
        :param pkgnarrow: a string specifying which types of packages
Packit 6f3914
           lists to produces, such as updates, installed, available,
Packit 6f3914
           etc.
Packit 6f3914
        :param patterns: a list of names or wildcards specifying
Packit 6f3914
           packages to list
Packit 6f3914
        :param showdups: whether to include duplicate packages in the
Packit 6f3914
           lists
Packit 6f3914
        :param ignore_case: whether to ignore case when searching by
Packit 6f3914
           package names
Packit 6f3914
        :param reponame: limit packages list to the given repository
Packit 6f3914
        :return: a :class:`misc.GenericHolder` instance with the
Packit 6f3914
           following lists defined::
Packit 6f3914
Packit 6f3914
             available = list of packageObjects
Packit 6f3914
             installed = list of packageObjects
Packit 6f3914
             upgrades = tuples of packageObjects (updating, installed)
Packit 6f3914
             extras = list of packageObjects
Packit 6f3914
             obsoletes = tuples of packageObjects (obsoleting, installed)
Packit 6f3914
             recent = list of packageObjects
Packit 6f3914
        """
Packit 6f3914
        if showdups is None:
Packit 6f3914
            showdups = self.conf.showdupesfromrepos
Packit 6f3914
        if patterns is None:
Packit 6f3914
            return self._list_pattern(
Packit 6f3914
                pkgnarrow, patterns, showdups, ignore_case, reponame)
Packit 6f3914
Packit 6f3914
        assert not dnf.util.is_string_type(patterns)
Packit 6f3914
        list_fn = functools.partial(
Packit 6f3914
            self._list_pattern, pkgnarrow, showdups=showdups,
Packit 6f3914
            ignore_case=ignore_case, reponame=reponame)
Packit 6f3914
        if patterns is None or len(patterns) == 0:
Packit 6f3914
            return list_fn(None)
Packit 6f3914
        yghs = map(list_fn, patterns)
Packit 6f3914
        return reduce(lambda a, b: a.merge_lists(b), yghs)
Packit 6f3914
Packit 6f3914
    def _list_pattern(self, pkgnarrow, pattern, showdups, ignore_case,
Packit 6f3914
                      reponame=None):
Packit 6f3914
        def is_from_repo(package):
Packit 6f3914
            """Test whether given package originates from the repository."""
Packit 6f3914
            if reponame is None:
Packit 6f3914
                return True
Packit 6f3914
            return self.history.repo(package) == reponame
Packit 6f3914
Packit 6f3914
        def pkgs_from_repo(packages):
Packit 6f3914
            """Filter out the packages which do not originate from the repo."""
Packit 6f3914
            return (package for package in packages if is_from_repo(package))
Packit 6f3914
Packit 6f3914
        def query_for_repo(query):
Packit 6f3914
            """Filter out the packages which do not originate from the repo."""
Packit 6f3914
            if reponame is None:
Packit 6f3914
                return query
Packit 6f3914
            return query.filter(reponame=reponame)
Packit 6f3914
Packit 6f3914
        ygh = misc.GenericHolder(iter=pkgnarrow)
Packit 6f3914
Packit 6f3914
        installed = []
Packit 6f3914
        available = []
Packit 6f3914
        reinstall_available = []
Packit 6f3914
        old_available = []
Packit 6f3914
        updates = []
Packit 6f3914
        obsoletes = []
Packit 6f3914
        obsoletesTuples = []
Packit 6f3914
        recent = []
Packit 6f3914
        extras = []
Packit 6f3914
        autoremove = []
Packit 6f3914
Packit 6f3914
        # do the initial pre-selection
Packit 6f3914
        ic = ignore_case
Packit 6f3914
        q = self.sack.query()
Packit 6f3914
        if pattern is not None:
Packit 6f3914
            subj = dnf.subject.Subject(pattern, ignore_case=ic)
Packit 6f3914
            q = subj.get_best_query(self.sack, with_provides=False)
Packit 6f3914
Packit 6f3914
        # list all packages - those installed and available:
Packit 6f3914
        if pkgnarrow == 'all':
Packit 6f3914
            dinst = {}
Packit 6f3914
            ndinst = {}  # Newest versions by name.arch
Packit 6f3914
            for po in q.installed():
Packit 6f3914
                dinst[po.pkgtup] = po
Packit 6f3914
                if showdups:
Packit 6f3914
                    continue
Packit 6f3914
                key = (po.name, po.arch)
Packit 6f3914
                if key not in ndinst or po > ndinst[key]:
Packit 6f3914
                    ndinst[key] = po
Packit 6f3914
            installed = list(pkgs_from_repo(dinst.values()))
Packit 6f3914
Packit 6f3914
            avail = query_for_repo(q)
Packit 6f3914
            if not showdups:
Packit 6f3914
                avail = avail.latest()
Packit 6f3914
            for pkg in avail:
Packit 6f3914
                if showdups:
Packit 6f3914
                    if pkg.pkgtup in dinst:
Packit 6f3914
                        reinstall_available.append(pkg)
Packit 6f3914
                    else:
Packit 6f3914
                        available.append(pkg)
Packit 6f3914
                else:
Packit 6f3914
                    key = (pkg.name, pkg.arch)
Packit 6f3914
                    if pkg.pkgtup in dinst:
Packit 6f3914
                        reinstall_available.append(pkg)
Packit 6f3914
                    elif key not in ndinst or pkg.evr_gt(ndinst[key]):
Packit 6f3914
                        available.append(pkg)
Packit 6f3914
                    else:
Packit 6f3914
                        old_available.append(pkg)
Packit 6f3914
Packit 6f3914
        # produce the updates list of tuples
Packit 6f3914
        elif pkgnarrow == 'upgrades':
Packit 6f3914
            updates = query_for_repo(q).upgrades()
Packit 6f3914
            # reduce a query to security upgrades if they are specified
Packit 6f3914
            updates = self._merge_update_filters(updates)
Packit 6f3914
            # reduce a query to latest packages
Packit 6f3914
            updates = updates.latest().run()
Packit 6f3914
Packit 6f3914
        # installed only
Packit 6f3914
        elif pkgnarrow == 'installed':
Packit 6f3914
            installed = list(pkgs_from_repo(q.installed()))
Packit 6f3914
Packit 6f3914
        # available in a repository
Packit 6f3914
        elif pkgnarrow == 'available':
Packit 6f3914
            if showdups:
Packit 6f3914
                avail = query_for_repo(q).available()
Packit 6f3914
                installed_dict = q.installed()._na_dict()
Packit 6f3914
                for avail_pkg in avail:
Packit 6f3914
                    key = (avail_pkg.name, avail_pkg.arch)
Packit 6f3914
                    installed_pkgs = installed_dict.get(key, [])
Packit 6f3914
                    same_ver = [pkg for pkg in installed_pkgs
Packit 6f3914
                                if pkg.evr == avail_pkg.evr]
Packit 6f3914
                    if len(same_ver) > 0:
Packit 6f3914
                        reinstall_available.append(avail_pkg)
Packit 6f3914
                    else:
Packit 6f3914
                        available.append(avail_pkg)
Packit 6f3914
            else:
Packit 6f3914
                # we will only look at the latest versions of packages:
Packit 6f3914
                available_dict = query_for_repo(
Packit 6f3914
                    q).available().latest()._na_dict()
Packit 6f3914
                installed_dict = q.installed().latest()._na_dict()
Packit 6f3914
                for (name, arch) in available_dict:
Packit 6f3914
                    avail_pkg = available_dict[(name, arch)][0]
Packit 6f3914
                    inst_pkg = installed_dict.get((name, arch), [None])[0]
Packit 6f3914
                    if not inst_pkg or avail_pkg.evr_gt(inst_pkg):
Packit 6f3914
                        available.append(avail_pkg)
Packit 6f3914
                    elif avail_pkg.evr_eq(inst_pkg):
Packit 6f3914
                        reinstall_available.append(avail_pkg)
Packit 6f3914
                    else:
Packit 6f3914
                        old_available.append(avail_pkg)
Packit 6f3914
Packit 6f3914
        # packages to be removed by autoremove
Packit 6f3914
        elif pkgnarrow == 'autoremove':
Packit 6f3914
            autoremove_q = query_for_repo(q)._unneeded(self.history.swdb)
Packit 6f3914
            autoremove = autoremove_q.run()
Packit 6f3914
Packit 6f3914
        # not in a repo but installed
Packit 6f3914
        elif pkgnarrow == 'extras':
Packit 6f3914
            extras = [pkg for pkg in q.extras() if is_from_repo(pkg)]
Packit 6f3914
Packit 6f3914
        # obsoleting packages (and what they obsolete)
Packit 6f3914
        elif pkgnarrow == 'obsoletes':
Packit 6f3914
            inst = q.installed()
Packit 6f3914
            obsoletes = query_for_repo(
Packit 6f3914
                self.sack.query()).filter(obsoletes=inst)
Packit 6f3914
            # reduce a query to security upgrades if they are specified
Packit 6f3914
            obsoletes = self._merge_update_filters(obsoletes, warning=False)
Packit 6f3914
            obsoletesTuples = []
Packit 6f3914
            for new in obsoletes:
Packit 6f3914
                obsoleted_reldeps = new.obsoletes
Packit 6f3914
                obsoletesTuples.extend(
Packit 6f3914
                    [(new, old) for old in
Packit 6f3914
                     inst.filter(provides=obsoleted_reldeps)])
Packit 6f3914
Packit 6f3914
        # packages recently added to the repositories
Packit 6f3914
        elif pkgnarrow == 'recent':
Packit 6f3914
            avail = q.available()
Packit 6f3914
            if not showdups:
Packit 6f3914
                avail = avail.latest()
Packit 6f3914
            recent = query_for_repo(avail)._recent(self.conf.recent)
Packit 6f3914
Packit 6f3914
        ygh.installed = installed
Packit 6f3914
        ygh.available = available
Packit 6f3914
        ygh.reinstall_available = reinstall_available
Packit 6f3914
        ygh.old_available = old_available
Packit 6f3914
        ygh.updates = updates
Packit 6f3914
        ygh.obsoletes = obsoletes
Packit 6f3914
        ygh.obsoletesTuples = obsoletesTuples
Packit 6f3914
        ygh.recent = recent
Packit 6f3914
        ygh.extras = extras
Packit 6f3914
        ygh.autoremove = autoremove
Packit 6f3914
Packit 6f3914
        return ygh
Packit 6f3914
Packit 6f3914
    def _add_comps_trans(self, trans):
Packit 6f3914
        self._comps_trans += trans
Packit 6f3914
        return len(trans)
Packit 6f3914
Packit 6f3914
    def _remove_if_unneeded(self, query):
Packit 6f3914
        """
Packit 6f3914
        Mark to remove packages that are not required by any user installed package (reason group
Packit 6f3914
        or user)
Packit 6f3914
        :param query: dnf.query.Query() object
Packit 6f3914
        """
Packit 6f3914
        query = query.installed()
Packit 6f3914
        if not query:
Packit 6f3914
            return
Packit 6f3914
Packit 6f3914
        unneeded_pkgs = query._safe_to_remove(self.history.swdb, debug_solver=False)
Packit 6f3914
        unneeded_pkgs_history = query.filter(
Packit 6f3914
            pkg=[i for i in query if self.history.group.is_removable_pkg(i.name)])
Packit 6f3914
        pkg_with_dependent_pkgs = unneeded_pkgs_history.difference(unneeded_pkgs)
Packit 6f3914
Packit 6f3914
        # mark packages with dependent packages as a dependency to allow removal with dependent
Packit 6f3914
        # package
Packit 6f3914
        for pkg in pkg_with_dependent_pkgs:
Packit 6f3914
            self.history.set_reason(pkg, libdnf.transaction.TransactionItemReason_DEPENDENCY)
Packit 6f3914
        unneeded_pkgs = unneeded_pkgs.intersection(unneeded_pkgs_history)
Packit 6f3914
Packit 6f3914
        remove_packages = query.intersection(unneeded_pkgs)
Packit 6f3914
        if remove_packages:
Packit 6f3914
            for pkg in remove_packages:
Packit 6f3914
                self._goal.erase(pkg, clean_deps=self.conf.clean_requirements_on_remove)
Packit 6f3914
Packit 6f3914
    def _finalize_comps_trans(self):
Packit 6f3914
        trans = self._comps_trans
Packit 6f3914
        basearch = self.conf.substitutions['basearch']
Packit 6f3914
Packit 6f3914
        def trans_upgrade(query, remove_query, comps_pkg):
Packit 6f3914
            sltr = dnf.selector.Selector(self.sack)
Packit 6f3914
            sltr.set(pkg=query)
Packit 6f3914
            self._goal.upgrade(select=sltr)
Packit 6f3914
            return remove_query
Packit 6f3914
Packit 6f3914
        def trans_install(query, remove_query, comps_pkg, strict):
Packit 6f3914
            if self.conf.multilib_policy == "all":
Packit 6f3914
                if not comps_pkg.requires:
Packit 6f3914
                    self._install_multiarch(query, strict=strict)
Packit 6f3914
                else:
Packit 6f3914
                    # it installs only one arch for conditional packages
Packit 6f3914
                    installed_query = query.installed().apply()
Packit 6f3914
                    self._report_already_installed(installed_query)
Packit 6f3914
                    sltr = dnf.selector.Selector(self.sack)
Packit 6f3914
                    sltr.set(provides="({} if {})".format(comps_pkg.name, comps_pkg.requires))
Packit 6f3914
                    self._goal.install(select=sltr, optional=not strict)
Packit 6f3914
Packit 6f3914
            else:
Packit 6f3914
                sltr = dnf.selector.Selector(self.sack)
Packit 6f3914
                if comps_pkg.requires:
Packit 6f3914
                    sltr.set(provides="({} if {})".format(comps_pkg.name, comps_pkg.requires))
Packit 6f3914
                else:
Packit 6f3914
                    if self.conf.obsoletes:
Packit 6f3914
                        query = query.union(self.sack.query().filterm(obsoletes=query))
Packit 6f3914
                    sltr.set(pkg=query)
Packit 6f3914
                self._goal.install(select=sltr, optional=not strict)
Packit 6f3914
            return remove_query
Packit 6f3914
Packit 6f3914
        def trans_remove(query, remove_query, comps_pkg):
Packit 6f3914
            remove_query = remove_query.union(query)
Packit 6f3914
            return remove_query
Packit 6f3914
Packit 6f3914
        remove_query = self.sack.query().filterm(empty=True)
Packit 6f3914
        attr_fn = ((trans.install, functools.partial(trans_install, strict=True)),
Packit 6f3914
                   (trans.install_opt, functools.partial(trans_install, strict=False)),
Packit 6f3914
                   (trans.upgrade, trans_upgrade),
Packit 6f3914
                   (trans.remove, trans_remove))
Packit 6f3914
Packit 6f3914
        for (attr, fn) in attr_fn:
Packit 6f3914
            for comps_pkg in attr:
Packit 6f3914
                query_args = {'name': comps_pkg.name}
Packit 6f3914
                if (comps_pkg.basearchonly):
Packit 6f3914
                    query_args.update({'arch': basearch})
Packit 6f3914
                q = self.sack.query().filterm(**query_args).apply()
Packit 6f3914
                q.filterm(arch__neq="src")
Packit 6f3914
                if not q:
Packit 6f3914
                    package_string = comps_pkg.name
Packit 6f3914
                    if comps_pkg.basearchonly:
Packit 6f3914
                        package_string += '.' + basearch
Packit 6f3914
                    logger.warning(_('No match for group package "{}"').format(package_string))
Packit 6f3914
                    continue
Packit 6f3914
                remove_query = fn(q, remove_query, comps_pkg)
Packit 6f3914
                self._goal.group_members.add(comps_pkg.name)
Packit 6f3914
Packit 6f3914
        self._remove_if_unneeded(remove_query)
Packit 6f3914
Packit 6f3914
    def _build_comps_solver(self):
Packit 6f3914
        def reason_fn(pkgname):
Packit 6f3914
            q = self.sack.query().installed().filterm(name=pkgname)
Packit 6f3914
            if not q:
Packit 6f3914
                return None
Packit 6f3914
            try:
Packit 6f3914
                return self.history.rpm.get_reason(q[0])
Packit 6f3914
            except AttributeError:
Packit 6f3914
                return libdnf.transaction.TransactionItemReason_UNKNOWN
Packit 6f3914
Packit 6f3914
        return dnf.comps.Solver(self.history, self._comps, reason_fn)
Packit 6f3914
Packit 6f3914
    def environment_install(self, env_id, types, exclude=None, strict=True, exclude_groups=None):
Packit 6f3914
        # :api
Packit 6f3914
        assert dnf.util.is_string_type(env_id)
Packit 6f3914
        solver = self._build_comps_solver()
Packit 6f3914
        types = self._translate_comps_pkg_types(types)
Packit 6f3914
        trans = dnf.comps.install_or_skip(solver._environment_install,
Packit 6f3914
                                          env_id, types, exclude or set(),
Packit 6f3914
                                          strict, exclude_groups)
Packit 6f3914
        if not trans:
Packit 6f3914
            return 0
Packit 6f3914
        return self._add_comps_trans(trans)
Packit 6f3914
Packit 6f3914
    def environment_remove(self, env_id):
Packit 6f3914
        # :api
Packit 6f3914
        assert dnf.util.is_string_type(env_id)
Packit 6f3914
        solver = self._build_comps_solver()
Packit 6f3914
        trans = solver._environment_remove(env_id)
Packit 6f3914
        return self._add_comps_trans(trans)
Packit 6f3914
Packit 6f3914
    _COMPS_TRANSLATION = {
Packit 6f3914
        'default': dnf.comps.DEFAULT,
Packit 6f3914
        'mandatory': dnf.comps.MANDATORY,
Packit 6f3914
        'optional': dnf.comps.OPTIONAL,
Packit 6f3914
        'conditional': dnf.comps.CONDITIONAL
Packit 6f3914
    }
Packit 6f3914
Packit 6f3914
    @staticmethod
Packit 6f3914
    def _translate_comps_pkg_types(pkg_types):
Packit 6f3914
        ret = 0
Packit 6f3914
        for (name, enum) in Base._COMPS_TRANSLATION.items():
Packit 6f3914
            if name in pkg_types:
Packit 6f3914
                ret |= enum
Packit 6f3914
        return ret
Packit 6f3914
Packit 6f3914
    def group_install(self, grp_id, pkg_types, exclude=None, strict=True):
Packit 6f3914
        # :api
Packit 6f3914
        """Installs packages of selected group
Packit 6f3914
        :param exclude: list of package name glob patterns
Packit 6f3914
            that will be excluded from install set
Packit 6f3914
        :param strict: boolean indicating whether group packages that
Packit 6f3914
            exist but are non-installable due to e.g. dependency
Packit 6f3914
            issues should be skipped (False) or cause transaction to
Packit 6f3914
            fail to resolve (True)
Packit 6f3914
        """
Packit 6f3914
        def _pattern_to_pkgname(pattern):
Packit 6f3914
            if dnf.util.is_glob_pattern(pattern):
Packit 6f3914
                q = self.sack.query().filterm(name__glob=pattern)
Packit 6f3914
                return map(lambda p: p.name, q)
Packit 6f3914
            else:
Packit 6f3914
                return (pattern,)
Packit 6f3914
Packit 6f3914
        assert dnf.util.is_string_type(grp_id)
Packit 6f3914
        exclude_pkgnames = None
Packit 6f3914
        if exclude:
Packit 6f3914
            nested_excludes = [_pattern_to_pkgname(p) for p in exclude]
Packit 6f3914
            exclude_pkgnames = itertools.chain.from_iterable(nested_excludes)
Packit 6f3914
Packit 6f3914
        solver = self._build_comps_solver()
Packit 6f3914
        pkg_types = self._translate_comps_pkg_types(pkg_types)
Packit 6f3914
        trans = dnf.comps.install_or_skip(solver._group_install,
Packit 6f3914
                                          grp_id, pkg_types, exclude_pkgnames,
Packit 6f3914
                                          strict)
Packit 6f3914
        if not trans:
Packit 6f3914
            return 0
Packit 6f3914
        if strict:
Packit 6f3914
            instlog = trans.install
Packit 6f3914
        else:
Packit 6f3914
            instlog = trans.install_opt
Packit 6f3914
        logger.debug(_("Adding packages from group '%s': %s"),
Packit 6f3914
                     grp_id, instlog)
Packit 6f3914
        return self._add_comps_trans(trans)
Packit 6f3914
Packit 6f3914
    def env_group_install(self, patterns, types, strict=True, exclude=None, exclude_groups=None):
Packit 6f3914
        q = CompsQuery(self.comps, self.history, CompsQuery.ENVIRONMENTS | CompsQuery.GROUPS,
Packit 6f3914
                       CompsQuery.AVAILABLE)
Packit 6f3914
        cnt = 0
Packit 6f3914
        done = True
Packit 6f3914
        for pattern in patterns:
Packit 6f3914
            try:
Packit 6f3914
                res = q.get(pattern)
Packit 6f3914
            except dnf.exceptions.CompsError as err:
Packit 6f3914
                logger.error(ucd(err))
Packit 6f3914
                done = False
Packit 6f3914
                continue
Packit 6f3914
            for group_id in res.groups:
Packit 6f3914
                if not exclude_groups or group_id not in exclude_groups:
Packit 6f3914
                    cnt += self.group_install(group_id, types, exclude=exclude, strict=strict)
Packit 6f3914
            for env_id in res.environments:
Packit 6f3914
                cnt += self.environment_install(env_id, types, exclude=exclude, strict=strict,
Packit 6f3914
                                                exclude_groups=exclude_groups)
Packit 6f3914
        if not done and strict:
Packit 6f3914
            raise dnf.exceptions.Error(_('Nothing to do.'))
Packit 6f3914
        return cnt
Packit 6f3914
Packit 6f3914
    def group_remove(self, grp_id):
Packit 6f3914
        # :api
Packit 6f3914
        assert dnf.util.is_string_type(grp_id)
Packit 6f3914
        solver = self._build_comps_solver()
Packit 6f3914
        trans = solver._group_remove(grp_id)
Packit 6f3914
        return self._add_comps_trans(trans)
Packit 6f3914
Packit 6f3914
    def env_group_remove(self, patterns):
Packit 6f3914
        q = CompsQuery(self.comps, self.history,
Packit 6f3914
                       CompsQuery.ENVIRONMENTS | CompsQuery.GROUPS,
Packit 6f3914
                       CompsQuery.INSTALLED)
Packit 6f3914
        try:
Packit 6f3914
            res = q.get(*patterns)
Packit 6f3914
        except dnf.exceptions.CompsError as err:
Packit 6f3914
            logger.error("Warning: %s", ucd(err))
Packit 6f3914
            raise dnf.exceptions.Error(_('No groups marked for removal.'))
Packit 6f3914
        cnt = 0
Packit 6f3914
        for env in res.environments:
Packit 6f3914
            cnt += self.environment_remove(env)
Packit 6f3914
        for grp in res.groups:
Packit 6f3914
            cnt += self.group_remove(grp)
Packit 6f3914
        return cnt
Packit 6f3914
Packit 6f3914
    def env_group_upgrade(self, patterns):
Packit 6f3914
        q = CompsQuery(self.comps, self.history,
Packit 6f3914
                       CompsQuery.GROUPS | CompsQuery.ENVIRONMENTS,
Packit 6f3914
                       CompsQuery.INSTALLED)
Packit 6f3914
        cnt = 0
Packit 6f3914
        done = True
Packit 6f3914
        for pattern in patterns:
Packit 6f3914
            try:
Packit 6f3914
                res = q.get(pattern)
Packit 6f3914
            except dnf.exceptions.CompsError as err:
Packit 6f3914
                logger.error(ucd(err))
Packit 6f3914
                done = False
Packit 6f3914
                continue
Packit 6f3914
            for env in res.environments:
Packit 6f3914
                try:
Packit 6f3914
                    cnt += self.environment_upgrade(env)
Packit 6f3914
                except dnf.exceptions.CompsError as err:
Packit 6f3914
                    logger.error(ucd(err))
Packit 6f3914
                    continue
Packit 6f3914
            for grp in res.groups:
Packit 6f3914
                try:
Packit 6f3914
                    cnt += self.group_upgrade(grp)
Packit 6f3914
                except dnf.exceptions.CompsError as err:
Packit 6f3914
                    logger.error(ucd(err))
Packit 6f3914
                    continue
Packit 6f3914
        if not done:
Packit 6f3914
            raise dnf.exceptions.Error(_('Nothing to do.'))
Packit 6f3914
        if not cnt:
Packit 6f3914
            msg = _('No group marked for upgrade.')
Packit 6f3914
            raise dnf.cli.CliError(msg)
Packit 6f3914
Packit 6f3914
    def environment_upgrade(self, env_id):
Packit 6f3914
        # :api
Packit 6f3914
        assert dnf.util.is_string_type(env_id)
Packit 6f3914
        solver = self._build_comps_solver()
Packit 6f3914
        trans = solver._environment_upgrade(env_id)
Packit 6f3914
        return self._add_comps_trans(trans)
Packit 6f3914
Packit 6f3914
    def group_upgrade(self, grp_id):
Packit 6f3914
        # :api
Packit 6f3914
        assert dnf.util.is_string_type(grp_id)
Packit 6f3914
        solver = self._build_comps_solver()
Packit 6f3914
        trans = solver._group_upgrade(grp_id)
Packit 6f3914
        return self._add_comps_trans(trans)
Packit 6f3914
Packit 6f3914
    def _gpg_key_check(self):
Packit 6f3914
        """Checks for the presence of GPG keys in the rpmdb.
Packit 6f3914
Packit 6f3914
        :return: 0 if there are no GPG keys in the rpmdb, and 1 if
Packit 6f3914
           there are keys
Packit 6f3914
        """
Packit 6f3914
        gpgkeyschecked = self.conf.cachedir + '/.gpgkeyschecked.yum'
Packit 6f3914
        if os.path.exists(gpgkeyschecked):
Packit 6f3914
            return 1
Packit 6f3914
Packit 6f3914
        installroot = self.conf.installroot
Packit 6f3914
        myts = dnf.rpm.transaction.initReadOnlyTransaction(root=installroot)
Packit 6f3914
        myts.pushVSFlags(~(rpm._RPMVSF_NOSIGNATURES | rpm._RPMVSF_NODIGESTS))
Packit 6f3914
        idx = myts.dbMatch('name', 'gpg-pubkey')
Packit 6f3914
        keys = len(idx)
Packit 6f3914
        del idx
Packit 6f3914
        del myts
Packit 6f3914
Packit 6f3914
        if keys == 0:
Packit 6f3914
            return 0
Packit 6f3914
        else:
Packit 6f3914
            mydir = os.path.dirname(gpgkeyschecked)
Packit 6f3914
            if not os.path.exists(mydir):
Packit 6f3914
                os.makedirs(mydir)
Packit 6f3914
Packit 6f3914
            fo = open(gpgkeyschecked, 'w')
Packit 6f3914
            fo.close()
Packit 6f3914
            del fo
Packit 6f3914
            return 1
Packit 6f3914
Packit 6f3914
    def _install_multiarch(self, query, reponame=None, strict=True):
Packit 6f3914
        already_inst, available = self._query_matches_installed(query)
Packit 6f3914
        self._report_already_installed(already_inst)
Packit 6f3914
        for packages in available:
Packit 6f3914
            sltr = dnf.selector.Selector(self.sack)
Packit 6f3914
            q = self.sack.query().filterm(pkg=packages)
Packit 6f3914
            if self.conf.obsoletes:
Packit 6f3914
                q = q.union(self.sack.query().filterm(obsoletes=q))
Packit 6f3914
            sltr = sltr.set(pkg=q)
Packit 6f3914
            if reponame is not None:
Packit 6f3914
                sltr = sltr.set(reponame=reponame)
Packit 6f3914
            self._goal.install(select=sltr, optional=(not strict))
Packit 6f3914
        return len(available)
Packit 6f3914
Packit 6f3914
    def _categorize_specs(self, install, exclude):
Packit 6f3914
        """
Packit 6f3914
        Categorize :param install and :param exclude list into two groups each (packages and groups)
Packit 6f3914
Packit 6f3914
        :param install: list of specs, whether packages ('foo') or groups/modules ('@bar')
Packit 6f3914
        :param exclude: list of specs, whether packages ('foo') or groups/modules ('@bar')
Packit 6f3914
        :return: categorized install and exclude specs (stored in argparse.Namespace class)
Packit 6f3914
Packit 6f3914
        To access packages use: specs.pkg_specs,
Packit 6f3914
        to access groups use: specs.grp_specs
Packit 6f3914
        """
Packit 6f3914
        install_specs = argparse.Namespace()
Packit 6f3914
        exclude_specs = argparse.Namespace()
Packit 6f3914
        _parse_specs(install_specs, install)
Packit 6f3914
        _parse_specs(exclude_specs, exclude)
Packit 6f3914
Packit 6f3914
        return install_specs, exclude_specs
Packit 6f3914
Packit 6f3914
    def _exclude_package_specs(self, exclude_specs):
Packit 6f3914
        glob_excludes = [exclude for exclude in exclude_specs.pkg_specs
Packit 6f3914
                         if dnf.util.is_glob_pattern(exclude)]
Packit 6f3914
        excludes = [exclude for exclude in exclude_specs.pkg_specs
Packit 6f3914
                    if exclude not in glob_excludes]
Packit 6f3914
Packit 6f3914
        exclude_query = self.sack.query().filter(name=excludes)
Packit 6f3914
        glob_exclude_query = self.sack.query().filter(name__glob=glob_excludes)
Packit 6f3914
Packit 6f3914
        self.sack.add_excludes(exclude_query)
Packit 6f3914
        self.sack.add_excludes(glob_exclude_query)
Packit 6f3914
Packit 6f3914
    def _expand_groups(self, group_specs):
Packit 6f3914
        groups = set()
Packit 6f3914
        q = CompsQuery(self.comps, self.history,
Packit 6f3914
                       CompsQuery.ENVIRONMENTS | CompsQuery.GROUPS,
Packit 6f3914
                       CompsQuery.AVAILABLE | CompsQuery.INSTALLED)
Packit 6f3914
Packit 6f3914
        for pattern in group_specs:
Packit 6f3914
            try:
Packit 6f3914
                res = q.get(pattern)
Packit 6f3914
            except dnf.exceptions.CompsError as err:
Packit 6f3914
                logger.error("Warning: Module or %s", ucd(err))
Packit 6f3914
                continue
Packit 6f3914
Packit 6f3914
            groups.update(res.groups)
Packit 6f3914
            groups.update(res.environments)
Packit 6f3914
Packit 6f3914
            for environment_id in res.environments:
Packit 6f3914
                environment = self.comps._environment_by_id(environment_id)
Packit 6f3914
                for group in environment.groups_iter():
Packit 6f3914
                    groups.add(group.id)
Packit 6f3914
Packit 6f3914
        return list(groups)
Packit 6f3914
Packit 6f3914
    def _install_groups(self, group_specs, excludes, skipped, strict=True):
Packit 6f3914
        for group_spec in group_specs:
Packit 6f3914
            try:
Packit 6f3914
                types = self.conf.group_package_types
Packit 6f3914
Packit 6f3914
                if '/' in group_spec:
Packit 6f3914
                    split = group_spec.split('/')
Packit 6f3914
                    group_spec = split[0]
Packit 6f3914
                    types = split[1].split(',')
Packit 6f3914
Packit 6f3914
                self.env_group_install([group_spec], types, strict, excludes.pkg_specs,
Packit 6f3914
                                       excludes.grp_specs)
Packit 6f3914
            except dnf.exceptions.Error:
Packit 6f3914
                skipped.append("@" + group_spec)
Packit 6f3914
Packit 6f3914
    def install_specs(self, install, exclude=None, reponame=None, strict=True, forms=None):
Packit 6f3914
        # :api
Packit 6f3914
        if exclude is None:
Packit 6f3914
            exclude = []
Packit 6f3914
        no_match_group_specs = []
Packit 6f3914
        error_group_specs = []
Packit 6f3914
        no_match_pkg_specs = []
Packit 6f3914
        error_pkg_specs = []
Packit 6f3914
        install_specs, exclude_specs = self._categorize_specs(install, exclude)
Packit 6f3914
Packit 6f3914
        self._exclude_package_specs(exclude_specs)
Packit 6f3914
        for spec in install_specs.pkg_specs:
Packit 6f3914
            try:
Packit 6f3914
                self.install(spec, reponame=reponame, strict=strict, forms=forms)
Packit 6f3914
            except dnf.exceptions.MarkingError as e:
Packit 6f3914
                logger.error(str(e))
Packit 6f3914
                no_match_pkg_specs.append(spec)
Packit 6f3914
        no_match_module_specs = []
Packit 6f3914
        module_depsolv_errors = ()
Packit 6f3914
        if WITH_MODULES and install_specs.grp_specs:
Packit 6f3914
            try:
Packit 6f3914
                module_base = dnf.module.module_base.ModuleBase(self)
Packit 6f3914
                module_base.install(install_specs.grp_specs, strict)
Packit 6f3914
            except dnf.exceptions.MarkingErrors as e:
Packit 6f3914
                if e.no_match_group_specs:
Packit 6f3914
                    for e_spec in e.no_match_group_specs:
Packit 6f3914
                        no_match_module_specs.append(e_spec)
Packit 6f3914
                if e.error_group_specs:
Packit 6f3914
                    for e_spec in e.error_group_specs:
Packit 6f3914
                        error_group_specs.append("@" + e_spec)
Packit 6f3914
                module_depsolv_errors = e.module_depsolv_errors
Packit 6f3914
Packit 6f3914
        else:
Packit 6f3914
            no_match_module_specs = install_specs.grp_specs
Packit 6f3914
Packit 6f3914
        if no_match_module_specs:
Packit 6f3914
            self.read_comps(arch_filter=True)
Packit 6f3914
            exclude_specs.grp_specs = self._expand_groups(exclude_specs.grp_specs)
Packit 6f3914
            self._install_groups(no_match_module_specs, exclude_specs, no_match_group_specs, strict)
Packit 6f3914
Packit 6f3914
        if no_match_group_specs or error_group_specs or no_match_pkg_specs or error_pkg_specs \
Packit 6f3914
                or module_depsolv_errors:
Packit 6f3914
            raise dnf.exceptions.MarkingErrors(no_match_group_specs=no_match_group_specs,
Packit 6f3914
                                               error_group_specs=error_group_specs,
Packit 6f3914
                                               no_match_pkg_specs=no_match_pkg_specs,
Packit 6f3914
                                               error_pkg_specs=error_pkg_specs,
Packit 6f3914
                                               module_depsolv_errors=module_depsolv_errors)
Packit 6f3914
Packit 6f3914
    def install(self, pkg_spec, reponame=None, strict=True, forms=None):
Packit 6f3914
        # :api
Packit 6f3914
        """Mark package(s) given by pkg_spec and reponame for installation."""
Packit 6f3914
Packit 6f3914
        subj = dnf.subject.Subject(pkg_spec)
Packit 6f3914
        solution = subj.get_best_solution(self.sack, forms=forms, with_src=False)
Packit 6f3914
Packit 6f3914
        if self.conf.multilib_policy == "all" or subj._is_arch_specified(solution):
Packit 6f3914
            q = solution['query']
Packit 6f3914
            if reponame is not None:
Packit 6f3914
                q.filterm(reponame=reponame)
Packit 6f3914
            if not q:
Packit 6f3914
                self._raise_package_not_found_error(pkg_spec, forms, reponame)
Packit 6f3914
            return self._install_multiarch(q, reponame=reponame, strict=strict)
Packit 6f3914
Packit 6f3914
        elif self.conf.multilib_policy == "best":
Packit 6f3914
            sltrs = subj._get_best_selectors(self,
Packit 6f3914
                                             forms=forms,
Packit 6f3914
                                             obsoletes=self.conf.obsoletes,
Packit 6f3914
                                             reponame=reponame,
Packit 6f3914
                                             reports=True,
Packit 6f3914
                                             solution=solution)
Packit 6f3914
            if not sltrs:
Packit 6f3914
                self._raise_package_not_found_error(pkg_spec, forms, reponame)
Packit 6f3914
Packit 6f3914
            for sltr in sltrs:
Packit 6f3914
                self._goal.install(select=sltr, optional=(not strict))
Packit 6f3914
            return 1
Packit 6f3914
        return 0
Packit 6f3914
Packit 6f3914
    def package_downgrade(self, pkg, strict=False):
Packit 6f3914
        # :api
Packit 6f3914
        if pkg._from_system:
Packit 6f3914
            msg = 'downgrade_package() for an installed package.'
Packit 6f3914
            raise NotImplementedError(msg)
Packit 6f3914
Packit 6f3914
        q = self.sack.query().installed().filterm(name=pkg.name, arch=[pkg.arch, "noarch"])
Packit 6f3914
        if not q:
Packit 6f3914
            msg = _("Package %s not installed, cannot downgrade it.")
Packit 6f3914
            logger.warning(msg, pkg.name)
Packit 6f3914
            raise dnf.exceptions.MarkingError(_('No match for argument: %s') % pkg.location, pkg.name)
Packit 6f3914
        elif sorted(q)[0] > pkg:
Packit 6f3914
            sltr = dnf.selector.Selector(self.sack)
Packit 6f3914
            sltr.set(pkg=[pkg])
Packit 6f3914
            self._goal.install(select=sltr, optional=(not strict))
Packit 6f3914
            return 1
Packit 6f3914
        else:
Packit 6f3914
            msg = _("Package %s of lower version already installed, "
Packit 6f3914
                    "cannot downgrade it.")
Packit 6f3914
            logger.warning(msg, pkg.name)
Packit 6f3914
            return 0
Packit 6f3914
Packit 6f3914
    def package_install(self, pkg, strict=True):
Packit 6f3914
        # :api
Packit 6f3914
        q = self.sack.query()._nevra(pkg.name, pkg.evr, pkg.arch)
Packit 6f3914
        already_inst, available = self._query_matches_installed(q)
Packit 6f3914
        if pkg in already_inst:
Packit 6f3914
            self._report_already_installed([pkg])
Packit 6f3914
        elif pkg not in itertools.chain.from_iterable(available):
Packit 6f3914
            raise dnf.exceptions.PackageNotFoundError(_('No match for argument: %s'), pkg.location)
Packit 6f3914
        else:
Packit 6f3914
            sltr = dnf.selector.Selector(self.sack)
Packit 6f3914
            sltr.set(pkg=[pkg])
Packit 6f3914
            self._goal.install(select=sltr, optional=(not strict))
Packit 6f3914
        return 1
Packit 6f3914
Packit 6f3914
    def package_reinstall(self, pkg):
Packit 6f3914
        if self.sack.query().installed().filterm(name=pkg.name, evr=pkg.evr, arch=pkg.arch):
Packit 6f3914
            self._goal.install(pkg)
Packit 6f3914
            return 1
Packit 6f3914
        msg = _("Package %s not installed, cannot reinstall it.")
Packit 6f3914
        logger.warning(msg, str(pkg))
Packit 6f3914
        raise dnf.exceptions.MarkingError(_('No match for argument: %s') % pkg.location, pkg.name)
Packit 6f3914
Packit 6f3914
    def package_remove(self, pkg):
Packit 6f3914
        self._goal.erase(pkg)
Packit 6f3914
        return 1
Packit 6f3914
Packit 6f3914
    def package_upgrade(self, pkg):
Packit 6f3914
        # :api
Packit 6f3914
        if pkg._from_system:
Packit 6f3914
            msg = 'upgrade_package() for an installed package.'
Packit 6f3914
            raise NotImplementedError(msg)
Packit 6f3914
Packit 6f3914
        if pkg.arch == 'src':
Packit 6f3914
            msg = _("File %s is a source package and cannot be updated, ignoring.")
Packit 6f3914
            logger.info(msg, pkg.location)
Packit 6f3914
            return 0
Packit 6f3914
Packit 6f3914
        q = self.sack.query().installed().filterm(name=pkg.name, arch=[pkg.arch, "noarch"])
Packit 6f3914
        if not q:
Packit 6f3914
            msg = _("Package %s not installed, cannot update it.")
Packit 6f3914
            logger.warning(msg, pkg.name)
Packit 6f3914
            raise dnf.exceptions.MarkingError(_('No match for argument: %s') % pkg.location, pkg.name)
Packit 6f3914
        elif sorted(q)[-1] < pkg:
Packit 6f3914
            sltr = dnf.selector.Selector(self.sack)
Packit 6f3914
            sltr.set(pkg=[pkg])
Packit 6f3914
            self._goal.upgrade(select=sltr)
Packit 6f3914
            return 1
Packit 6f3914
        else:
Packit 6f3914
            msg = _("The same or higher version of %s is already installed, "
Packit 6f3914
                    "cannot update it.")
Packit 6f3914
            logger.warning(msg, pkg.name)
Packit 6f3914
            return 0
Packit 6f3914
Packit 6f3914
    def _upgrade_internal(self, query, obsoletes, reponame, pkg_spec=None):
Packit b53504
        installed_all = self.sack.query().installed()
Packit b53504
        q = query.intersection(self.sack.query().filterm(name=[pkg.name for pkg in installed_all]))
Packit b53504
        installed_query = q.installed()
Packit 6f3914
        if obsoletes:
Packit 6f3914
            obsoletes = self.sack.query().available().filterm(
Packit b53504
                obsoletes=installed_query.union(q.upgrades()))
Packit 6f3914
            # add obsoletes into transaction
Packit 6f3914
            q = q.union(obsoletes)
Packit 6f3914
        if reponame is not None:
Packit 6f3914
            q.filterm(reponame=reponame)
Packit 6f3914
        q = self._merge_update_filters(q, pkg_spec=pkg_spec)
Packit 6f3914
        if q:
Packit b53504
            q = q.available().union(installed_query.latest())
Packit 6f3914
            sltr = dnf.selector.Selector(self.sack)
Packit 6f3914
            sltr.set(pkg=q)
Packit 6f3914
            self._goal.upgrade(select=sltr)
Packit 6f3914
        return 1
Packit 6f3914
Packit 6f3914
Packit 6f3914
    def upgrade(self, pkg_spec, reponame=None):
Packit 6f3914
        # :api
Packit 6f3914
        subj = dnf.subject.Subject(pkg_spec)
Packit 6f3914
        solution = subj.get_best_solution(self.sack)
Packit 6f3914
        q = solution["query"]
Packit 6f3914
        if q:
Packit 6f3914
            wildcard = dnf.util.is_glob_pattern(pkg_spec)
Packit 6f3914
            # wildcard shouldn't print not installed packages
Packit 6f3914
            # only solution with nevra.name provide packages with same name
Packit 6f3914
            if not wildcard and solution['nevra'] and solution['nevra'].name:
Packit 6f3914
                installed = self.sack.query().installed()
Packit 6f3914
                pkg_name = solution['nevra'].name
Packit 6f3914
                installed.filterm(name=pkg_name).apply()
Packit 6f3914
                if not installed:
Packit 6f3914
                    msg = _('Package %s available, but not installed.')
Packit 6f3914
                    logger.warning(msg, pkg_name)
Packit 6f3914
                    raise dnf.exceptions.PackagesNotInstalledError(
Packit 6f3914
                        _('No match for argument: %s') % pkg_spec, pkg_spec)
Packit 6f3914
                if solution['nevra'].arch and not dnf.util.is_glob_pattern(solution['nevra'].arch):
Packit 6f3914
                    if not installed.filter(arch=solution['nevra'].arch):
Packit 6f3914
                        msg = _('Package %s available, but installed for different architecture.')
Packit 6f3914
                        logger.warning(msg, "{}.{}".format(pkg_name, solution['nevra'].arch))
Packit 6f3914
            obsoletes = self.conf.obsoletes and solution['nevra'] \
Packit 6f3914
                        and solution['nevra'].has_just_name()
Packit 6f3914
            return self._upgrade_internal(q, obsoletes, reponame, pkg_spec)
Packit 6f3914
        raise dnf.exceptions.MarkingError(_('No match for argument: %s') % pkg_spec, pkg_spec)
Packit 6f3914
Packit 6f3914
    def upgrade_all(self, reponame=None):
Packit 6f3914
        # :api
Packit 6f3914
        # provide only available packages to solver to trigger targeted upgrade
Packit 6f3914
        # possibilities will be ignored
Packit 6f3914
        # usage of selected packages will unify dnf behavior with other upgrade functions
Packit 6f3914
        return self._upgrade_internal(
Packit 6f3914
            self.sack.query(), self.conf.obsoletes, reponame, pkg_spec=None)
Packit 6f3914
Packit 6f3914
    def distro_sync(self, pkg_spec=None):
Packit 6f3914
        if pkg_spec is None:
Packit 6f3914
            self._goal.distupgrade_all()
Packit 6f3914
        else:
Packit 6f3914
            subject = dnf.subject.Subject(pkg_spec)
Packit 6f3914
            solution = subject.get_best_solution(self.sack, with_src=False)
Packit 6f3914
            solution["query"].filterm(reponame__neq=hawkey.SYSTEM_REPO_NAME)
Packit 6f3914
            sltrs = subject._get_best_selectors(self, solution=solution,
Packit 6f3914
                                                obsoletes=self.conf.obsoletes, reports=True)
Packit 6f3914
            if not sltrs:
Packit 6f3914
                logger.info(_('No package %s installed.'), pkg_spec)
Packit 6f3914
                return 0
Packit 6f3914
            for sltr in sltrs:
Packit 6f3914
                self._goal.distupgrade(select=sltr)
Packit 6f3914
        return 1
Packit 6f3914
Packit 6f3914
    def autoremove(self, forms=None, pkg_specs=None, grp_specs=None, filenames=None):
Packit 6f3914
        # :api
Packit 6f3914
        """Removes all 'leaf' packages from the system that were originally
Packit 6f3914
        installed as dependencies of user-installed packages but which are
Packit 6f3914
        no longer required by any such package."""
Packit 6f3914
Packit 6f3914
        if any([grp_specs, pkg_specs, filenames]):
Packit 6f3914
            pkg_specs += filenames
Packit 6f3914
            done = False
Packit 6f3914
            # Remove groups.
Packit 6f3914
            if grp_specs and forms:
Packit 6f3914
                for grp_spec in grp_specs:
Packit 6f3914
                    msg = _('Not a valid form: %s')
Packit 6f3914
                    logger.warning(msg, grp_spec)
Packit 6f3914
            elif grp_specs:
Packit 6f3914
                self.read_comps(arch_filter=True)
Packit 6f3914
                if self.env_group_remove(grp_specs):
Packit 6f3914
                    done = True
Packit 6f3914
Packit 6f3914
            for pkg_spec in pkg_specs:
Packit 6f3914
                try:
Packit 6f3914
                    self.remove(pkg_spec, forms=forms)
Packit 6f3914
                except dnf.exceptions.MarkingError as e:
Packit 6f3914
                    logger.info(str(e))
Packit 6f3914
                else:
Packit 6f3914
                    done = True
Packit 6f3914
Packit 6f3914
            if not done:
Packit 6f3914
                logger.warning(_('No packages marked for removal.'))
Packit 6f3914
Packit 6f3914
        else:
Packit 6f3914
            pkgs = self.sack.query()._unneeded(self.history.swdb,
Packit 6f3914
                                               debug_solver=self.conf.debug_solver)
Packit 6f3914
            for pkg in pkgs:
Packit 6f3914
                self.package_remove(pkg)
Packit 6f3914
Packit 6f3914
    def remove(self, pkg_spec, reponame=None, forms=None):
Packit 6f3914
        # :api
Packit 6f3914
        """Mark the specified package for removal."""
Packit 6f3914
Packit 6f3914
        matches = dnf.subject.Subject(pkg_spec).get_best_query(self.sack, forms=forms)
Packit 6f3914
        installed = [
Packit 6f3914
            pkg for pkg in matches.installed()
Packit 6f3914
            if reponame is None or
Packit 6f3914
            self.history.repo(pkg) == reponame]
Packit 6f3914
        if not installed:
Packit 6f3914
            self._raise_package_not_installed_error(pkg_spec, forms, reponame)
Packit 6f3914
Packit 6f3914
        clean_deps = self.conf.clean_requirements_on_remove
Packit 6f3914
        for pkg in installed:
Packit 6f3914
            self._goal.erase(pkg, clean_deps=clean_deps)
Packit 6f3914
        return len(installed)
Packit 6f3914
Packit 6f3914
    def reinstall(self, pkg_spec, old_reponame=None, new_reponame=None,
Packit 6f3914
                  new_reponame_neq=None, remove_na=False):
Packit 6f3914
        subj = dnf.subject.Subject(pkg_spec)
Packit 6f3914
        q = subj.get_best_query(self.sack)
Packit 6f3914
        installed_pkgs = [
Packit 6f3914
            pkg for pkg in q.installed()
Packit 6f3914
            if old_reponame is None or
Packit 6f3914
            self.history.repo(pkg) == old_reponame]
Packit 6f3914
Packit 6f3914
        available_q = q.available()
Packit 6f3914
        if new_reponame is not None:
Packit 6f3914
            available_q.filterm(reponame=new_reponame)
Packit 6f3914
        if new_reponame_neq is not None:
Packit 6f3914
            available_q.filterm(reponame__neq=new_reponame_neq)
Packit 6f3914
        available_nevra2pkg = dnf.query._per_nevra_dict(available_q)
Packit 6f3914
Packit 6f3914
        if not installed_pkgs:
Packit 6f3914
            raise dnf.exceptions.PackagesNotInstalledError(
Packit 6f3914
                'no package matched', pkg_spec, available_nevra2pkg.values())
Packit 6f3914
Packit 6f3914
        cnt = 0
Packit 6f3914
        clean_deps = self.conf.clean_requirements_on_remove
Packit 6f3914
        for installed_pkg in installed_pkgs:
Packit 6f3914
            try:
Packit 6f3914
                available_pkg = available_nevra2pkg[ucd(installed_pkg)]
Packit 6f3914
            except KeyError:
Packit 6f3914
                if not remove_na:
Packit 6f3914
                    continue
Packit 6f3914
                self._goal.erase(installed_pkg, clean_deps=clean_deps)
Packit 6f3914
            else:
Packit 6f3914
                self._goal.install(available_pkg)
Packit 6f3914
            cnt += 1
Packit 6f3914
Packit 6f3914
        if cnt == 0:
Packit 6f3914
            raise dnf.exceptions.PackagesNotAvailableError(
Packit 6f3914
                'no package matched', pkg_spec, installed_pkgs)
Packit 6f3914
Packit 6f3914
        return cnt
Packit 6f3914
Packit 6f3914
    def downgrade(self, pkg_spec):
Packit 6f3914
        # :api
Packit 6f3914
        """Mark a package to be downgraded.
Packit 6f3914
Packit 6f3914
        This is equivalent to first removing the currently installed package,
Packit 6f3914
        and then installing an older version.
Packit 6f3914
Packit 6f3914
        """
Packit 6f3914
        return self.downgrade_to(pkg_spec)
Packit 6f3914
Packit 6f3914
    def downgrade_to(self, pkg_spec, strict=False):
Packit 6f3914
        """Downgrade to specific version if specified otherwise downgrades
Packit 6f3914
        to one version lower than the package installed.
Packit 6f3914
        """
Packit 6f3914
        subj = dnf.subject.Subject(pkg_spec)
Packit 6f3914
        q = subj.get_best_query(self.sack)
Packit 6f3914
        if not q:
Packit 6f3914
            msg = _('No match for argument: %s') % pkg_spec
Packit 6f3914
            raise dnf.exceptions.PackageNotFoundError(msg, pkg_spec)
Packit 6f3914
        done = 0
Packit 6f3914
        available_pkgs = q.available()
Packit 6f3914
        available_pkg_names = list(available_pkgs._name_dict().keys())
Packit 6f3914
        q_installed = self.sack.query().installed().filterm(name=available_pkg_names)
Packit 6f3914
        if len(q_installed) == 0:
Packit 6f3914
            msg = _('Packages for argument %s available, but not installed.') % pkg_spec
Packit 6f3914
            raise dnf.exceptions.PackagesNotInstalledError(msg, pkg_spec, available_pkgs)
Packit 6f3914
        for pkg_name in q_installed._name_dict().keys():
Packit 6f3914
            downgrade_pkgs = available_pkgs.downgrades().filter(name=pkg_name)
Packit 6f3914
            if not downgrade_pkgs:
Packit 6f3914
                msg = _("Package %s of lowest version already installed, cannot downgrade it.")
Packit 6f3914
                logger.warning(msg, pkg_name)
Packit 6f3914
                continue
Packit 6f3914
            sltr = dnf.selector.Selector(self.sack)
Packit 6f3914
            sltr.set(pkg=downgrade_pkgs)
Packit 6f3914
            self._goal.install(select=sltr, optional=(not strict))
Packit 6f3914
            done = 1
Packit 6f3914
        return done
Packit 6f3914
Packit 6f3914
    def provides(self, provides_spec):
Packit 6f3914
        providers = self.sack.query().filterm(file__glob=provides_spec)
Packit 6f3914
        if providers:
Packit 6f3914
            return providers, [provides_spec]
Packit 6f3914
        providers = dnf.query._by_provides(self.sack, provides_spec)
Packit 6f3914
        if providers:
Packit 6f3914
            return providers, [provides_spec]
Packit 6f3914
        if provides_spec.startswith('/bin/') or provides_spec.startswith('/sbin/'):
Packit 6f3914
            # compatibility for packages that didn't do UsrMove
Packit 6f3914
            binary_provides = ['/usr' + provides_spec]
Packit 6f3914
        elif provides_spec.startswith('/'):
Packit 6f3914
            # provides_spec is a file path
Packit 6f3914
            return providers, [provides_spec]
Packit 6f3914
        else:
Packit 6f3914
            # suppose that provides_spec is a command, search in /usr/sbin/
Packit 6f3914
            binary_provides = [prefix + provides_spec
Packit 6f3914
                               for prefix in ['/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/']]
Packit 6f3914
        return self.sack.query().filterm(file__glob=binary_provides), binary_provides
Packit 6f3914
Packit 6f3914
    def _history_undo_operations(self, operations, first_trans, rollback=False, strict=True):
Packit 6f3914
        """Undo the operations on packages by their NEVRAs.
Packit 6f3914
Packit 6f3914
        :param operations: a NEVRAOperations to be undone
Packit 6f3914
        :param first_trans: first transaction id being undone
Packit 6f3914
        :param rollback: True if transaction is performing a rollback
Packit 6f3914
        :param strict: if True, raise an exception on any errors
Packit 6f3914
        """
Packit 6f3914
Packit 6f3914
        # map actions to their opposites
Packit 6f3914
        action_map = {
Packit 6f3914
            libdnf.transaction.TransactionItemAction_DOWNGRADE: None,
Packit 6f3914
            libdnf.transaction.TransactionItemAction_DOWNGRADED: libdnf.transaction.TransactionItemAction_UPGRADE,
Packit 6f3914
            libdnf.transaction.TransactionItemAction_INSTALL: libdnf.transaction.TransactionItemAction_REMOVE,
Packit 6f3914
            libdnf.transaction.TransactionItemAction_OBSOLETE: None,
Packit 6f3914
            libdnf.transaction.TransactionItemAction_OBSOLETED: libdnf.transaction.TransactionItemAction_INSTALL,
Packit 6f3914
            libdnf.transaction.TransactionItemAction_REINSTALL: None,
Packit 6f3914
            # reinstalls are skipped as they are considered as no-operation from history perspective
Packit 6f3914
            libdnf.transaction.TransactionItemAction_REINSTALLED: None,
Packit 6f3914
            libdnf.transaction.TransactionItemAction_REMOVE: libdnf.transaction.TransactionItemAction_INSTALL,
Packit 6f3914
            libdnf.transaction.TransactionItemAction_UPGRADE: None,
Packit 6f3914
            libdnf.transaction.TransactionItemAction_UPGRADED: libdnf.transaction.TransactionItemAction_DOWNGRADE,
Packit 6f3914
            libdnf.transaction.TransactionItemAction_REASON_CHANGE: None,
Packit 6f3914
        }
Packit 6f3914
Packit 6f3914
        failed = False
Packit 6f3914
        for ti in operations.packages():
Packit 6f3914
            try:
Packit 6f3914
                action = action_map[ti.action]
Packit 6f3914
            except KeyError:
Packit 6f3914
                raise RuntimeError(_("Action not handled: {}".format(action)))
Packit 6f3914
Packit 6f3914
            if action is None:
Packit 6f3914
                continue
Packit 6f3914
Packit 6f3914
            if action == libdnf.transaction.TransactionItemAction_REMOVE:
Packit 6f3914
                query = self.sack.query().installed().filterm(nevra_strict=str(ti))
Packit 6f3914
                if not query:
Packit 6f3914
                    logger.error(_('No package %s installed.'), ucd(str(ti)))
Packit 6f3914
                    failed = True
Packit 6f3914
                    continue
Packit 6f3914
            else:
Packit 6f3914
                query = self.sack.query().filterm(nevra_strict=str(ti))
Packit 6f3914
                if not query:
Packit 6f3914
                    logger.error(_('No package %s available.'), ucd(str(ti)))
Packit 6f3914
                    failed = True
Packit 6f3914
                    continue
Packit 6f3914
Packit 6f3914
            if action == libdnf.transaction.TransactionItemAction_REMOVE:
Packit 6f3914
                for pkg in query:
Packit 6f3914
                    self._goal.erase(pkg)
Packit 6f3914
            else:
Packit 6f3914
                selector = dnf.selector.Selector(self.sack)
Packit 6f3914
                selector.set(pkg=query)
Packit 6f3914
                self._goal.install(select=selector, optional=(not strict))
Packit 6f3914
Packit 6f3914
        if strict and failed:
Packit 6f3914
            raise dnf.exceptions.PackageNotFoundError(_('no package matched'))
Packit 6f3914
Packit 6f3914
    def _merge_update_filters(self, q, pkg_spec=None, warning=True):
Packit 6f3914
        """
Packit 6f3914
        Merge Queries in _update_filters and return intersection with q Query
Packit 6f3914
        @param q: Query
Packit 6f3914
        @return: Query
Packit 6f3914
        """
Packit 6f3914
        if not self._update_security_filters or not q:
Packit 6f3914
            return q
Packit 6f3914
        merged_queries = self._update_security_filters[0]
Packit 6f3914
        for query in self._update_security_filters[1:]:
Packit 6f3914
            merged_queries = merged_queries.union(query)
Packit 6f3914
Packit 6f3914
        self._update_security_filters = [merged_queries]
Packit 6f3914
        merged_queries = q.intersection(merged_queries)
Packit 6f3914
        if not merged_queries:
Packit 6f3914
            if warning:
Packit 6f3914
                q = q.upgrades()
Packit 6f3914
                count = len(q._name_dict().keys())
Packit 6f3914
                if pkg_spec is None:
Packit 6f3914
                    msg1 = _("No security updates needed, but {} update "
Packit 6f3914
                             "available").format(count)
Packit 6f3914
                    msg2 = _("No security updates needed, but {} updates "
Packit 6f3914
                             "available").format(count)
Packit 6f3914
                    logger.warning(P_(msg1, msg2, count))
Packit 6f3914
                else:
Packit 6f3914
                    msg1 = _('No security updates needed for "{}", but {} '
Packit 6f3914
                             'update available').format(pkg_spec, count)
Packit 6f3914
                    msg2 = _('No security updates needed for "{}", but {} '
Packit 6f3914
                             'updates available').format(pkg_spec, count)
Packit 6f3914
                    logger.warning(P_(msg1, msg2, count))
Packit 6f3914
        return merged_queries
Packit 6f3914
Packit 6f3914
    def _get_key_for_package(self, po, askcb=None, fullaskcb=None):
Packit 6f3914
        """Retrieve a key for a package. If needed, use the given
Packit 6f3914
        callback to prompt whether the key should be imported.
Packit 6f3914
Packit 6f3914
        :param po: the package object to retrieve the key of
Packit 6f3914
        :param askcb: Callback function to use to ask permission to
Packit 6f3914
           import a key.  The arguments *askck* should take are the
Packit 6f3914
           package object, the userid of the key, and the keyid
Packit 6f3914
        :param fullaskcb: Callback function to use to ask permission to
Packit 6f3914
           import a key.  This differs from *askcb* in that it gets
Packit 6f3914
           passed a dictionary so that we can expand the values passed.
Packit 6f3914
        :raises: :class:`dnf.exceptions.Error` if there are errors
Packit 6f3914
           retrieving the keys
Packit 6f3914
        """
Packit 6f3914
        repo = self.repos[po.repoid]
Packit 6f3914
        key_installed = repo.id in self._repo_set_imported_gpg_keys
Packit 6f3914
        keyurls = [] if key_installed else repo.gpgkey
Packit 6f3914
Packit 6f3914
        def _prov_key_data(msg):
Packit 6f3914
            msg += _('. Failing package is: %s') % (po) + '\n '
Packit 6f3914
            msg += _('GPG Keys are configured as: %s') % \
Packit 6f3914
                    (', '.join(repo.gpgkey))
Packit 6f3914
            return msg
Packit 6f3914
Packit 6f3914
        user_cb_fail = False
Packit 6f3914
        self._repo_set_imported_gpg_keys.add(repo.id)
Packit 6f3914
        for keyurl in keyurls:
Packit 6f3914
            keys = dnf.crypto.retrieve(keyurl, repo)
Packit 6f3914
Packit 6f3914
            for info in keys:
Packit 6f3914
                # Check if key is already installed
Packit 6f3914
                if misc.keyInstalled(self._ts, info.rpm_id, info.timestamp) >= 0:
Packit 6f3914
                    msg = _('GPG key at %s (0x%s) is already installed')
Packit 6f3914
                    logger.info(msg, keyurl, info.short_id)
Packit 6f3914
                    continue
Packit 6f3914
Packit 6f3914
                # DNS Extension: create a key object, pass it to the verification class
Packit 6f3914
                # and print its result as an advice to the user.
Packit 6f3914
                if self.conf.gpgkey_dns_verification:
Packit 6f3914
                    dns_input_key = dnf.dnssec.KeyInfo.from_rpm_key_object(info.userid,
Packit 6f3914
                                                                           info.raw_key)
Packit 6f3914
                    dns_result = dnf.dnssec.DNSSECKeyVerification.verify(dns_input_key)
Packit 6f3914
                    logger.info(dnf.dnssec.nice_user_msg(dns_input_key, dns_result))
Packit 6f3914
Packit 6f3914
                # Try installing/updating GPG key
Packit 6f3914
                info.url = keyurl
Packit 6f3914
                dnf.crypto.log_key_import(info)
Packit 6f3914
                rc = False
Packit 6f3914
                if self.conf.assumeno:
Packit 6f3914
                    rc = False
Packit 6f3914
                elif self.conf.assumeyes:
Packit 6f3914
                    # DNS Extension: We assume, that the key is trusted in case it is valid,
Packit 6f3914
                    # its existence is explicitly denied or in case the domain is not signed
Packit 6f3914
                    # and therefore there is no way to know for sure (this is mainly for
Packit 6f3914
                    # backward compatibility)
Packit 6f3914
                    # FAQ:
Packit 6f3914
                    # * What is PROVEN_NONEXISTENCE?
Packit 6f3914
                    #    In DNSSEC, your domain does not need to be signed, but this state
Packit 6f3914
                    #    (not signed) has to be proven by the upper domain. e.g. when example.com.
Packit 6f3914
                    #    is not signed, com. servers have to sign the message, that example.com.
Packit 6f3914
                    #    does not have any signing key (KSK to be more precise).
Packit 6f3914
                    if self.conf.gpgkey_dns_verification:
Packit 6f3914
                        if dns_result in (dnf.dnssec.Validity.VALID,
Packit 6f3914
                                          dnf.dnssec.Validity.PROVEN_NONEXISTENCE):
Packit 6f3914
                            rc = True
Packit 6f3914
                            logger.info(dnf.dnssec.any_msg(_("The key has been approved.")))
Packit 6f3914
                        else:
Packit 6f3914
                            rc = False
Packit 6f3914
                            logger.info(dnf.dnssec.any_msg(_("The key has been rejected.")))
Packit 6f3914
                    else:
Packit 6f3914
                        rc = True
Packit 6f3914
Packit 6f3914
                # grab the .sig/.asc for the keyurl, if it exists if it
Packit 6f3914
                # does check the signature on the key if it is signed by
Packit 6f3914
                # one of our ca-keys for this repo or the global one then
Packit 6f3914
                # rc = True else ask as normal.
Packit 6f3914
Packit 6f3914
                elif fullaskcb:
Packit 6f3914
                    rc = fullaskcb({"po": po, "userid": info.userid,
Packit 6f3914
                                    "hexkeyid": info.short_id,
Packit 6f3914
                                    "keyurl": keyurl,
Packit 6f3914
                                    "fingerprint": info.fingerprint,
Packit 6f3914
                                    "timestamp": info.timestamp})
Packit 6f3914
                elif askcb:
Packit 6f3914
                    rc = askcb(po, info.userid, info.short_id)
Packit 6f3914
Packit 6f3914
                if not rc:
Packit 6f3914
                    user_cb_fail = True
Packit 6f3914
                    continue
Packit 6f3914
Packit 6f3914
                # Import the key
Packit 6f3914
                # If rpm.RPMTRANS_FLAG_TEST in self._ts, gpg keys cannot be imported successfully
Packit 6f3914
                # therefore the flag was removed for import operation
Packit 6f3914
                test_flag = self._ts.isTsFlagSet(rpm.RPMTRANS_FLAG_TEST)
Packit 6f3914
                if test_flag:
Packit 6f3914
                    orig_flags = self._ts.getTsFlags()
Packit 6f3914
                    self._ts.setFlags(orig_flags - rpm.RPMTRANS_FLAG_TEST)
Packit 6f3914
                result = self._ts.pgpImportPubkey(misc.procgpgkey(info.raw_key))
Packit 6f3914
                if test_flag:
Packit 6f3914
                    self._ts.setFlags(orig_flags)
Packit 6f3914
                if result != 0:
Packit 6f3914
                    msg = _('Key import failed (code %d)') % result
Packit 6f3914
                    raise dnf.exceptions.Error(_prov_key_data(msg))
Packit 6f3914
                logger.info(_('Key imported successfully'))
Packit 6f3914
                key_installed = True
Packit 6f3914
Packit 6f3914
        if not key_installed and user_cb_fail:
Packit 6f3914
            raise dnf.exceptions.Error(_("Didn't install any keys"))
Packit 6f3914
Packit 6f3914
        if not key_installed:
Packit 6f3914
            msg = _('The GPG keys listed for the "%s" repository are '
Packit 6f3914
                    'already installed but they are not correct for this '
Packit 6f3914
                    'package.\n'
Packit 6f3914
                    'Check that the correct key URLs are configured for '
Packit 6f3914
                    'this repository.') % repo.name
Packit 6f3914
            raise dnf.exceptions.Error(_prov_key_data(msg))
Packit 6f3914
Packit 6f3914
        # Check if the newly installed keys helped
Packit 6f3914
        result, errmsg = self._sig_check_pkg(po)
Packit 6f3914
        if result != 0:
Packit 6f3914
            if keyurls:
Packit 6f3914
                msg = _("Import of key(s) didn't help, wrong key(s)?")
Packit 6f3914
                logger.info(msg)
Packit 6f3914
            errmsg = ucd(errmsg)
Packit 6f3914
            raise dnf.exceptions.Error(_prov_key_data(errmsg))
Packit 6f3914
Packit 6f3914
    def _run_rpm_check(self):
Packit 6f3914
        results = []
Packit 6f3914
        self._ts.check()
Packit 6f3914
        for prob in self._ts.problems():
Packit 6f3914
            #  Newer rpm (4.8.0+) has problem objects, older have just strings.
Packit 6f3914
            #  Should probably move to using the new objects, when we can. For
Packit 6f3914
            # now just be compatible.
Packit 6f3914
            results.append(ucd(prob))
Packit 6f3914
Packit 6f3914
        return results
Packit 6f3914
Packit 6f3914
    def urlopen(self, url, repo=None, mode='w+b', **kwargs):
Packit 6f3914
        # :api
Packit 6f3914
        """
Packit 6f3914
        Open the specified absolute url, return a file object
Packit 6f3914
        which respects proxy setting even for non-repo downloads
Packit 6f3914
        """
Packit 6f3914
        return dnf.util._urlopen(url, self.conf, repo, mode, **kwargs)
Packit 6f3914
Packit 6f3914
    def _get_installonly_query(self, q=None):
Packit 6f3914
        if q is None:
Packit 6f3914
            q = self._sack.query()
Packit 6f3914
        installonly = q.filter(provides=self.conf.installonlypkgs)
Packit 6f3914
        return installonly
Packit 6f3914
Packit 6f3914
    def _report_icase_hint(self, pkg_spec):
Packit 6f3914
        subj = dnf.subject.Subject(pkg_spec, ignore_case=True)
Packit 6f3914
        solution = subj.get_best_solution(self.sack, with_nevra=True,
Packit 6f3914
                                          with_provides=False, with_filenames=False)
Packit 6f3914
        if solution['query'] and solution['nevra'] and solution['nevra'].name and \
Packit 6f3914
                pkg_spec != solution['query'][0].name:
Packit 6f3914
            logger.info(_("  * Maybe you meant: {}").format(solution['query'][0].name))
Packit 6f3914
Packit 6f3914
    def _select_remote_pkgs(self, install_pkgs):
Packit 6f3914
        """ Check checksum of packages from local repositories and returns list packages from remote
Packit 6f3914
        repositories that will be downloaded. Packages from commandline are skipped.
Packit 6f3914
Packit 6f3914
        :param install_pkgs: list of packages
Packit 6f3914
        :return: list of remote pkgs
Packit 6f3914
        """
Packit 6f3914
        def _verification_of_packages(pkg_list, logger_msg):
Packit 6f3914
            all_packages_verified = True
Packit 6f3914
            for pkg in pkg_list:
Packit 6f3914
                pkg_successfully_verified = False
Packit 6f3914
                try:
Packit 6f3914
                    pkg_successfully_verified = pkg.verifyLocalPkg()
Packit 6f3914
                except Exception as e:
Packit 6f3914
                    logger.critical(str(e))
Packit 6f3914
                if pkg_successfully_verified is not True:
Packit 6f3914
                    logger.critical(logger_msg.format(pkg, pkg.reponame))
Packit 6f3914
                    all_packages_verified = False
Packit 6f3914
Packit 6f3914
            return all_packages_verified
Packit 6f3914
Packit 6f3914
        remote_pkgs = []
Packit 6f3914
        local_repository_pkgs = []
Packit 6f3914
        for pkg in install_pkgs:
Packit 6f3914
            if pkg._is_local_pkg():
Packit 6f3914
                if pkg.reponame != hawkey.CMDLINE_REPO_NAME:
Packit 6f3914
                    local_repository_pkgs.append(pkg)
Packit 6f3914
            else:
Packit 6f3914
                remote_pkgs.append(pkg)
Packit 6f3914
Packit 6f3914
        msg = _('Package "{}" from local repository "{}" has incorrect checksum')
Packit 6f3914
        if not _verification_of_packages(local_repository_pkgs, msg):
Packit 6f3914
            raise dnf.exceptions.Error(
Packit 6f3914
                _("Some packages from local repository have incorrect checksum"))
Packit 6f3914
Packit 6f3914
        if self.conf.cacheonly:
Packit 6f3914
            msg = _('Package "{}" from repository "{}" has incorrect checksum')
Packit 6f3914
            if not _verification_of_packages(remote_pkgs, msg):
Packit 6f3914
                raise dnf.exceptions.Error(
Packit 6f3914
                    _('Some packages have invalid cache, but cannot be downloaded due to '
Packit 6f3914
                      '"--cacheonly" option'))
Packit 6f3914
            remote_pkgs = []
Packit 6f3914
Packit 6f3914
        return remote_pkgs, local_repository_pkgs
Packit 6f3914
Packit 6f3914
    def _report_already_installed(self, packages):
Packit 6f3914
        for pkg in packages:
Packit 6f3914
            _msg_installed(pkg)
Packit 6f3914
Packit 6f3914
    def _raise_package_not_found_error(self, pkg_spec, forms, reponame):
Packit 6f3914
        all_query = self.sack.query(flags=hawkey.IGNORE_EXCLUDES)
Packit 6f3914
        subject = dnf.subject.Subject(pkg_spec)
Packit 6f3914
        solution = subject.get_best_solution(
Packit 6f3914
            self.sack, forms=forms, with_src=False, query=all_query)
Packit 6f3914
        if reponame is not None:
Packit 6f3914
            solution['query'].filterm(reponame=reponame)
Packit 6f3914
        if not solution['query']:
Packit 6f3914
            raise dnf.exceptions.PackageNotFoundError(_('No match for argument'), pkg_spec)
Packit 6f3914
        else:
Packit 6f3914
            with_regular_query = self.sack.query(flags=hawkey.IGNORE_REGULAR_EXCLUDES)
Packit 6f3914
            with_regular_query = solution['query'].intersection(with_regular_query)
Packit 6f3914
            # Modular filtering is applied on a package set that already has regular excludes
Packit 6f3914
            # filtered out. So if a package wasn't filtered out by regular excludes, it must have
Packit 6f3914
            # been filtered out by modularity.
Packit 6f3914
            if with_regular_query:
Packit 6f3914
                msg = _('All matches were filtered out by exclude filtering for argument')
Packit 6f3914
            else:
Packit 6f3914
                msg = _('All matches were filtered out by modular filtering for argument')
Packit 6f3914
            raise dnf.exceptions.PackageNotFoundError(msg, pkg_spec)
Packit 6f3914
Packit 6f3914
    def _raise_package_not_installed_error(self, pkg_spec, forms, reponame):
Packit 6f3914
        all_query = self.sack.query(flags=hawkey.IGNORE_EXCLUDES).installed()
Packit 6f3914
        subject = dnf.subject.Subject(pkg_spec)
Packit 6f3914
        solution = subject.get_best_solution(
Packit 6f3914
            self.sack, forms=forms, with_src=False, query=all_query)
Packit 6f3914
Packit 6f3914
        if not solution['query']:
Packit 6f3914
            raise dnf.exceptions.PackagesNotInstalledError(_('No match for argument'), pkg_spec)
Packit 6f3914
        if reponame is not None:
Packit 6f3914
            installed = [pkg for pkg in solution['query'] if self.history.repo(pkg) == reponame]
Packit 6f3914
        else:
Packit 6f3914
            installed = solution['query']
Packit 6f3914
        if not installed:
Packit 6f3914
            msg = _('All matches were installed from a different repository for argument')
Packit 6f3914
        else:
Packit 6f3914
            msg = _('All matches were filtered out by exclude filtering for argument')
Packit 6f3914
        raise dnf.exceptions.PackagesNotInstalledError(msg, pkg_spec)
Packit 6f3914
Packit 6f3914
Packit 6f3914
def _msg_installed(pkg):
Packit 6f3914
    name = ucd(pkg)
Packit 6f3914
    msg = _('Package %s is already installed.')
Packit 6f3914
    logger.info(msg, name)