]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/dag/dag.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / dag / dag.go
1 package dag
2
3 import (
4 "fmt"
5 "sort"
6 "strings"
7
8 "github.com/hashicorp/go-multierror"
9 )
10
11 // AcyclicGraph is a specialization of Graph that cannot have cycles. With
12 // this property, we get the property of sane graph traversal.
13 type AcyclicGraph struct {
14 Graph
15 }
16
17 // WalkFunc is the callback used for walking the graph.
18 type WalkFunc func(Vertex) error
19
20 // DepthWalkFunc is a walk function that also receives the current depth of the
21 // walk as an argument
22 type DepthWalkFunc func(Vertex, int) error
23
24 func (g *AcyclicGraph) DirectedGraph() Grapher {
25 return g
26 }
27
28 // Returns a Set that includes every Vertex yielded by walking down from the
29 // provided starting Vertex v.
30 func (g *AcyclicGraph) Ancestors(v Vertex) (*Set, error) {
31 s := new(Set)
32 start := AsVertexList(g.DownEdges(v))
33 memoFunc := func(v Vertex, d int) error {
34 s.Add(v)
35 return nil
36 }
37
38 if err := g.DepthFirstWalk(start, memoFunc); err != nil {
39 return nil, err
40 }
41
42 return s, nil
43 }
44
45 // Returns a Set that includes every Vertex yielded by walking up from the
46 // provided starting Vertex v.
47 func (g *AcyclicGraph) Descendents(v Vertex) (*Set, error) {
48 s := new(Set)
49 start := AsVertexList(g.UpEdges(v))
50 memoFunc := func(v Vertex, d int) error {
51 s.Add(v)
52 return nil
53 }
54
55 if err := g.ReverseDepthFirstWalk(start, memoFunc); err != nil {
56 return nil, err
57 }
58
59 return s, nil
60 }
61
62 // Root returns the root of the DAG, or an error.
63 //
64 // Complexity: O(V)
65 func (g *AcyclicGraph) Root() (Vertex, error) {
66 roots := make([]Vertex, 0, 1)
67 for _, v := range g.Vertices() {
68 if g.UpEdges(v).Len() == 0 {
69 roots = append(roots, v)
70 }
71 }
72
73 if len(roots) > 1 {
74 // TODO(mitchellh): make this error message a lot better
75 return nil, fmt.Errorf("multiple roots: %#v", roots)
76 }
77
78 if len(roots) == 0 {
79 return nil, fmt.Errorf("no roots found")
80 }
81
82 return roots[0], nil
83 }
84
85 // TransitiveReduction performs the transitive reduction of graph g in place.
86 // The transitive reduction of a graph is a graph with as few edges as
87 // possible with the same reachability as the original graph. This means
88 // that if there are three nodes A => B => C, and A connects to both
89 // B and C, and B connects to C, then the transitive reduction is the
90 // same graph with only a single edge between A and B, and a single edge
91 // between B and C.
92 //
93 // The graph must be valid for this operation to behave properly. If
94 // Validate() returns an error, the behavior is undefined and the results
95 // will likely be unexpected.
96 //
97 // Complexity: O(V(V+E)), or asymptotically O(VE)
98 func (g *AcyclicGraph) TransitiveReduction() {
99 // For each vertex u in graph g, do a DFS starting from each vertex
100 // v such that the edge (u,v) exists (v is a direct descendant of u).
101 //
102 // For each v-prime reachable from v, remove the edge (u, v-prime).
103 defer g.debug.BeginOperation("TransitiveReduction", "").End("")
104
105 for _, u := range g.Vertices() {
106 uTargets := g.DownEdges(u)
107 vs := AsVertexList(g.DownEdges(u))
108
109 g.DepthFirstWalk(vs, func(v Vertex, d int) error {
110 shared := uTargets.Intersection(g.DownEdges(v))
111 for _, vPrime := range AsVertexList(shared) {
112 g.RemoveEdge(BasicEdge(u, vPrime))
113 }
114
115 return nil
116 })
117 }
118 }
119
120 // Validate validates the DAG. A DAG is valid if it has a single root
121 // with no cycles.
122 func (g *AcyclicGraph) Validate() error {
123 if _, err := g.Root(); err != nil {
124 return err
125 }
126
127 // Look for cycles of more than 1 component
128 var err error
129 cycles := g.Cycles()
130 if len(cycles) > 0 {
131 for _, cycle := range cycles {
132 cycleStr := make([]string, len(cycle))
133 for j, vertex := range cycle {
134 cycleStr[j] = VertexName(vertex)
135 }
136
137 err = multierror.Append(err, fmt.Errorf(
138 "Cycle: %s", strings.Join(cycleStr, ", ")))
139 }
140 }
141
142 // Look for cycles to self
143 for _, e := range g.Edges() {
144 if e.Source() == e.Target() {
145 err = multierror.Append(err, fmt.Errorf(
146 "Self reference: %s", VertexName(e.Source())))
147 }
148 }
149
150 return err
151 }
152
153 func (g *AcyclicGraph) Cycles() [][]Vertex {
154 var cycles [][]Vertex
155 for _, cycle := range StronglyConnected(&g.Graph) {
156 if len(cycle) > 1 {
157 cycles = append(cycles, cycle)
158 }
159 }
160 return cycles
161 }
162
163 // Walk walks the graph, calling your callback as each node is visited.
164 // This will walk nodes in parallel if it can. Because the walk is done
165 // in parallel, the error returned will be a multierror.
166 func (g *AcyclicGraph) Walk(cb WalkFunc) error {
167 defer g.debug.BeginOperation(typeWalk, "").End("")
168
169 w := &Walker{Callback: cb, Reverse: true}
170 w.Update(g)
171 return w.Wait()
172 }
173
174 // simple convenience helper for converting a dag.Set to a []Vertex
175 func AsVertexList(s *Set) []Vertex {
176 rawList := s.List()
177 vertexList := make([]Vertex, len(rawList))
178 for i, raw := range rawList {
179 vertexList[i] = raw.(Vertex)
180 }
181 return vertexList
182 }
183
184 type vertexAtDepth struct {
185 Vertex Vertex
186 Depth int
187 }
188
189 // depthFirstWalk does a depth-first walk of the graph starting from
190 // the vertices in start. This is not exported now but it would make sense
191 // to export this publicly at some point.
192 func (g *AcyclicGraph) DepthFirstWalk(start []Vertex, f DepthWalkFunc) error {
193 defer g.debug.BeginOperation(typeDepthFirstWalk, "").End("")
194
195 seen := make(map[Vertex]struct{})
196 frontier := make([]*vertexAtDepth, len(start))
197 for i, v := range start {
198 frontier[i] = &vertexAtDepth{
199 Vertex: v,
200 Depth: 0,
201 }
202 }
203 for len(frontier) > 0 {
204 // Pop the current vertex
205 n := len(frontier)
206 current := frontier[n-1]
207 frontier = frontier[:n-1]
208
209 // Check if we've seen this already and return...
210 if _, ok := seen[current.Vertex]; ok {
211 continue
212 }
213 seen[current.Vertex] = struct{}{}
214
215 // Visit the current node
216 if err := f(current.Vertex, current.Depth); err != nil {
217 return err
218 }
219
220 // Visit targets of this in a consistent order.
221 targets := AsVertexList(g.DownEdges(current.Vertex))
222 sort.Sort(byVertexName(targets))
223 for _, t := range targets {
224 frontier = append(frontier, &vertexAtDepth{
225 Vertex: t,
226 Depth: current.Depth + 1,
227 })
228 }
229 }
230
231 return nil
232 }
233
234 // reverseDepthFirstWalk does a depth-first walk _up_ the graph starting from
235 // the vertices in start.
236 func (g *AcyclicGraph) ReverseDepthFirstWalk(start []Vertex, f DepthWalkFunc) error {
237 defer g.debug.BeginOperation(typeReverseDepthFirstWalk, "").End("")
238
239 seen := make(map[Vertex]struct{})
240 frontier := make([]*vertexAtDepth, len(start))
241 for i, v := range start {
242 frontier[i] = &vertexAtDepth{
243 Vertex: v,
244 Depth: 0,
245 }
246 }
247 for len(frontier) > 0 {
248 // Pop the current vertex
249 n := len(frontier)
250 current := frontier[n-1]
251 frontier = frontier[:n-1]
252
253 // Check if we've seen this already and return...
254 if _, ok := seen[current.Vertex]; ok {
255 continue
256 }
257 seen[current.Vertex] = struct{}{}
258
259 // Add next set of targets in a consistent order.
260 targets := AsVertexList(g.UpEdges(current.Vertex))
261 sort.Sort(byVertexName(targets))
262 for _, t := range targets {
263 frontier = append(frontier, &vertexAtDepth{
264 Vertex: t,
265 Depth: current.Depth + 1,
266 })
267 }
268
269 // Visit the current node
270 if err := f(current.Vertex, current.Depth); err != nil {
271 return err
272 }
273 }
274
275 return nil
276 }
277
278 // byVertexName implements sort.Interface so a list of Vertices can be sorted
279 // consistently by their VertexName
280 type byVertexName []Vertex
281
282 func (b byVertexName) Len() int { return len(b) }
283 func (b byVertexName) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
284 func (b byVertexName) Less(i, j int) bool {
285 return VertexName(b[i]) < VertexName(b[j])
286 }