Index: recipe_engine/depgraph.py |
diff --git a/recipe_engine/depgraph.py b/recipe_engine/depgraph.py |
index efd2022e991620d7a271e3734e874033eff4a720..91a1f2ffb0d06d18036d55a54d80fa67d8b02622 100644 |
--- a/recipe_engine/depgraph.py |
+++ b/recipe_engine/depgraph.py |
@@ -4,6 +4,9 @@ |
from __future__ import print_function |
+import argparse |
+import sys |
+ |
from . import loader |
@@ -17,25 +20,53 @@ _GRAPH_FOOTER = """} |
""" |
-def main(universe, own_package, ignore_packages, stdout, recipe_filter): |
+def add_subparser(parser): |
+ depgraph_p = parser.add_parser( |
+ 'depgraph', |
+ description=( |
+ 'Produce graph of recipe and recipe module dependencies. Example: ' |
+ './recipes.py --package infra/config/recipes.cfg depgraph | tred | ' |
+ 'dot -Tpdf > graph.pdf')) |
+ depgraph_p.add_argument( |
+ '--output', type=argparse.FileType('w'), default=sys.stdout, |
+ help='The file to write output to') |
+ depgraph_p.add_argument( |
+ '--ignore-package', action='append', default=[], |
+ dest='ignore_packages', |
+ help='Ignore a recipe package (e.g. recipe_engine). Can be passed ' |
+ 'multiple times') |
+ depgraph_p.add_argument( |
+ '--recipe-filter', default='', |
+ help='A recipe substring to examine. If present, the depgraph will ' |
+ 'include a recipe section containing recipes whose names contain ' |
+ 'this substring. It will also filter all nodes of the graph to only ' |
+ 'include modules touched by the filtered recipes.') |
+ |
+ depgraph_p.set_defaults(command='depgraph', func=main) |
+ |
+ |
+def main(package_deps, args): |
+ universe = loader.RecipeUniverse(package_deps, args.package) |
+ own_package = package_deps.root_package |
+ |
module_to_package = {} |
# All deps maps a tuple of (is_recipe, id) to deps (list of ids). is_recipe is |
# a boolean, all ids are strings. |
all_deps = {} |
for package, module_name in universe.loop_over_recipe_modules(): |
- if package in ignore_packages: |
+ if package in args.ignore_packages: |
continue |
mod = universe.load(package, module_name) |
all_deps[(False, mod.NAME)] = mod.LOADED_DEPS |
module_to_package[mod.NAME] = package.name |
- if recipe_filter: |
+ if args.recipe_filter: |
recipe_to_package = {} |
universe_view = loader.UniverseView(universe, own_package) |
for _, recipe_name in universe_view.loop_over_recipes(): |
- if recipe_filter not in recipe_name: |
+ if args.recipe_filter not in recipe_name: |
continue |
recipe = universe_view.load_recipe(recipe_name) |
@@ -72,7 +103,7 @@ def main(universe, own_package, ignore_packages, stdout, recipe_filter): |
if r_name in recipe_names} |
- print(_GRAPH_HEADER, file=stdout) |
+ print(_GRAPH_HEADER, file=args.output) |
edges = [] |
for (is_recipe, name), deps in all_deps.items(): |
for dep in deps: |
@@ -82,33 +113,33 @@ def main(universe, own_package, ignore_packages, stdout, recipe_filter): |
(is_recipe, first_name), second_name = edge |
if not is_recipe: |
- if module_to_package[first_name] in ignore_packages: |
+ if module_to_package[first_name] in args.ignore_packages: |
continue |
else: |
- if recipe_to_package[first_name] in ignore_packages: |
+ if recipe_to_package[first_name] in args.ignore_packages: |
continue |
first_name = 'recipe ' + first_name |
- if module_to_package[second_name] in ignore_packages: |
+ if module_to_package[second_name] in args.ignore_packages: |
continue |
- print(' "%s" -> "%s"' % (first_name, second_name), file=stdout) |
+ print(' "%s" -> "%s"' % (first_name, second_name), file=args.output) |
packages = {} |
for module, package in module_to_package.iteritems(): |
packages.setdefault(package, []).append(module) |
for package, modules in packages.iteritems(): |
- if package in ignore_packages: |
+ if package in args.ignore_packages: |
continue |
# The "cluster_" prefix has magic meaning for graphviz and makes it |
# draw a box around the subgraph. |
print(' subgraph "cluster_%s" { label="%s"; %s; }' % ( |
- package, package, '; '.join(modules)), file=stdout) |
+ package, package, '; '.join(modules)), file=args.output) |
- if recipe_filter and recipe_to_package: |
+ if args.recipe_filter and recipe_to_package: |
recipe_names = [ |
'"recipe %s"' % name for name in recipe_to_package.keys()] |
print(' subgraph "cluster_recipes" { label="recipes"; %s; }' % ( |
- '; '.join(recipe_names)), file=stdout) |
+ '; '.join(recipe_names)), file=args.output) |
- print(_GRAPH_FOOTER, file=stdout) |
+ print(_GRAPH_FOOTER, file=args.output) |