Merge lp:~dotdepends-team/dotdepends/prune into lp:dotdepends

Proposed by Kyle Nitzsche
Status: Merged
Approved by: Mike Carifio
Approved revision: 89
Merged at revision: 84
Proposed branch: lp:~dotdepends-team/dotdepends/prune
Merge into: lp:dotdepends
Diff against target: 333 lines (+286/-1)
6 files modified
Dotdepends/Dot.py (+20/-0)
data/dotdepends-prune.1 (+74/-0)
debian/changelog (+8/-0)
debian/manpages (+1/-0)
usr/bin/dotdepends (+1/-1)
usr/bin/dotdepends-prune (+182/-0)
To merge this branch: bzr merge lp:~dotdepends-team/dotdepends/prune
Reviewer Review Type Date Requested Status
Mike Carifio Approve
Review via email: mp+123330@code.launchpad.net

Description of the change

add dotdepends-prune and manpage.

dotdepends-prune tool provides a quick path for generating reverse dependency dot files and png files by pruning a (possibly very large), pre-existing dotdepends dot file (one for ubuntu-desktop, for example) to:
* only include the parts of the tree that lead to a "bottom" pkg (this creates the reverse dependency tree)
* and then optionally "top pruning" the tree to exclude bits that don't involve the 'top' package.

Bottom line: fast png graphs of highly targeted rdepends trees.

To post a comment you must log in.
lp:~dotdepends-team/dotdepends/prune updated
89. By Kyle Nitzsche

usr/bin/dotdepends-prune:
* add copyright header
* fix typo ('reversly')

Revision history for this message
Mike Carifio (carifio) wrote :

gtg

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Dotdepends/Dot.py'
--- Dotdepends/Dot.py 2012-07-11 20:17:42 +0000
+++ Dotdepends/Dot.py 2012-09-07 18:40:25 +0000
@@ -71,6 +71,26 @@
71 self.rnodes = self.get_rnodes()71 self.rnodes = self.get_rnodes()
72 self.footer = "}\n}"72 self.footer = "}\n}"
73 self.shape = shape73 self.shape = shape
74 self.nodePkg, self.pkgNode = self.getNodeNames(self.nodes)
75
76 def getNodeNames(self, nodes):
77 """Return two dicts used to convert between pkg names and dot node
78 names."""
79
80 nodePkg = dict()
81 pkgNode = dict()
82 for node in nodes:
83 style = nodes[node]
84 label = style[style.find('label="'):]
85 pkgName = label[label.find('"')+1:].rstrip('"')
86 if len(pkgName) > 0:
87 pkg = pkgName
88 else:
89 pkg = node
90 nodePkg[node] = pkg
91 pkgNode[pkg] = node
92
93 return nodePkg, pkgNode
7494
75 def get_root(self):95 def get_root(self):
76 line = self.dot[0]96 line = self.dot[0]
7797
=== added file 'data/dotdepends-prune.1'
--- data/dotdepends-prune.1 1970-01-01 00:00:00 +0000
+++ data/dotdepends-prune.1 2012-09-07 18:40:25 +0000
@@ -0,0 +1,74 @@
1.TH dotdepends-prune 1 "5 Sep 2012" "version 0.1"
2.SH NAME
3\fBdotdepends-prune\fP
4.SH SYNOPSIS
5.B dotdepends-prune [-t TOPPACKAGE] -b BOTTOMPACKAGE FILE
6.br
7.SH DESCRIPTION
8Prunes a dependency tree in a dot file produced by dotdepends to include only
9the dependency chains that lead to a specified package (the 'bottom' package).
10This tree represents the reverse dependencies of the 'bottom' package within
11the scope of the initial dot file. For example, you can create a dot file for
12ubuntu-desktop, then, with dotdepends-prune, create a new dot file that only
13includes the 'rdepends' tree for a particular package.
14.SS TOP PRUNING
15You can further prune the tree by specifying a 'top' package. When a top
16package is also specified, the rdepends tree is processed again to prune out
17all dependency chains that do not include the top package. The result is a
18tree that shows all dependency chains that include the top package and that
19lead to the bottom package. For example, you can prune the ubuntu-desktop tree
20with a top package of update-manager and a bottom package of aptdaemon. This
21produces a tightly focused graph.
22.SS TARGETED, FAST REVERSE DEPENDS GRAPHS
23This approach allows you to create a final dot file that is small enough that
24it can be converted into a png very quickly. (Typically reverse dependencies
25trees are very large. It takes a very long time to generate a png for them and
26the png is so crowded and the text is so small that they are very hard to
27read.)
28.SS DONT DRAW INTERMEDIATE GRAPHS
29Since png creation (with the dot tool) is often the bottleneck that prevents
30creating rdepends dot files and pngs, we can skip creating the png until the
31final, pruned dot file is produced. This is done with dotdepends 'don't run dot'
32mode, set with the -d argument. So, one could create the first
33dot file for ubuntu-desktop without creating a png for it. Then use
34dotdepends-prune to create the final dot file and convert that to a png.
35.SH EXAMPLE
36.PP
37Create the initial dot file for ubuntu-desktop in depends mode, with recommends
38included, and in 'don't draw mode':
39.PP
40dotdepends -m depends -r -d ubuntu-desktop
41.PP
42That command produces this initial dot file that defines the scope from which
43further pruning can be done:
44ubuntu-desktop/ubuntu-desktop-depends-Recommends-NoSuggests-NoEnhances.dot
45.PP
46Top prune that dot file to update-manager, bottom prune it to
47aptdaemon, and pipe it to dot to create a png whose default node shape is 'box':
48.PP
49dotdepends-prune -t update-manager -b aptdaemon
50ubuntu-desktop/ubuntu-desktop-depends-Recommends-NoSuggests-NoEnhances.dot |
51dot -Tpng -Nshape=box > my.png
52.br
53.SH OPTIONS
54\fB\-t\fR TOPPACKAGE, \fB\-\-top\-package\fR=\fITOPPACKAGE\fR
55.PP
56Dot tree is pruned to only include dependency chains
57between an optional 'top' package node and a required 'bottom' package node.
58This argument specifies the 'top' package node. When it is omitted, the
59generated tree includes all dependency chains leading to the bottom package.
60.HP
61\fB\-b\fR BOTTOMPACKAGE, \fB\-\-bottom\-package\fR=\fIBOTTOMPACKAGE\fR
62.PP
63This argument specifies the required 'bottom' package node to prune the tree
64to. This generates a tree of all reverse dependencies to the bottom package
65found in the dot file being processed.
66.PP
67.SH COLOR CODING
68.PP
69\fBBlack arrows\fR show depends relationships.
70.HP
71\fBRed arrows\fR show recommends relationships.
72.br
73.SH AUTHOR
74This manpage was written by Kyle Nitzsche <kyle.nitzsche@canonical.com>
075
=== modified file 'debian/changelog'
--- debian/changelog 2012-07-16 17:05:10 +0000
+++ debian/changelog 2012-09-07 18:40:25 +0000
@@ -1,3 +1,11 @@
1dotdepends (0.3.19dev1) UNRELEASED; urgency=low
2
3 * add dotdepends-prune: a new script that top and bottom prunes dot file
4 trees to produce smaller, targeted rdepends graphs for efficient conversion
5 to pngs and its man page.
6
7 -- Kyle Nitzsche <kyle.nitzsche@canonical.com> Fri, 07 Sep 2012 12:57:56 -0400
8
1dotdepends (0.3.19) precise; urgency=low9dotdepends (0.3.19) precise; urgency=low
210
3 * test/test_Dot.py: Add a unittest suite for the Dot object and populate with11 * test/test_Dot.py: Add a unittest suite for the Dot object and populate with
412
=== modified file 'debian/manpages'
--- debian/manpages 2012-07-09 14:42:21 +0000
+++ debian/manpages 2012-09-07 18:40:25 +0000
@@ -1,2 +1,3 @@
1data/dotdepends.11data/dotdepends.1
2data/dotdepends-merge.12data/dotdepends-merge.1
3data/dotdepends-prune.1
34
=== modified file 'usr/bin/dotdepends'
--- usr/bin/dotdepends 2012-07-16 15:23:44 +0000
+++ usr/bin/dotdepends 2012-09-07 18:40:25 +0000
@@ -427,7 +427,7 @@
427 node = ""427 node = ""
428 if v == pkg:428 if v == pkg:
429 styles['label'] = v429 styles['label'] = v
430 styles['fillecolor'] = "blue"430 styles['fillcolor'] = "blue"
431 styles['style'] = "filled"431 styles['style'] = "filled"
432 styles['fontcolor'] = "white"432 styles['fontcolor'] = "white"
433 else:433 else:
434434
=== added file 'usr/bin/dotdepends-prune'
--- usr/bin/dotdepends-prune 1970-01-01 00:00:00 +0000
+++ usr/bin/dotdepends-prune 2012-09-07 18:40:25 +0000
@@ -0,0 +1,182 @@
1#!/usr/bin/python
2#
3# Copyright 2012 Canonical Ltd
4# Authors:
5# Kyle Nitzsche <kyle.nitzsche@canonical.com>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, version 3 of the License.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18from __future__ import print_function
19from optparse import OptionParser
20import Dotdepends.Dot
21import sys
22import os
23
24def pruneChainsToBottomPkg(btmPkg, chain):
25 """Searches through the dot file and finds every chain of dependencies that
26 leads to the bottomPkg node (reversely depends on it). Each such chain
27 is appended to global 'chains' var."""
28
29 lnodes = dot.get_lnodes_for_rnode(btmPkg)
30 for lnode in lnodes:
31 if lnode in processedLnodes: continue
32 else: processedLnodes.append(lnode)
33 newChain = list(chain)
34 newChain.append(lnode)
35 if chain in chains: chains.remove(chain)
36 chains.append(newChain)
37 pruneChainsToBottomPkg(lnode,newChain)
38
39if __name__ == "__main__":
40
41 # dotdepends with no arguments or with -h should run help
42 if (
43 len(sys.argv) == 1
44 or sys.argv[1] == '-h'
45 or sys.argv[1].find('help')
46 ) > -1:
47 print("See 'man dotdepends-prune' for help", file=sys.stderr)
48 sys.exit(0)
49
50 # command help is in the dotdepends man page
51
52 parser = OptionParser()
53
54 parser.add_option(
55 "-t", "--top-package",
56 dest="topPkg",
57 type="string",
58 default="",
59 )
60 parser.add_option(
61 "-b", "--bottom-package",
62 dest="bottomPkg",
63 type="string",
64 default="",
65 )
66 (opt, args) = parser.parse_args()
67
68 dotfile = args[0]
69
70 if len(opt.bottomPkg) < 2:
71 print(
72 "Error: You must specify the 'bottom' package to prune the tree to.",
73 "Stopping."
74 )
75 sys.exit(1)
76 if len(dotfile) < 1:
77 print(
78 "Error: You must specify the dot file to process.",
79 "Stopping."
80 )
81 sys.exit(1)
82
83 if not os.path.exists(dotfile):
84 print(
85 "Error: ",
86 dotfile,
87 "does not exist."
88 "Stopping."
89 )
90 sys.exit(1)
91
92 dot = Dotdepends.Dot.Dot(dotfile)
93 bottomPkg = dot.pkgNode[opt.bottomPkg]
94 hasTop = False
95 if len(opt.topPkg) > 0:
96 hasTop = True
97 top = dot.pkgNode[opt.topPkg]
98 joins = dict()
99 chains = [[bottomPkg]]
100 processedLnodes = []
101
102 pruneChainsToBottomPkg(bottomPkg, chains[0])
103
104 # now ,'chains' has every linear dependency chain that leads to
105 # our bottomPkg. That is, we have 'pruned' the full tree to include
106 # only chains rooted in our bottomPkg.
107
108 prunedChains = []
109
110 # Next, if a topPkg is specified, we need to prune the tree to exclude
111 # all pkgs that do not include our top pkg.
112
113 if hasTop:
114 for chain in chains:
115 if top not in chain: continue
116 prunedChains.append(chain)
117 topPkg = opt.topPkg
118 else:
119 prunedChains = chains
120 topPkg = "None"
121 # time to print a dot file that consists of a header, content, and footer
122
123 for line in dot.header:
124 if not line.startswith("label"): # print extant header but not label
125 print(line.rstrip('\n'), sep="")
126 # make label for current prune and print
127 print(
128 'label="',
129 "Dotdepends graph pruned to:\\nTop package: ",
130 topPkg,
131 ". Bottom package: ",
132 dot.nodePkg[bottomPkg],
133 '"',
134 sep=""
135 )
136
137 # print the pruned tree chains. each chain consists of a series of joins,
138 # with one join per line. each join is two nodes followed by a style.
139 # the style (drawn from the dot file for the join), sets the color of the
140 # arrow in the graph: red for recommends, unset (black) for depends.
141 for chain in prunedChains:
142 idx = -1
143 for item in chain:
144 idx += 1
145 if idx == 0: continue
146 found = False
147 for line in dot.joins:
148 if line[0] == chain[idx] and line[1] == chain[idx-1]:
149 found = True
150 print(chain[idx], " -> ", chain[idx-1], line[2], ';', sep="")
151 if not found:
152 print(
153 "Error: join not found in dot: ",
154 chain[idx],
155 " -> ",
156 chain[idx-1],
157 " Stopping."
158 )
159 sys.exit(1)
160
161 # print nodes. each node is a dot-style node name followed
162 # by a style that contains a label that shows the pkg nam
163 printedNodes = []
164 for chain in prunedChains:
165 for node in chain:
166 if node in printedNodes: continue
167 printedNodes.append(node)
168 if node in dot.nodes.keys():
169 print(
170 node,
171 ' [',
172 dot.nodes[node],
173 '];',
174 sep=""
175 )
176
177 # print footer
178 print(dot.footer, sep="")
179
180 sys.exit()
181
182

Subscribers

People subscribed via source and target branches

to all changes: