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