|
Packit Service |
27f74b |
# repograph.py
|
|
Packit Service |
27f74b |
# DNF plugin adding a command to Output a full package dependency graph in dot
|
|
Packit Service |
27f74b |
# format.
|
|
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 _, logger
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
import dnf.cli
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
DOT_HEADER = """
|
|
Packit Service |
27f74b |
size="20.69,25.52";
|
|
Packit Service |
27f74b |
ratio="fill";
|
|
Packit Service |
27f74b |
rankdir="TB";
|
|
Packit Service |
27f74b |
orientation=port;
|
|
Packit Service |
27f74b |
node[style="filled"];
|
|
Packit Service |
27f74b |
"""
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
class RepoGraph(dnf.Plugin):
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
name = "repograph"
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
def __init__(self, base, cli):
|
|
Packit Service |
27f74b |
super(RepoGraph, self).__init__(base, cli)
|
|
Packit Service |
27f74b |
if cli is None:
|
|
Packit Service |
27f74b |
return
|
|
Packit Service |
27f74b |
cli.register_command(RepoGraphCommand)
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
class RepoGraphCommand(dnf.cli.Command):
|
|
Packit Service |
27f74b |
aliases = ("repograph", "repo-graph",)
|
|
Packit Service |
27f74b |
summary = _("Output a full package dependency graph in dot format")
|
|
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:
|
|
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 |
self.do_dot(DOT_HEADER)
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
def do_dot(self, header):
|
|
Packit Service |
27f74b |
maxdeps = 0
|
|
Packit Service |
27f74b |
deps = self._get_deps(self.base.sack)
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
print("digraph packages {")
|
|
Packit Service |
27f74b |
print("{}".format(header))
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
for pkg in deps.keys():
|
|
Packit Service |
27f74b |
if len(deps[pkg]) > maxdeps:
|
|
Packit Service |
27f74b |
maxdeps = len(deps[pkg])
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
# color calculations lifted from rpmgraph
|
|
Packit Service |
27f74b |
h = 0.5 + (0.6 / 23 * len(deps[pkg]))
|
|
Packit Service |
27f74b |
s = h + 0.1
|
|
Packit Service |
27f74b |
b = 1.0
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
print('"{}" [color="{:.12g} {:.12g} {}"];'.format(pkg, h, s, b))
|
|
Packit Service |
27f74b |
print('"{}" -> {{'.format(pkg))
|
|
Packit Service |
27f74b |
for req in deps[pkg]:
|
|
Packit Service |
27f74b |
print('"{}"'.format(req))
|
|
Packit Service |
27f74b |
print('}} [color="{:.12g} {:.12g} {}"];\n'.format(h, s, b))
|
|
Packit Service |
27f74b |
print("}")
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
@staticmethod
|
|
Packit Service |
27f74b |
def _get_deps(sack):
|
|
Packit Service |
27f74b |
requires = {}
|
|
Packit Service |
27f74b |
prov = {}
|
|
Packit Service |
27f74b |
skip = []
|
|
Packit Service |
27f74b |
|
|
Packit Service |
27f74b |
available = sack.query().available()
|
|
Packit Service |
27f74b |
for pkg in available:
|
|
Packit Service |
27f74b |
xx = {}
|
|
Packit Service |
27f74b |
for req in pkg.requires:
|
|
Packit Service |
27f74b |
reqname = str(req)
|
|
Packit Service |
27f74b |
if reqname in skip:
|
|
Packit Service |
27f74b |
continue
|
|
Packit Service |
27f74b |
# XXX: https://bugzilla.redhat.com/show_bug.cgi?id=1186721
|
|
Packit Service |
27f74b |
if reqname.startswith("solvable:"):
|
|
Packit Service |
27f74b |
continue
|
|
Packit Service |
27f74b |
if reqname in prov:
|
|
Packit Service |
27f74b |
provider = prov[reqname]
|
|
Packit Service |
27f74b |
else:
|
|
Packit Service |
27f74b |
provider = available.filter(provides=reqname)
|
|
Packit Service |
27f74b |
if not provider:
|
|
Packit Service |
27f74b |
logger.debug(_("Nothing provides: '%s'"), reqname)
|
|
Packit Service |
27f74b |
skip.append(reqname)
|
|
Packit Service |
27f74b |
continue
|
|
Packit Service |
27f74b |
else:
|
|
Packit Service |
27f74b |
provider = provider[0].name
|
|
Packit Service |
27f74b |
prov[reqname] = provider
|
|
Packit Service |
27f74b |
if provider == pkg.name:
|
|
Packit Service |
27f74b |
xx[provider] = None
|
|
Packit Service |
27f74b |
if provider in xx or provider in skip:
|
|
Packit Service |
27f74b |
continue
|
|
Packit Service |
27f74b |
else:
|
|
Packit Service |
27f74b |
xx[provider] = None
|
|
Packit Service |
27f74b |
requires[pkg.name] = xx.keys()
|
|
Packit Service |
27f74b |
return requires
|