Blame dnf/cli/commands/module.py

Packit 6f3914
# supplies the 'module' command.
Packit 6f3914
#
Packit 6f3914
# Copyright (C) 2014-2017  Red Hat, Inc.
Packit 6f3914
#
Packit 6f3914
# This copyrighted material is made available to anyone wishing to use,
Packit 6f3914
# modify, copy, or redistribute it subject to the terms and conditions of
Packit 6f3914
# the GNU General Public License v.2, or (at your option) any later version.
Packit 6f3914
# This program is distributed in the hope that it will be useful, but WITHOUT
Packit 6f3914
# ANY WARRANTY expressed or implied, including the implied warranties of
Packit 6f3914
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
Packit 6f3914
# Public License for more details.  You should have received a copy of the
Packit 6f3914
# GNU General Public License along with this program; if not, write to the
Packit 6f3914
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit 6f3914
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
Packit 6f3914
# source code or documentation are not subject to the GNU General Public
Packit 6f3914
# License and may only be used or replicated with the express permission of
Packit 6f3914
# Red Hat, Inc.
Packit 6f3914
#
Packit 6f3914
Packit 6f3914
from __future__ import print_function
Packit 6f3914
Packit 6f3914
from dnf.cli import commands, CliError
Packit 6f3914
from dnf.i18n import _
Packit 6f3914
from dnf.module.exceptions import NoModuleException
Packit 6f3914
from dnf.util import logger
Packit 6f3914
import dnf.util
Packit 6f3914
Packit 6f3914
import sys
Packit 6f3914
import os
Packit 6f3914
Packit 6f3914
import hawkey
Packit 6f3914
import libdnf
Packit 6f3914
import dnf.module.module_base
Packit 6f3914
import dnf.exceptions
Packit 6f3914
Packit 6f3914
Packit 6f3914
class ModuleCommand(commands.Command):
Packit 6f3914
    class SubCommand(commands.Command):
Packit 6f3914
Packit 6f3914
        def __init__(self, cli):
Packit 6f3914
            super(ModuleCommand.SubCommand, self).__init__(cli)
Packit 6f3914
            self.module_base = dnf.module.module_base.ModuleBase(self.base)
Packit 6f3914
Packit 6f3914
        def _get_modules_from_name_stream_specs(self):
Packit 6f3914
            modules_from_specs = set()
Packit 6f3914
            for module_spec in self.opts.module_spec:
Packit 6f3914
                __, nsvcap = self.module_base._get_modules(module_spec)
Packit 6f3914
                name = nsvcap.name if nsvcap.name else ""
Packit 6f3914
                stream = nsvcap.stream if nsvcap.stream else ""
Packit 6f3914
                if (nsvcap.version and nsvcap.version != -1) or nsvcap.context:
Packit 6f3914
                    logger.info(_("Only module name, stream, architecture or profile is used. "
Packit 6f3914
                                  "Ignoring unneeded information in argument: '{}'").format(
Packit 6f3914
                        module_spec))
Packit 6f3914
                arch = nsvcap.arch if nsvcap.arch else ""
Packit 6f3914
                modules = self.base._moduleContainer.query(name, stream, "", "", arch)
Packit 6f3914
                modules_from_specs.update(modules)
Packit 6f3914
            return modules_from_specs
Packit 6f3914
Packit 6f3914
        def _get_module_artifact_names(self, use_modules, skip_modules):
Packit 6f3914
            artifacts = set()
Packit 6f3914
            pkg_names = set()
Packit 6f3914
            for module in use_modules:
Packit 6f3914
                if module not in skip_modules:
Packit 6f3914
                    if self.base._moduleContainer.isModuleActive(module):
Packit 6f3914
                        artifacts.update(module.getArtifacts())
Packit 6f3914
            for artifact in artifacts:
Packit 6f3914
                subj = hawkey.Subject(artifact)
Packit 6f3914
                for nevra_obj in subj.get_nevra_possibilities(
Packit 6f3914
                        forms=[hawkey.FORM_NEVRA]):
Packit 6f3914
                    if nevra_obj.name:
Packit 6f3914
                        pkg_names.add(nevra_obj.name)
Packit 6f3914
            return pkg_names, artifacts
Packit 6f3914
Packit 6f3914
    class ListSubCommand(SubCommand):
Packit 6f3914
Packit 6f3914
        aliases = ('list',)
Packit 6f3914
Packit 6f3914
        def configure(self):
Packit 6f3914
            demands = self.cli.demands
Packit 6f3914
            demands.available_repos = True
Packit 6f3914
            demands.sack_activation = True
Packit 6f3914
Packit 6f3914
        def run_on_module(self):
Packit 6f3914
            mods = self.module_base
Packit 6f3914
Packit 6f3914
            if self.opts.enabled:
Packit 6f3914
                output = mods._get_brief_description(
Packit 6f3914
                    self.opts.module_spec, libdnf.module.ModulePackageContainer.ModuleState_ENABLED)
Packit 6f3914
            elif self.opts.disabled:
Packit 6f3914
                output = mods._get_brief_description(
Packit 6f3914
                    self.opts.module_spec,
Packit 6f3914
                    libdnf.module.ModulePackageContainer.ModuleState_DISABLED)
Packit 6f3914
            elif self.opts.installed:
Packit 6f3914
                output = mods._get_brief_description(
Packit 6f3914
                    self.opts.module_spec,
Packit 6f3914
                    libdnf.module.ModulePackageContainer.ModuleState_INSTALLED)
Packit 6f3914
            else:
Packit 6f3914
                output = mods._get_brief_description(
Packit 6f3914
                    self.opts.module_spec, libdnf.module.ModulePackageContainer.ModuleState_UNKNOWN)
Packit 6f3914
            if output:
Packit 6f3914
                print(output)
Packit 6f3914
                return
Packit 6f3914
            if self.opts.module_spec:
Packit 6f3914
                msg = _('No matching Modules to list')
Packit 6f3914
                raise dnf.exceptions.Error(msg)
Packit 6f3914
Packit 6f3914
    class InfoSubCommand(SubCommand):
Packit 6f3914
Packit 6f3914
        aliases = ('info',)
Packit 6f3914
Packit 6f3914
        def configure(self):
Packit 6f3914
            demands = self.cli.demands
Packit 6f3914
            demands.available_repos = True
Packit 6f3914
            demands.sack_activation = True
Packit 6f3914
Packit 6f3914
        def run_on_module(self):
Packit 6f3914
            if self.opts.verbose:
Packit 6f3914
                output = self.module_base._get_full_info(self.opts.module_spec)
Packit 6f3914
            elif self.opts.profile:
Packit 6f3914
                output = self.module_base._get_info_profiles(self.opts.module_spec)
Packit 6f3914
            else:
Packit 6f3914
                output = self.module_base._get_info(self.opts.module_spec)
Packit 6f3914
            if output:
Packit 6f3914
                print(output)
Packit 6f3914
            else:
Packit 6f3914
                raise dnf.exceptions.Error(_('No matching Modules to list'))
Packit 6f3914
Packit 6f3914
    class EnableSubCommand(SubCommand):
Packit 6f3914
Packit 6f3914
        aliases = ('enable',)
Packit 6f3914
Packit 6f3914
        def configure(self):
Packit 6f3914
            demands = self.cli.demands
Packit 6f3914
            demands.available_repos = True
Packit 6f3914
            demands.sack_activation = True
Packit 6f3914
            demands.resolving = True
Packit 6f3914
            demands.root_user = True
Packit 6f3914
Packit 6f3914
        def run_on_module(self):
Packit 6f3914
            try:
Packit 6f3914
                self.module_base.enable(self.opts.module_spec)
Packit 6f3914
            except dnf.exceptions.MarkingErrors as e:
Packit 6f3914
                if self.base.conf.strict:
Packit 6f3914
                    if e.no_match_group_specs or e.error_group_specs:
Packit 6f3914
                        raise e
Packit 6f3914
                    if e.module_depsolv_errors and e.module_depsolv_errors[1] != \
Packit 6f3914
                            libdnf.module.ModulePackageContainer.ModuleErrorType_ERROR_IN_DEFAULTS:
Packit 6f3914
                        raise e
Packit 6f3914
                logger.error(str(e))
Packit 6f3914
Packit 6f3914
    class DisableSubCommand(SubCommand):
Packit 6f3914
Packit 6f3914
        aliases = ('disable',)
Packit 6f3914
Packit 6f3914
        def configure(self):
Packit 6f3914
            demands = self.cli.demands
Packit 6f3914
            demands.available_repos = True
Packit 6f3914
            demands.sack_activation = True
Packit 6f3914
            demands.resolving = True
Packit 6f3914
            demands.root_user = True
Packit 6f3914
Packit 6f3914
        def run_on_module(self):
Packit 6f3914
            try:
Packit 6f3914
                self.module_base.disable(self.opts.module_spec)
Packit 6f3914
            except dnf.exceptions.MarkingErrors as e:
Packit 6f3914
                if self.base.conf.strict:
Packit 6f3914
                    if e.no_match_group_specs or e.error_group_specs:
Packit 6f3914
                        raise e
Packit 6f3914
                    if e.module_depsolv_errors and e.module_depsolv_errors[1] != \
Packit 6f3914
                            libdnf.module.ModulePackageContainer.ModuleErrorType_ERROR_IN_DEFAULTS:
Packit 6f3914
                        raise e
Packit 6f3914
                logger.error(str(e))
Packit 6f3914
Packit 6f3914
    class ResetSubCommand(SubCommand):
Packit 6f3914
Packit 6f3914
        aliases = ('reset',)
Packit 6f3914
Packit 6f3914
        def configure(self):
Packit 6f3914
            demands = self.cli.demands
Packit 6f3914
            demands.available_repos = True
Packit 6f3914
            demands.sack_activation = True
Packit 6f3914
            demands.resolving = True
Packit 6f3914
            demands.root_user = True
Packit 6f3914
Packit 6f3914
        def run_on_module(self):
Packit 6f3914
            try:
Packit 6f3914
                self.module_base.reset(self.opts.module_spec)
Packit 6f3914
            except dnf.exceptions.MarkingErrors as e:
Packit 6f3914
                if self.base.conf.strict:
Packit 6f3914
                    if e.no_match_group_specs:
Packit 6f3914
                        raise e
Packit 6f3914
                logger.error(str(e))
Packit 6f3914
Packit 6f3914
    class InstallSubCommand(SubCommand):
Packit 6f3914
Packit 6f3914
        aliases = ('install',)
Packit 6f3914
Packit 6f3914
        def configure(self):
Packit 6f3914
            demands = self.cli.demands
Packit 6f3914
            demands.available_repos = True
Packit 6f3914
            demands.sack_activation = True
Packit 6f3914
            demands.resolving = True
Packit 6f3914
            demands.root_user = True
Packit 6f3914
Packit 6f3914
        def run_on_module(self):
Packit 6f3914
            try:
Packit 6f3914
                self.module_base.install(self.opts.module_spec, self.base.conf.strict)
Packit 6f3914
            except dnf.exceptions.MarkingErrors as e:
Packit 6f3914
                if self.base.conf.strict:
Packit 6f3914
                    if e.no_match_group_specs or e.error_group_specs:
Packit 6f3914
                        raise e
Packit 6f3914
                logger.error(str(e))
Packit 6f3914
Packit 6f3914
    class UpdateSubCommand(SubCommand):
Packit 6f3914
Packit 6f3914
        aliases = ('update',)
Packit 6f3914
Packit 6f3914
        def configure(self):
Packit 6f3914
            demands = self.cli.demands
Packit 6f3914
            demands.available_repos = True
Packit 6f3914
            demands.sack_activation = True
Packit 6f3914
            demands.resolving = True
Packit 6f3914
            demands.root_user = True
Packit 6f3914
Packit 6f3914
        def run_on_module(self):
Packit 6f3914
            module_specs = self.module_base.upgrade(self.opts.module_spec)
Packit 6f3914
            if module_specs:
Packit 6f3914
                raise NoModuleException(", ".join(module_specs))
Packit 6f3914
Packit 6f3914
    class RemoveSubCommand(SubCommand):
Packit 6f3914
Packit 6f3914
        aliases = ('remove', 'erase',)
Packit 6f3914
Packit 6f3914
        def configure(self):
Packit 6f3914
            demands = self.cli.demands
Packit 6f3914
            demands.allow_erasing = True
Packit 6f3914
            demands.available_repos = True
Packit 6f3914
            demands.fresh_metadata = False
Packit 6f3914
            demands.resolving = True
Packit 6f3914
            demands.root_user = True
Packit 6f3914
            demands.sack_activation = True
Packit 6f3914
Packit 6f3914
        def run_on_module(self):
Packit 6f3914
            skipped_groups = self.module_base.remove(self.opts.module_spec)
Packit 6f3914
            if self.opts.all:
Packit 6f3914
                modules_from_specs = self._get_modules_from_name_stream_specs()
Packit 6f3914
                remove_names_from_spec, __ = self._get_module_artifact_names(
Packit 6f3914
                    modules_from_specs, set())
Packit 6f3914
                keep_names, __ = self._get_module_artifact_names(
Packit 6f3914
                    self.base._moduleContainer.getModulePackages(), modules_from_specs)
Packit 6f3914
                remove_query = self.base.sack.query().installed().filterm(
Packit 6f3914
                    name=remove_names_from_spec)
Packit 6f3914
                keep_query = self.base.sack.query().installed().filterm(name=keep_names)
Packit 6f3914
                for pkg in remove_query:
Packit 6f3914
                    if pkg in keep_query:
Packit 6f3914
                        msg = _("Package {} belongs to multiple modules, skipping").format(pkg)
Packit 6f3914
                        logger.info(msg)
Packit 6f3914
                    else:
Packit 6f3914
                        self.base.goal.erase(
Packit 6f3914
                            pkg, clean_deps=self.base.conf.clean_requirements_on_remove)
Packit 6f3914
            if not skipped_groups:
Packit 6f3914
                return
Packit 6f3914
Packit 6f3914
            logger.error(dnf.exceptions.MarkingErrors(no_match_group_specs=skipped_groups))
Packit 6f3914
Packit 6f3914
    class ProvidesSubCommand(SubCommand):
Packit 6f3914
Packit 6f3914
        aliases = ("provides", )
Packit 6f3914
Packit 6f3914
        def configure(self):
Packit 6f3914
            demands = self.cli.demands
Packit 6f3914
            demands.available_repos = True
Packit 6f3914
            demands.sack_activation = True
Packit 6f3914
Packit 6f3914
        def run_on_module(self):
Packit 6f3914
            output = self.module_base._what_provides(self.opts.module_spec)
Packit 6f3914
            if output:
Packit 6f3914
                print(output)
Packit 6f3914
Packit 6f3914
    class RepoquerySubCommand(SubCommand):
Packit 6f3914
Packit 6f3914
        aliases = ("repoquery", )
Packit 6f3914
Packit 6f3914
        def configure(self):
Packit 6f3914
            demands = self.cli.demands
Packit 6f3914
            demands.available_repos = True
Packit 6f3914
            demands.sack_activation = True
Packit 6f3914
Packit 6f3914
        def run_on_module(self):
Packit 6f3914
            modules_from_specs = set()
Packit 6f3914
            for module_spec in self.opts.module_spec:
Packit 6f3914
                modules, __ = self.module_base._get_modules(module_spec)
Packit 6f3914
                modules_from_specs.update(modules)
Packit 6f3914
            names_from_spec, spec_artifacts = self._get_module_artifact_names(
Packit 6f3914
                modules_from_specs, set())
Packit 6f3914
            package_strings = set()
Packit 6f3914
            if self.opts.available or not self.opts.installed:
Packit 6f3914
                query = self.base.sack.query().available().filterm(nevra_strict=spec_artifacts)
Packit 6f3914
                for pkg in query:
Packit 6f3914
                    package_strings.add(str(pkg))
Packit 6f3914
            if self.opts.installed:
Packit 6f3914
                query = self.base.sack.query().installed().filterm(name=names_from_spec)
Packit 6f3914
                for pkg in query:
Packit 6f3914
                    package_strings.add(str(pkg))
Packit 6f3914
Packit 6f3914
            output = "\n".join(sorted(package_strings))
Packit 6f3914
            print(output)
Packit 6f3914
Packit 6f3914
Packit 6f3914
    SUBCMDS = {ListSubCommand, InfoSubCommand, EnableSubCommand,
Packit 6f3914
               DisableSubCommand, ResetSubCommand, InstallSubCommand, UpdateSubCommand,
Packit 6f3914
               RemoveSubCommand, ProvidesSubCommand, RepoquerySubCommand}
Packit 6f3914
Packit 6f3914
    SUBCMDS_NOT_REQUIRED_ARG = {ListSubCommand}
Packit 6f3914
Packit 6f3914
    aliases = ("module",)
Packit 6f3914
    summary = _("Interact with Modules.")
Packit 6f3914
Packit 6f3914
    def __init__(self, cli):
Packit 6f3914
        super(ModuleCommand, self).__init__(cli)
Packit 6f3914
        subcmd_objs = (subcmd(cli) for subcmd in self.SUBCMDS)
Packit 6f3914
        self.subcmd = None
Packit 6f3914
        self._subcmd_name2obj = {
Packit 6f3914
            alias: subcmd for subcmd in subcmd_objs for alias in subcmd.aliases}
Packit 6f3914
Packit 6f3914
    def set_argparser(self, parser):
Packit 6f3914
        narrows = parser.add_mutually_exclusive_group()
Packit 6f3914
        narrows.add_argument('--enabled', dest='enabled',
Packit 6f3914
                             action='store_true',
Packit 6f3914
                             help=_("show only enabled modules"))
Packit 6f3914
        narrows.add_argument('--disabled', dest='disabled',
Packit 6f3914
                             action='store_true',
Packit 6f3914
                             help=_("show only disabled modules"))
Packit 6f3914
        narrows.add_argument('--installed', dest='installed',
Packit 6f3914
                             action='store_true',
Packit 6f3914
                             help=_("show only installed modules or packages"))
Packit 6f3914
        narrows.add_argument('--profile', dest='profile',
Packit 6f3914
                             action='store_true',
Packit 6f3914
                             help=_("show profile content"))
Packit 6f3914
        parser.add_argument('--available', dest='available', action='store_true',
Packit 6f3914
                            help=_("show only available packages"))
Packit 6f3914
        narrows.add_argument('--all', dest='all',
Packit 6f3914
                             action='store_true',
Packit 6f3914
                             help=_("remove all modular packages"))
Packit 6f3914
Packit 6f3914
        subcommand_help = [subcmd.aliases[0] for subcmd in self.SUBCMDS]
Packit 6f3914
        parser.add_argument('subcmd', nargs=1, choices=subcommand_help,
Packit 6f3914
                            help=_("Modular command"))
Packit 6f3914
        parser.add_argument('module_spec', metavar='module-spec', nargs='*',
Packit 6f3914
                            help=_("Module specification"))
Packit 6f3914
Packit 6f3914
    def configure(self):
Packit 6f3914
        try:
Packit 6f3914
            self.subcmd = self._subcmd_name2obj[self.opts.subcmd[0]]
Packit 6f3914
        except (CliError, KeyError):
Packit 6f3914
            self.cli.optparser.print_usage()
Packit 6f3914
            raise CliError
Packit 6f3914
        self.subcmd.opts = self.opts
Packit 6f3914
        self.subcmd.configure()
Packit 6f3914
Packit 6f3914
    def run(self):
Packit 6f3914
        self.check_required_argument()
Packit 6f3914
        self.subcmd.run_on_module()
Packit 6f3914
Packit 6f3914
    def check_required_argument(self):
Packit 6f3914
        not_required_argument = [alias
Packit 6f3914
                                 for subcmd in self.SUBCMDS_NOT_REQUIRED_ARG
Packit 6f3914
                                 for alias in subcmd.aliases]
Packit 6f3914
        if self.opts.subcmd[0] not in not_required_argument:
Packit 6f3914
            if not self.opts.module_spec:
Packit 6f3914
                raise CliError(
Packit 6f3914
                    _("{} {} {}: too few arguments").format(dnf.util.MAIN_PROG,
Packit 6f3914
                                                            self.opts.command,
Packit 6f3914
                                                            self.opts.subcmd[0]))