"""CFNgin graph action."""
import json
import logging
import sys
from ..plan import merge_graphs
from .base import BaseAction
LOGGER = logging.getLogger(__name__)
[docs]def each_step(graph):
"""Yield each step and it's direct dependencies.
Args:
graph (:class:`runway.cfngin.plan.Graph`): Graph to iterate over.
Yields:
Tuple[Step, Set(str)]
"""
steps = graph.topological_sort()
steps.reverse()
for step in steps:
deps = graph.downstream(step.name)
yield step, deps
FORMATTERS = {
"dot": dot_format,
"json": json_format,
}
[docs]class Action(BaseAction):
"""Responsible for outputing a graph for the current CFNgin config."""
DESCRIPTION = "Print graph"
NAME = "graph"
@property
def _stack_action(self):
"""Run against a step."""
return None
[docs] def run(self, **kwargs):
"""Generate the underlying graph and prints it."""
graph = self._generate_plan(
require_unlocked=False, include_persistent_graph=True
).graph
if self.context.persistent_graph:
graph = merge_graphs(self.context.persistent_graph, graph)
if kwargs.get("reduce"):
# This will performa a transitive reduction on the underlying
# graph, producing less edges. Mostly useful for the "dot" format,
# when converting to PNG, so it creates a prettier/cleaner
# dependency graph.
graph.transitive_reduction()
fn = FORMATTERS[kwargs.get("format")]
fn(sys.stdout, graph)
sys.stdout.flush()