1cb93a386Sopenharmony_ci#!/usr/bin/env python 2cb93a386Sopenharmony_ci# Copyright 2013 The Chromium Authors. All rights reserved. 3cb93a386Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be 4cb93a386Sopenharmony_ci# found in the LICENSE file. 5cb93a386Sopenharmony_ci 6cb93a386Sopenharmony_ci"""Dumps a graph of allowed and disallowed inter-module dependencies described 7cb93a386Sopenharmony_ciby the DEPS files in the source tree. Supports DOT and PNG as the output format. 8cb93a386Sopenharmony_ci 9cb93a386Sopenharmony_ciEnables filtering and differential highlighting of parts of the graph based on 10cb93a386Sopenharmony_cithe specified criteria. This allows for a much easier visual analysis of the 11cb93a386Sopenharmony_cidependencies, including answering questions such as "if a new source must 12cb93a386Sopenharmony_cidepend on modules A, B, and C, what valid options among the existing modules 13cb93a386Sopenharmony_ciare there to put it in." 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ciSee README.md for a detailed description of the DEPS format. 16cb93a386Sopenharmony_ci""" 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ciimport os 19cb93a386Sopenharmony_ciimport optparse 20cb93a386Sopenharmony_ciimport pipes 21cb93a386Sopenharmony_ciimport re 22cb93a386Sopenharmony_ciimport sys 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_cifrom builddeps import DepsBuilder 25cb93a386Sopenharmony_cifrom rules import Rule 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ciclass DepsGrapher(DepsBuilder): 29cb93a386Sopenharmony_ci """Parses include_rules from DEPS files and outputs a DOT graph of the 30cb93a386Sopenharmony_ci allowed and disallowed dependencies between directories and specific file 31cb93a386Sopenharmony_ci regexps. Can generate only a subgraph of the whole dependency graph 32cb93a386Sopenharmony_ci corresponding to the provided inclusion and exclusion regexp filters. 33cb93a386Sopenharmony_ci Also can highlight fanins and/or fanouts of certain nodes matching the 34cb93a386Sopenharmony_ci provided regexp patterns. 35cb93a386Sopenharmony_ci """ 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ci def __init__(self, 38cb93a386Sopenharmony_ci base_directory, 39cb93a386Sopenharmony_ci extra_repos, 40cb93a386Sopenharmony_ci verbose, 41cb93a386Sopenharmony_ci being_tested, 42cb93a386Sopenharmony_ci ignore_temp_rules, 43cb93a386Sopenharmony_ci ignore_specific_rules, 44cb93a386Sopenharmony_ci hide_disallowed_deps, 45cb93a386Sopenharmony_ci out_file, 46cb93a386Sopenharmony_ci out_format, 47cb93a386Sopenharmony_ci layout_engine, 48cb93a386Sopenharmony_ci unflatten_graph, 49cb93a386Sopenharmony_ci incl, 50cb93a386Sopenharmony_ci excl, 51cb93a386Sopenharmony_ci hilite_fanins, 52cb93a386Sopenharmony_ci hilite_fanouts): 53cb93a386Sopenharmony_ci """Creates a new DepsGrapher. 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_ci Args: 56cb93a386Sopenharmony_ci base_directory: OS-compatible path to root of checkout, e.g. C:\chr\src. 57cb93a386Sopenharmony_ci verbose: Set to true for debug output. 58cb93a386Sopenharmony_ci being_tested: Set to true to ignore the DEPS file at tools/graphdeps/DEPS. 59cb93a386Sopenharmony_ci ignore_temp_rules: Ignore rules that start with Rule.TEMP_ALLOW ("!"). 60cb93a386Sopenharmony_ci ignore_specific_rules: Ignore rules from specific_include_rules sections. 61cb93a386Sopenharmony_ci hide_disallowed_deps: Hide disallowed dependencies from the output graph. 62cb93a386Sopenharmony_ci out_file: Output file name. 63cb93a386Sopenharmony_ci out_format: Output format (anything GraphViz dot's -T option supports). 64cb93a386Sopenharmony_ci layout_engine: Layout engine for formats other than 'dot' 65cb93a386Sopenharmony_ci (anything that GraphViz dot's -K option supports). 66cb93a386Sopenharmony_ci unflatten_graph: Try to reformat the output graph so it is narrower and 67cb93a386Sopenharmony_ci taller. Helps fight overly flat and wide graphs, but 68cb93a386Sopenharmony_ci sometimes produces a worse result. 69cb93a386Sopenharmony_ci incl: Include only nodes matching this regexp; such nodes' fanin/fanout 70cb93a386Sopenharmony_ci is also included. 71cb93a386Sopenharmony_ci excl: Exclude nodes matching this regexp; such nodes' fanin/fanout is 72cb93a386Sopenharmony_ci processed independently. 73cb93a386Sopenharmony_ci hilite_fanins: Highlight fanins of nodes matching this regexp with a 74cb93a386Sopenharmony_ci different edge and node color. 75cb93a386Sopenharmony_ci hilite_fanouts: Highlight fanouts of nodes matching this regexp with a 76cb93a386Sopenharmony_ci different edge and node color. 77cb93a386Sopenharmony_ci """ 78cb93a386Sopenharmony_ci DepsBuilder.__init__( 79cb93a386Sopenharmony_ci self, 80cb93a386Sopenharmony_ci base_directory, 81cb93a386Sopenharmony_ci extra_repos, 82cb93a386Sopenharmony_ci verbose, 83cb93a386Sopenharmony_ci being_tested, 84cb93a386Sopenharmony_ci ignore_temp_rules, 85cb93a386Sopenharmony_ci ignore_specific_rules) 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci self.ignore_temp_rules = ignore_temp_rules 88cb93a386Sopenharmony_ci self.ignore_specific_rules = ignore_specific_rules 89cb93a386Sopenharmony_ci self.hide_disallowed_deps = hide_disallowed_deps 90cb93a386Sopenharmony_ci self.out_file = out_file 91cb93a386Sopenharmony_ci self.out_format = out_format 92cb93a386Sopenharmony_ci self.layout_engine = layout_engine 93cb93a386Sopenharmony_ci self.unflatten_graph = unflatten_graph 94cb93a386Sopenharmony_ci self.incl = incl 95cb93a386Sopenharmony_ci self.excl = excl 96cb93a386Sopenharmony_ci self.hilite_fanins = hilite_fanins 97cb93a386Sopenharmony_ci self.hilite_fanouts = hilite_fanouts 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci self.deps = set() 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci def DumpDependencies(self): 102cb93a386Sopenharmony_ci """ Builds a dependency rule table and dumps the corresponding dependency 103cb93a386Sopenharmony_ci graph to all requested formats.""" 104cb93a386Sopenharmony_ci self._BuildDepsGraph() 105cb93a386Sopenharmony_ci self._DumpDependencies() 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci def _BuildDepsGraph(self): 108cb93a386Sopenharmony_ci """Recursively traverses the source tree starting at the specified directory 109cb93a386Sopenharmony_ci and builds a dependency graph representation in self.deps.""" 110cb93a386Sopenharmony_ci for (rules, _) in self.GetAllRulesAndFiles(): 111cb93a386Sopenharmony_ci deps = rules.AsDependencyTuples( 112cb93a386Sopenharmony_ci include_general_rules=True, 113cb93a386Sopenharmony_ci include_specific_rules=not self.ignore_specific_rules) 114cb93a386Sopenharmony_ci self.deps.update(deps) 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci def _DumpDependencies(self): 117cb93a386Sopenharmony_ci """Dumps the built dependency graph to the specified file with specified 118cb93a386Sopenharmony_ci format.""" 119cb93a386Sopenharmony_ci if self.out_format == 'dot' and not self.layout_engine: 120cb93a386Sopenharmony_ci if self.unflatten_graph: 121cb93a386Sopenharmony_ci pipe = pipes.Template() 122cb93a386Sopenharmony_ci pipe.append('unflatten -l 2 -c 3', '--') 123cb93a386Sopenharmony_ci out = pipe.open(self.out_file, 'w') 124cb93a386Sopenharmony_ci else: 125cb93a386Sopenharmony_ci out = open(self.out_file, 'w') 126cb93a386Sopenharmony_ci else: 127cb93a386Sopenharmony_ci pipe = pipes.Template() 128cb93a386Sopenharmony_ci if self.unflatten_graph: 129cb93a386Sopenharmony_ci pipe.append('unflatten -l 2 -c 3', '--') 130cb93a386Sopenharmony_ci dot_cmd = 'dot -T' + self.out_format 131cb93a386Sopenharmony_ci if self.layout_engine: 132cb93a386Sopenharmony_ci dot_cmd += ' -K' + self.layout_engine 133cb93a386Sopenharmony_ci pipe.append(dot_cmd, '--') 134cb93a386Sopenharmony_ci out = pipe.open(self.out_file, 'w') 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_ci self._DumpDependenciesImpl(self.deps, out) 137cb93a386Sopenharmony_ci out.close() 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci def _DumpDependenciesImpl(self, deps, out): 140cb93a386Sopenharmony_ci """Computes nodes' and edges' properties for the dependency graph |deps| and 141cb93a386Sopenharmony_ci carries out the actual dumping to a file/pipe |out|.""" 142cb93a386Sopenharmony_ci deps_graph = dict() 143cb93a386Sopenharmony_ci deps_srcs = set() 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci # Pre-initialize the graph with src->(dst, allow) pairs. 146cb93a386Sopenharmony_ci for (allow, src, dst) in deps: 147cb93a386Sopenharmony_ci if allow == Rule.TEMP_ALLOW and self.ignore_temp_rules: 148cb93a386Sopenharmony_ci continue 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ci deps_srcs.add(src) 151cb93a386Sopenharmony_ci if src not in deps_graph: 152cb93a386Sopenharmony_ci deps_graph[src] = [] 153cb93a386Sopenharmony_ci deps_graph[src].append((dst, allow)) 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci # Add all hierarchical parents too, in case some of them don't have their 156cb93a386Sopenharmony_ci # own DEPS, and therefore are missing from the list of rules. Those will 157cb93a386Sopenharmony_ci # be recursively populated with their parents' rules in the next block. 158cb93a386Sopenharmony_ci parent_src = os.path.dirname(src) 159cb93a386Sopenharmony_ci while parent_src: 160cb93a386Sopenharmony_ci if parent_src not in deps_graph: 161cb93a386Sopenharmony_ci deps_graph[parent_src] = [] 162cb93a386Sopenharmony_ci parent_src = os.path.dirname(parent_src) 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ci # For every node, propagate its rules down to all its children. 165cb93a386Sopenharmony_ci deps_srcs = list(deps_srcs) 166cb93a386Sopenharmony_ci deps_srcs.sort() 167cb93a386Sopenharmony_ci for src in deps_srcs: 168cb93a386Sopenharmony_ci parent_src = os.path.dirname(src) 169cb93a386Sopenharmony_ci if parent_src: 170cb93a386Sopenharmony_ci # We presort the list, so parents are guaranteed to precede children. 171cb93a386Sopenharmony_ci assert parent_src in deps_graph,\ 172cb93a386Sopenharmony_ci "src: %s, parent_src: %s" % (src, parent_src) 173cb93a386Sopenharmony_ci for (dst, allow) in deps_graph[parent_src]: 174cb93a386Sopenharmony_ci # Check that this node does not explicitly override a rule from the 175cb93a386Sopenharmony_ci # parent that we're about to add. 176cb93a386Sopenharmony_ci if ((dst, Rule.ALLOW) not in deps_graph[src]) and \ 177cb93a386Sopenharmony_ci ((dst, Rule.TEMP_ALLOW) not in deps_graph[src]) and \ 178cb93a386Sopenharmony_ci ((dst, Rule.DISALLOW) not in deps_graph[src]): 179cb93a386Sopenharmony_ci deps_graph[src].append((dst, allow)) 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci node_props = {} 182cb93a386Sopenharmony_ci edges = [] 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_ci # 1) Populate a list of edge specifications in DOT format; 185cb93a386Sopenharmony_ci # 2) Populate a list of computed raw node attributes to be output as node 186cb93a386Sopenharmony_ci # specifications in DOT format later on. 187cb93a386Sopenharmony_ci # Edges and nodes are emphasized with color and line/border weight depending 188cb93a386Sopenharmony_ci # on how many of incl/excl/hilite_fanins/hilite_fanouts filters they hit, 189cb93a386Sopenharmony_ci # and in what way. 190cb93a386Sopenharmony_ci for src in deps_graph.keys(): 191cb93a386Sopenharmony_ci for (dst, allow) in deps_graph[src]: 192cb93a386Sopenharmony_ci if allow == Rule.DISALLOW and self.hide_disallowed_deps: 193cb93a386Sopenharmony_ci continue 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_ci if allow == Rule.ALLOW and src == dst: 196cb93a386Sopenharmony_ci continue 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci edge_spec = "%s->%s" % (src, dst) 199cb93a386Sopenharmony_ci if not re.search(self.incl, edge_spec) or \ 200cb93a386Sopenharmony_ci re.search(self.excl, edge_spec): 201cb93a386Sopenharmony_ci continue 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci if src not in node_props: 204cb93a386Sopenharmony_ci node_props[src] = {'hilite': None, 'degree': 0} 205cb93a386Sopenharmony_ci if dst not in node_props: 206cb93a386Sopenharmony_ci node_props[dst] = {'hilite': None, 'degree': 0} 207cb93a386Sopenharmony_ci 208cb93a386Sopenharmony_ci edge_weight = 1 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_ci if self.hilite_fanouts and re.search(self.hilite_fanouts, src): 211cb93a386Sopenharmony_ci node_props[src]['hilite'] = 'lightgreen' 212cb93a386Sopenharmony_ci node_props[dst]['hilite'] = 'lightblue' 213cb93a386Sopenharmony_ci node_props[dst]['degree'] += 1 214cb93a386Sopenharmony_ci edge_weight += 1 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci if self.hilite_fanins and re.search(self.hilite_fanins, dst): 217cb93a386Sopenharmony_ci node_props[src]['hilite'] = 'lightblue' 218cb93a386Sopenharmony_ci node_props[dst]['hilite'] = 'lightgreen' 219cb93a386Sopenharmony_ci node_props[src]['degree'] += 1 220cb93a386Sopenharmony_ci edge_weight += 1 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_ci if allow == Rule.ALLOW: 223cb93a386Sopenharmony_ci edge_color = (edge_weight > 1) and 'blue' or 'green' 224cb93a386Sopenharmony_ci edge_style = 'solid' 225cb93a386Sopenharmony_ci elif allow == Rule.TEMP_ALLOW: 226cb93a386Sopenharmony_ci edge_color = (edge_weight > 1) and 'blue' or 'green' 227cb93a386Sopenharmony_ci edge_style = 'dashed' 228cb93a386Sopenharmony_ci else: 229cb93a386Sopenharmony_ci edge_color = 'red' 230cb93a386Sopenharmony_ci edge_style = 'dashed' 231cb93a386Sopenharmony_ci edges.append(' "%s" -> "%s" [style=%s,color=%s,penwidth=%d];' % \ 232cb93a386Sopenharmony_ci (src, dst, edge_style, edge_color, edge_weight)) 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci # Reformat the computed raw node attributes into a final DOT representation. 235cb93a386Sopenharmony_ci nodes = [] 236cb93a386Sopenharmony_ci for (node, attrs) in node_props.items(): 237cb93a386Sopenharmony_ci attr_strs = [] 238cb93a386Sopenharmony_ci if attrs['hilite']: 239cb93a386Sopenharmony_ci attr_strs.append('style=filled,fillcolor=%s' % attrs['hilite']) 240cb93a386Sopenharmony_ci attr_strs.append('penwidth=%d' % (attrs['degree'] or 1)) 241cb93a386Sopenharmony_ci nodes.append(' "%s" [%s];' % (node, ','.join(attr_strs))) 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_ci # Output nodes and edges to |out| (can be a file or a pipe). 244cb93a386Sopenharmony_ci edges.sort() 245cb93a386Sopenharmony_ci nodes.sort() 246cb93a386Sopenharmony_ci out.write('digraph DEPS {\n' 247cb93a386Sopenharmony_ci ' fontsize=8;\n') 248cb93a386Sopenharmony_ci out.write('\n'.join(nodes)) 249cb93a386Sopenharmony_ci out.write('\n\n') 250cb93a386Sopenharmony_ci out.write('\n'.join(edges)) 251cb93a386Sopenharmony_ci out.write('\n}\n') 252cb93a386Sopenharmony_ci out.close() 253cb93a386Sopenharmony_ci 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_cidef PrintUsage(): 256cb93a386Sopenharmony_ci print("""Usage: python graphdeps.py [--root <root>] 257cb93a386Sopenharmony_ci 258cb93a386Sopenharmony_ci --root ROOT Specifies the repository root. This defaults to "../../.." 259cb93a386Sopenharmony_ci relative to the script file. This will be correct given the 260cb93a386Sopenharmony_ci normal location of the script in "<root>/tools/graphdeps". 261cb93a386Sopenharmony_ci 262cb93a386Sopenharmony_ci --(others) There are a few lesser-used options; run with --help to show them. 263cb93a386Sopenharmony_ci 264cb93a386Sopenharmony_ciExamples: 265cb93a386Sopenharmony_ci Dump the whole dependency graph: 266cb93a386Sopenharmony_ci graphdeps.py 267cb93a386Sopenharmony_ci Find a suitable place for a new source that must depend on /apps and 268cb93a386Sopenharmony_ci /content/browser/renderer_host. Limit potential candidates to /apps, 269cb93a386Sopenharmony_ci /chrome/browser and content/browser, and descendants of those three. 270cb93a386Sopenharmony_ci Generate both DOT and PNG output. The output will highlight the fanins 271cb93a386Sopenharmony_ci of /apps and /content/browser/renderer_host. Overlapping nodes in both fanins 272cb93a386Sopenharmony_ci will be emphasized by a thicker border. Those nodes are the ones that are 273cb93a386Sopenharmony_ci allowed to depend on both targets, therefore they are all legal candidates 274cb93a386Sopenharmony_ci to place the new source in: 275cb93a386Sopenharmony_ci graphdeps.py \ 276cb93a386Sopenharmony_ci --root=./src \ 277cb93a386Sopenharmony_ci --out=./DEPS.svg \ 278cb93a386Sopenharmony_ci --format=svg \ 279cb93a386Sopenharmony_ci --incl='^(apps|chrome/browser|content/browser)->.*' \ 280cb93a386Sopenharmony_ci --excl='.*->third_party' \ 281cb93a386Sopenharmony_ci --fanin='^(apps|content/browser/renderer_host)$' \ 282cb93a386Sopenharmony_ci --ignore-specific-rules \ 283cb93a386Sopenharmony_ci --ignore-temp-rules""") 284cb93a386Sopenharmony_ci 285cb93a386Sopenharmony_ci 286cb93a386Sopenharmony_cidef main(): 287cb93a386Sopenharmony_ci option_parser = optparse.OptionParser() 288cb93a386Sopenharmony_ci option_parser.add_option( 289cb93a386Sopenharmony_ci "", "--root", 290cb93a386Sopenharmony_ci default="", dest="base_directory", 291cb93a386Sopenharmony_ci help="Specifies the repository root. This defaults " 292cb93a386Sopenharmony_ci "to '../../..' relative to the script file, which " 293cb93a386Sopenharmony_ci "will normally be the repository root.") 294cb93a386Sopenharmony_ci option_parser.add_option( 295cb93a386Sopenharmony_ci '', '--extra-repos', 296cb93a386Sopenharmony_ci action='append', dest='extra_repos', default=[], 297cb93a386Sopenharmony_ci help='Specifies extra repositories relative to root repository.') 298cb93a386Sopenharmony_ci option_parser.add_option( 299cb93a386Sopenharmony_ci "-f", "--format", 300cb93a386Sopenharmony_ci dest="out_format", default="dot", 301cb93a386Sopenharmony_ci help="Output file format. " 302cb93a386Sopenharmony_ci "Can be anything that GraphViz dot's -T option supports. " 303cb93a386Sopenharmony_ci "The most useful ones are: dot (text), svg (image), pdf (image)." 304cb93a386Sopenharmony_ci "NOTES: dotty has a known problem with fonts when displaying DOT " 305cb93a386Sopenharmony_ci "files on Ubuntu - if labels are unreadable, try other formats.") 306cb93a386Sopenharmony_ci option_parser.add_option( 307cb93a386Sopenharmony_ci "-o", "--out", 308cb93a386Sopenharmony_ci dest="out_file", default="DEPS", 309cb93a386Sopenharmony_ci help="Output file name. If the name does not end in an extension " 310cb93a386Sopenharmony_ci "matching the output format, that extension is automatically " 311cb93a386Sopenharmony_ci "appended.") 312cb93a386Sopenharmony_ci option_parser.add_option( 313cb93a386Sopenharmony_ci "-l", "--layout-engine", 314cb93a386Sopenharmony_ci dest="layout_engine", default="", 315cb93a386Sopenharmony_ci help="Layout rendering engine. " 316cb93a386Sopenharmony_ci "Can be anything that GraphViz dot's -K option supports. " 317cb93a386Sopenharmony_ci "The most useful are in decreasing order: dot, fdp, circo, osage. " 318cb93a386Sopenharmony_ci "NOTE: '-f dot' and '-f dot -l dot' are different: the former " 319cb93a386Sopenharmony_ci "will dump a raw DOT graph and stop; the latter will further " 320cb93a386Sopenharmony_ci "filter it through 'dot -Tdot -Kdot' layout engine.") 321cb93a386Sopenharmony_ci option_parser.add_option( 322cb93a386Sopenharmony_ci "-i", "--incl", 323cb93a386Sopenharmony_ci default="^.*$", dest="incl", 324cb93a386Sopenharmony_ci help="Include only edges of the graph that match the specified regexp. " 325cb93a386Sopenharmony_ci "The regexp is applied to edges of the graph formatted as " 326cb93a386Sopenharmony_ci "'source_node->target_node', where the '->' part is vebatim. " 327cb93a386Sopenharmony_ci "Therefore, a reliable regexp should look like " 328cb93a386Sopenharmony_ci "'^(chrome|chrome/browser|chrome/common)->content/public/browser$' " 329cb93a386Sopenharmony_ci "or similar, with both source and target node regexps present, " 330cb93a386Sopenharmony_ci "explicit ^ and $, and otherwise being as specific as possible.") 331cb93a386Sopenharmony_ci option_parser.add_option( 332cb93a386Sopenharmony_ci "-e", "--excl", 333cb93a386Sopenharmony_ci default="^$", dest="excl", 334cb93a386Sopenharmony_ci help="Exclude dependent nodes that match the specified regexp. " 335cb93a386Sopenharmony_ci "See --incl for details on the format.") 336cb93a386Sopenharmony_ci option_parser.add_option( 337cb93a386Sopenharmony_ci "", "--fanin", 338cb93a386Sopenharmony_ci default="", dest="hilite_fanins", 339cb93a386Sopenharmony_ci help="Highlight fanins of nodes matching the specified regexp.") 340cb93a386Sopenharmony_ci option_parser.add_option( 341cb93a386Sopenharmony_ci "", "--fanout", 342cb93a386Sopenharmony_ci default="", dest="hilite_fanouts", 343cb93a386Sopenharmony_ci help="Highlight fanouts of nodes matching the specified regexp.") 344cb93a386Sopenharmony_ci option_parser.add_option( 345cb93a386Sopenharmony_ci "", "--ignore-temp-rules", 346cb93a386Sopenharmony_ci action="store_true", dest="ignore_temp_rules", default=False, 347cb93a386Sopenharmony_ci help="Ignore !-prefixed (temporary) rules in DEPS files.") 348cb93a386Sopenharmony_ci option_parser.add_option( 349cb93a386Sopenharmony_ci "", "--ignore-specific-rules", 350cb93a386Sopenharmony_ci action="store_true", dest="ignore_specific_rules", default=False, 351cb93a386Sopenharmony_ci help="Ignore specific_include_rules section of DEPS files.") 352cb93a386Sopenharmony_ci option_parser.add_option( 353cb93a386Sopenharmony_ci "", "--hide-disallowed-deps", 354cb93a386Sopenharmony_ci action="store_true", dest="hide_disallowed_deps", default=False, 355cb93a386Sopenharmony_ci help="Hide disallowed dependencies in the output graph.") 356cb93a386Sopenharmony_ci option_parser.add_option( 357cb93a386Sopenharmony_ci "", "--unflatten", 358cb93a386Sopenharmony_ci action="store_true", dest="unflatten_graph", default=False, 359cb93a386Sopenharmony_ci help="Try to reformat the output graph so it is narrower and taller. " 360cb93a386Sopenharmony_ci "Helps fight overly flat and wide graphs, but sometimes produces " 361cb93a386Sopenharmony_ci "inferior results.") 362cb93a386Sopenharmony_ci option_parser.add_option( 363cb93a386Sopenharmony_ci "-v", "--verbose", 364cb93a386Sopenharmony_ci action="store_true", default=False, 365cb93a386Sopenharmony_ci help="Print debug logging") 366cb93a386Sopenharmony_ci options, args = option_parser.parse_args() 367cb93a386Sopenharmony_ci 368cb93a386Sopenharmony_ci if not options.out_file.endswith(options.out_format): 369cb93a386Sopenharmony_ci options.out_file += '.' + options.out_format 370cb93a386Sopenharmony_ci 371cb93a386Sopenharmony_ci deps_grapher = DepsGrapher( 372cb93a386Sopenharmony_ci base_directory=options.base_directory, 373cb93a386Sopenharmony_ci extra_repos=options.extra_repos, 374cb93a386Sopenharmony_ci verbose=options.verbose, 375cb93a386Sopenharmony_ci being_tested=False, 376cb93a386Sopenharmony_ci 377cb93a386Sopenharmony_ci ignore_temp_rules=options.ignore_temp_rules, 378cb93a386Sopenharmony_ci ignore_specific_rules=options.ignore_specific_rules, 379cb93a386Sopenharmony_ci hide_disallowed_deps=options.hide_disallowed_deps, 380cb93a386Sopenharmony_ci 381cb93a386Sopenharmony_ci out_file=options.out_file, 382cb93a386Sopenharmony_ci out_format=options.out_format, 383cb93a386Sopenharmony_ci layout_engine=options.layout_engine, 384cb93a386Sopenharmony_ci unflatten_graph=options.unflatten_graph, 385cb93a386Sopenharmony_ci 386cb93a386Sopenharmony_ci incl=options.incl, 387cb93a386Sopenharmony_ci excl=options.excl, 388cb93a386Sopenharmony_ci hilite_fanins=options.hilite_fanins, 389cb93a386Sopenharmony_ci hilite_fanouts=options.hilite_fanouts) 390cb93a386Sopenharmony_ci 391cb93a386Sopenharmony_ci if len(args) > 0: 392cb93a386Sopenharmony_ci PrintUsage() 393cb93a386Sopenharmony_ci return 1 394cb93a386Sopenharmony_ci 395cb93a386Sopenharmony_ci print('Using base directory: ', deps_grapher.base_directory) 396cb93a386Sopenharmony_ci print('include nodes : ', options.incl) 397cb93a386Sopenharmony_ci print('exclude nodes : ', options.excl) 398cb93a386Sopenharmony_ci print('highlight fanins of : ', options.hilite_fanins) 399cb93a386Sopenharmony_ci print('highlight fanouts of: ', options.hilite_fanouts) 400cb93a386Sopenharmony_ci 401cb93a386Sopenharmony_ci deps_grapher.DumpDependencies() 402cb93a386Sopenharmony_ci return 0 403cb93a386Sopenharmony_ci 404cb93a386Sopenharmony_ci 405cb93a386Sopenharmony_ciif '__main__' == __name__: 406cb93a386Sopenharmony_ci sys.exit(main()) 407