def _make_dependency_graph(root, reversed=True, rreqs=None, edge_attrs=_E_ATTRS): """ Make RPM dependency graph with using Networkx.DiGraph for given root. :param root: RPM Database root dir :param reversed: Resolve reversed dependency from required to requires :param rreqs: A dict represents RPM dependencies; {x: [package_requires_x]} or {x: [package_required_by_x]}. :param edge_attrs: Default edge attributes :: dict :return: networkx.DiGraph instance """ g = NX.DiGraph() if rreqs is None: rreqs = RU.make_requires_dict(root, reversed) for k, vs in rreqs.iteritems(): g.add_node(k, names=[k]) g.add_edges_from([(k, v, edge_attrs) for v in vs]) # Remove edges of self cyclic nodes: g.remove_edges_from(g.selfloop_edges()) return g
def dump_gv_depgraph(root, workdir, tpaths=_TEMPLATE_PATHS, engine=_GV_ENGINE, html=True): """ Generate dependency graph with graphviz. TODO: Utilize graph, DAG and trees generated w/ ``dump_graphs``. :param root: Root dir where 'var/lib/rpm' exists :param workdir: Working dir to dump the result :param tpaths: Template path list :param engine: Graphviz rendering engine to choose, e.g. neato :param html: Generate HTML graph files if True """ reqs = RU.make_requires_dict(root) # Set virtual root for root rpms: for p, rs in reqs.iteritems(): if not rs: # This is a root RPM: reqs[p] = ["<rpmlibs>"] # Set virtual root for this root rpm. # Remove self dependency refs: ctx = dict(dependencies=[(r, [p for p in ps if p != r]) for r, ps in reqs.iteritems()]) depgraph_s = RT.render("rpmdep_graph_gv.j2", ctx, tpaths, ask=True) src = os.path.join(workdir, "rpmdep_graph.dot") U.copen(src, "w").write(depgraph_s) output = src + ".svg" SH.run("%s -Tsvg -o %s %s" % (engine, output, src), workdir=workdir) if html: logging.info("Generate HTML files for graphviz outputs") for t in ("js/graphviz-svg.js.j2", "js/jquery.js.j2", "rpmdep_graph_gv.html.j2"): _renderfile(workdir, t, ctx={}, tpaths=tpaths)
def gen_depgraph_gv(root, workdir, template_paths=_TEMPLATE_PATHS, engine=_GV_ENGINE): """ Generate dependency graph with using graphviz. :param root: Root dir where 'var/lib/rpm' exists :param workdir: Working dir to dump the result :param template_paths: Template path list :param engine: Graphviz rendering engine to choose, e.g. neato """ reqs = RU.make_requires_dict(root) # Set virtual root for root rpms: for p, rs in reqs.iteritems(): if not rs: # This is a root RPM: reqs[p] = ["<rpmlibs>"] ctx = dict(dependencies=[(r, ps) for r, ps in reqs.iteritems()]) renderfile("rpm_dependencies.html.j2", workdir, ctx, tpaths=template_paths) depgraph_s = RT.render("rpm_dependencies.graphviz.j2", ctx, template_paths, ask=True) src = os.path.join(workdir, "rpm_dependencies.graphviz") copen(src, 'w').write(depgraph_s) output = src + ".svg" (outlog, errlog) = (os.path.join(workdir, "graphviz_out.log"), os.path.join(workdir, "graphviz_err.log")) cmd = "%s -Tsvg -o %s %s" % (engine, output, src) proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) (out, err) = proc.communicate() if proc.returncode != 0: logging.warn( "Failed to generate graphviz data: " "engine=%s, out=%s, src=%s", engine, out, src) copen(outlog, 'w').write(out) copen(errlog, 'w').write(err)
def make_dependencies_dag(root, reqs=None, rreqs=None): """ Make directed acyclic graph of RPM dependencies. see also: * http://en.wikipedia.org/wiki/Directed_acyclic_graph * http://en.wikipedia.org/wiki/Strongly_connected_component :param root: RPM Database root dir :param reqs: A dict represents RPM deps, {x: [package_requires_x]}. :param rreqs: A dict represents RPM deps, {x: [package_required_by_x]}. :return: networkx.DiGraph instance represents the dag of rpm deps. """ if rreqs is None: rreqs = RU.make_reversed_requires_dict(root) if reqs is None: reqs = RU.make_requires_dict(root) g = make_dependency_graph(root, rreqs=rreqs) # Degenerate strongly connected components: for scc in list(NX.strongly_connected_components(g)): scc = sorted(U.uniq(scc)) # TODO: Is this needed? if len(scc) == 1: # Ignore sccs of which length is 1. continue _degenerate_nodes(g, scc, "Strongly Connected Components") # Degenerate cyclic nodes: for cns in NX.simple_cycles(g): cns = sorted(U.uniq(cns)) # TODO: Likewise # Should not happen as selc cyclic nodes were removed in advance. assert len(cns) != 1, "Self cyclic node: " + cns[0] _degenerate_nodes(g, cns, "Cyclic nodes") assert NX.is_directed_acyclic_graph(g), \ "I'm still missing something to make the dep. graph to dag..." return g
def make_dependencies_dag(root, reqs=None, rreqs=None): """ Make directed acyclic graph of RPM dependencies. see also: * http://en.wikipedia.org/wiki/Directed_acyclic_graph * http://en.wikipedia.org/wiki/Strongly_connected_component :param root: RPM Database root dir :param reqs: A dict represents RPM deps, {x: [package_requires_x]}. :param rreqs: A dict represents RPM deps, {x: [package_required_by_x]}. :return: networkx.DiGraph instance represents the dag of rpm deps. """ if rreqs is None: rreqs = RU.make_reversed_requires_dict(root) if reqs is None: reqs = RU.make_requires_dict(root) g = make_dependency_graph(root, rreqs=rreqs) # Degenerate strongly connected components: for scc in list(NX.strongly_connected_components(g)): scc = sorted(U.uniq(scc)) # TODO: Is this needed? if len(scc) == 1: # Ignore sccs of which length is 1. continue _degenerate_nodes(g, scc, "Strongly Connected Components") # Degenerate cyclic nodes: for cns in NX.simple_cycles(g): cns = sorted(U.uniq(cns)) # TODO: Likewise # Should not happen as selc cyclic nodes were removed in advance. assert len(cns) != 1, "Self cyclic node: " + cns[0] _degenerate_nodes(g, cns, "Cyclic nodes") assert NX.is_directed_acyclic_graph(g), "I'm still missing something to make the dep. graph to dag..." return g
def gen_depgraph_gv(root, workdir, template_paths=_TEMPLATE_PATHS, engine=_GV_ENGINE): """ Generate dependency graph with using graphviz. :param root: Root dir where 'var/lib/rpm' exists :param workdir: Working dir to dump the result :param template_paths: Template path list :param engine: Graphviz rendering engine to choose, e.g. neato """ reqs = RU.make_requires_dict(root) # Set virtual root for root rpms: for p, rs in reqs.iteritems(): if not rs: # This is a root RPM: reqs[p] = ["<rpmlibs>"] ctx = dict(dependencies=[(r, ps) for r, ps in reqs.iteritems()]) renderfile("rpm_dependencies.html.j2", workdir, ctx, tpaths=template_paths) depgraph_s = RT.render("rpm_dependencies.graphviz.j2", ctx, template_paths, ask=True) src = os.path.join(workdir, "rpm_dependencies.graphviz") copen(src, 'w').write(depgraph_s) output = src + ".svg" (outlog, errlog) = (os.path.join(workdir, "graphviz_out.log"), os.path.join(workdir, "graphviz_err.log")) cmd = "%s -Tsvg -o %s %s" % (engine, output, src) proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) (out, err) = proc.communicate() if proc.returncode != 0: logging.warn("Failed to generate graphviz data: " "engine=%s, out=%s, src=%s", engine, out, src) copen(outlog, 'w').write(out) copen(errlog, 'w').write(err)
def dump_gv_depgraph(root, workdir, tpaths=_TEMPLATE_PATHS, engine=_GV_ENGINE, html=True): """ Generate dependency graph with graphviz. TODO: Utilize graph, DAG and trees generated w/ ``dump_graphs``. :param root: Root dir where 'var/lib/rpm' exists :param workdir: Working dir to dump the result :param tpaths: Template path list :param engine: Graphviz rendering engine to choose, e.g. neato :param html: Generate HTML graph files if True """ reqs = RU.make_requires_dict(root) # Set virtual root for root rpms: for p, rs in reqs.iteritems(): if not rs: # This is a root RPM: reqs[p] = ["<rpmlibs>"] # Set virtual root for this root rpm. # Remove self dependency refs: ctx = dict(dependencies=[(r, [p for p in ps if p != r]) for r, ps in reqs.iteritems()]) depgraph_s = RT.render("rpmdep_graph_gv.j2", ctx, tpaths, ask=True) src = os.path.join(workdir, "rpmdep_graph.dot") U.copen(src, 'w').write(depgraph_s) output = src + ".svg" SH.run("%s -Tsvg -o %s %s" % (engine, output, src), workdir=workdir) if html: logging.info("Generate HTML files for graphviz outputs") for t in ("js/graphviz-svg.js.j2", "js/jquery.js.j2", "rpmdep_graph_gv.html.j2"): _renderfile(workdir, t, ctx={}, tpaths=tpaths)