]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/hashicorp/terraform/terraform/graph.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / graph.go
CommitLineData
bae9f6d2
JC
1package terraform
2
3import (
4 "fmt"
5 "log"
bae9f6d2 6
107c1cdb 7 "github.com/hashicorp/terraform/tfdiags"
bae9f6d2 8
107c1cdb 9 "github.com/hashicorp/terraform/addrs"
bae9f6d2 10
107c1cdb
ND
11 "github.com/hashicorp/terraform/dag"
12)
bae9f6d2
JC
13
14// Graph represents the graph that Terraform uses to represent resources
15// and their dependencies.
16type Graph struct {
17 // Graph is the actual DAG. This is embedded so you can call the DAG
18 // methods directly.
19 dag.AcyclicGraph
20
21 // Path is the path in the module tree that this Graph represents.
107c1cdb 22 Path addrs.ModuleInstance
bae9f6d2
JC
23
24 // debugName is a name for reference in the debug output. This is usually
25 // to indicate what topmost builder was, and if this graph is a shadow or
26 // not.
27 debugName string
28}
29
30func (g *Graph) DirectedGraph() dag.Grapher {
31 return &g.AcyclicGraph
32}
33
34// Walk walks the graph with the given walker for callbacks. The graph
35// will be walked with full parallelism, so the walker should expect
36// to be called in concurrently.
107c1cdb 37func (g *Graph) Walk(walker GraphWalker) tfdiags.Diagnostics {
bae9f6d2
JC
38 return g.walk(walker)
39}
40
107c1cdb 41func (g *Graph) walk(walker GraphWalker) tfdiags.Diagnostics {
bae9f6d2
JC
42 // The callbacks for enter/exiting a graph
43 ctx := walker.EnterPath(g.Path)
44 defer walker.ExitPath(g.Path)
45
46 // Get the path for logs
107c1cdb 47 path := ctx.Path().String()
bae9f6d2
JC
48
49 debugName := "walk-graph.json"
50 if g.debugName != "" {
51 debugName = g.debugName + "-" + debugName
52 }
53
bae9f6d2
JC
54 // Walk the graph.
55 var walkFn dag.WalkFunc
107c1cdb
ND
56 walkFn = func(v dag.Vertex) (diags tfdiags.Diagnostics) {
57 log.Printf("[TRACE] vertex %q: starting visit (%T)", dag.VertexName(v), v)
bae9f6d2
JC
58 g.DebugVisitInfo(v, g.debugName)
59
bae9f6d2 60 defer func() {
107c1cdb 61 log.Printf("[TRACE] vertex %q: visit complete", dag.VertexName(v))
bae9f6d2
JC
62 }()
63
64 walker.EnterVertex(v)
107c1cdb 65 defer walker.ExitVertex(v, diags)
bae9f6d2
JC
66
67 // vertexCtx is the context that we use when evaluating. This
68 // is normally the context of our graph but can be overridden
69 // with a GraphNodeSubPath impl.
70 vertexCtx := ctx
71 if pn, ok := v.(GraphNodeSubPath); ok && len(pn.Path()) > 0 {
107c1cdb 72 vertexCtx = walker.EnterPath(pn.Path())
bae9f6d2
JC
73 defer walker.ExitPath(pn.Path())
74 }
75
76 // If the node is eval-able, then evaluate it.
77 if ev, ok := v.(GraphNodeEvalable); ok {
78 tree := ev.EvalTree()
79 if tree == nil {
107c1cdb 80 panic(fmt.Sprintf("%q (%T): nil eval tree", dag.VertexName(v), v))
bae9f6d2
JC
81 }
82
83 // Allow the walker to change our tree if needed. Eval,
84 // then callback with the output.
107c1cdb 85 log.Printf("[TRACE] vertex %q: evaluating", dag.VertexName(v))
bae9f6d2
JC
86
87 g.DebugVertexInfo(v, fmt.Sprintf("evaluating %T(%s)", v, path))
88
89 tree = walker.EnterEvalTree(v, tree)
90 output, err := Eval(tree, vertexCtx)
107c1cdb
ND
91 diags = diags.Append(walker.ExitEvalTree(v, output, err))
92 if diags.HasErrors() {
bae9f6d2
JC
93 return
94 }
95 }
96
97 // If the node is dynamically expanded, then expand it
98 if ev, ok := v.(GraphNodeDynamicExpandable); ok {
107c1cdb 99 log.Printf("[TRACE] vertex %q: expanding dynamic subgraph", dag.VertexName(v))
bae9f6d2
JC
100
101 g.DebugVertexInfo(v, fmt.Sprintf("expanding %T(%s)", v, path))
102
103 g, err := ev.DynamicExpand(vertexCtx)
104 if err != nil {
107c1cdb 105 diags = diags.Append(err)
bae9f6d2
JC
106 return
107 }
108 if g != nil {
109 // Walk the subgraph
107c1cdb
ND
110 log.Printf("[TRACE] vertex %q: entering dynamic subgraph", dag.VertexName(v))
111 subDiags := g.walk(walker)
112 diags = diags.Append(subDiags)
113 if subDiags.HasErrors() {
114 log.Printf("[TRACE] vertex %q: dynamic subgraph encountered errors", dag.VertexName(v))
bae9f6d2
JC
115 return
116 }
107c1cdb
ND
117 log.Printf("[TRACE] vertex %q: dynamic subgraph completed successfully", dag.VertexName(v))
118 } else {
119 log.Printf("[TRACE] vertex %q: produced no dynamic subgraph", dag.VertexName(v))
bae9f6d2
JC
120 }
121 }
122
123 // If the node has a subgraph, then walk the subgraph
124 if sn, ok := v.(GraphNodeSubgraph); ok {
107c1cdb 125 log.Printf("[TRACE] vertex %q: entering static subgraph", dag.VertexName(v))
bae9f6d2
JC
126
127 g.DebugVertexInfo(v, fmt.Sprintf("subgraph: %T(%s)", v, path))
128
107c1cdb
ND
129 subDiags := sn.Subgraph().(*Graph).walk(walker)
130 if subDiags.HasErrors() {
131 log.Printf("[TRACE] vertex %q: static subgraph encountered errors", dag.VertexName(v))
bae9f6d2
JC
132 return
133 }
107c1cdb 134 log.Printf("[TRACE] vertex %q: static subgraph completed successfully", dag.VertexName(v))
bae9f6d2
JC
135 }
136
107c1cdb 137 return
bae9f6d2
JC
138 }
139
140 return g.AcyclicGraph.Walk(walkFn)
141}