Index: recipe_engine/depgraph.py |
diff --git a/recipe_engine/depgraph.py b/recipe_engine/depgraph.py |
index e12ac38c37b5353bf2d227c8c2a1dd43e47d47f8..dab070e957b7d093787cf5aa0223fca32235a9c4 100644 |
--- a/recipe_engine/depgraph.py |
+++ b/recipe_engine/depgraph.py |
@@ -6,6 +6,7 @@ from __future__ import print_function |
import sys |
import os |
+import collections |
from . import loader |
@@ -20,29 +21,98 @@ _GRAPH_FOOTER = """} |
""" |
-def main(universe, ignore_packages, stdout): |
- packages = {} |
+def main(universe, own_package, ignore_packages, stdout, recipe_filter): |
module_to_package = {} |
- edges = [] |
+ |
+ # 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: |
+ continue |
mod = universe.load(package, module_name) |
- for dep in mod.LOADED_DEPS: |
- edges.append((mod.NAME, dep)) |
- packages.setdefault(package.name, []).append(mod.NAME) |
+ all_deps[(False, mod.NAME)] = mod.LOADED_DEPS |
module_to_package[mod.NAME] = package.name |
+ if 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: |
+ continue |
+ |
+ recipe = universe_view.load_recipe(recipe_name) |
+ |
+ all_deps[(True, recipe_name)] = recipe.LOADED_DEPS |
+ recipe_to_package[recipe_name] = own_package |
+ |
+ # If we actually found any recipes |
+ if recipe_to_package: |
+ # Prune anything our recipe doesn't see via BFS. |
+ queue = [ |
+ (True, name) for (is_recipe, name), _ in all_deps.items() |
+ if is_recipe] |
+ |
+ to_keep = set() |
+ while queue: |
+ itm = queue.pop() |
+ to_keep.add(itm) |
+ for dep in all_deps[itm]: |
+ queue.append((False, dep)) |
+ |
+ all_deps = {key: deps for key, deps in all_deps.items() if key in to_keep} |
+ |
+ mod_names = [ |
+ name for (is_recipe, name), _ in all_deps.items() if not is_recipe] |
+ module_to_package = { |
+ m_name: p_name for m_name, p_name in module_to_package.items() |
+ if m_name in mod_names} |
+ |
+ recipe_names = [ |
+ name for (is_recipe, name), _ in all_deps.items() if is_recipe] |
+ recipe_to_package = { |
+ r_name: p_name for r_name, p_name in recipe_to_package.items() |
+ if r_name in recipe_names} |
+ |
+ |
print(_GRAPH_HEADER, file=stdout) |
+ edges = [] |
+ for (is_recipe, name), deps in all_deps.items(): |
+ for dep in deps: |
+ edges.append(((is_recipe, name), dep)) |
+ |
for edge in edges: |
- if (module_to_package[edge[0]] in ignore_packages or |
- module_to_package[edge[1]] in ignore_packages): |
+ (is_recipe, first_name), second_name = edge |
+ |
+ if not is_recipe: |
+ if module_to_package[first_name] in ignore_packages: |
+ continue |
+ else: |
+ if recipe_to_package[first_name] in ignore_packages: |
+ continue |
+ first_name = 'recipe ' + first_name |
+ |
+ if module_to_package[second_name] in ignore_packages: |
continue |
- print(' %s -> %s' % (edge[0], edge[1]), file=stdout) |
+ |
+ print(' "%s" -> "%s"' % (first_name, second_name), file=stdout) |
+ |
+ 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: |
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=stdout) |
+ |
+ if 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) |
+ |
print(_GRAPH_FOOTER, file=stdout) |