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