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 11from __future__ import print_function 12 13import collections 14import json 15import sys 16 17 18def ParseTarget(target): 19 target, _, suffix = target.partition('#') 20 filename, _, target = target.partition(':') 21 return filename, target, suffix 22 23 24def 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 45def 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(' "%s" [shape=box, label="%s\\n%s"]' % (target, filename, 69 target_name)) 70 else: 71 # Group multiple nodes together in a subgraph. 72 print(' subgraph "cluster_%s" {' % filename) 73 print(' label = "%s"' % filename) 74 for target in targets: 75 build_file, target_name, toolset = ParseTarget(target) 76 print(' "%s" [label="%s"]' % (target, target_name)) 77 print(' }') 78 79 # Now that we've placed all the nodes within subgraphs, output all 80 # the edges between nodes. 81 for src, dsts in edges.items(): 82 for dst in dsts: 83 print(' "%s" -> "%s"' % (src, dst)) 84 85 print('}') 86 87 88def main(): 89 if len(sys.argv) < 2: 90 print(__doc__, file=sys.stderr) 91 print(file=sys.stderr) 92 print('usage: %s target1 target2...' % (sys.argv[0]), file=sys.stderr) 93 return 1 94 95 edges = LoadEdges('dump.json', sys.argv[1:]) 96 97 WriteGraph(edges) 98 return 0 99 100 101if __name__ == '__main__': 102 sys.exit(main()) 103