|
Packit Service |
27f74b |
# repoclosure.py
|
|
Packit Service |
27f74b |
# DNF plugin adding a command to display a list of unresolved dependencies
|
|
Packit Service |
27f74b |
# for repositories.
|
|
Packit Service |
27f74b |
#
|
|
Packit Service |
27f74b |
# Copyright (C) 2015 Igor Gnatenko
|
|
Packit Service |
27f74b |
#
|
|
Packit Service |
27f74b |
# This copyrighted material is made available to anyone wishing to use,
|
|
Packit Service |
27f74b |
# modify, copy, or redistribute it subject to the terms and conditions of
|
|
Packit Service |
27f74b |
# the GNU General Public License v.2, or (at your option) any later version.
|
|
Packit Service |
27f74b |
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
Packit Service |
27f74b |
# ANY WARRANTY expressed or implied, including the implied warranties of
|
|
Packit Service |
27f74b |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|
Packit Service |
27f74b |
# Public License for more details. You should have received a copy of the
|
|
Packit Service |
27f74b |
# GNU General Public License along with this program; if not, write to the
|
|
Packit Service |
27f74b |
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
27f74b |
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
|
|
Packit Service |
27f74b |
# source code or documentation are not subject to the GNU General Public
|
|
Packit Service |
27f74b |
# License and may only be used or replicated with the express permission of
|
|
Packit Service |
27f74b |
# Red Hat, Inc.
|
|
Packit Service |
27f74b |
#
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
from __future__ import absolute_import
|
|
Packit Service |
27f74b |
from __future__ import unicode_literals
|
|
Packit Service |
27f74b |
from dnfpluginscore import _
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
import dnf.cli
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
class RepoClosure(dnf.Plugin):
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
name = "repoclosure"
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
def __init__(self, base, cli):
|
|
Packit Service |
27f74b |
super(RepoClosure, self).__init__(base, cli)
|
|
Packit Service |
27f74b |
if cli is None:
|
|
Packit Service |
27f74b |
return
|
|
Packit Service |
27f74b |
cli.register_command(RepoClosureCommand)
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
class RepoClosureCommand(dnf.cli.Command):
|
|
Packit Service |
27f74b |
aliases = ("repoclosure",)
|
|
Packit Service |
27f74b |
summary = _("Display a list of unresolved dependencies for repositories")
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
def configure(self):
|
|
Packit Service |
27f74b |
demands = self.cli.demands
|
|
Packit Service |
27f74b |
demands.sack_activation = True
|
|
Packit Service |
27f74b |
demands.available_repos = True
|
|
Packit Service |
27f74b |
if self.opts.repo:
|
|
Packit Service |
27f74b |
for repo in self.base.repos.all():
|
|
Packit Service |
27f74b |
if repo.id not in self.opts.repo and repo.id not in self.opts.check:
|
|
Packit Service |
27f74b |
repo.disable()
|
|
Packit Service |
27f74b |
else:
|
|
Packit Service |
27f74b |
repo.enable()
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
def run(self):
|
|
Packit Service |
27f74b |
if self.opts.arches:
|
|
Packit Service |
27f74b |
unresolved = self._get_unresolved(self.opts.arches)
|
|
Packit Service |
27f74b |
else:
|
|
Packit Service |
27f74b |
unresolved = self._get_unresolved()
|
|
Packit Service |
27f74b |
for pkg in sorted(unresolved.keys()):
|
|
Packit Service |
27f74b |
print("package: {} from {}".format(str(pkg), pkg.reponame))
|
|
Packit Service |
27f74b |
print(" unresolved deps:")
|
|
Packit Service |
27f74b |
for dep in unresolved[pkg]:
|
|
Packit Service |
27f74b |
print(" {}".format(dep))
|
|
Packit Service |
27f74b |
if len(unresolved) > 0:
|
|
Packit Service |
27f74b |
msg = _("Repoclosure ended with unresolved dependencies.")
|
|
Packit Service |
27f74b |
raise dnf.exceptions.Error(msg)
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
def _get_unresolved(self, arch=None):
|
|
Packit Service |
27f74b |
unresolved = {}
|
|
Packit Service |
27f74b |
deps = set()
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
# We have two sets of packages, available and to_check:
|
|
Packit Service |
27f74b |
# * available is the set of packages used to satisfy dependencies
|
|
Packit Service |
27f74b |
# * to_check is the set of packages we are checking the dependencies of
|
|
Packit Service |
27f74b |
#
|
|
Packit Service |
27f74b |
# to_check can be a subset of available if the --arch, --best, --check,
|
|
Packit Service |
27f74b |
# --newest, or --pkg options are used
|
|
Packit Service |
27f74b |
#
|
|
Packit Service |
27f74b |
# --arch: only packages matching arch are checked
|
|
Packit Service |
27f74b |
# --best: available only contains the latest packages per arch across all repos
|
|
Packit Service |
27f74b |
# --check: only check packages in the specified repo(s)
|
|
Packit Service |
27f74b |
# --newest: only consider the latest versions of a package from each repo
|
|
Packit Service |
27f74b |
# --pkg: only check the specified packages
|
|
Packit Service |
27f74b |
#
|
|
Packit Service |
27f74b |
# Relationship of --best and --newest:
|
|
Packit Service |
27f74b |
#
|
|
Packit Service |
27f74b |
# Pkg Set | Neither | --best | --newest | --best and --newest |
|
|
Packit Service |
27f74b |
# available | all | latest in all repos | latest per repo | latest in all repos |
|
|
Packit Service |
27f74b |
# to_check | all | all | latest per repo | latest per repo |
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
if self.opts.newest:
|
|
Packit Service |
27f74b |
available = self.base.sack.query().filter(empty=True)
|
|
Packit Service |
27f74b |
to_check = self.base.sack.query().filter(empty=True)
|
|
Packit Service |
27f74b |
for repo in self.base.repos.iter_enabled():
|
|
Packit Service |
27f74b |
available = \
|
|
Packit Service |
27f74b |
available.union(self.base.sack.query().filter(reponame=repo.id).latest())
|
|
Packit Service |
27f74b |
to_check = \
|
|
Packit Service |
27f74b |
to_check.union(self.base.sack.query().filter(reponame=repo.id).latest())
|
|
Packit Service |
27f74b |
else:
|
|
Packit Service |
27f74b |
available = self.base.sack.query().available()
|
|
Packit Service |
27f74b |
to_check = self.base.sack.query().available()
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
if self.opts.pkglist:
|
|
Packit Service |
27f74b |
pkglist_q = self.base.sack.query().filter(empty=True)
|
|
Packit Service |
27f74b |
errors = []
|
|
Packit Service |
27f74b |
for pkg in self.opts.pkglist:
|
|
Packit Service |
27f74b |
subj = dnf.subject.Subject(pkg)
|
|
Packit Service |
27f74b |
pkg_q = to_check.intersection(
|
|
Packit Service |
27f74b |
subj.get_best_query(self.base.sack, with_nevra=True,
|
|
Packit Service |
27f74b |
with_provides=False, with_filenames=False))
|
|
Packit Service |
27f74b |
if pkg_q:
|
|
Packit Service |
27f74b |
pkglist_q = pkglist_q.union(pkg_q)
|
|
Packit Service |
27f74b |
else:
|
|
Packit Service |
27f74b |
errors.append(pkg)
|
|
Packit Service |
27f74b |
if errors:
|
|
Packit Service |
27f74b |
raise dnf.exceptions.Error(
|
|
Packit Service |
27f74b |
_('no package matched: %s') % ', '.join(errors))
|
|
Packit Service |
27f74b |
to_check = pkglist_q
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
if self.opts.check:
|
|
Packit Service |
27f74b |
to_check.filterm(reponame=self.opts.check)
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
if arch is not None:
|
|
Packit Service |
27f74b |
to_check.filterm(arch=arch)
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
if self.base.conf.best:
|
|
Packit Service |
27f74b |
available.filterm(latest_per_arch=True)
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
available.apply()
|
|
Packit Service |
27f74b |
to_check.apply()
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
for pkg in to_check:
|
|
Packit Service |
27f74b |
unresolved[pkg] = set()
|
|
Packit Service |
27f74b |
for req in pkg.requires:
|
|
Packit Service |
27f74b |
reqname = str(req)
|
|
Packit Service |
27f74b |
# XXX: https://bugzilla.redhat.com/show_bug.cgi?id=1186721
|
|
Packit Service |
27f74b |
if reqname.startswith("solvable:") or \
|
|
Packit Service |
27f74b |
reqname.startswith("rpmlib("):
|
|
Packit Service |
27f74b |
continue
|
|
Packit Service |
27f74b |
deps.add(req)
|
|
Packit Service |
27f74b |
unresolved[pkg].add(req)
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
unresolved_deps = set(x for x in deps if not available.filter(provides=x))
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
unresolved_transition = {k: set(x for x in v if x in unresolved_deps)
|
|
Packit Service |
27f74b |
for k, v in unresolved.items()}
|
|
Packit Service |
27f74b |
return {k: v for k, v in unresolved_transition.items() if v}
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
@staticmethod
|
|
Packit Service |
27f74b |
def set_argparser(parser):
|
|
Packit Service |
27f74b |
parser.add_argument("--arch", default=[], action="append", dest='arches',
|
|
Packit Service |
27f74b |
help=_("check packages of the given archs, can be "
|
|
Packit Service |
27f74b |
"specified multiple times"))
|
|
Packit Service |
27f74b |
parser.add_argument("--check", default=[], action="append",
|
|
Packit Service |
27f74b |
help=_("Specify repositories to check"))
|
|
Packit Service |
27f74b |
parser.add_argument("-n", "--newest", action="store_true",
|
|
Packit Service |
27f74b |
help=_("Check only the newest packages in the "
|
|
Packit Service |
27f74b |
"repos"))
|
|
Packit Service |
27f74b |
parser.add_argument("--pkg", default=[], action="append",
|
|
Packit Service |
27f74b |
help=_("Check closure for this package only"),
|
|
Packit Service |
27f74b |
dest="pkglist")
|