Blame dnf/module/module_base.py

Packit 6f3914
# Copyright (C) 2017-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
from collections import OrderedDict
Packit 6f3914
Packit 6f3914
import hawkey
Packit 6f3914
import libdnf.smartcols
Packit 6f3914
import libdnf.module
Packit 6f3914
import dnf.selector
Packit 6f3914
import dnf.exceptions
Packit 6f3914
Packit 6f3914
from dnf.module.exceptions import EnableMultipleStreamsException
Packit 6f3914
from dnf.util import logger
Packit 6f3914
from dnf.i18n import _, P_, ucd
Packit 6f3914
Packit 6f3914
STATE_DEFAULT = libdnf.module.ModulePackageContainer.ModuleState_DEFAULT
Packit 6f3914
STATE_ENABLED = libdnf.module.ModulePackageContainer.ModuleState_ENABLED
Packit 6f3914
STATE_DISABLED = libdnf.module.ModulePackageContainer.ModuleState_DISABLED
Packit 6f3914
STATE_UNKNOWN = libdnf.module.ModulePackageContainer.ModuleState_UNKNOWN
Packit 6f3914
MODULE_TABLE_HINT = _("\n\nHint: [d]efault, [e]nabled, [x]disabled, [i]nstalled")
Packit 6f3914
MODULE_INFO_TABLE_HINT = _("\n\nHint: [d]efault, [e]nabled, [x]disabled, [i]nstalled, [a]ctive")
Packit 6f3914
Packit 6f3914
Packit 6f3914
def _profile_comparison_key(profile):
Packit 6f3914
    return profile.getName()
Packit 6f3914
Packit 6f3914
Packit 6f3914
class ModuleBase(object):
Packit 6f3914
    # :api
Packit 6f3914
Packit 6f3914
    def __init__(self, base):
Packit 6f3914
        # :api
Packit 6f3914
        self.base = base
Packit 6f3914
Packit 6f3914
    def enable(self, module_specs):
Packit 6f3914
        # :api
Packit 6f3914
        no_match_specs, error_specs, solver_errors, module_dicts = \
Packit 6f3914
            self._resolve_specs_enable_update_sack(module_specs)
Packit 6f3914
        for spec, (nsvcap, module_dict) in module_dicts.items():
Packit 6f3914
            if nsvcap.profile:
Packit 6f3914
                logger.info(_("Ignoring unnecessary profile: '{}/{}'").format(
Packit 6f3914
                    nsvcap.name, nsvcap.profile))
Packit 6f3914
        if no_match_specs or error_specs or solver_errors:
Packit 6f3914
            raise dnf.exceptions.MarkingErrors(no_match_group_specs=no_match_specs,
Packit 6f3914
                                               error_group_specs=error_specs,
Packit 6f3914
                                               module_depsolv_errors=solver_errors)
Packit 6f3914
Packit 6f3914
    def disable(self, module_specs):
Packit 6f3914
        # :api
Packit 6f3914
        no_match_specs, solver_errors = self._modules_reset_or_disable(module_specs, STATE_DISABLED)
Packit 6f3914
        if no_match_specs or solver_errors:
Packit 6f3914
            raise dnf.exceptions.MarkingErrors(no_match_group_specs=no_match_specs,
Packit 6f3914
                                               module_depsolv_errors=solver_errors)
Packit 6f3914
Packit 6f3914
    def install(self, module_specs, strict=True):
Packit 6f3914
        # :api
Packit 6f3914
        no_match_specs, error_specs, solver_errors, module_dicts = \
Packit 6f3914
            self._resolve_specs_enable_update_sack(module_specs)
Packit 6f3914
Packit 6f3914
        # <package_name, set_of_spec>
Packit 6f3914
        fail_safe_repo = hawkey.MODULE_FAIL_SAFE_REPO_NAME
Packit 6f3914
        install_dict = {}
Packit 6f3914
        install_set_artefacts = set()
Packit 6f3914
        fail_safe_repo_used = False
Packit 6f3914
        for spec, (nsvcap, moduledict) in module_dicts.items():
Packit 6f3914
            for name, streamdict in moduledict.items():
Packit 6f3914
                for stream, module_list in streamdict.items():
Packit 6f3914
                    install_module_list = [x for x in module_list
Packit 6f3914
                                           if self.base._moduleContainer.isModuleActive(x.getId())]
Packit 6f3914
                    if not install_module_list:
Packit 6f3914
                        logger.error(_("All matches for argument '{0}' in module '{1}:{2}' are not "
Packit 6f3914
                                       "active").format(spec, name, stream))
Packit 6f3914
                        error_specs.append(spec)
Packit 6f3914
                        continue
Packit 6f3914
                    profiles = []
Packit 6f3914
                    latest_module = self._get_latest(install_module_list)
Packit 6f3914
                    if latest_module.getRepoID() == fail_safe_repo:
Packit 6f3914
                        msg = _(
Packit 6f3914
                            "Installing module '{0}' from Fail-Safe repository {1} is not allowed")
Packit 6f3914
                        logger.critical(msg.format(latest_module.getNameStream(), fail_safe_repo))
Packit 6f3914
                        fail_safe_repo_used = True
Packit 6f3914
                    if nsvcap.profile:
Packit 6f3914
                        profiles.extend(latest_module.getProfiles(nsvcap.profile))
Packit 6f3914
                        if not profiles:
Packit 6f3914
                            available_profiles = latest_module.getProfiles()
Packit 6f3914
                            if available_profiles:
Packit 6f3914
                                profile_names = ", ".join(sorted(
Packit 6f3914
                                    [profile.getName() for profile in available_profiles]))
Packit 6f3914
                                msg = _("Unable to match profile for argument {}. Available "
Packit 6f3914
                                        "profiles for '{}:{}': {}").format(
Packit 6f3914
                                    spec, name, stream, profile_names)
Packit 6f3914
                            else:
Packit 6f3914
                                msg = _("Unable to match profile for argument {}").format(spec)
Packit 6f3914
                            logger.error(msg)
Packit 6f3914
                            no_match_specs.append(spec)
Packit 6f3914
                            continue
Packit 6f3914
                    else:
Packit 6f3914
                        profiles_strings = self.base._moduleContainer.getDefaultProfiles(
Packit 6f3914
                            name, stream)
Packit 6f3914
                        if not profiles_strings:
Packit 6f3914
                            available_profiles = latest_module.getProfiles()
Packit 6f3914
                            if available_profiles:
Packit 6f3914
                                profile_names = ", ".join(sorted(
Packit 6f3914
                                    [profile.getName() for profile in available_profiles]))
Packit 6f3914
                                msg = _("No default profiles for module {}:{}. Available profiles"
Packit 6f3914
                                        ": {}").format(
Packit 6f3914
                                    name, stream, profile_names)
Packit 6f3914
                            else:
Packit 6f3914
                                msg = _("No default profiles for module {}:{}").format(name, stream)
Packit 6f3914
                            logger.error(msg)
Packit 6f3914
                            no_match_specs.append(spec)
Packit 6f3914
                        for profile in set(profiles_strings):
Packit 6f3914
                            module_profiles = latest_module.getProfiles(profile)
Packit 6f3914
                            if not module_profiles:
Packit 6f3914
                                logger.error(
Packit 6f3914
                                    _("Default profile {} not available in module {}:{}").format(
Packit 6f3914
                                        profile, name, stream))
Packit 6f3914
                                no_match_specs.append(spec)
Packit 6f3914
Packit 6f3914
                            profiles.extend(module_profiles)
Packit 6f3914
                    for profile in profiles:
Packit 6f3914
                        self.base._moduleContainer.install(latest_module ,profile.getName())
Packit 6f3914
                        for pkg_name in profile.getContent():
Packit 6f3914
                            install_dict.setdefault(pkg_name, set()).add(spec)
Packit 6f3914
                    for module in install_module_list:
Packit 6f3914
                        install_set_artefacts.update(module.getArtifacts())
Packit 6f3914
        if fail_safe_repo_used:
Packit 6f3914
            raise dnf.exceptions.Error(_(
Packit 6f3914
                "Installing module from Fail-Safe repository is not allowed"))
Packit 6f3914
        install_base_query = self.base.sack.query().filterm(
Packit 6f3914
            nevra_strict=install_set_artefacts).apply()
Packit 6f3914
Packit 6f3914
        # add hot-fix packages
Packit 6f3914
        hot_fix_repos = [i.id for i in self.base.repos.iter_enabled() if i.module_hotfixes]
Packit 6f3914
        hotfix_packages = self.base.sack.query().filterm(reponame=hot_fix_repos).filterm(
Packit 6f3914
            name=install_dict.keys())
Packit 6f3914
        install_base_query = install_base_query.union(hotfix_packages)
Packit 6f3914
Packit 6f3914
        for pkg_name, set_specs in install_dict.items():
Packit 6f3914
            query = install_base_query.filter(name=pkg_name)
Packit 6f3914
            if not query:
Packit 6f3914
                # package can also be non-modular or part of another stream
Packit 6f3914
                query = self.base.sack.query().filterm(name=pkg_name)
Packit 6f3914
                if not query:
Packit 6f3914
                    for spec in set_specs:
Packit 6f3914
                        logger.error(_("Unable to resolve argument {}").format(spec))
Packit 6f3914
                    logger.error(_("No match for package {}").format(pkg_name))
Packit 6f3914
                    error_specs.extend(set_specs)
Packit 6f3914
                    continue
Packit 6f3914
            self.base._goal.group_members.add(pkg_name)
Packit 6f3914
            sltr = dnf.selector.Selector(self.base.sack)
Packit 6f3914
            sltr.set(pkg=query)
Packit 6f3914
            self.base._goal.install(select=sltr, optional=(not strict))
Packit 6f3914
        if no_match_specs or error_specs or solver_errors:
Packit 6f3914
            raise dnf.exceptions.MarkingErrors(no_match_group_specs=no_match_specs,
Packit 6f3914
                                               error_group_specs=error_specs,
Packit 6f3914
                                               module_depsolv_errors=solver_errors)
Packit 6f3914
Packit 6f3914
    def reset(self, module_specs):
Packit 6f3914
        # :api
Packit 6f3914
        no_match_specs, solver_errors = self._modules_reset_or_disable(module_specs, STATE_UNKNOWN)
Packit 6f3914
        if no_match_specs:
Packit 6f3914
            raise dnf.exceptions.MarkingErrors(no_match_group_specs=no_match_specs,
Packit 6f3914
                                               module_depsolv_errors=solver_errors)
Packit 6f3914
Packit 6f3914
    def upgrade(self, module_specs):
Packit 6f3914
        # :api
Packit 6f3914
        no_match_specs = []
Packit 6f3914
        fail_safe_repo = hawkey.MODULE_FAIL_SAFE_REPO_NAME
Packit 6f3914
        fail_safe_repo_used = False
Packit 6f3914
Packit 6f3914
        for spec in module_specs:
Packit 6f3914
            module_list, nsvcap = self._get_modules(spec)
Packit 6f3914
            if not module_list:
Packit 6f3914
                no_match_specs.append(spec)
Packit 6f3914
                continue
Packit 6f3914
            update_module_list = [x for x in module_list
Packit 6f3914
                                  if self.base._moduleContainer.isModuleActive(x.getId())]
Packit 6f3914
            if not update_module_list:
Packit 6f3914
                logger.error(_("Unable to resolve argument {}").format(spec))
Packit 6f3914
                continue
Packit 6f3914
            module_dict = self._create_module_dict_and_enable(update_module_list, False)
Packit 6f3914
            upgrade_package_set = set()
Packit 6f3914
            for name, streamdict in module_dict.items():
Packit 6f3914
                for stream, module_list_from_dict in streamdict.items():
Packit 6f3914
                    upgrade_package_set.update(self._get_package_name_set_and_remove_profiles(
Packit 6f3914
                        module_list_from_dict, nsvcap))
Packit 6f3914
                    latest_module = self._get_latest(module_list_from_dict)
Packit 6f3914
                    if latest_module.getRepoID() == fail_safe_repo:
Packit 6f3914
                        msg = _(
Packit 6f3914
                            "Upgrading module '{0}' from Fail-Safe repository {1} is not allowed")
Packit 6f3914
                        logger.critical(msg.format(latest_module.getNameStream(), fail_safe_repo))
Packit 6f3914
                        fail_safe_repo_used = True
Packit 6f3914
                    if nsvcap.profile:
Packit 6f3914
                        profiles_set = latest_module.getProfiles(nsvcap.profile)
Packit 6f3914
                        if not profiles_set:
Packit 6f3914
                            continue
Packit 6f3914
                        for profile in profiles_set:
Packit 6f3914
                            upgrade_package_set.update(profile.getContent())
Packit 6f3914
                    else:
Packit 6f3914
                        for profile in latest_module.getProfiles():
Packit 6f3914
                            upgrade_package_set.update(profile.getContent())
Packit 6f3914
                        for artefact in latest_module.getArtifacts():
Packit 6f3914
                            subj = hawkey.Subject(artefact)
Packit 6f3914
                            for nevra_obj in subj.get_nevra_possibilities(
Packit 6f3914
                                    forms=[hawkey.FORM_NEVRA]):
Packit 6f3914
                                upgrade_package_set.add(nevra_obj.name)
Packit 6f3914
Packit 6f3914
            if not upgrade_package_set:
Packit 6f3914
                logger.error(_("Unable to match profile in argument {}").format(spec))
Packit 6f3914
            query = self.base.sack.query().filterm(name=upgrade_package_set)
Packit 6f3914
            if query:
Packit 6f3914
                sltr = dnf.selector.Selector(self.base.sack)
Packit 6f3914
                sltr.set(pkg=query)
Packit 6f3914
                self.base._goal.upgrade(select=sltr)
Packit 6f3914
        if fail_safe_repo_used:
Packit 6f3914
            raise dnf.exceptions.Error(_(
Packit 6f3914
                "Upgrading module from Fail-Safe repository is not allowed"))
Packit 6f3914
        return no_match_specs
Packit 6f3914
Packit 6f3914
    def remove(self, module_specs):
Packit 6f3914
        # :api
Packit 6f3914
        no_match_specs = []
Packit 6f3914
        remove_package_set = set()
Packit 6f3914
Packit 6f3914
        for spec in module_specs:
Packit 6f3914
            module_list, nsvcap = self._get_modules(spec)
Packit 6f3914
            if not module_list:
Packit 6f3914
                no_match_specs.append(spec)
Packit 6f3914
                continue
Packit 6f3914
            module_dict = self._create_module_dict_and_enable(module_list, False)
Packit 6f3914
            remove_packages_names = []
Packit 6f3914
            for name, streamdict in module_dict.items():
Packit 6f3914
                for stream, module_list_from_dict in streamdict.items():
Packit 6f3914
                    remove_packages_names.extend(self._get_package_name_set_and_remove_profiles(
Packit 6f3914
                        module_list_from_dict, nsvcap, True))
Packit 6f3914
            if not remove_packages_names:
Packit 6f3914
                logger.error(_("Unable to match profile in argument {}").format(spec))
Packit 6f3914
            remove_package_set.update(remove_packages_names)
Packit 6f3914
Packit 6f3914
        if remove_package_set:
Packit 6f3914
            keep_pkg_names = self.base._moduleContainer.getInstalledPkgNames()
Packit 6f3914
            remove_package_set = remove_package_set.difference(keep_pkg_names)
Packit 6f3914
            if remove_package_set:
Packit 6f3914
                query = self.base.sack.query().installed().filterm(name=remove_package_set)
Packit 6f3914
                if query:
Packit 6f3914
                    self.base._remove_if_unneeded(query)
Packit 6f3914
        return no_match_specs
Packit 6f3914
Packit 6f3914
    def get_modules(self, module_spec):
Packit 6f3914
        # :api
Packit 6f3914
        return self._get_modules(module_spec)
Packit 6f3914
Packit 6f3914
    def _get_modules(self, module_spec):
Packit 6f3914
        # used by ansible (lib/ansible/modules/packaging/os/dnf.py)
Packit 6f3914
        subj = hawkey.Subject(module_spec)
Packit 6f3914
        for nsvcap in subj.nsvcap_possibilities():
Packit 6f3914
            name = nsvcap.name if nsvcap.name else ""
Packit 6f3914
            stream = nsvcap.stream if nsvcap.stream else ""
Packit 6f3914
            version = ""
Packit 6f3914
            context = nsvcap.context if nsvcap.context else ""
Packit 6f3914
            arch = nsvcap.arch if nsvcap.arch else ""
Packit 6f3914
            if nsvcap.version and nsvcap.version != -1:
Packit 6f3914
                version = str(nsvcap.version)
Packit 6f3914
            modules = self.base._moduleContainer.query(name, stream, version, context, arch)
Packit 6f3914
            if modules:
Packit 6f3914
                return modules, nsvcap
Packit 6f3914
        return (), None
Packit 6f3914
Packit 6f3914
    def _get_latest(self, module_list):
Packit 6f3914
        latest = None
Packit 6f3914
        if module_list:
Packit 6f3914
            latest = module_list[0]
Packit 6f3914
            for module in module_list[1:]:
Packit 6f3914
                if module.getVersion() > latest.getVersion():
Packit 6f3914
                    latest = module
Packit 6f3914
        return latest
Packit 6f3914
Packit 6f3914
    def _create_module_dict_and_enable(self, module_list, enable=True):
Packit 6f3914
        moduleDict = {}
Packit 6f3914
        for module in module_list:
Packit 6f3914
            moduleDict.setdefault(
Packit 6f3914
                module.getName(), {}).setdefault(module.getStream(), []).append(module)
Packit 6f3914
Packit 6f3914
        for moduleName, streamDict in moduleDict.items():
Packit 6f3914
            moduleState = self.base._moduleContainer.getModuleState(moduleName)
Packit 6f3914
            if len(streamDict) > 1:
Packit 6f3914
                if moduleState != STATE_DEFAULT and moduleState != STATE_ENABLED \
Packit 6f3914
                        and moduleState != STATE_DISABLED:
Packit 6f3914
                    raise EnableMultipleStreamsException(moduleName)
Packit 6f3914
                if moduleState == STATE_ENABLED:
Packit 6f3914
                    stream = self.base._moduleContainer.getEnabledStream(moduleName)
Packit 6f3914
                else:
Packit 6f3914
                    stream = self.base._moduleContainer.getDefaultStream(moduleName)
Packit 6f3914
                if not stream or stream not in streamDict:
Packit 6f3914
                    raise EnableMultipleStreamsException(moduleName)
Packit 6f3914
                for key in sorted(streamDict.keys()):
Packit 6f3914
                    if key == stream:
Packit 6f3914
                        if enable:
Packit 6f3914
                            self.base._moduleContainer.enable(moduleName, key)
Packit 6f3914
                        continue
Packit 6f3914
                    del streamDict[key]
Packit 6f3914
            elif enable:
Packit 6f3914
                for key in streamDict.keys():
Packit 6f3914
                    self.base._moduleContainer.enable(moduleName, key)
Packit 6f3914
            assert len(streamDict) == 1
Packit 6f3914
        return moduleDict
Packit 6f3914
Packit 6f3914
    def _resolve_specs_enable_update_sack(self, module_specs):
Packit 6f3914
        no_match_specs = []
Packit 6f3914
        error_spec = []
Packit 6f3914
        module_dicts = {}
Packit 6f3914
        for spec in module_specs:
Packit 6f3914
            module_list, nsvcap = self._get_modules(spec)
Packit 6f3914
            if not module_list:
Packit 6f3914
                no_match_specs.append(spec)
Packit 6f3914
                continue
Packit 6f3914
            try:
Packit 6f3914
                module_dict = self._create_module_dict_and_enable(module_list, True)
Packit 6f3914
                module_dicts[spec] = (nsvcap, module_dict)
Packit 6f3914
            except (RuntimeError, EnableMultipleStreamsException) as e:
Packit 6f3914
                error_spec.append(spec)
Packit 6f3914
                logger.error(ucd(e))
Packit 6f3914
                logger.error(_("Unable to resolve argument {}").format(spec))
Packit 6f3914
        hot_fix_repos = [i.id for i in self.base.repos.iter_enabled() if i.module_hotfixes]
Packit 6f3914
        try:
Packit 6f3914
            solver_errors = self.base.sack.filter_modules(
Packit 6f3914
                self.base._moduleContainer, hot_fix_repos, self.base.conf.installroot,
Packit 6f3914
                self.base.conf.module_platform_id, update_only=True,
Packit 6f3914
                debugsolver=self.base.conf.debug_solver)
Packit 6f3914
        except hawkey.Exception as e:
Packit 6f3914
            raise dnf.exceptions.Error(ucd(e))
Packit 6f3914
        for spec, (nsvcap, moduleDict) in module_dicts.items():
Packit 6f3914
            for streamDict in moduleDict.values():
Packit 6f3914
                for modules in streamDict.values():
Packit 6f3914
                    try:
Packit 6f3914
                        self.base._moduleContainer.enableDependencyTree(
Packit 6f3914
                            libdnf.module.VectorModulePackagePtr(modules))
Packit 6f3914
                    except RuntimeError as e:
Packit 6f3914
                        error_spec.append(spec)
Packit 6f3914
                        logger.error(ucd(e))
Packit 6f3914
                        logger.error(_("Unable to resolve argument {}").format(spec))
Packit 6f3914
        return no_match_specs, error_spec, solver_errors, module_dicts
Packit 6f3914
Packit 6f3914
    def _modules_reset_or_disable(self, module_specs, to_state):
Packit 6f3914
        no_match_specs = []
Packit 6f3914
        for spec in module_specs:
Packit 6f3914
            module_list, nsvcap = self._get_modules(spec)
Packit 6f3914
            if not module_list:
Packit 6f3914
                logger.error(_("Unable to resolve argument {}").format(spec))
Packit 6f3914
                no_match_specs.append(spec)
Packit 6f3914
                continue
Packit 6f3914
            if nsvcap.stream or nsvcap.version or nsvcap.context or nsvcap.arch or nsvcap.profile:
Packit 6f3914
                logger.info(_("Only module name is required. "
Packit 6f3914
                              "Ignoring unneeded information in argument: '{}'").format(spec))
Packit 6f3914
            module_names = set()
Packit 6f3914
            for module in module_list:
Packit 6f3914
                module_names.add(module.getName())
Packit 6f3914
            for name in module_names:
Packit 6f3914
                if to_state == STATE_UNKNOWN:
Packit 6f3914
                    self.base._moduleContainer.reset(name)
Packit 6f3914
                if to_state == STATE_DISABLED:
Packit 6f3914
                    self.base._moduleContainer.disable(name)
Packit 6f3914
Packit 6f3914
        hot_fix_repos = [i.id for i in self.base.repos.iter_enabled() if i.module_hotfixes]
Packit 6f3914
        try:
Packit 6f3914
            solver_errors = self.base.sack.filter_modules(
Packit 6f3914
                self.base._moduleContainer, hot_fix_repos, self.base.conf.installroot,
Packit 6f3914
                self.base.conf.module_platform_id, update_only=True,
Packit 6f3914
                debugsolver=self.base.conf.debug_solver)
Packit 6f3914
        except hawkey.Exception as e:
Packit 6f3914
            raise dnf.exceptions.Error(ucd(e))
Packit 6f3914
        return no_match_specs, solver_errors
Packit 6f3914
Packit 6f3914
    def _get_package_name_set_and_remove_profiles(self, module_list, nsvcap, remove=False):
Packit 6f3914
        package_name_set = set()
Packit 6f3914
        latest_module = self._get_latest(module_list)
Packit 6f3914
        installed_profiles_strings = set(self.base._moduleContainer.getInstalledProfiles(
Packit 6f3914
            latest_module.getName()))
Packit 6f3914
        if not installed_profiles_strings:
Packit 6f3914
            return set()
Packit 6f3914
        if nsvcap.profile:
Packit 6f3914
            profiles_set = latest_module.getProfiles(nsvcap.profile)
Packit 6f3914
            if not profiles_set:
Packit 6f3914
                return set()
Packit 6f3914
            for profile in profiles_set:
Packit 6f3914
                if profile.getName() in installed_profiles_strings:
Packit 6f3914
                    if remove:
Packit 6f3914
                        self.base._moduleContainer.uninstall(latest_module, profile.getName())
Packit 6f3914
                    package_name_set.update(profile.getContent())
Packit 6f3914
        else:
Packit 6f3914
            for profile_string in installed_profiles_strings:
Packit 6f3914
                if remove:
Packit 6f3914
                    self.base._moduleContainer.uninstall(latest_module, profile_string)
Packit 6f3914
                for profile in latest_module.getProfiles(profile_string):
Packit 6f3914
                    package_name_set.update(profile.getContent())
Packit 6f3914
        return package_name_set
Packit 6f3914
Packit 6f3914
    def _get_info_profiles(self, module_specs):
Packit 6f3914
        output = set()
Packit 6f3914
        for module_spec in module_specs:
Packit 6f3914
            module_list, nsvcap = self._get_modules(module_spec)
Packit 6f3914
            if not module_list:
Packit 6f3914
                logger.info(_("Unable to resolve argument {}").format(module_spec))
Packit 6f3914
                continue
Packit 6f3914
Packit 6f3914
            if nsvcap.profile:
Packit 6f3914
                logger.info(_("Ignoring unnecessary profile: '{}/{}'").format(
Packit 6f3914
                    nsvcap.name, nsvcap.profile))
Packit 6f3914
            for module in module_list:
Packit 6f3914
Packit 6f3914
                lines = OrderedDict()
Packit 6f3914
                lines["Name"] = module.getFullIdentifier()
Packit 6f3914
Packit 6f3914
                for profile in sorted(module.getProfiles(), key=_profile_comparison_key):
Packit 6f3914
                    lines[profile.getName()] = "\n".join(
Packit 6f3914
                        [pkgName for pkgName in profile.getContent()])
Packit 6f3914
Packit 6f3914
                output.add(self._create_simple_table(lines).toString())
Packit 6f3914
        return "\n\n".join(sorted(output))
Packit 6f3914
Packit 6f3914
    def _profile_report_formatter(self, modulePackage, default_profiles, enabled_str):
Packit 6f3914
        installed_profiles = self.base._moduleContainer.getInstalledProfiles(
Packit 6f3914
            modulePackage.getName())
Packit 6f3914
        available_profiles = modulePackage.getProfiles()
Packit 6f3914
        profiles_str = ""
Packit 6f3914
        for profile in sorted(available_profiles, key=_profile_comparison_key):
Packit 6f3914
            profiles_str += "{}{}".format(
Packit 6f3914
                profile.getName(), " [d]" if profile.getName() in default_profiles else "")
Packit 6f3914
            profiles_str += " [i], " if profile.getName() in installed_profiles and enabled_str \
Packit 6f3914
                else ", "
Packit 6f3914
        return profiles_str[:-2]
Packit 6f3914
Packit 6f3914
    def _module_strs_formatter(self, modulePackage, markActive=False):
Packit 6f3914
        default_str = ""
Packit 6f3914
        enabled_str = ""
Packit 6f3914
        disabled_str = ""
Packit 6f3914
        if modulePackage.getStream() == self.base._moduleContainer.getDefaultStream(
Packit 6f3914
                modulePackage.getName()):
Packit 6f3914
            default_str = " [d]"
Packit 6f3914
        if self.base._moduleContainer.isEnabled(modulePackage):
Packit 6f3914
            if not default_str:
Packit 6f3914
                enabled_str = " "
Packit 6f3914
            enabled_str += "[e]"
Packit 6f3914
        elif self.base._moduleContainer.isDisabled(modulePackage):
Packit 6f3914
            if not default_str:
Packit 6f3914
                disabled_str = " "
Packit 6f3914
            disabled_str += "[x]"
Packit 6f3914
        if markActive and self.base._moduleContainer.isModuleActive(modulePackage):
Packit 6f3914
            if not default_str:
Packit 6f3914
                disabled_str = " "
Packit 6f3914
            disabled_str += "[a]"
Packit 6f3914
        return default_str, enabled_str, disabled_str
Packit 6f3914
Packit 6f3914
    def _get_info(self, module_specs):
Packit 6f3914
        output = set()
Packit 6f3914
        for module_spec in module_specs:
Packit 6f3914
            module_list, nsvcap = self._get_modules(module_spec)
Packit 6f3914
            if not module_list:
Packit 6f3914
                logger.info(_("Unable to resolve argument {}").format(module_spec))
Packit 6f3914
                continue
Packit 6f3914
Packit 6f3914
            if nsvcap.profile:
Packit 6f3914
                logger.info(_("Ignoring unnecessary profile: '{}/{}'").format(
Packit 6f3914
                    nsvcap.name, nsvcap.profile))
Packit 6f3914
            for modulePackage in module_list:
Packit 6f3914
                default_str, enabled_str, disabled_str = self._module_strs_formatter(
Packit 6f3914
                    modulePackage, markActive=True)
Packit 6f3914
                default_profiles = self.base._moduleContainer.getDefaultProfiles(
Packit 6f3914
                    modulePackage.getName(), modulePackage.getStream())
Packit 6f3914
Packit 6f3914
                profiles_str = self._profile_report_formatter(
Packit 6f3914
                    modulePackage, default_profiles, enabled_str)
Packit 6f3914
Packit 6f3914
                lines = OrderedDict()
Packit 6f3914
                lines["Name"] = modulePackage.getName()
Packit 6f3914
                lines["Stream"] = modulePackage.getStream() + default_str + enabled_str + \
Packit 6f3914
                                  disabled_str
Packit 6f3914
                lines["Version"] = modulePackage.getVersion()
Packit 6f3914
                lines["Context"] = modulePackage.getContext()
Packit 6f3914
                lines["Architecture"] = modulePackage.getArch()
Packit 6f3914
                lines["Profiles"] = profiles_str
Packit 6f3914
                lines["Default profiles"] = " ".join(default_profiles)
Packit 6f3914
                lines["Repo"] = modulePackage.getRepoID()
Packit 6f3914
                lines["Summary"] = modulePackage.getSummary()
Packit 6f3914
                lines["Description"] = modulePackage.getDescription()
Packit 6f3914
                req_set = set()
Packit 6f3914
                for req in modulePackage.getModuleDependencies():
Packit 6f3914
                    for require_dict in req.getRequires():
Packit 6f3914
                        for mod_require, stream in require_dict.items():
Packit 6f3914
                            req_set.add("{}:[{}]".format(mod_require, ",".join(stream)))
Packit 6f3914
                lines["Requires"] = "\n".join(sorted(req_set))
Packit 6f3914
                lines["Artifacts"] = "\n".join(sorted(modulePackage.getArtifacts()))
Packit 6f3914
                output.add(self._create_simple_table(lines).toString())
Packit 6f3914
        str_table = "\n\n".join(sorted(output))
Packit 6f3914
        if str_table:
Packit 6f3914
            str_table += MODULE_INFO_TABLE_HINT
Packit 6f3914
        return str_table
Packit 6f3914
Packit 6f3914
    @staticmethod
Packit 6f3914
    def _create_simple_table(lines):
Packit 6f3914
        table = libdnf.smartcols.Table()
Packit 6f3914
        table.enableNoheadings(True)
Packit 6f3914
        table.setColumnSeparator(" : ")
Packit 6f3914
Packit 6f3914
        column_name = table.newColumn("Name")
Packit 6f3914
        column_value = table.newColumn("Value")
Packit 6f3914
        column_value.setWrap(True)
Packit 6f3914
        column_value.setSafechars("\n")
Packit 6f3914
        column_value.setNewlineWrapFunction()
Packit 6f3914
Packit 6f3914
        for line_name, value in lines.items():
Packit 6f3914
            if value is None:
Packit 6f3914
                value = ""
Packit 6f3914
            line = table.newLine()
Packit 6f3914
            line.getColumnCell(column_name).setData(line_name)
Packit 6f3914
            line.getColumnCell(column_value).setData(str(value))
Packit 6f3914
Packit 6f3914
        return table
Packit 6f3914
Packit 6f3914
    def _get_full_info(self, module_specs):
Packit 6f3914
        output = set()
Packit 6f3914
        for module_spec in module_specs:
Packit 6f3914
            module_list, nsvcap = self._get_modules(module_spec)
Packit 6f3914
            if not module_list:
Packit 6f3914
                logger.info(_("Unable to resolve argument {}").format(module_spec))
Packit 6f3914
                continue
Packit 6f3914
Packit 6f3914
            if nsvcap.profile:
Packit 6f3914
                logger.info(_("Ignoring unnecessary profile: '{}/{}'").format(
Packit 6f3914
                    nsvcap.name, nsvcap.profile))
Packit 6f3914
            for modulePackage in module_list:
Packit 6f3914
                info = modulePackage.getYaml()
Packit 6f3914
                if info:
Packit 6f3914
                    output.add(info)
Packit 6f3914
        output_string = "\n\n".join(sorted(output))
Packit 6f3914
        return output_string
Packit 6f3914
Packit 6f3914
    def _what_provides(self, rpm_specs):
Packit 6f3914
        output = set()
Packit 6f3914
        modulePackages = self.base._moduleContainer.getModulePackages()
Packit 6f3914
        baseQuery = self.base.sack.query().filterm(empty=True).apply()
Packit 6f3914
        getBestInitQuery = self.base.sack.query(flags=hawkey.IGNORE_MODULAR_EXCLUDES)
Packit 6f3914
Packit 6f3914
        for spec in rpm_specs:
Packit 6f3914
            subj = dnf.subject.Subject(spec)
Packit 6f3914
            baseQuery = baseQuery.union(subj.get_best_query(
Packit 6f3914
                self.base.sack, with_nevra=True, with_provides=False, with_filenames=False,
Packit 6f3914
                query=getBestInitQuery))
Packit 6f3914
Packit 6f3914
        baseQuery.apply()
Packit 6f3914
Packit 6f3914
        for modulePackage in modulePackages:
Packit 6f3914
            artifacts = modulePackage.getArtifacts()
Packit 6f3914
            if not artifacts:
Packit 6f3914
                continue
Packit 6f3914
            query = baseQuery.filter(nevra_strict=artifacts)
Packit 6f3914
            if query:
Packit 6f3914
                for pkg in query:
Packit 6f3914
                    string_output = ""
Packit 6f3914
                    profiles = []
Packit 6f3914
                    for profile in sorted(modulePackage.getProfiles(), key=_profile_comparison_key):
Packit 6f3914
                        if pkg.name in profile.getContent():
Packit 6f3914
                            profiles.append(profile.getName())
Packit 6f3914
                    lines = OrderedDict()
Packit 6f3914
                    lines["Module"] = modulePackage.getFullIdentifier()
Packit 6f3914
                    lines["Profiles"] = " ".join(sorted(profiles))
Packit 6f3914
                    lines["Repo"] = modulePackage.getRepoID()
Packit 6f3914
                    lines["Summary"] = modulePackage.getSummary()
Packit 6f3914
Packit 6f3914
                    table = self._create_simple_table(lines)
Packit 6f3914
Packit 6f3914
                    string_output += "{}\n".format(self.base.output.term.bold(str(pkg)))
Packit 6f3914
                    string_output += "{}".format(table.toString())
Packit 6f3914
                    output.add(string_output)
Packit 6f3914
Packit 6f3914
        return "\n\n".join(sorted(output))
Packit 6f3914
Packit 6f3914
    def _create_and_fill_table(self, latest):
Packit 6f3914
        table = libdnf.smartcols.Table()
Packit 6f3914
        table.setTermforce(libdnf.smartcols.Table.TermForce_AUTO)
Packit 6f3914
        table.enableMaxout(True)
Packit 6f3914
        column_name = table.newColumn("Name")
Packit 6f3914
        column_stream = table.newColumn("Stream")
Packit 6f3914
        column_profiles = table.newColumn("Profiles")
Packit 6f3914
        column_profiles.setWrap(True)
Packit 6f3914
        column_info = table.newColumn("Summary")
Packit 6f3914
        column_info.setWrap(True)
Packit 6f3914
Packit 6f3914
        if not self.base.conf.verbose:
Packit 6f3914
            column_info.hidden = True
Packit 6f3914
Packit 6f3914
        for latest_per_repo in latest:
Packit 6f3914
            for nameStreamArch in latest_per_repo:
Packit 6f3914
                if len(nameStreamArch) == 1:
Packit 6f3914
                    modulePackage = nameStreamArch[0]
Packit 6f3914
                else:
Packit 6f3914
                    active = [module for module in nameStreamArch
Packit 6f3914
                              if self.base._moduleContainer.isModuleActive(module)]
Packit 6f3914
                    if active:
Packit 6f3914
                        modulePackage = active[0]
Packit 6f3914
                    else:
Packit 6f3914
                        modulePackage = nameStreamArch[0]
Packit 6f3914
                line = table.newLine()
Packit 6f3914
                default_str, enabled_str, disabled_str = self._module_strs_formatter(
Packit 6f3914
                    modulePackage, markActive=False)
Packit 6f3914
                default_profiles = self.base._moduleContainer.getDefaultProfiles(
Packit 6f3914
                    modulePackage.getName(), modulePackage.getStream())
Packit 6f3914
                profiles_str = self._profile_report_formatter(modulePackage, default_profiles,
Packit 6f3914
                                                             enabled_str)
Packit 6f3914
                line.getColumnCell(column_name).setData(modulePackage.getName())
Packit 6f3914
                line.getColumnCell(
Packit 6f3914
                    column_stream).setData(
Packit 6f3914
                    modulePackage.getStream() + default_str + enabled_str + disabled_str)
Packit 6f3914
                line.getColumnCell(column_profiles).setData(profiles_str)
Packit 6f3914
                line.getColumnCell(column_info).setData(modulePackage.getSummary())
Packit 6f3914
Packit 6f3914
        return table
Packit 6f3914
Packit 6f3914
    def _get_brief_description(self, module_specs, module_state):
Packit 6f3914
        modules = []
Packit 6f3914
        if module_specs:
Packit 6f3914
            for spec in module_specs:
Packit 6f3914
                module_list, nsvcap = self._get_modules(spec)
Packit 6f3914
                modules.extend(module_list)
Packit 6f3914
        else:
Packit 6f3914
            modules = self.base._moduleContainer.getModulePackages()
Packit 6f3914
        latest = self.base._moduleContainer.getLatestModulesPerRepo(module_state, modules)
Packit 6f3914
        if not latest:
Packit 6f3914
            return ""
Packit 6f3914
Packit 6f3914
        table = self._create_and_fill_table(latest)
Packit 6f3914
        current_repo_id_index = 0
Packit 6f3914
        already_printed_lines = 0
Packit 6f3914
        try:
Packit 6f3914
            repo_name = self.base.repos[latest[0][0][0].getRepoID()].name
Packit 6f3914
        except KeyError:
Packit 6f3914
            repo_name = latest[0][0][0].getRepoID()
Packit 6f3914
        versions = len(latest[0])
Packit 6f3914
        header = self._format_header(table)
Packit 6f3914
        str_table = self._format_repoid(repo_name)
Packit 6f3914
        str_table += header
Packit 6f3914
        for i in range(0, table.getNumberOfLines()):
Packit 6f3914
            if versions + already_printed_lines <= i:
Packit 6f3914
                already_printed_lines += versions
Packit 6f3914
                current_repo_id_index += 1
Packit 6f3914
                # Fail-Safe repository is not in self.base.repos
Packit 6f3914
                try:
Packit 6f3914
                    repo_name = self.base.repos[
Packit 6f3914
                        latest[current_repo_id_index][0][0].getRepoID()].name
Packit 6f3914
                except KeyError:
Packit 6f3914
                    repo_name = latest[current_repo_id_index][0][0].getRepoID()
Packit 6f3914
                versions = len(latest[current_repo_id_index])
Packit 6f3914
                str_table += "\n"
Packit 6f3914
                str_table += self._format_repoid(repo_name)
Packit 6f3914
                str_table += header
Packit 6f3914
Packit 6f3914
            line = table.getLine(i)
Packit 6f3914
            str_table += table.toString(line, line)
Packit 6f3914
        return str_table + MODULE_TABLE_HINT
Packit 6f3914
Packit 6f3914
    def _format_header(self, table):
Packit 6f3914
        line = table.getLine(0)
Packit 6f3914
        return table.toString(line, line).split('\n', 1)[0] + '\n'
Packit 6f3914
Packit 6f3914
    def _format_repoid(self, repo_name):
Packit 6f3914
        return "{}\n".format(self.base.output.term.bold(repo_name))
Packit 6f3914
Packit 6f3914
Packit 6f3914
def format_modular_solver_errors(errors):
Packit 6f3914
    msg = dnf.util._format_resolve_problems(errors)
Packit 6f3914
    return "\n".join(
Packit 6f3914
        [P_('Modular dependency problem:', 'Modular dependency problems:', len(errors)), msg])