Blame dnf/cli/commands/repoquery.py

Packit Service 21c75c
#
Packit Service 21c75c
# Copyright (C) 2014 Red Hat, Inc.
Packit Service 21c75c
#
Packit Service 21c75c
# This copyrighted material is made available to anyone wishing to use,
Packit Service 21c75c
# modify, copy, or redistribute it subject to the terms and conditions of
Packit Service 21c75c
# the GNU General Public License v.2, or (at your option) any later version.
Packit Service 21c75c
# This program is distributed in the hope that it will be useful, but WITHOUT
Packit Service 21c75c
# ANY WARRANTY expressed or implied, including the implied warranties of
Packit Service 21c75c
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
Packit Service 21c75c
# Public License for more details.  You should have received a copy of the
Packit Service 21c75c
# GNU General Public License along with this program; if not, write to the
Packit Service 21c75c
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit Service 21c75c
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
Packit Service 21c75c
# source code or documentation are not subject to the GNU General Public
Packit Service 21c75c
# License and may only be used or replicated with the express permission of
Packit Service 21c75c
# Red Hat, Inc.
Packit Service 21c75c
#
Packit Service 21c75c
Packit Service 21c75c
from __future__ import absolute_import
Packit Service 21c75c
from __future__ import print_function
Packit Service 21c75c
from __future__ import unicode_literals
Packit Service 21c75c
from dnf.i18n import _
Packit Service 21c75c
from dnf.cli import commands
Packit Service 21c75c
from dnf.cli.option_parser import OptionParser
Packit Service 21c75c
Packit Service 21c75c
import argparse
Packit Service 21c75c
import datetime
Packit Service 21c75c
import logging
Packit Service 21c75c
import re
Packit Service 21c75c
import sys
Packit Service 21c75c
Packit Service 21c75c
import dnf
Packit Service 21c75c
import dnf.cli
Packit Service 21c75c
import dnf.exceptions
Packit Service 21c75c
import dnf.subject
Packit Service 21c75c
import dnf.util
Packit Service 21c75c
import hawkey
Packit Service 21c75c
Packit Service 21c75c
logger = logging.getLogger('dnf')
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
QFORMAT_DEFAULT = '%{name}-%{epoch}:%{version}-%{release}.%{arch}'
Packit Service 21c75c
# matches %[-][dd]{attr}
Packit Service 21c75c
QFORMAT_MATCH = re.compile(r'%(-?\d*?){([:.\w]+?)}')
Packit Service 21c75c
Packit Service 21c75c
QUERY_TAGS = """\
Packit Service 21c75c
name, arch, epoch, version, release, reponame (repoid), evr,
Packit Service 21c75c
debug_name, source_name, source_debug_name,
Packit Service 21c75c
installtime, buildtime, size, downloadsize, installsize,
Packit Service 21c75c
provides, requires, obsoletes, conflicts, sourcerpm,
Packit Service 21c75c
description, summary, license, url, reason"""
Packit Service 21c75c
Packit Service 21c75c
OPTS_MAPPING = {
Packit Service 21c75c
    'conflicts': 'conflicts',
Packit Service 21c75c
    'enhances': 'enhances',
Packit Service 21c75c
    'obsoletes': 'obsoletes',
Packit Service 21c75c
    'provides': 'provides',
Packit Service 21c75c
    'recommends': 'recommends',
Packit Service 21c75c
    'requires': 'requires',
Packit Service 21c75c
    'requires-pre': 'requires_pre',
Packit Service 21c75c
    'suggests': 'suggests',
Packit Service 21c75c
    'supplements': 'supplements'
Packit Service 21c75c
}
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def rpm2py_format(queryformat):
Packit Service 21c75c
    """Convert a rpm like QUERYFMT to an python .format() string."""
Packit Service 21c75c
    def fmt_repl(matchobj):
Packit Service 21c75c
        fill = matchobj.groups()[0]
Packit Service 21c75c
        key = matchobj.groups()[1]
Packit Service 21c75c
        if fill:
Packit Service 21c75c
            if fill[0] == '-':
Packit Service 21c75c
                fill = '>' + fill[1:]
Packit Service 21c75c
            else:
Packit Service 21c75c
                fill = '<' + fill
Packit Service 21c75c
            fill = ':' + fill
Packit Service 21c75c
        return '{0.' + key.lower() + fill + "}"
Packit Service 21c75c
Packit Service 21c75c
    def brackets(txt):
Packit Service 21c75c
        return txt.replace('{', '{{').replace('}', '}}')
Packit Service 21c75c
Packit Service 21c75c
    queryformat = queryformat.replace("\\n", "\n").replace("\\t", "\t")
Packit Service 21c75c
    for key, value in OPTS_MAPPING.items():
Packit Service 21c75c
        queryformat = queryformat.replace(key, value)
Packit Service 21c75c
    fmt = ""
Packit Service 21c75c
    spos = 0
Packit Service 21c75c
    for item in QFORMAT_MATCH.finditer(queryformat):
Packit Service 21c75c
        fmt += brackets(queryformat[spos:item.start()])
Packit Service 21c75c
        fmt += fmt_repl(item)
Packit Service 21c75c
        spos = item.end()
Packit Service 21c75c
    fmt += brackets(queryformat[spos:])
Packit Service 21c75c
    return fmt
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
class _CommaSplitCallback(OptionParser._SplitCallback):
Packit Service 21c75c
    SPLITTER = r'\s*,\s*'
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
class RepoQueryCommand(commands.Command):
Packit Service 21c75c
    """A class containing methods needed by the cli to execute the repoquery command.
Packit Service 21c75c
    """
Packit Service 21c75c
    nevra_forms = {'repoquery-n': hawkey.FORM_NAME,
Packit Service 21c75c
                   'repoquery-na': hawkey.FORM_NA,
Packit Service 21c75c
                   'repoquery-nevra': hawkey.FORM_NEVRA}
Packit Service 21c75c
Packit Service 21c75c
    aliases = ('repoquery', 'rq') + tuple(nevra_forms.keys())
Packit Service 21c75c
    summary = _('search for packages matching keyword')
Packit Service 21c75c
Packit Service 21c75c
    @staticmethod
Packit Service 21c75c
    def filter_repo_arch(opts, query):
Packit Service 21c75c
        """Filter query by repoid and arch options"""
Packit Service 21c75c
        if opts.repo:
Packit Service 21c75c
            query.filterm(reponame=opts.repo)
Packit Service 21c75c
        if opts.arches:
Packit Service 21c75c
            query.filterm(arch=opts.arches)
Packit Service 21c75c
        return query
Packit Service 21c75c
Packit Service 21c75c
    @staticmethod
Packit Service 21c75c
    def set_argparser(parser):
Packit Service 21c75c
        parser.add_argument('-a', '--all', dest='queryall', action='store_true',
Packit Service 21c75c
                            help=_("Query all packages (shorthand for repoquery '*' "
Packit Service 21c75c
                                   "or repoquery without argument)"))
Packit Service 21c75c
        parser.add_argument('--show-duplicates', action='store_true',
Packit Service 21c75c
                            help=_("Query all versions of packages (default)"))
Packit Service 21c75c
        parser.add_argument('--arch', '--archlist', dest='arches', default=[],
Packit Service 21c75c
                            action=_CommaSplitCallback, metavar='[arch]',
Packit Service 21c75c
                            help=_('show only results from this ARCH'))
Packit Service 21c75c
        parser.add_argument('-f', '--file', metavar='FILE', nargs='+',
Packit Service 21c75c
                            help=_('show only results that owns FILE'))
Packit Service 21c75c
        parser.add_argument('--whatconflicts', default=[], action=_CommaSplitCallback,
Packit Service 21c75c
                            metavar='REQ',
Packit Service 21c75c
                            help=_('show only results that conflict REQ'))
Packit Service 21c75c
        parser.add_argument('--whatdepends', default=[], action=_CommaSplitCallback,
Packit Service 21c75c
                            metavar='REQ',
Packit Service 21c75c
                            help=_('shows results that requires, suggests, supplements, enhances,'
Packit Service 21c75c
                                   'or recommends package provides and files REQ'))
Packit Service 21c75c
        parser.add_argument('--whatobsoletes', default=[], action=_CommaSplitCallback,
Packit Service 21c75c
                            metavar='REQ',
Packit Service 21c75c
                            help=_('show only results that obsolete REQ'))
Packit Service 21c75c
        parser.add_argument('--whatprovides', default=[], action=_CommaSplitCallback,
Packit Service 21c75c
                            metavar='REQ',
Packit Service 21c75c
                            help=_('show only results that provide REQ'))
Packit Service 21c75c
        parser.add_argument('--whatrequires', default=[], action=_CommaSplitCallback,
Packit Service 21c75c
                            metavar='REQ',
Packit Service 21c75c
                            help=_('shows results that requires package provides and files REQ'))
Packit Service 21c75c
        parser.add_argument('--whatrecommends', default=[], action=_CommaSplitCallback,
Packit Service 21c75c
                            metavar='REQ',
Packit Service 21c75c
                            help=_('show only results that recommend REQ'))
Packit Service 21c75c
        parser.add_argument('--whatenhances', default=[], action=_CommaSplitCallback,
Packit Service 21c75c
                            metavar='REQ',
Packit Service 21c75c
                            help=_('show only results that enhance REQ'))
Packit Service 21c75c
        parser.add_argument('--whatsuggests', default=[], action=_CommaSplitCallback,
Packit Service 21c75c
                            metavar='REQ',
Packit Service 21c75c
                            help=_('show only results that suggest REQ'))
Packit Service 21c75c
        parser.add_argument('--whatsupplements', default=[], action=_CommaSplitCallback,
Packit Service 21c75c
                            metavar='REQ',
Packit Service 21c75c
                            help=_('show only results that supplement REQ'))
Packit Service 21c75c
        whatrequiresform = parser.add_mutually_exclusive_group()
Packit Service 21c75c
        whatrequiresform.add_argument("--alldeps", action="store_true",
Packit Service 21c75c
                                      help=_("check non-explicit dependencies (files and Provides); default"))
Packit Service 21c75c
        whatrequiresform.add_argument("--exactdeps", action="store_true",
Packit Service 21c75c
                                      help=_('check dependencies exactly as given, opposite of --alldeps'))
Packit Service 21c75c
        parser.add_argument("--recursive", action="store_true", help=_(
Packit Service 21c75c
            'used with --whatrequires, and --requires --resolve, query packages recursively.'))
Packit Service 21c75c
        parser.add_argument('--deplist', action='store_true', help=_(
Packit Service 21c75c
            "show a list of all dependencies and what packages provide them"))
Packit Service 21c75c
        parser.add_argument('--resolve', action='store_true',
Packit Service 21c75c
                            help=_('resolve capabilities to originating package(s)'))
Packit Service 21c75c
        parser.add_argument("--tree", action="store_true",
Packit Service 21c75c
                            help=_('show recursive tree for package(s)'))
Packit Service 21c75c
        parser.add_argument('--srpm', action='store_true',
Packit Service 21c75c
                            help=_('operate on corresponding source RPM'))
Packit Service 21c75c
        parser.add_argument("--latest-limit", dest='latest_limit', type=int,
Packit Service 21c75c
                             help=_('show N latest packages for a given name.arch'
Packit Service 21c75c
                                    ' (or latest but N if N is negative)'))
Packit Service 21c75c
        parser.add_argument("--disable-modular-filtering", action="store_true",
Packit Service 21c75c
                            help=_("list also packages of inactive module streams"))
Packit Service 21c75c
Packit Service 21c75c
        outform = parser.add_mutually_exclusive_group()
Packit Service 21c75c
        outform.add_argument('-i', "--info", dest='queryinfo',
Packit Service 21c75c
                             default=False, action='store_true',
Packit Service 21c75c
                             help=_('show detailed information about the package'))
Packit Service 21c75c
        outform.add_argument('-l', "--list", dest='queryfilelist',
Packit Service 21c75c
                             default=False, action='store_true',
Packit Service 21c75c
                             help=_('show list of files in the package'))
Packit Service 21c75c
        outform.add_argument('-s', "--source", dest='querysourcerpm',
Packit Service 21c75c
                             default=False, action='store_true',
Packit Service 21c75c
                             help=_('show package source RPM name'))
Packit Service 21c75c
        outform.add_argument('--changelogs', dest='querychangelogs',
Packit Service 21c75c
                             default=False, action='store_true',
Packit Service 21c75c
                             help=_('show changelogs of the package'))
Packit Service 21c75c
        outform.add_argument('--qf', "--queryformat", dest='queryformat',
Packit Service 21c75c
                             default=QFORMAT_DEFAULT,
Packit Service 21c75c
                             help=_('display format for listing packages: '
Packit Service 21c75c
                                    '"%%{name} %%{version} ...", '
Packit Service 21c75c
                                    'use --querytags to view full tag list'))
Packit Service 21c75c
        parser.add_argument('--querytags', action='store_true',
Packit Service 21c75c
                            help=_('show available tags to use with '
Packit Service 21c75c
                                   '--queryformat'))
Packit Service 21c75c
        outform.add_argument("--nevra", dest='queryformat', const=QFORMAT_DEFAULT,
Packit Service 21c75c
                             action='store_const',
Packit Service 21c75c
                             help=_('use name-epoch:version-release.architecture format for '
Packit Service 21c75c
                                    'displaying found packages (default)'))
Packit Service 21c75c
        outform.add_argument("--nvr", dest='queryformat', const='%{name}-%{version}-%{release}',
Packit Service 21c75c
                             action='store_const', help=_('use name-version-release format for '
Packit Service 21c75c
                                                          'displaying found packages '
Packit Service 21c75c
                                                          '(rpm query default)'))
Packit Service 21c75c
        outform.add_argument("--envra", dest='queryformat',
Packit Service 21c75c
                             const='%{epoch}:%{name}-%{version}-%{release}.%{arch}',
Packit Service 21c75c
                             action='store_const',
Packit Service 21c75c
                             help=_('use epoch:name-version-release.architecture format for '
Packit Service 21c75c
                                    'displaying found packages'))
Packit Service 21c75c
        outform.add_argument('--groupmember', action="store_true", help=_(
Packit Service 21c75c
            'Display in which comps groups are presented selected packages'))
Packit Service 21c75c
        pkgfilter = parser.add_mutually_exclusive_group()
Packit Service 21c75c
        pkgfilter.add_argument("--duplicates", dest='pkgfilter',
Packit Service 21c75c
                               const='duplicated', action='store_const',
Packit Service 21c75c
                               help=_('limit the query to installed duplicate '
Packit Service 21c75c
                                      'packages'))
Packit Service 21c75c
        pkgfilter.add_argument("--duplicated", dest='pkgfilter',
Packit Service 21c75c
                               const='duplicated', action='store_const',
Packit Service 21c75c
                               help=argparse.SUPPRESS)
Packit Service 21c75c
        pkgfilter.add_argument("--installonly", dest='pkgfilter',
Packit Service 21c75c
                               const='installonly', action='store_const',
Packit Service 21c75c
                               help=_('limit the query to installed installonly packages'))
Packit Service 21c75c
        pkgfilter.add_argument("--unsatisfied", dest='pkgfilter',
Packit Service 21c75c
                               const='unsatisfied', action='store_const',
Packit Service 21c75c
                               help=_('limit the query to installed packages with unsatisfied dependencies'))
Packit Service 21c75c
        parser.add_argument('--location', action='store_true',
Packit Service 21c75c
                            help=_('show a location from where packages can be downloaded'))
Packit Service 21c75c
        package_attribute = parser.add_mutually_exclusive_group()
Packit Service 21c75c
        help_msgs = {
Packit Service 21c75c
            'conflicts': _('Display capabilities that the package conflicts with.'),
Packit Service 21c75c
            'depends': _('Display capabilities that the package can depend on, enhance, recommend,'
Packit Service 21c75c
                         ' suggest, and supplement.'),
Packit Service 21c75c
            'enhances': _('Display capabilities that the package can enhance.'),
Packit Service 21c75c
            'provides': _('Display capabilities provided by the package.'),
Packit Service 21c75c
            'recommends':  _('Display capabilities that the package recommends.'),
Packit Service 21c75c
            'requires':  _('Display capabilities that the package depends on.'),
Packit Service 21c75c
            'requires-pre':  _('If the package is not installed display capabilities that it depends on for '
Packit Service 21c75c
                               'running %%pre and %%post scriptlets. If the package is installed display '
Packit Service 21c75c
                               'capabilities that is depends for %%pre, %%post, %%preun and %%postun.'),
Packit Service 21c75c
            'suggests':  _('Display capabilities that the package suggests.'),
Packit Service 21c75c
            'supplements':  _('Display capabilities that the package can supplement.')
Packit Service 21c75c
        }
Packit Service 21c75c
        for arg, help_msg in help_msgs.items():
Packit Service 21c75c
            name = '--%s' % arg
Packit Service 21c75c
            package_attribute.add_argument(name, dest='packageatr', action='store_const',
Packit Service 21c75c
                                           const=arg, help=help_msg)
Packit Service 21c75c
        parser.add_argument('--available', action="store_true", help=_('Display only available packages.'))
Packit Service 21c75c
Packit Service 21c75c
        help_list = {
Packit Service 21c75c
            'installed': _('Display only installed packages.'),
Packit Service 21c75c
            'extras': _('Display only packages that are not present in any of available repositories.'),
Packit Service 21c75c
            'upgrades': _('Display only packages that provide an upgrade for some already installed package.'),
Packit Service 21c75c
            'unneeded': _('Display only packages that can be removed by "{prog} autoremove" '
Packit Service 21c75c
                          'command.').format(prog=dnf.util.MAIN_PROG),
Packit Service 21c75c
            'userinstalled': _('Display only packages that were installed by user.')
Packit Service 21c75c
        }
Packit Service 21c75c
        list_group = parser.add_mutually_exclusive_group()
Packit Service 21c75c
        for list_arg, help_arg in help_list.items():
Packit Service 21c75c
            switch = '--%s' % list_arg
Packit Service 21c75c
            list_group.add_argument(switch, dest='list', action='store_const',
Packit Service 21c75c
                                    const=list_arg, help=help_arg)
Packit Service 21c75c
Packit Service 21c75c
        # make --autoremove hidden compatibility alias for --unneeded
Packit Service 21c75c
        list_group.add_argument(
Packit Service 21c75c
            '--autoremove', dest='list', action='store_const',
Packit Service 21c75c
            const="unneeded", help=argparse.SUPPRESS)
Packit Service 21c75c
        parser.add_argument('--recent', action="store_true", help=_('Display only recently edited packages'))
Packit Service 21c75c
Packit Service 21c75c
        parser.add_argument('key', nargs='*', metavar="KEY",
Packit Service 21c75c
                            help=_('the key to search for'))
Packit Service 21c75c
Packit Service 21c75c
    def pre_configure(self):
Packit Service 21c75c
        if not self.opts.quiet:
Packit Service 21c75c
            self.cli.redirect_logger(stdout=logging.WARNING, stderr=logging.INFO)
Packit Service 21c75c
Packit Service 21c75c
    def configure(self):
Packit Service 21c75c
        if not self.opts.quiet:
Packit Service 21c75c
            self.cli.redirect_repo_progress()
Packit Service 21c75c
        demands = self.cli.demands
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.obsoletes:
Packit Service 21c75c
            if self.opts.packageatr:
Packit Service 21c75c
                self.cli._option_conflict("--obsoletes", "--" + self.opts.packageatr)
Packit Service 21c75c
            else:
Packit Service 21c75c
                self.opts.packageatr = "obsoletes"
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.querytags:
Packit Service 21c75c
            return
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.resolve and not self.opts.packageatr:
Packit Service 21c75c
            raise dnf.cli.CliError(
Packit Service 21c75c
                _("Option '--resolve' has to be used together with one of the "
Packit Service 21c75c
                  "'--conflicts', '--depends', '--enhances', '--provides', '--recommends', "
Packit Service 21c75c
                  "'--requires', '--requires-pre', '--suggests' or '--supplements' options"))
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.recursive:
Packit Service 21c75c
            if self.opts.exactdeps:
Packit Service 21c75c
                self.cli._option_conflict("--recursive", "--exactdeps")
Packit Service 21c75c
            if not any([self.opts.whatrequires,
Packit Service 21c75c
                        (self.opts.packageatr == "requires" and self.opts.resolve)]):
Packit Service 21c75c
                raise dnf.cli.CliError(
Packit Service 21c75c
                    _("Option '--recursive' has to be used with '--whatrequires <REQ>' "
Packit Service 21c75c
                      "(optionally with '--alldeps', but not with '--exactdeps'), or with "
Packit Service 21c75c
                      "'--requires <REQ> --resolve'"))
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.alldeps or self.opts.exactdeps:
Packit Service 21c75c
            if not (self.opts.whatrequires or self.opts.whatdepends):
Packit Service 21c75c
                raise dnf.cli.CliError(
Packit Service 21c75c
                    _("argument {} requires --whatrequires or --whatdepends option".format(
Packit Service 21c75c
                        '--alldeps' if self.opts.alldeps else '--exactdeps')))
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.srpm:
Packit Service 21c75c
            self.base.repos.enable_source_repos()
Packit Service 21c75c
Packit Service 21c75c
        if (self.opts.list not in ["installed", "userinstalled"] and
Packit Service 21c75c
           self.opts.pkgfilter != "installonly") or self.opts.available:
Packit Service 21c75c
            demands.available_repos = True
Packit Service 21c75c
Packit Service 21c75c
        demands.sack_activation = True
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.querychangelogs:
Packit Service 21c75c
            demands.changelogs = True
Packit Service 21c75c
Packit Service 21c75c
    def build_format_fn(self, opts, pkg):
Packit Service 21c75c
        if opts.querychangelogs:
Packit Service 21c75c
            out = []
Packit Service 21c75c
            out.append('Changelog for %s' % str(pkg))
Packit Service 21c75c
            for chlog in pkg.changelogs:
Packit Service 21c75c
                dt = chlog['timestamp']
Packit Service 21c75c
                out.append('* %s %s\n%s\n' % (dt.strftime("%a %b %d %Y"),
Packit Service 21c75c
                                              dnf.i18n.ucd(chlog['author']),
Packit Service 21c75c
                                              dnf.i18n.ucd(chlog['text'])))
Packit Service 21c75c
            return '\n'.join(out)
Packit Service 21c75c
        try:
Packit Service 21c75c
            po = PackageWrapper(pkg)
Packit Service 21c75c
            if opts.queryinfo:
Packit Service 21c75c
                return self.base.output.infoOutput(pkg)
Packit Service 21c75c
            elif opts.queryfilelist:
Packit Service 21c75c
                filelist = po.files
Packit Service 21c75c
                if not filelist:
Packit Service 21c75c
                    print(_('Package {} contains no files').format(pkg), file=sys.stderr)
Packit Service 21c75c
                return filelist
Packit Service 21c75c
            elif opts.querysourcerpm:
Packit Service 21c75c
                return po.sourcerpm
Packit Service 21c75c
            else:
Packit Service 21c75c
                return rpm2py_format(opts.queryformat).format(po)
Packit Service 21c75c
        except AttributeError as e:
Packit Service 21c75c
            # catch that the user has specified attributes
Packit Service 21c75c
            # there don't exist on the dnf Package object.
Packit Service 21c75c
            raise dnf.exceptions.Error(str(e))
Packit Service 21c75c
Packit Service 21c75c
    def _resolve_nevras(self, nevras, base_query):
Packit Service 21c75c
        resolved_nevras_query = self.base.sack.query().filterm(empty=True)
Packit Service 21c75c
        for nevra in nevras:
Packit Service 21c75c
            resolved_nevras_query = resolved_nevras_query.union(base_query.intersection(
Packit Service 21c75c
                dnf.subject.Subject(nevra).get_best_query(
Packit Service 21c75c
                    self.base.sack,
Packit Service 21c75c
                    with_provides=False,
Packit Service 21c75c
                    with_filenames=False
Packit Service 21c75c
                )
Packit Service 21c75c
            ))
Packit Service 21c75c
Packit Service 21c75c
        return resolved_nevras_query
Packit Service 21c75c
Packit Service 21c75c
    def _do_recursive_deps(self, query_in, query_select, done=None):
Packit Service 21c75c
        done = done if done else query_select
Packit Service 21c75c
Packit Service 21c75c
        query_required = query_in.filter(requires=query_select)
Packit Service 21c75c
Packit Service 21c75c
        query_select = query_required.difference(done)
Packit Service 21c75c
        done = query_required.union(done)
Packit Service 21c75c
Packit Service 21c75c
        if query_select:
Packit Service 21c75c
            done = self._do_recursive_deps(query_in, query_select, done=done)
Packit Service 21c75c
Packit Service 21c75c
        return done
Packit Service 21c75c
Packit Service 21c75c
    def by_all_deps(self, names, query, all_dep_types=False):
Packit Service 21c75c
        # in case of arguments being NEVRAs, resolve them to packages
Packit Service 21c75c
        resolved_nevras_query = self._resolve_nevras(names, query)
Packit Service 21c75c
Packit Service 21c75c
        # filter the arguments directly as reldeps
Packit Service 21c75c
        depquery = query.filter(requires__glob=names)
Packit Service 21c75c
Packit Service 21c75c
        # filter the resolved NEVRAs as packages
Packit Service 21c75c
        depquery = depquery.union(query.filter(requires=resolved_nevras_query))
Packit Service 21c75c
Packit Service 21c75c
        if all_dep_types:
Packit Service 21c75c
            # TODO this is very inefficient, as it resolves the `names` glob to
Packit Service 21c75c
            # reldeps four more times, which in a reasonably wide glob like
Packit Service 21c75c
            # `dnf repoquery --whatdepends "libdnf*"` can take roughly 50% of
Packit Service 21c75c
            # the total execution time.
Packit Service 21c75c
            depquery = depquery.union(query.filter(recommends__glob=names))
Packit Service 21c75c
            depquery = depquery.union(query.filter(enhances__glob=names))
Packit Service 21c75c
            depquery = depquery.union(query.filter(supplements__glob=names))
Packit Service 21c75c
            depquery = depquery.union(query.filter(suggests__glob=names))
Packit Service 21c75c
Packit Service 21c75c
            depquery = depquery.union(query.filter(recommends=resolved_nevras_query))
Packit Service 21c75c
            depquery = depquery.union(query.filter(enhances=resolved_nevras_query))
Packit Service 21c75c
            depquery = depquery.union(query.filter(supplements=resolved_nevras_query))
Packit Service 21c75c
            depquery = depquery.union(query.filter(suggests=resolved_nevras_query))
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.recursive:
Packit Service 21c75c
            depquery = self._do_recursive_deps(query, depquery)
Packit Service 21c75c
Packit Service 21c75c
        return depquery
Packit Service 21c75c
Packit Service 21c75c
    def _get_recursive_providers_query(self, query_in, providers, done=None):
Packit Service 21c75c
        done = done if done else self.base.sack.query().filterm(empty=True)
Packit Service 21c75c
        t = self.base.sack.query().filterm(empty=True)
Packit Service 21c75c
        for pkg in providers.run():
Packit Service 21c75c
            t = t.union(query_in.filter(provides=pkg.requires))
Packit Service 21c75c
        query_select = t.difference(done)
Packit Service 21c75c
        if query_select:
Packit Service 21c75c
            done = self._get_recursive_providers_query(query_in, query_select, done=t.union(done))
Packit Service 21c75c
        return t.union(done)
Packit Service 21c75c
Packit Service 21c75c
    def _add_add_remote_packages(self):
Packit Service 21c75c
        rpmnames = []
Packit Service 21c75c
        remote_packages = []
Packit Service 21c75c
        for key in self.opts.key:
Packit Service 21c75c
            schemes = dnf.pycomp.urlparse.urlparse(key)[0]
Packit Service 21c75c
            if key.endswith('.rpm'):
Packit Service 21c75c
                rpmnames.append(key)
Packit Service 21c75c
            elif schemes and schemes in ('http', 'ftp', 'file', 'https'):
Packit Service 21c75c
                rpmnames.append(key)
Packit Service 21c75c
        if rpmnames:
Packit Service 21c75c
            remote_packages = self.base.add_remote_rpms(
Packit Service 21c75c
                rpmnames, strict=False, progress=self.base.output.progress)
Packit Service 21c75c
        return remote_packages
Packit Service 21c75c
Packit Service 21c75c
    def run(self):
Packit Service 21c75c
        if self.opts.querytags:
Packit Service 21c75c
            print(QUERY_TAGS)
Packit Service 21c75c
            return
Packit Service 21c75c
Packit Service 21c75c
        self.cli._populate_update_security_filter(self.opts, self.base.sack.query())
Packit Service 21c75c
Packit Service 21c75c
        q = self.base.sack.query(
Packit Service 21c75c
            flags=hawkey.IGNORE_MODULAR_EXCLUDES
Packit Service 21c75c
            if self.opts.disable_modular_filtering
Packit Service 21c75c
            else hawkey.APPLY_EXCLUDES
Packit Service 21c75c
        )
Packit Service 21c75c
        if self.opts.key:
Packit Service 21c75c
            remote_packages = self._add_add_remote_packages()
Packit Service 21c75c
Packit Service 21c75c
            kwark = {}
Packit Service 21c75c
            if self.opts.command in self.nevra_forms:
Packit Service 21c75c
                kwark["forms"] = [self.nevra_forms[self.opts.command]]
Packit Service 21c75c
            pkgs = []
Packit Service 21c75c
            query_results = q.filter(empty=True)
Packit Service 21c75c
Packit Service 21c75c
            if remote_packages:
Packit Service 21c75c
                query_results = query_results.union(
Packit Service 21c75c
                    self.base.sack.query().filterm(pkg=remote_packages))
Packit Service 21c75c
Packit Service 21c75c
            for key in self.opts.key:
Packit Service 21c75c
                query_results = query_results.union(
Packit Service 21c75c
                    dnf.subject.Subject(key, ignore_case=True).get_best_query(
Packit Service 21c75c
                        self.base.sack, with_provides=False, query=q, **kwark))
Packit Service 21c75c
            q = query_results
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.recent:
Packit Service 21c75c
            q = q._recent(self.base.conf.recent)
Packit Service 21c75c
        if self.opts.available:
Packit Service 21c75c
            if self.opts.list and self.opts.list != "installed":
Packit Service 21c75c
                print(self.cli.optparser.print_usage())
Packit Service 21c75c
                raise dnf.exceptions.Error(_("argument {}: not allowed with argument {}".format(
Packit Service 21c75c
                    "--available", "--" + self.opts.list)))
Packit Service 21c75c
        elif self.opts.list == "unneeded":
Packit Service 21c75c
            q = q._unneeded(self.base.history.swdb)
Packit Service 21c75c
        elif self.opts.list and self.opts.list != 'userinstalled':
Packit Service 21c75c
            q = getattr(q, self.opts.list)()
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.pkgfilter == "duplicated":
Packit Service 21c75c
            installonly = self.base._get_installonly_query(q)
Packit Service 21c75c
            q = q.difference(installonly).duplicated()
Packit Service 21c75c
        elif self.opts.pkgfilter == "installonly":
Packit Service 21c75c
            q = self.base._get_installonly_query(q)
Packit Service 21c75c
        elif self.opts.pkgfilter == "unsatisfied":
Packit Service 21c75c
            rpmdb = dnf.sack.rpmdb_sack(self.base)
Packit Service 21c75c
            rpmdb._configure(self.base.conf.installonlypkgs, self.base.conf.installonly_limit)
Packit Service 21c75c
            goal = dnf.goal.Goal(rpmdb)
Packit Service 21c75c
            goal.protect_running_kernel = False
Packit Service 21c75c
            solved = goal.run(verify=True)
Packit Service 21c75c
            if not solved:
Packit Service 21c75c
                print(dnf.util._format_resolve_problems(goal.problem_rules()))
Packit Service 21c75c
            return
Packit Service 21c75c
        elif not self.opts.list:
Packit Service 21c75c
            # do not show packages from @System repo
Packit Service 21c75c
            q = q.available()
Packit Service 21c75c
Packit Service 21c75c
        # filter repo and arch
Packit Service 21c75c
        q = self.filter_repo_arch(self.opts, q)
Packit Service 21c75c
        orquery = q
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.file:
Packit Service 21c75c
            q.filterm(file__glob=self.opts.file)
Packit Service 21c75c
        if self.opts.whatconflicts:
Packit Service 21c75c
            rels = q.filter(conflicts__glob=self.opts.whatconflicts)
Packit Service 21c75c
            q = rels.union(q.filter(conflicts=self._resolve_nevras(self.opts.whatconflicts, q)))
Packit Service 21c75c
        if self.opts.whatobsoletes:
Packit Service 21c75c
            q.filterm(obsoletes=self.opts.whatobsoletes)
Packit Service 21c75c
        if self.opts.whatprovides:
Packit Service 21c75c
            query_for_provide = q.filter(provides__glob=self.opts.whatprovides)
Packit Service 21c75c
            if query_for_provide:
Packit Service 21c75c
                q = query_for_provide
Packit Service 21c75c
            else:
Packit Service 21c75c
                q.filterm(file__glob=self.opts.whatprovides)
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.whatrequires:
Packit Service 21c75c
            if (self.opts.exactdeps):
Packit Service 21c75c
                q.filterm(requires__glob=self.opts.whatrequires)
Packit Service 21c75c
            else:
Packit Service 21c75c
                q = self.by_all_deps(self.opts.whatrequires, q)
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.whatdepends:
Packit Service 21c75c
            if (self.opts.exactdeps):
Packit Service 21c75c
                dependsquery = q.filter(requires__glob=self.opts.whatdepends)
Packit Service 21c75c
                dependsquery = dependsquery.union(q.filter(recommends__glob=self.opts.whatdepends))
Packit Service 21c75c
                dependsquery = dependsquery.union(q.filter(enhances__glob=self.opts.whatdepends))
Packit Service 21c75c
                dependsquery = dependsquery.union(q.filter(supplements__glob=self.opts.whatdepends))
Packit Service 21c75c
                q = dependsquery.union(q.filter(suggests__glob=self.opts.whatdepends))
Packit Service 21c75c
            else:
Packit Service 21c75c
                q = self.by_all_deps(self.opts.whatdepends, q, True)
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.whatrecommends:
Packit Service 21c75c
            rels = q.filter(recommends__glob=self.opts.whatrecommends)
Packit Service 21c75c
            q = rels.union(q.filter(recommends=self._resolve_nevras(self.opts.whatrecommends, q)))
Packit Service 21c75c
        if self.opts.whatenhances:
Packit Service 21c75c
            rels = q.filter(enhances__glob=self.opts.whatenhances)
Packit Service 21c75c
            q = rels.union(q.filter(enhances=self._resolve_nevras(self.opts.whatenhances, q)))
Packit Service 21c75c
        if self.opts.whatsupplements:
Packit Service 21c75c
            rels = q.filter(supplements__glob=self.opts.whatsupplements)
Packit Service 21c75c
            q = rels.union(q.filter(supplements=self._resolve_nevras(self.opts.whatsupplements, q)))
Packit Service 21c75c
        if self.opts.whatsuggests:
Packit Service 21c75c
            rels = q.filter(suggests__glob=self.opts.whatsuggests)
Packit Service 21c75c
            q = rels.union(q.filter(suggests=self._resolve_nevras(self.opts.whatsuggests, q)))
Packit Service 21c75c
Packit Service 21c75c
        if self.opts.latest_limit:
Packit Service 21c75c
            q = q.latest(self.opts.latest_limit)
Packit Service 21c75c
        # reduce a query to security upgrades if they are specified
Packit Service 21c75c
        q = self.base._merge_update_filters(q, warning=False)
Packit Service 21c75c
        if self.opts.srpm:
Packit Service 21c75c
            pkg_list = []
Packit Service 21c75c
            for pkg in q:
Packit Service 21c75c
                srcname = pkg.source_name
Packit Service 21c75c
                if srcname is not None:
Packit Service 21c75c
                    tmp_query = self.base.sack.query().filterm(name=srcname, evr=pkg.evr,
Packit Service 21c75c
                                                               arch='src')
Packit Service 21c75c
                    pkg_list += tmp_query.run()
Packit Service 21c75c
            q = self.base.sack.query().filterm(pkg=pkg_list)
Packit Service 21c75c
        if self.opts.tree:
Packit Service 21c75c
            if not self.opts.whatrequires and self.opts.packageatr not in (
Packit Service 21c75c
                    'conflicts', 'enhances', 'obsoletes', 'provides', 'recommends',
Packit Service 21c75c
                    'requires', 'suggests', 'supplements'):
Packit Service 21c75c
                raise dnf.exceptions.Error(
Packit Service 21c75c
                    _("No valid switch specified\nusage: {prog} repoquery [--conflicts|"
Packit Service 21c75c
                      "--enhances|--obsoletes|--provides|--recommends|--requires|"
Packit Service 21c75c
                      "--suggest|--supplements|--whatrequires] [key] [--tree]\n\n"
Packit Service 21c75c
                      "description:\n  For the given packages print a tree of the"
Packit Service 21c75c
                      "packages.").format(prog=dnf.util.MAIN_PROG))
Packit Service 21c75c
            self.tree_seed(q, orquery, self.opts)
Packit Service 21c75c
            return
Packit Service 21c75c
Packit Service 21c75c
        pkgs = set()
Packit Service 21c75c
        if self.opts.packageatr:
Packit Service 21c75c
            rels = set()
Packit Service 21c75c
            for pkg in q.run():
Packit Service 21c75c
                if self.opts.list != 'userinstalled' or self.base.history.user_installed(pkg):
Packit Service 21c75c
                    if self.opts.packageatr == 'depends':
Packit Service 21c75c
                        rels.update(pkg.requires + pkg.enhances + pkg.suggests +
Packit Service 21c75c
                                    pkg.supplements + pkg.recommends)
Packit Service 21c75c
                    else:
Packit Service 21c75c
                        rels.update(getattr(pkg, OPTS_MAPPING[self.opts.packageatr]))
Packit Service 21c75c
            if self.opts.resolve:
Packit Service 21c75c
                # find the providing packages and show them
Packit Service 21c75c
                if self.opts.list == "installed":
Packit Service 21c75c
                    query = self.filter_repo_arch(self.opts, self.base.sack.query())
Packit Service 21c75c
                else:
Packit Service 21c75c
                    query = self.filter_repo_arch(self.opts, self.base.sack.query().available())
Packit Service 21c75c
                providers = query.filter(provides=rels)
Packit Service 21c75c
                if self.opts.recursive:
Packit Service 21c75c
                    providers = providers.union(
Packit Service 21c75c
                        self._get_recursive_providers_query(query, providers))
Packit Service 21c75c
                pkgs = set()
Packit Service 21c75c
                for pkg in providers.latest().run():
Packit Service 21c75c
                    pkgs.add(self.build_format_fn(self.opts, pkg))
Packit Service 21c75c
            else:
Packit Service 21c75c
                pkgs.update(str(rel) for rel in rels)
Packit Service 21c75c
        elif self.opts.location:
Packit Service 21c75c
            for pkg in q.run():
Packit Service 21c75c
                location = pkg.remote_location()
Packit Service 21c75c
                if location is not None:
Packit Service 21c75c
                    pkgs.add(location)
Packit Service 21c75c
        elif self.opts.deplist:
Packit Service 21c75c
            pkgs = []
Packit Service 21c75c
            for pkg in sorted(set(q.run())):
Packit Service 21c75c
                if self.opts.list != 'userinstalled' or self.base.history.user_installed(pkg):
Packit Service 21c75c
                    deplist_output = []
Packit Service 21c75c
                    deplist_output.append('package: ' + str(pkg))
Packit Service 21c75c
                    for req in sorted([str(req) for req in pkg.requires]):
Packit Service 21c75c
                        deplist_output.append('  dependency: ' + req)
Packit Service 21c75c
                        subject = dnf.subject.Subject(req)
Packit Service 21c75c
                        query = subject.get_best_query(self.base.sack)
Packit Service 21c75c
                        query = self.filter_repo_arch(
Packit Service 21c75c
                            self.opts, query.available())
Packit Service 21c75c
                        if not self.opts.verbose:
Packit Service 21c75c
                            query = query.latest()
Packit Service 21c75c
                        for provider in query.run():
Packit Service 21c75c
                            deplist_output.append('   provider: ' + str(provider))
Packit Service 21c75c
                    pkgs.append('\n'.join(deplist_output))
Packit Service 21c75c
            if pkgs:
Packit Service 21c75c
                print('\n\n'.join(pkgs))
Packit Service 21c75c
            return
Packit Service 21c75c
        elif self.opts.groupmember:
Packit Service 21c75c
            self._group_member_report(q)
Packit Service 21c75c
            return
Packit Service 21c75c
Packit Service 21c75c
        else:
Packit Service 21c75c
            for pkg in q.run():
Packit Service 21c75c
                if self.opts.list != 'userinstalled' or self.base.history.user_installed(pkg):
Packit Service 21c75c
                    pkgs.add(self.build_format_fn(self.opts, pkg))
Packit Service 21c75c
Packit Service 21c75c
        if pkgs:
Packit Service 21c75c
            if self.opts.queryinfo:
Packit Service 21c75c
                print("\n\n".join(sorted(pkgs)))
Packit Service 21c75c
            else:
Packit Service 21c75c
                print("\n".join(sorted(pkgs)))
Packit Service 21c75c
Packit Service 21c75c
    def _group_member_report(self, query):
Packit Service 21c75c
        package_conf_dict = {}
Packit Service 21c75c
        for group in self.base.comps.groups:
Packit Service 21c75c
            package_conf_dict[group.id] = set([pkg.name for pkg in group.packages_iter()])
Packit Service 21c75c
        group_package_dict = {}
Packit Service 21c75c
        pkg_not_in_group = []
Packit Service 21c75c
        for pkg in query.run():
Packit Service 21c75c
            group_id_list = []
Packit Service 21c75c
            for group_id, package_name_set in package_conf_dict.items():
Packit Service 21c75c
                if pkg.name in package_name_set:
Packit Service 21c75c
                    group_id_list.append(group_id)
Packit Service 21c75c
            if group_id_list:
Packit Service 21c75c
                group_package_dict.setdefault(
Packit Service 21c75c
                    '$'.join(sorted(group_id_list)), []).append(str(pkg))
Packit Service 21c75c
            else:
Packit Service 21c75c
                pkg_not_in_group.append(str(pkg))
Packit Service 21c75c
        output = []
Packit Service 21c75c
        for key, package_list in sorted(group_package_dict.items()):
Packit Service 21c75c
            output.append(
Packit Service 21c75c
                '\n'.join(sorted(package_list) + sorted(['  @' + id for id in key.split('$')])))
Packit Service 21c75c
        output.append('\n'.join(sorted(pkg_not_in_group)))
Packit Service 21c75c
        if output:
Packit Service 21c75c
            print('\n'.join(output))
Packit Service 21c75c
Packit Service 21c75c
    def grow_tree(self, level, pkg, opts):
Packit Service 21c75c
        pkg_string = self.build_format_fn(opts, pkg)
Packit Service 21c75c
        if level == -1:
Packit Service 21c75c
            print(pkg_string)
Packit Service 21c75c
            return
Packit Service 21c75c
        spacing = " "
Packit Service 21c75c
        for x in range(0, level):
Packit Service 21c75c
            spacing += "|   "
Packit Service 21c75c
        requires = []
Packit Service 21c75c
        for requirepkg in pkg.requires:
Packit Service 21c75c
            requires.append(str(requirepkg))
Packit Service 21c75c
        reqstr = "[" + str(len(requires)) + ": " + ", ".join(requires) + "]"
Packit Service 21c75c
        print(spacing + r"\_ " + pkg_string + " " + reqstr)
Packit Service 21c75c
Packit Service 21c75c
    def tree_seed(self, query, aquery, opts, level=-1, usedpkgs=None):
Packit Service 21c75c
        for pkg in sorted(set(query.run()), key=lambda p: p.name):
Packit Service 21c75c
            usedpkgs = set() if usedpkgs is None or level == -1 else usedpkgs
Packit Service 21c75c
            if pkg.name.startswith("rpmlib") or pkg.name.startswith("solvable"):
Packit Service 21c75c
                return
Packit Service 21c75c
            self.grow_tree(level, pkg, opts)
Packit Service 21c75c
            if pkg not in usedpkgs:
Packit Service 21c75c
                usedpkgs.add(pkg)
Packit Service 21c75c
                if opts.packageatr:
Packit Service 21c75c
                    strpkg = getattr(pkg, opts.packageatr)
Packit Service 21c75c
                    ar = {}
Packit Service 21c75c
                    for name in set(strpkg):
Packit Service 21c75c
                        pkgquery = self.base.sack.query().filterm(provides=name)
Packit Service 21c75c
                        for querypkg in pkgquery:
Packit Service 21c75c
                            ar[querypkg.name + "." + querypkg.arch] = querypkg
Packit Service 21c75c
                    pkgquery = self.base.sack.query().filterm(pkg=list(ar.values()))
Packit Service 21c75c
                else:
Packit Service 21c75c
                    pkgquery = self.by_all_deps((pkg.name, ), aquery) if opts.alldeps \
Packit Service 21c75c
                        else aquery.filter(requires__glob=pkg.name)
Packit Service 21c75c
                self.tree_seed(pkgquery, aquery, opts, level + 1, usedpkgs)
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
class PackageWrapper(object):
Packit Service 21c75c
Packit Service 21c75c
    """Wrapper for dnf.package.Package, so we can control formatting."""
Packit Service 21c75c
Packit Service 21c75c
    def __init__(self, pkg):
Packit Service 21c75c
        self._pkg = pkg
Packit Service 21c75c
Packit Service 21c75c
    def __getattr__(self, attr):
Packit Service 21c75c
        atr = getattr(self._pkg, attr)
Packit Service 21c75c
        if atr is None:
Packit Service 21c75c
            return "(none)"
Packit Service 21c75c
        if isinstance(atr, list):
Packit Service 21c75c
            return '\n'.join(sorted({dnf.i18n.ucd(reldep) for reldep in atr}))
Packit Service 21c75c
        return dnf.i18n.ucd(atr)
Packit Service 21c75c
Packit Service 21c75c
    @staticmethod
Packit Service 21c75c
    def _get_timestamp(timestamp):
Packit Service 21c75c
        if timestamp > 0:
Packit Service 21c75c
            dt = datetime.datetime.utcfromtimestamp(timestamp)
Packit Service 21c75c
            return dt.strftime("%Y-%m-%d %H:%M")
Packit Service 21c75c
        else:
Packit Service 21c75c
            return ''
Packit Service 21c75c
Packit Service 21c75c
    @property
Packit Service 21c75c
    def buildtime(self):
Packit Service 21c75c
        return self._get_timestamp(self._pkg.buildtime)
Packit Service 21c75c
Packit Service 21c75c
    @property
Packit Service 21c75c
    def installtime(self):
Packit Service 21c75c
        return self._get_timestamp(self._pkg.installtime)