1 | #!/usr/bin/env python
|
---|
2 |
|
---|
3 | # Copyright (c) 2011 Google Inc. All rights reserved.
|
---|
4 | # Use of this source code is governed by a BSD-style license that can be
|
---|
5 | # found in the LICENSE file.
|
---|
6 |
|
---|
7 | """Using the JSON dumped by the dump-dependency-json generator,
|
---|
8 | generate input suitable for graphviz to render a dependency graph of
|
---|
9 | targets."""
|
---|
10 |
|
---|
11 | from __future__ import print_function
|
---|
12 |
|
---|
13 | import collections
|
---|
14 | import json
|
---|
15 | import sys
|
---|
16 |
|
---|
17 |
|
---|
18 | def ParseTarget(target):
|
---|
19 | target, _, suffix = target.partition("#")
|
---|
20 | filename, _, target = target.partition(":")
|
---|
21 | return filename, target, suffix
|
---|
22 |
|
---|
23 |
|
---|
24 | def LoadEdges(filename, targets):
|
---|
25 | """Load the edges map from the dump file, and filter it to only
|
---|
26 | show targets in |targets| and their depedendents."""
|
---|
27 |
|
---|
28 | file = open("dump.json")
|
---|
29 | edges = json.load(file)
|
---|
30 | file.close()
|
---|
31 |
|
---|
32 | # Copy out only the edges we're interested in from the full edge list.
|
---|
33 | target_edges = {}
|
---|
34 | to_visit = targets[:]
|
---|
35 | while to_visit:
|
---|
36 | src = to_visit.pop()
|
---|
37 | if src in target_edges:
|
---|
38 | continue
|
---|
39 | target_edges[src] = edges[src]
|
---|
40 | to_visit.extend(edges[src])
|
---|
41 |
|
---|
42 | return target_edges
|
---|
43 |
|
---|
44 |
|
---|
45 | def WriteGraph(edges):
|
---|
46 | """Print a graphviz graph to stdout.
|
---|
47 | |edges| is a map of target to a list of other targets it depends on."""
|
---|
48 |
|
---|
49 | # Bucket targets by file.
|
---|
50 | files = collections.defaultdict(list)
|
---|
51 | for src, dst in edges.items():
|
---|
52 | build_file, target_name, toolset = ParseTarget(src)
|
---|
53 | files[build_file].append(src)
|
---|
54 |
|
---|
55 | print("digraph D {")
|
---|
56 | print(" fontsize=8") # Used by subgraphs.
|
---|
57 | print(" node [fontsize=8]")
|
---|
58 |
|
---|
59 | # Output nodes by file. We must first write out each node within
|
---|
60 | # its file grouping before writing out any edges that may refer
|
---|
61 | # to those nodes.
|
---|
62 | for filename, targets in files.items():
|
---|
63 | if len(targets) == 1:
|
---|
64 | # If there's only one node for this file, simplify
|
---|
65 | # the display by making it a box without an internal node.
|
---|
66 | target = targets[0]
|
---|
67 | build_file, target_name, toolset = ParseTarget(target)
|
---|
68 | print(
|
---|
69 | ' "%s" [shape=box, label="%s\\n%s"]' % (target, filename, target_name)
|
---|
70 | )
|
---|
71 | else:
|
---|
72 | # Group multiple nodes together in a subgraph.
|
---|
73 | print(' subgraph "cluster_%s" {' % filename)
|
---|
74 | print(' label = "%s"' % filename)
|
---|
75 | for target in targets:
|
---|
76 | build_file, target_name, toolset = ParseTarget(target)
|
---|
77 | print(' "%s" [label="%s"]' % (target, target_name))
|
---|
78 | print(" }")
|
---|
79 |
|
---|
80 | # Now that we've placed all the nodes within subgraphs, output all
|
---|
81 | # the edges between nodes.
|
---|
82 | for src, dsts in edges.items():
|
---|
83 | for dst in dsts:
|
---|
84 | print(' "%s" -> "%s"' % (src, dst))
|
---|
85 |
|
---|
86 | print("}")
|
---|
87 |
|
---|
88 |
|
---|
89 | def main():
|
---|
90 | if len(sys.argv) < 2:
|
---|
91 | print(__doc__, file=sys.stderr)
|
---|
92 | print(file=sys.stderr)
|
---|
93 | print("usage: %s target1 target2..." % (sys.argv[0]), file=sys.stderr)
|
---|
94 | return 1
|
---|
95 |
|
---|
96 | edges = LoadEdges("dump.json", sys.argv[1:])
|
---|
97 |
|
---|
98 | WriteGraph(edges)
|
---|
99 | return 0
|
---|
100 |
|
---|
101 |
|
---|
102 | if __name__ == "__main__":
|
---|
103 | sys.exit(main())
|
---|