Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(415)

Side by Side Diff: recipe_engine/depgraph.py

Issue 2846683002: [recipes.py] move depgraph arg parsing to its module (Closed)
Patch Set: rebase Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | recipes.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2016 The LUCI Authors. All rights reserved. 1 # Copyright 2016 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0 2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file. 3 # that can be found in the LICENSE file.
4 4
5 from __future__ import print_function 5 from __future__ import print_function
6 6
7 import argparse
8 import sys
9
7 from . import loader 10 from . import loader
8 11
9 12
10 _GRAPH_HEADER = """strict digraph { 13 _GRAPH_HEADER = """strict digraph {
11 concentrate = true; 14 concentrate = true;
12 ranksep = 2; 15 ranksep = 2;
13 nodesep = 0.25; 16 nodesep = 0.25;
14 """ 17 """
15 18
16 _GRAPH_FOOTER = """} 19 _GRAPH_FOOTER = """}
17 """ 20 """
18 21
19 22
20 def main(universe, own_package, ignore_packages, stdout, recipe_filter): 23 def add_subparser(parser):
24 depgraph_p = parser.add_parser(
25 'depgraph',
26 description=(
27 'Produce graph of recipe and recipe module dependencies. Example: '
28 './recipes.py --package infra/config/recipes.cfg depgraph | tred | '
29 'dot -Tpdf > graph.pdf'))
30 depgraph_p.add_argument(
31 '--output', type=argparse.FileType('w'), default=sys.stdout,
32 help='The file to write output to')
33 depgraph_p.add_argument(
34 '--ignore-package', action='append', default=[],
35 dest='ignore_packages',
36 help='Ignore a recipe package (e.g. recipe_engine). Can be passed '
37 'multiple times')
38 depgraph_p.add_argument(
39 '--recipe-filter', default='',
40 help='A recipe substring to examine. If present, the depgraph will '
41 'include a recipe section containing recipes whose names contain '
42 'this substring. It will also filter all nodes of the graph to only '
43 'include modules touched by the filtered recipes.')
44
45 depgraph_p.set_defaults(command='depgraph', func=main)
46
47
48 def main(package_deps, args):
49 universe = loader.RecipeUniverse(package_deps, args.package)
50 own_package = package_deps.root_package
51
21 module_to_package = {} 52 module_to_package = {}
22 53
23 # All deps maps a tuple of (is_recipe, id) to deps (list of ids). is_recipe is 54 # All deps maps a tuple of (is_recipe, id) to deps (list of ids). is_recipe is
24 # a boolean, all ids are strings. 55 # a boolean, all ids are strings.
25 all_deps = {} 56 all_deps = {}
26 for package, module_name in universe.loop_over_recipe_modules(): 57 for package, module_name in universe.loop_over_recipe_modules():
27 if package in ignore_packages: 58 if package in args.ignore_packages:
28 continue 59 continue
29 mod = universe.load(package, module_name) 60 mod = universe.load(package, module_name)
30 61
31 all_deps[(False, mod.NAME)] = mod.LOADED_DEPS 62 all_deps[(False, mod.NAME)] = mod.LOADED_DEPS
32 module_to_package[mod.NAME] = package.name 63 module_to_package[mod.NAME] = package.name
33 64
34 if recipe_filter: 65 if args.recipe_filter:
35 recipe_to_package = {} 66 recipe_to_package = {}
36 universe_view = loader.UniverseView(universe, own_package) 67 universe_view = loader.UniverseView(universe, own_package)
37 for _, recipe_name in universe_view.loop_over_recipes(): 68 for _, recipe_name in universe_view.loop_over_recipes():
38 if recipe_filter not in recipe_name: 69 if args.recipe_filter not in recipe_name:
39 continue 70 continue
40 71
41 recipe = universe_view.load_recipe(recipe_name) 72 recipe = universe_view.load_recipe(recipe_name)
42 73
43 all_deps[(True, recipe_name)] = recipe.LOADED_DEPS 74 all_deps[(True, recipe_name)] = recipe.LOADED_DEPS
44 recipe_to_package[recipe_name] = own_package 75 recipe_to_package[recipe_name] = own_package
45 76
46 # If we actually found any recipes 77 # If we actually found any recipes
47 if recipe_to_package: 78 if recipe_to_package:
48 # Prune anything our recipe doesn't see via BFS. 79 # Prune anything our recipe doesn't see via BFS.
(...skipping 16 matching lines...) Expand all
65 m_name: p_name for m_name, p_name in module_to_package.items() 96 m_name: p_name for m_name, p_name in module_to_package.items()
66 if m_name in mod_names} 97 if m_name in mod_names}
67 98
68 recipe_names = [ 99 recipe_names = [
69 name for (is_recipe, name), _ in all_deps.items() if is_recipe] 100 name for (is_recipe, name), _ in all_deps.items() if is_recipe]
70 recipe_to_package = { 101 recipe_to_package = {
71 r_name: p_name for r_name, p_name in recipe_to_package.items() 102 r_name: p_name for r_name, p_name in recipe_to_package.items()
72 if r_name in recipe_names} 103 if r_name in recipe_names}
73 104
74 105
75 print(_GRAPH_HEADER, file=stdout) 106 print(_GRAPH_HEADER, file=args.output)
76 edges = [] 107 edges = []
77 for (is_recipe, name), deps in all_deps.items(): 108 for (is_recipe, name), deps in all_deps.items():
78 for dep in deps: 109 for dep in deps:
79 edges.append(((is_recipe, name), dep)) 110 edges.append(((is_recipe, name), dep))
80 111
81 for edge in edges: 112 for edge in edges:
82 (is_recipe, first_name), second_name = edge 113 (is_recipe, first_name), second_name = edge
83 114
84 if not is_recipe: 115 if not is_recipe:
85 if module_to_package[first_name] in ignore_packages: 116 if module_to_package[first_name] in args.ignore_packages:
86 continue 117 continue
87 else: 118 else:
88 if recipe_to_package[first_name] in ignore_packages: 119 if recipe_to_package[first_name] in args.ignore_packages:
89 continue 120 continue
90 first_name = 'recipe ' + first_name 121 first_name = 'recipe ' + first_name
91 122
92 if module_to_package[second_name] in ignore_packages: 123 if module_to_package[second_name] in args.ignore_packages:
93 continue 124 continue
94 125
95 print(' "%s" -> "%s"' % (first_name, second_name), file=stdout) 126 print(' "%s" -> "%s"' % (first_name, second_name), file=args.output)
96 127
97 packages = {} 128 packages = {}
98 for module, package in module_to_package.iteritems(): 129 for module, package in module_to_package.iteritems():
99 packages.setdefault(package, []).append(module) 130 packages.setdefault(package, []).append(module)
100 for package, modules in packages.iteritems(): 131 for package, modules in packages.iteritems():
101 if package in ignore_packages: 132 if package in args.ignore_packages:
102 continue 133 continue
103 # The "cluster_" prefix has magic meaning for graphviz and makes it 134 # The "cluster_" prefix has magic meaning for graphviz and makes it
104 # draw a box around the subgraph. 135 # draw a box around the subgraph.
105 print(' subgraph "cluster_%s" { label="%s"; %s; }' % ( 136 print(' subgraph "cluster_%s" { label="%s"; %s; }' % (
106 package, package, '; '.join(modules)), file=stdout) 137 package, package, '; '.join(modules)), file=args.output)
107 138
108 if recipe_filter and recipe_to_package: 139 if args.recipe_filter and recipe_to_package:
109 recipe_names = [ 140 recipe_names = [
110 '"recipe %s"' % name for name in recipe_to_package.keys()] 141 '"recipe %s"' % name for name in recipe_to_package.keys()]
111 print(' subgraph "cluster_recipes" { label="recipes"; %s; }' % ( 142 print(' subgraph "cluster_recipes" { label="recipes"; %s; }' % (
112 '; '.join(recipe_names)), file=stdout) 143 '; '.join(recipe_names)), file=args.output)
113 144
114 print(_GRAPH_FOOTER, file=stdout) 145 print(_GRAPH_FOOTER, file=args.output)
OLDNEW
« no previous file with comments | « no previous file | recipes.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698