Blame dnf/cli/commands/repoquery.py

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