diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/moduledeps/module.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/moduledeps/module.go | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/moduledeps/module.go b/vendor/github.com/hashicorp/terraform/moduledeps/module.go new file mode 100644 index 0000000..d6cbaf5 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/moduledeps/module.go | |||
@@ -0,0 +1,204 @@ | |||
1 | package moduledeps | ||
2 | |||
3 | import ( | ||
4 | "sort" | ||
5 | "strings" | ||
6 | |||
7 | "github.com/hashicorp/terraform/plugin/discovery" | ||
8 | ) | ||
9 | |||
10 | // Module represents the dependencies of a single module, as well being | ||
11 | // a node in a tree of such structures representing the dependencies of | ||
12 | // an entire configuration. | ||
13 | type Module struct { | ||
14 | Name string | ||
15 | Providers Providers | ||
16 | Children []*Module | ||
17 | } | ||
18 | |||
19 | // WalkFunc is a callback type for use with Module.WalkTree | ||
20 | type WalkFunc func(path []string, parent *Module, current *Module) error | ||
21 | |||
22 | // WalkTree calls the given callback once for the receiver and then | ||
23 | // once for each descendent, in an order such that parents are called | ||
24 | // before their children and siblings are called in the order they | ||
25 | // appear in the Children slice. | ||
26 | // | ||
27 | // When calling the callback, parent will be nil for the first call | ||
28 | // for the receiving module, and then set to the direct parent of | ||
29 | // each module for the subsequent calls. | ||
30 | // | ||
31 | // The path given to the callback is valid only until the callback | ||
32 | // returns, after which it will be mutated and reused. Callbacks must | ||
33 | // therefore copy the path slice if they wish to retain it. | ||
34 | // | ||
35 | // If the given callback returns an error, the walk will be aborted at | ||
36 | // that point and that error returned to the caller. | ||
37 | // | ||
38 | // This function is not thread-safe for concurrent modifications of the | ||
39 | // data structure, so it's the caller's responsibility to arrange for that | ||
40 | // should it be needed. | ||
41 | // | ||
42 | // It is safe for a callback to modify the descendents of the "current" | ||
43 | // module, including the ordering of the Children slice itself, but the | ||
44 | // callback MUST NOT modify the parent module. | ||
45 | func (m *Module) WalkTree(cb WalkFunc) error { | ||
46 | return walkModuleTree(make([]string, 0, 1), nil, m, cb) | ||
47 | } | ||
48 | |||
49 | func walkModuleTree(path []string, parent *Module, current *Module, cb WalkFunc) error { | ||
50 | path = append(path, current.Name) | ||
51 | err := cb(path, parent, current) | ||
52 | if err != nil { | ||
53 | return err | ||
54 | } | ||
55 | |||
56 | for _, child := range current.Children { | ||
57 | err := walkModuleTree(path, current, child, cb) | ||
58 | if err != nil { | ||
59 | return err | ||
60 | } | ||
61 | } | ||
62 | return nil | ||
63 | } | ||
64 | |||
65 | // SortChildren sorts the Children slice into lexicographic order by | ||
66 | // name, in-place. | ||
67 | // | ||
68 | // This is primarily useful prior to calling WalkTree so that the walk | ||
69 | // will proceed in a consistent order. | ||
70 | func (m *Module) SortChildren() { | ||
71 | sort.Sort(sortModules{m.Children}) | ||
72 | } | ||
73 | |||
74 | // SortDescendents is a convenience wrapper for calling SortChildren on | ||
75 | // the receiver and all of its descendent modules. | ||
76 | func (m *Module) SortDescendents() { | ||
77 | m.WalkTree(func(path []string, parent *Module, current *Module) error { | ||
78 | current.SortChildren() | ||
79 | return nil | ||
80 | }) | ||
81 | } | ||
82 | |||
83 | type sortModules struct { | ||
84 | modules []*Module | ||
85 | } | ||
86 | |||
87 | func (s sortModules) Len() int { | ||
88 | return len(s.modules) | ||
89 | } | ||
90 | |||
91 | func (s sortModules) Less(i, j int) bool { | ||
92 | cmp := strings.Compare(s.modules[i].Name, s.modules[j].Name) | ||
93 | return cmp < 0 | ||
94 | } | ||
95 | |||
96 | func (s sortModules) Swap(i, j int) { | ||
97 | s.modules[i], s.modules[j] = s.modules[j], s.modules[i] | ||
98 | } | ||
99 | |||
100 | // PluginRequirements produces a PluginRequirements structure that can | ||
101 | // be used with discovery.PluginMetaSet.ConstrainVersions to identify | ||
102 | // suitable plugins to satisfy the module's provider dependencies. | ||
103 | // | ||
104 | // This method only considers the direct requirements of the receiver. | ||
105 | // Use AllPluginRequirements to flatten the dependencies for the | ||
106 | // entire tree of modules. | ||
107 | // | ||
108 | // Requirements returned by this method include only version constraints, | ||
109 | // and apply no particular SHA256 hash constraint. | ||
110 | func (m *Module) PluginRequirements() discovery.PluginRequirements { | ||
111 | ret := make(discovery.PluginRequirements) | ||
112 | for inst, dep := range m.Providers { | ||
113 | // m.Providers is keyed on provider names, such as "aws.foo". | ||
114 | // a PluginRequirements wants keys to be provider *types*, such | ||
115 | // as "aws". If there are multiple aliases for the same | ||
116 | // provider then we will flatten them into a single requirement | ||
117 | // by combining their constraint sets. | ||
118 | pty := inst.Type() | ||
119 | if existing, exists := ret[pty]; exists { | ||
120 | ret[pty].Versions = existing.Versions.Append(dep.Constraints) | ||
121 | } else { | ||
122 | ret[pty] = &discovery.PluginConstraints{ | ||
123 | Versions: dep.Constraints, | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | return ret | ||
128 | } | ||
129 | |||
130 | // AllPluginRequirements calls PluginRequirements for the receiver and all | ||
131 | // of its descendents, and merges the result into a single PluginRequirements | ||
132 | // structure that would satisfy all of the modules together. | ||
133 | // | ||
134 | // Requirements returned by this method include only version constraints, | ||
135 | // and apply no particular SHA256 hash constraint. | ||
136 | func (m *Module) AllPluginRequirements() discovery.PluginRequirements { | ||
137 | var ret discovery.PluginRequirements | ||
138 | m.WalkTree(func(path []string, parent *Module, current *Module) error { | ||
139 | ret = ret.Merge(current.PluginRequirements()) | ||
140 | return nil | ||
141 | }) | ||
142 | return ret | ||
143 | } | ||
144 | |||
145 | // Equal returns true if the receiver is the root of an identical tree | ||
146 | // to the other given Module. This is a deep comparison that considers | ||
147 | // the equality of all downstream modules too. | ||
148 | // | ||
149 | // The children are considered to be ordered, so callers may wish to use | ||
150 | // SortDescendents first to normalize the order of the slices of child nodes. | ||
151 | // | ||
152 | // The implementation of this function is not optimized since it is provided | ||
153 | // primarily for use in tests. | ||
154 | func (m *Module) Equal(other *Module) bool { | ||
155 | // take care of nils first | ||
156 | if m == nil && other == nil { | ||
157 | return true | ||
158 | } else if (m == nil && other != nil) || (m != nil && other == nil) { | ||
159 | return false | ||
160 | } | ||
161 | |||
162 | if m.Name != other.Name { | ||
163 | return false | ||
164 | } | ||
165 | |||
166 | if len(m.Providers) != len(other.Providers) { | ||
167 | return false | ||
168 | } | ||
169 | if len(m.Children) != len(other.Children) { | ||
170 | return false | ||
171 | } | ||
172 | |||
173 | // Can't use reflect.DeepEqual on this provider structure because | ||
174 | // the nested Constraints objects contain function pointers that | ||
175 | // never compare as equal. So we'll need to walk it the long way. | ||
176 | for inst, dep := range m.Providers { | ||
177 | if _, exists := other.Providers[inst]; !exists { | ||
178 | return false | ||
179 | } | ||
180 | |||
181 | if dep.Reason != other.Providers[inst].Reason { | ||
182 | return false | ||
183 | } | ||
184 | |||
185 | // Constraints are not too easy to compare robustly, so | ||
186 | // we'll just use their string representations as a proxy | ||
187 | // for now. | ||
188 | if dep.Constraints.String() != other.Providers[inst].Constraints.String() { | ||
189 | return false | ||
190 | } | ||
191 | } | ||
192 | |||
193 | // Above we already checked that we have the same number of children | ||
194 | // in each module, so now we just need to check that they are | ||
195 | // recursively equal. | ||
196 | for i := range m.Children { | ||
197 | if !m.Children[i].Equal(other.Children[i]) { | ||
198 | return false | ||
199 | } | ||
200 | } | ||
201 | |||
202 | // If we fall out here then they are equal | ||
203 | return true | ||
204 | } | ||