Upstream version 8.36.161.0
[platform/framework/web/crosswalk.git] / src / third_party / chromite / scripts / cros_generate_deps_graphs.py
1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """Generates pretty dependency graphs for Chrome OS packages."""
6
7 import json
8 import optparse
9 import os
10 import sys
11
12 from chromite.lib import dot_helper
13
14
15 NORMAL_COLOR = 'black'
16 TARGET_COLOR = 'red'
17 SEED_COLOR = 'green'
18 CHILD_COLOR = 'grey'
19
20
21 def GetReverseDependencyClosure(full_name, deps_map):
22   """Gets the closure of the reverse dependencies of a node.
23
24   Walks the tree along all the reverse dependency paths to find all the nodes
25   that transitively depend on the input node.
26   """
27   s = set()
28   def GetClosure(name):
29     s.add(name)
30     node = deps_map[name]
31     for dep in node['rev_deps']:
32       if dep in s:
33         continue
34       GetClosure(dep)
35
36   GetClosure(full_name)
37   return s
38
39
40 def GetOutputBaseName(node, options):
41   """Gets the basename of the output file for a node."""
42   return '%s_%s-%s.%s' % (node['category'], node['name'], node['version'],
43                           options.format)
44
45
46 def AddNodeToSubgraph(subgraph, node, options, color):
47   """Gets the dot definition for a node."""
48   name = node['full_name']
49   href = None
50   if options.link:
51     filename = GetOutputBaseName(node, options)
52     href = '%s%s' % (options.base_url, filename)
53   subgraph.AddNode(name, name, color, href)
54
55
56
57 def GenerateDotGraph(package, deps_map, options):
58   """Generates the dot source for the dependency graph leading to a node.
59
60   The output is a list of lines.
61   """
62   deps = GetReverseDependencyClosure(package, deps_map)
63   node = deps_map[package]
64
65   # Keep track of all the emitted nodes so that we don't issue multiple
66   # definitions
67   emitted = set()
68
69   graph = dot_helper.Graph(package)
70
71   # Add all the children if we want them, all of them in their own subgraph,
72   # as a sink. Keep the arcs outside of the subgraph though (it generates
73   # better layout).
74   children_subgraph = None
75   if options.children and node['deps']:
76     children_subgraph = graph.AddNewSubgraph('sink')
77     for child in node['deps']:
78       child_node = deps_map[child]
79       AddNodeToSubgraph(children_subgraph, child_node, options, CHILD_COLOR)
80       emitted.add(child)
81       graph.AddArc(package, child)
82
83   # Add the package in its own subgraph. If we didn't have children, make it
84   # a sink
85   if children_subgraph:
86     rank = 'same'
87   else:
88     rank = 'sink'
89   package_subgraph = graph.AddNewSubgraph(rank)
90   AddNodeToSubgraph(package_subgraph, node, options, TARGET_COLOR)
91   emitted.add(package)
92
93   # Add all the other nodes, as well as all the arcs.
94   for dep in deps:
95     dep_node = deps_map[dep]
96     if not dep in emitted:
97       color = NORMAL_COLOR
98       if dep_node['action'] == 'seed':
99         color = SEED_COLOR
100       AddNodeToSubgraph(graph, dep_node, options, color)
101     for j in dep_node['rev_deps']:
102       graph.AddArc(j, dep)
103
104   return graph.Gen()
105
106
107 def GenerateImages(data, options):
108   """Generate the output images for all the nodes in the input."""
109   deps_map = json.loads(data)
110
111   for package in deps_map:
112     lines = GenerateDotGraph(package, deps_map, options)
113
114     filename = os.path.join(options.output_dir,
115                             GetOutputBaseName(deps_map[package], options))
116
117     save_dot_filename = None
118     if options.save_dot:
119       save_dot_filename = filename + '.dot'
120
121     dot_helper.GenerateImage(lines, filename, options.format, save_dot_filename)
122
123
124 def main(argv):
125   parser = optparse.OptionParser(usage='usage: %prog [options] input')
126   parser.add_option('-f', '--format', default='svg',
127                     help='Dot output format (png, svg, etc.).')
128   parser.add_option('-o', '--output-dir', default='.',
129                     help='Output directory.')
130   parser.add_option('-c', '--children', action='store_true',
131                     help='Also add children.')
132   parser.add_option('-l', '--link', action='store_true',
133                     help='Embed links.')
134   parser.add_option('-b', '--base-url', default='',
135                     help='Base url for links.')
136   parser.add_option('-s', '--save-dot', action='store_true',
137                     help='Save dot files.')
138   (options, inputs) = parser.parse_args(argv)
139
140   try:
141     os.makedirs(options.output_dir)
142   except OSError:
143     # The directory already exists.
144     pass
145
146   if not inputs:
147     GenerateImages(sys.stdin.read(), options)
148   else:
149     for i in inputs:
150       with open(i) as handle:
151         GenerateImages(handle.read(), options)