implement dag.Subgrapher interface
This allows the dag package to detect subgraphs, even when impelemnted by types from other packages
This commit is contained in:
parent
28d406c040
commit
7b774f771b
|
@ -24,6 +24,10 @@ type WalkFunc func(Vertex) error
|
|||
// walk as an argument
|
||||
type DepthWalkFunc func(Vertex, int) error
|
||||
|
||||
func (g *AcyclicGraph) DirectedGraph() Grapher {
|
||||
return g
|
||||
}
|
||||
|
||||
// Returns a Set that includes every Vertex yielded by walking down from the
|
||||
// provided starting Vertex v.
|
||||
func (g *AcyclicGraph) Ancestors(v Vertex) (*Set, error) {
|
||||
|
|
16
dag/graph.go
16
dag/graph.go
|
@ -17,6 +17,18 @@ type Graph struct {
|
|||
once sync.Once
|
||||
}
|
||||
|
||||
// Subgrapher allows a Vertex to be a Graph itself, by returning a Grapher.
|
||||
type Subgrapher interface {
|
||||
Subgraph() Grapher
|
||||
}
|
||||
|
||||
// A Grapher is any type that returns a Grapher, mainly used to identify
|
||||
// dag.Graph and dag.AcyclicGraph. In the case of Graph and AcyclicGraph, they
|
||||
// return themselves.
|
||||
type Grapher interface {
|
||||
DirectedGraph() Grapher
|
||||
}
|
||||
|
||||
// Vertex of the graph.
|
||||
type Vertex interface{}
|
||||
|
||||
|
@ -27,6 +39,10 @@ type NamedVertex interface {
|
|||
Name() string
|
||||
}
|
||||
|
||||
func (g *Graph) DirectedGraph() Grapher {
|
||||
return g
|
||||
}
|
||||
|
||||
// Vertices returns the list of all the vertices in the graph.
|
||||
func (g *Graph) Vertices() []Vertex {
|
||||
list := g.vertices.List()
|
||||
|
|
|
@ -60,7 +60,7 @@ func newMarshalGraph(name string, g *Graph) *marshalGraph {
|
|||
|
||||
for _, v := range g.Vertices() {
|
||||
id := marshalVertexID(v)
|
||||
if sg, ok := marshalSubgraph(v); ok {
|
||||
if sg, ok := marshalSubgrapher(v); ok {
|
||||
|
||||
sdg := newMarshalGraph(VertexName(v), sg)
|
||||
sdg.ID = id
|
||||
|
@ -129,22 +129,19 @@ func marshalVertexID(v Vertex) string {
|
|||
panic("unhashable value in graph")
|
||||
}
|
||||
|
||||
func debugSubgraph(v Vertex) (*Graph, bool) {
|
||||
val := reflect.ValueOf(v)
|
||||
m, ok := val.Type().MethodByName("Subgraph")
|
||||
// check for a Subgrapher, and return the underlying *Graph.
|
||||
func marshalSubgrapher(v Vertex) (*Graph, bool) {
|
||||
sg, ok := v.(Subgrapher)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if m.Type.NumOut() != 1 {
|
||||
return nil, false
|
||||
switch g := sg.Subgraph().DirectedGraph().(type) {
|
||||
case *Graph:
|
||||
return g, true
|
||||
case *AcyclicGraph:
|
||||
return &g.Graph, true
|
||||
}
|
||||
|
||||
// can't check for the subgraph type, because we can't import terraform, so
|
||||
// we assume this is the correct method.
|
||||
// TODO: create a dag interface type that we can satisfy
|
||||
|
||||
sg := val.MethodByName("Subgraph").Call(nil)[0]
|
||||
ag := sg.Elem().FieldByName("AcyclicGraph").Interface().(AcyclicGraph)
|
||||
return &ag.Graph, true
|
||||
return nil, false
|
||||
}
|
||||
|
|
|
@ -43,6 +43,10 @@ type Graph struct {
|
|||
once sync.Once
|
||||
}
|
||||
|
||||
func (g *Graph) DirectedGraph() dag.Grapher {
|
||||
return &g.AcyclicGraph
|
||||
}
|
||||
|
||||
// Annotations returns the annotations that are configured for the
|
||||
// given vertex. The map is guaranteed to be non-nil but may be empty.
|
||||
//
|
||||
|
@ -317,7 +321,7 @@ func (g *Graph) walk(walker GraphWalker) error {
|
|||
walker.Debug().Printf(
|
||||
"[DEBUG] vertex %T(%s.%s): subgraph\n", v, path, dag.VertexName(v))
|
||||
|
||||
if rerr = sn.Subgraph().walk(walker); rerr != nil {
|
||||
if rerr = sn.Subgraph().(*Graph).walk(walker); rerr != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ func (n *graphNodeModuleExpanded) EvalTree() EvalNode {
|
|||
|
||||
// GraphNodeFlattenable impl.
|
||||
func (n *graphNodeModuleExpanded) FlattenGraph() *Graph {
|
||||
graph := n.Subgraph()
|
||||
graph := n.Subgraph().(*Graph)
|
||||
input := n.Original.Module.RawConfig
|
||||
|
||||
// Go over each vertex and do some modifications to the graph for
|
||||
|
@ -189,7 +189,7 @@ func (n *graphNodeModuleExpanded) FlattenGraph() *Graph {
|
|||
}
|
||||
|
||||
// GraphNodeSubgraph impl.
|
||||
func (n *graphNodeModuleExpanded) Subgraph() *Graph {
|
||||
func (n *graphNodeModuleExpanded) Subgraph() dag.Grapher {
|
||||
return n.Graph
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ func TestGraphNodeConfigModuleExpand(t *testing.T) {
|
|||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := strings.TrimSpace(g.Subgraph().String())
|
||||
actual := strings.TrimSpace(g.Subgraph().(*Graph).String())
|
||||
expected := strings.TrimSpace(testGraphNodeModuleExpandStr)
|
||||
if actual != expected {
|
||||
t.Fatalf("bad:\n\n%s", actual)
|
||||
|
|
|
@ -184,7 +184,7 @@ func (dg *DebugGraph) buildSubgraph(modName string, g *Graph, modDepth int) erro
|
|||
|
||||
for _, v := range g.Vertices() {
|
||||
if sn, ok := v.(GraphNodeSubgraph); ok {
|
||||
subgraphVertices[v] = sn.Subgraph()
|
||||
subgraphVertices[v] = sn.Subgraph().(*Graph)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,7 @@ func (dg *DebugGraph) buildSubgraph(modName string, g *Graph, modDepth int) erro
|
|||
toDraw = append(toDraw, v)
|
||||
|
||||
if sn, ok := v.(GraphNodeSubgraph); ok {
|
||||
subgraphVertices[v] = sn.Subgraph()
|
||||
subgraphVertices[v] = sn.Subgraph().(*Graph)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -299,7 +299,7 @@ type testDrawableSubgraph struct {
|
|||
func (node *testDrawableSubgraph) Name() string {
|
||||
return node.VertexName
|
||||
}
|
||||
func (node *testDrawableSubgraph) Subgraph() *Graph {
|
||||
func (node *testDrawableSubgraph) Subgraph() dag.Grapher {
|
||||
return node.SubgraphMock
|
||||
}
|
||||
func (node *testDrawableSubgraph) DotNode(n string, opts *dag.DotOpts) *dot.Node {
|
||||
|
|
|
@ -24,7 +24,7 @@ type GraphNodeDynamicExpandable interface {
|
|||
// GraphNodeSubgraph is an interface a node can implement if it has
|
||||
// a larger subgraph that should be walked.
|
||||
type GraphNodeSubgraph interface {
|
||||
Subgraph() *Graph
|
||||
Subgraph() dag.Grapher
|
||||
}
|
||||
|
||||
// ExpandTransform is a transformer that does a subgraph expansion
|
||||
|
@ -56,7 +56,7 @@ func (n *GraphNodeBasicSubgraph) Name() string {
|
|||
return n.NameValue
|
||||
}
|
||||
|
||||
func (n *GraphNodeBasicSubgraph) Subgraph() *Graph {
|
||||
func (n *GraphNodeBasicSubgraph) Subgraph() dag.Grapher {
|
||||
return n.Graph
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ func TestExpandTransform(t *testing.T) {
|
|||
t.Fatalf("not subgraph: %#v", out)
|
||||
}
|
||||
|
||||
actual := strings.TrimSpace(sn.Subgraph().String())
|
||||
actual := strings.TrimSpace(sn.Subgraph().(*Graph).String())
|
||||
expected := strings.TrimSpace(testExpandTransformStr)
|
||||
if actual != expected {
|
||||
t.Fatalf("bad: %s", actual)
|
||||
|
@ -66,7 +66,7 @@ type testSubgraph struct {
|
|||
Graph *Graph
|
||||
}
|
||||
|
||||
func (n *testSubgraph) Subgraph() *Graph {
|
||||
func (n *testSubgraph) Subgraph() dag.Grapher {
|
||||
return n.Graph
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue