#!/usr/bin/python # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # (c) 2005 Panu Matilainen # generates graphviz .dot's from repomd data # usage something like # $ ./package-graph.py --package=foo > foo.dot # $ twopi -Tsvg -O foo.dot import sys from yum.misc import getCacheDir from optparse import OptionParser from repoquery import YumBaseQuery default_header = """ size="20.69,25.52"; ratio="fill"; rankdir="TB"; orientation=port; node[style="filled"]; outputorder="edgesfirst"; ranksep="1"; overlap="scalexy"; """ class yumQuiet(YumBaseQuery): """ Inherited class from YumBaseQuery defined in repoquery, used to build dot file for packages """ def doDot(self, header, deps): """ Transform the hash to a dot output """ maxdeps = 0 print 'digraph packages {', print '%s' % header for pkg in deps.keys(): if len(deps[pkg]) > maxdeps: maxdeps=len(deps[pkg]) # color calculations lifted from rpmgraph h=0.5+(0.6/23*len(deps[pkg])) s=h+0.1 b=1.0 print '"%s" [color="%s %s %s"];' % (pkg, h, s, b) print '"%s" -> {' % pkg for req in deps[pkg]: print '"%s"' % req print '} [color="%s %s %s"];\n' % (h, s, b) print "}" def getDepsRequires(self, packages): """ For a list of package retrieves all their dependency in a hash """ requires = {} for name in packages: if name not in requires.keys(): requires[name] = [] req = my.fmt_requires(name) for el in set(req): if str(el) not in requires[name]: requires[name].append(str(el)) return requires def getDepsWhatRequires(self, packages): """ For a list of package retrieves all the list of package requiring them in a hash """ requires = {} for name in packages: if name not in requires.keys(): requires[name] = [] req = my.fmt_whatrequires(name) for el in set(req): if str(el) not in requires[name]: requires[name].append(str(el)) return requires if __name__ == '__main__': parser = OptionParser() parser.add_option("--packages", default=[], action="append", help="specify packages to use") parser.add_option("--pkgnarrow", default="repos", help="limit query to installed / available / recent / updates / extras / all (available + installed) / repository (default) packages") parser.add_option("--alldeps", action="store_true", default=True, help="check non-explicit dependencies (files and Provides:) as well, defaults to on") parser.add_option("--qf", "--queryformat", dest="queryformat", default='%{name}', help="specify a custom output format for queries") parser.add_option("--recursive", action="store_true", help="recursively query for packages (for whatrequires)") parser.add_option("--tree-whatrequires", action="store_true", dest="tree_what_requires", help="list recursive what requires, in tree form") parser.add_option("--tree-requires", action="store_true", dest="tree_requires", help="list recursive requirements, in tree form") (opts, args) = parser.parse_args() my = yumQuiet(options = opts) my.doConfigSetup(init_plugins=False) cachedir = getCacheDir() my.repos.setCacheDir(cachedir) if len(opts.packages) > 0: deps = None if opts.tree_what_requires: deps = my.getDepsWhatRequires(opts.packages) elif opts.tree_requires: deps = my.getDepsRequires(opts.packages) if deps is None: print "No graph method specified" sys.exit(1) try: my.doDot(default_header, deps) except yum.Errors.YumBaseError, e: print "Encountered an error creating graph: %s" % e sys.exit(1)