Compare commits
1 Commits
balay/cuda
...
feat/merma
Author | SHA1 | Date | |
---|---|---|---|
![]() |
23197b78f9 |
@@ -9,7 +9,7 @@
|
|||||||
import spack.environment as ev
|
import spack.environment as ev
|
||||||
import spack.store
|
import spack.store
|
||||||
from spack.cmd.common import arguments
|
from spack.cmd.common import arguments
|
||||||
from spack.graph import DAGWithDependencyTypes, SimpleDAG, graph_ascii, graph_dot, static_graph_dot
|
from spack.graph import DotGraph, MermaidGraph, DAGWithDependencyTypes, SimpleDAG, graph_ascii, graph_dot, static_graph_dot
|
||||||
|
|
||||||
description = "generate graphs of package dependency relationships"
|
description = "generate graphs of package dependency relationships"
|
||||||
section = "basic"
|
section = "basic"
|
||||||
@@ -33,6 +33,9 @@ def setup_parser(subparser):
|
|||||||
method.add_argument(
|
method.add_argument(
|
||||||
"-d", "--dot", action="store_true", help="generate graph in dot format and print to stdout"
|
"-d", "--dot", action="store_true", help="generate graph in dot format and print to stdout"
|
||||||
)
|
)
|
||||||
|
method.add_argument(
|
||||||
|
"-m", "--mermaid", action="store_true", help="generate graph in mermaid format and print to stdout"
|
||||||
|
)
|
||||||
|
|
||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
"-s",
|
"-s",
|
||||||
@@ -85,10 +88,14 @@ def graph(parser, args):
|
|||||||
static_graph_dot(specs, depflag=args.deptype)
|
static_graph_dot(specs, depflag=args.deptype)
|
||||||
return
|
return
|
||||||
|
|
||||||
if args.dot:
|
if args.dot or args.mermaid:
|
||||||
builder = SimpleDAG()
|
if args.dot:
|
||||||
|
graph = DotGraph()
|
||||||
|
if args.mermaid:
|
||||||
|
graph = MermaidGraph()
|
||||||
|
builder = SimpleDAG(graph=graph)
|
||||||
if args.color:
|
if args.color:
|
||||||
builder = DAGWithDependencyTypes()
|
builder = DAGWithDependencyTypes(graph=graph)
|
||||||
graph_dot(specs, builder=builder, depflag=args.deptype)
|
graph_dot(specs, builder=builder, depflag=args.deptype)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@@ -34,7 +34,7 @@
|
|||||||
/
|
/
|
||||||
o boost
|
o boost
|
||||||
|
|
||||||
graph_dot() will output a graph of a spec (or multiple specs) in dot format.
|
graph_dot() will output a graph of a spec (or multiple specs) in dot or mermaid format.
|
||||||
"""
|
"""
|
||||||
import enum
|
import enum
|
||||||
import sys
|
import sys
|
||||||
@@ -446,10 +446,27 @@ def graph_ascii(
|
|||||||
graph.write(spec, color=color, out=out)
|
graph.write(spec, color=color, out=out)
|
||||||
|
|
||||||
|
|
||||||
class DotGraphBuilder:
|
class DotGraph:
|
||||||
"""Visit edges of a graph a build DOT options for nodes and edges"""
|
"""Configuration for DOT graphs"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self.label = "label="
|
||||||
|
self.template = "misc/graph.dot"
|
||||||
|
|
||||||
|
|
||||||
|
class MermaidGraph:
|
||||||
|
"""Configuration for Mermaid graphs"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.label = ""
|
||||||
|
self.template = "misc/graph.md"
|
||||||
|
|
||||||
|
|
||||||
|
class GraphBuilder:
|
||||||
|
"""Visit edges of a graph a build options for nodes and edges"""
|
||||||
|
|
||||||
|
def __init__(self, graph = DotGraph()):
|
||||||
|
self.graph: Union[DotGraph, MermaidGraph] = graph
|
||||||
self.nodes: Set[Tuple[str, str]] = set()
|
self.nodes: Set[Tuple[str, str]] = set()
|
||||||
self.edges: Set[Tuple[str, str, str]] = set()
|
self.edges: Set[Tuple[str, str, str]] = set()
|
||||||
|
|
||||||
@@ -472,40 +489,40 @@ def edge_entry(self, edge: spack.spec.DependencySpec) -> Tuple[str, str, str]:
|
|||||||
raise NotImplementedError("Need to be implemented by derived classes")
|
raise NotImplementedError("Need to be implemented by derived classes")
|
||||||
|
|
||||||
def context(self):
|
def context(self):
|
||||||
"""Return the context to be used to render the DOT graph template"""
|
"""Return the context to be used to render the graph template"""
|
||||||
result = {"nodes": self.nodes, "edges": self.edges}
|
result = {"nodes": self.nodes, "edges": self.edges}
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def render(self) -> str:
|
def render(self) -> str:
|
||||||
"""Return a string with the output in DOT format"""
|
"""Return a string with the output in format"""
|
||||||
environment = spack.tengine.make_environment()
|
environment = spack.tengine.make_environment()
|
||||||
template = environment.get_template("misc/graph.dot")
|
template = environment.get_template(self.graph.template)
|
||||||
return template.render(self.context())
|
return template.render(self.context())
|
||||||
|
|
||||||
|
|
||||||
class SimpleDAG(DotGraphBuilder):
|
class SimpleDAG(GraphBuilder):
|
||||||
"""Simple DOT graph, with nodes colored uniformly and edges without properties"""
|
"""Simple graph, with nodes colored uniformly and edges without properties"""
|
||||||
|
|
||||||
def node_entry(self, node):
|
def node_entry(self, node):
|
||||||
format_option = "{name}{@version}{%compiler}{/hash:7}"
|
format_option = "{name}{@version}{%compiler}{/hash:7}"
|
||||||
return node.dag_hash(), f'[label="{node.format(format_option)}"]'
|
return node.dag_hash(), f'[{self.graph.label}"{node.format(format_option)}"]'
|
||||||
|
|
||||||
def edge_entry(self, edge):
|
def edge_entry(self, edge):
|
||||||
return edge.parent.dag_hash(), edge.spec.dag_hash(), None
|
return edge.parent.dag_hash(), edge.spec.dag_hash(), None
|
||||||
|
|
||||||
|
|
||||||
class StaticDag(DotGraphBuilder):
|
class StaticDag(GraphBuilder):
|
||||||
"""DOT graph for possible dependencies"""
|
"""Graph for possible dependencies"""
|
||||||
|
|
||||||
def node_entry(self, node):
|
def node_entry(self, node):
|
||||||
return node.name, f'[label="{node.name}"]'
|
return node.name, f'[{self.graph.label}"{node.name}"]'
|
||||||
|
|
||||||
def edge_entry(self, edge):
|
def edge_entry(self, edge):
|
||||||
return edge.parent.name, edge.spec.name, None
|
return edge.parent.name, edge.spec.name, None
|
||||||
|
|
||||||
|
|
||||||
class DAGWithDependencyTypes(DotGraphBuilder):
|
class DAGWithDependencyTypes(GraphBuilder):
|
||||||
"""DOT graph with link,run nodes grouped together and edges colored according to
|
"""Graph with link,run nodes grouped together and edges colored according to
|
||||||
the dependency types.
|
the dependency types.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -521,7 +538,7 @@ def visit(self, edge):
|
|||||||
|
|
||||||
def node_entry(self, node):
|
def node_entry(self, node):
|
||||||
node_str = node.format("{name}{@version}{%compiler}{/hash:7}")
|
node_str = node.format("{name}{@version}{%compiler}{/hash:7}")
|
||||||
options = f'[label="{node_str}", group="build_dependencies", fillcolor="coral"]'
|
options = f'[{self.graph.label}"{node_str}", group="build_dependencies", fillcolor="coral"]'
|
||||||
if node.dag_hash() in self.main_unified_space:
|
if node.dag_hash() in self.main_unified_space:
|
||||||
options = f'[label="{node_str}", group="main_psid"]'
|
options = f'[label="{node_str}", group="main_psid"]'
|
||||||
return node.dag_hash(), options
|
return node.dag_hash(), options
|
||||||
@@ -574,7 +591,7 @@ def static_graph_dot(
|
|||||||
|
|
||||||
def graph_dot(
|
def graph_dot(
|
||||||
specs: List[spack.spec.Spec],
|
specs: List[spack.spec.Spec],
|
||||||
builder: Optional[DotGraphBuilder] = None,
|
builder: Optional[GraphBuilder] = None,
|
||||||
depflag: dt.DepFlag = dt.ALL,
|
depflag: dt.DepFlag = dt.ALL,
|
||||||
out: Optional[TextIO] = None,
|
out: Optional[TextIO] = None,
|
||||||
):
|
):
|
||||||
|
16
share/spack/templates/misc/graph.md
Normal file
16
share/spack/templates/misc/graph.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
flowchart TD
|
||||||
|
|
||||||
|
{% for node, node_options in nodes %}
|
||||||
|
{% if node_options %}
|
||||||
|
{{ node }}{{ node_options }}
|
||||||
|
{% else %}
|
||||||
|
{{ node }}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for edge_parent, edge_child, edge_options in edges %}
|
||||||
|
{% if edge_options %}
|
||||||
|
{{ edge_parent }} --> {{ edge_child }}{{ edge_options }}
|
||||||
|
{% else %}
|
||||||
|
{{ edge_parent }} --> {{ edge_child }}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
Reference in New Issue
Block a user