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

Side by Side Diff: cros_generate_deps_graphs

Issue 2859039: Refactor the dot graph generation out of cros_generate_deps_graphs (Closed) Base URL: ssh://git@chromiumos-git//crosutils.git
Patch Set: address review comments Created 10 years, 5 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 | dot_helper.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 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 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Generates pretty dependency graphs for Chrome OS packages.""" 6 """Generates pretty dependency graphs for Chrome OS packages."""
7 7
8 import dot_helper
8 import optparse 9 import optparse
9 import os 10 import os
10 import subprocess
11 import sys 11 import sys
12 12
13 13
14 NORMAL_COLOR = 'black' 14 NORMAL_COLOR = 'black'
15 TARGET_COLOR = 'red' 15 TARGET_COLOR = 'red'
16 SEED_COLOR = 'green' 16 SEED_COLOR = 'green'
17 CHILD_COLOR = 'grey' 17 CHILD_COLOR = 'grey'
18 18
19 19
20 def GetReverseDependencyClosure(full_name, deps_map): 20 def GetReverseDependencyClosure(full_name, deps_map):
(...skipping 13 matching lines...) Expand all
34 GetClosure(full_name) 34 GetClosure(full_name)
35 return s 35 return s
36 36
37 37
38 def GetOutputBaseName(node, options): 38 def GetOutputBaseName(node, options):
39 """Gets the basename of the output file for a node.""" 39 """Gets the basename of the output file for a node."""
40 return '%s_%s-%s.%s' % (node['category'], node['name'], node['version'], 40 return '%s_%s-%s.%s' % (node['category'], node['name'], node['version'],
41 options.format) 41 options.format)
42 42
43 43
44 def GetNodeLines(node, options, color): 44 def AddNodeToSubgraph(subgraph, node, options, color):
45 """Gets the dot definition for a node.""" 45 """Gets the dot definition for a node."""
46 name = node['full_name'] 46 name = node['full_name']
47 tags = ['label="%s (%s)"' % (name, node['action']), 47 href = None
48 'color="%s"' % color,
49 'fontcolor="%s"' % color]
50 if options.link: 48 if options.link:
51 filename = GetOutputBaseName(node, options) 49 filename = GetOutputBaseName(node, options)
52 tags.append('href="%s%s"' % (options.base_url, filename)) 50 href = '%s%s' % (options.base_url, filename)
53 return ['"%s" [%s];' % (name, ', '.join(tags))] 51 subgraph.AddNode(name, name, color, href)
54 52
55 53
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 54
65 def GenerateDotGraph(package, deps_map, options): 55 def GenerateDotGraph(package, deps_map, options):
66 """Generates the dot source for the dependency graph leading to a node. 56 """Generates the dot source for the dependency graph leading to a node.
67 57
68 The output is a list of lines.""" 58 The output is a list of lines."""
69 deps = GetReverseDependencyClosure(package, deps_map) 59 deps = GetReverseDependencyClosure(package, deps_map)
70 node = deps_map[package] 60 node = deps_map[package]
71 61
72 # Keep track of all the emitted nodes so that we don't issue multiple 62 # Keep track of all the emitted nodes so that we don't issue multiple
73 # definitions 63 # definitions
74 emitted = set() 64 emitted = set()
75 65
76 lines = ['digraph dep {', 66 graph = dot_helper.Graph(package)
77 'graph [name="%s"];' % package]
78 67
79 # Add all the children if we want them, all of them in their own subgraph, 68 # 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 69 # as a sink. Keep the arcs outside of the subgraph though (it generates
81 # better layout). 70 # better layout).
82 has_children = False 71 children_subgraph = None
83 if options.children and node['deps']: 72 if options.children and node['deps']:
84 has_children = True 73 children_subgraph = graph.AddNewSubgraph('sink')
85 lines += ['subgraph {',
86 'rank=sink;']
87 arc_lines = []
88 for child in node['deps']: 74 for child in node['deps']:
89 child_node = deps_map[child] 75 child_node = deps_map[child]
90 lines += GetNodeLines(child_node, options, CHILD_COLOR) 76 AddNodeToSubgraph(children_subgraph, child_node, options, CHILD_COLOR)
91 emitted.add(child) 77 emitted.add(child)
92 # If child is in the rev_deps, we'll get the arc later. 78 graph.AddArc(package, child)
93 if not child in node['rev_deps']:
94 arc_lines.append('"%s" -> "%s";' % (package, child))
95 lines += ['}']
96 lines += arc_lines
97 79
98 # Add the package in its own subgraph. If we didn't have children, make it 80 # Add the package in its own subgraph. If we didn't have children, make it
99 # a sink 81 # a sink
100 lines += ['subgraph {'] 82 if children_subgraph:
101 if has_children: 83 rank = 'same'
102 lines += ['rank=same;']
103 else: 84 else:
104 lines += ['rank=sink;'] 85 rank = 'sink'
105 lines += GetNodeLines(node, options, TARGET_COLOR) 86 package_subgraph = graph.AddNewSubgraph(rank)
87 AddNodeToSubgraph(package_subgraph, node, options, TARGET_COLOR)
106 emitted.add(package) 88 emitted.add(package)
107 lines += ['}']
108 89
109 # Add all the other nodes, as well as all the arcs. 90 # Add all the other nodes, as well as all the arcs.
110 for dep in deps: 91 for dep in deps:
111 dep_node = deps_map[dep] 92 dep_node = deps_map[dep]
112 if not dep in emitted: 93 if not dep in emitted:
113 color = NORMAL_COLOR 94 color = NORMAL_COLOR
114 if dep_node['action'] == 'seed': 95 if dep_node['action'] == 'seed':
115 color = SEED_COLOR 96 color = SEED_COLOR
116 lines += GetNodeLines(dep_node, options, color) 97 AddNodeToSubgraph(graph, dep_node, options, color)
117 lines += GetReverseDependencyArcLines(dep_node, options) 98 for j in dep_node['rev_deps']:
99 graph.AddArc(j, dep)
118 100
119 lines += ['}'] 101 return graph.Gen()
120 return lines
121 102
122 103
123 def GenerateImages(input, options): 104 def GenerateImages(input, options):
124 """Generate the output images for all the nodes in the input.""" 105 """Generate the output images for all the nodes in the input."""
125 deps_map = eval(input.read()) 106 deps_map = eval(input.read())
126 107
127 for package in deps_map: 108 for package in deps_map:
128 lines = GenerateDotGraph(package, deps_map, options) 109 lines = GenerateDotGraph(package, deps_map, options)
129 data = '\n'.join(lines)
130 110
131 filename = os.path.join(options.output_dir, 111 filename = os.path.join(options.output_dir,
132 GetOutputBaseName(deps_map[package], options)) 112 GetOutputBaseName(deps_map[package], options))
133 113
134 # Send the source to dot. 114 save_dot_filename = None
135 proc = subprocess.Popen(['dot', '-T' + options.format, '-o' + filename], 115 if options.save_dot:
136 stdin=subprocess.PIPE) 116 save_dot_filename = filename + '.dot'
137 proc.communicate(data)
138 117
139 if options.save_dot: 118 dot_helper.GenerateImage(lines, filename, options.format, save_dot_filename)
140 file = open(filename + '.dot', 'w')
141 file.write(data)
142 file.close()
143 119
144 120
145 def main(): 121 def main():
146 parser = optparse.OptionParser(usage='usage: %prog [options] input') 122 parser = optparse.OptionParser(usage='usage: %prog [options] input')
147 parser.add_option('-f', '--format', default='svg', 123 parser.add_option('-f', '--format', default='svg',
148 help='Dot output format (png, svg, etc.).') 124 help='Dot output format (png, svg, etc.).')
149 parser.add_option('-o', '--output-dir', default='.', 125 parser.add_option('-o', '--output-dir', default='.',
150 help='Output directory.') 126 help='Output directory.')
151 parser.add_option('-c', '--children', action='store_true', 127 parser.add_option('-c', '--children', action='store_true',
152 help='Also add children.') 128 help='Also add children.')
(...skipping 14 matching lines...) Expand all
167 if not inputs: 143 if not inputs:
168 GenerateImages(sys.stdin, options) 144 GenerateImages(sys.stdin, options)
169 else: 145 else:
170 for i in inputs: 146 for i in inputs:
171 file = open(i) 147 file = open(i)
172 GenerateImages(file, options) 148 GenerateImages(file, options)
173 file.close() 149 file.close()
174 150
175 if __name__ == '__main__': 151 if __name__ == '__main__':
176 main() 152 main()
OLDNEW
« no previous file with comments | « no previous file | dot_helper.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698