Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1587)

Side by Side Diff: cros_generate_deps_graphs

Issue 2840020: Add a tool to generate graphs for Chrome OS packages. (Closed) Base URL: ssh://git@chromiumos-git//crosutils.git
Patch Set: Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/python
2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Generates pretty dependency graphs for Chrome OS packages."""
7
8 import optparse
9 import os
10 import subprocess
11 import sys
12
13
14 NORMAL_COLOR = 'black'
15 TARGET_COLOR = 'red'
16 SEED_COLOR = 'green'
17 CHILD_COLOR = 'grey'
18
19
20 def GetReverseDependencyClosure(full_name, deps_map):
21 """Gets the closure of the reverse dependencies of a node.
22
23 Walks the tree along all the reverse dependency paths to find all the nodes
24 that transitively depend on the input node."""
25 s = set()
26 def GetClosure(name):
27 s.add(name)
28 node = deps_map[name]
29 for dep in node['rev_deps']:
30 if dep in s:
31 continue
32 GetClosure(dep)
33
34 GetClosure(full_name)
35 return s
36
37
38 def GetOutputBaseName(node, options):
39 """Gets the basename of the output file for a node."""
40 return '%s_%s-%s.%s' % (node['category'], node['name'], node['version'],
41 options.format)
42
43
44 def GetNodeLines(node, options, color):
45 """Gets the dot definition for a node."""
46 name = node['full_name']
47 tags = ['label="%s (%s)"' % (name, node['action']),
48 'color="%s"' % color,
49 'fontcolor="%s"' % color]
50 if options.link:
51 filename = GetOutputBaseName(node, options)
52 tags.append('href="%s%s"' % (options.base_url, filename))
53 return ['"%s" [%s];' % (name, ', '.join(tags))]
54
55
56 def GetReverseDependencyArcLines(node, options):
57 """Gets the dot definitions for the arcs leading to a node."""
58 lines = []
59 name = node['full_name']
60 for j in node['rev_deps']:
61 lines.append('"%s" -> "%s";' % (j, name))
62 return lines
63
64
65 def GenerateDotGraph(package, deps_map, options):
66 """Generates the dot source for the dependency graph leading to a node.
67
68 The output is a list of lines."""
69 deps = GetReverseDependencyClosure(package, deps_map)
70 node = deps_map[package]
71
72 # Keep track of all the emitted nodes so that we don't issue multiple
73 # definitions
74 emitted = set()
75
76 lines = ['digraph dep {',
77 'graph [name="%s"];' % package]
78
79 # Add all the children if we want them, all of them in their own subgraph,
80 # as a sink. Keep the arcs outside of the subgraph though (it generates
81 # better layout).
82 has_children = False
83 if options.children and node['deps']:
84 has_children = True
85 lines += ['subgraph {',
86 'rank=sink;']
87 arc_lines = []
88 for child in node['deps']:
89 child_node = deps_map[child]
90 lines += GetNodeLines(child_node, options, CHILD_COLOR)
91 emitted.add(child)
92 # If child is in the rev_deps, we'll get the arc later.
93 if not child in node['rev_deps']:
94 arc_lines.append('"%s" -> "%s";' % (package, child))
95 lines += ['}']
96 lines += arc_lines
97
98 # Add the package in its own subgraph. If we didn't have children, make it
99 # a sink
100 lines += ['subgraph {']
101 if has_children:
102 lines += ['rank=same;']
103 else:
104 lines += ['rank=sink;']
105 lines += GetNodeLines(node, options, TARGET_COLOR)
106 emitted.add(package)
107 lines += ['}']
108
109 # Add all the other nodes, as well as all the arcs.
110 for dep in deps:
111 dep_node = deps_map[dep]
112 if not dep in emitted:
113 color = NORMAL_COLOR
114 if dep_node['action'] == 'seed':
115 color = SEED_COLOR
116 lines += GetNodeLines(dep_node, options, color)
117 lines += GetReverseDependencyArcLines(dep_node, options)
118
119 lines += ['}']
120 return lines
121
122
123 def GenerateImages(input, options):
124 """Generate the output images for all the nodes in the input."""
125 deps_map = eval(input.read())
126
127 for package in deps_map:
128 lines = GenerateDotGraph(package, deps_map, options)
129 data = '\n'.join(lines)
130
131 filename = os.path.join(options.output_dir,
132 GetOutputBaseName(deps_map[package], options))
133
134 # Send the source to dot.
135 proc = subprocess.Popen(['dot', '-T' + options.format, '-o' + filename],
136 stdin=subprocess.PIPE)
137 proc.communicate(data)
138
139 if options.save_dot:
140 file = open(filename + '.dot', 'w')
141 file.write(data)
142 file.close()
143
144
145 def main():
146 parser = optparse.OptionParser(usage='usage: %prog [options] input')
147 parser.add_option('-f', '--format', default='svg',
148 help='Dot output format (png, svg, etc.).')
149 parser.add_option('-o', '--output-dir', default='.',
150 help='Output directory.')
151 parser.add_option('-c', '--children', action='store_true',
152 help='Also add children.')
153 parser.add_option('-l', '--link', action='store_true',
154 help='Embed links.')
155 parser.add_option('-b', '--base-url', default='',
156 help='Base url for links.')
157 parser.add_option('-s', '--save-dot', action='store_true',
158 help='Save dot files.')
159 (options, inputs) = parser.parse_args()
160
161 try:
162 os.makedirs(options.output_dir)
163 except OSError:
164 # The directory already exists.
165 pass
166
167 if not inputs:
168 GenerateImages(sys.stdin, options)
169 else:
170 for i in inputs:
171 file = open(i)
172 GenerateImages(file, options)
173 file.close()
174
175 if __name__ == '__main__':
176 main()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698