diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/configs/config_build.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/configs/config_build.go | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/configs/config_build.go b/vendor/github.com/hashicorp/terraform/configs/config_build.go new file mode 100644 index 0000000..948b2c8 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/configs/config_build.go | |||
@@ -0,0 +1,179 @@ | |||
1 | package configs | ||
2 | |||
3 | import ( | ||
4 | "sort" | ||
5 | |||
6 | version "github.com/hashicorp/go-version" | ||
7 | "github.com/hashicorp/hcl2/hcl" | ||
8 | "github.com/hashicorp/terraform/addrs" | ||
9 | ) | ||
10 | |||
11 | // BuildConfig constructs a Config from a root module by loading all of its | ||
12 | // descendent modules via the given ModuleWalker. | ||
13 | // | ||
14 | // The result is a module tree that has so far only had basic module- and | ||
15 | // file-level invariants validated. If the returned diagnostics contains errors, | ||
16 | // the returned module tree may be incomplete but can still be used carefully | ||
17 | // for static analysis. | ||
18 | func BuildConfig(root *Module, walker ModuleWalker) (*Config, hcl.Diagnostics) { | ||
19 | var diags hcl.Diagnostics | ||
20 | cfg := &Config{ | ||
21 | Module: root, | ||
22 | } | ||
23 | cfg.Root = cfg // Root module is self-referential. | ||
24 | cfg.Children, diags = buildChildModules(cfg, walker) | ||
25 | return cfg, diags | ||
26 | } | ||
27 | |||
28 | func buildChildModules(parent *Config, walker ModuleWalker) (map[string]*Config, hcl.Diagnostics) { | ||
29 | var diags hcl.Diagnostics | ||
30 | ret := map[string]*Config{} | ||
31 | |||
32 | calls := parent.Module.ModuleCalls | ||
33 | |||
34 | // We'll sort the calls by their local names so that they'll appear in a | ||
35 | // predictable order in any logging that's produced during the walk. | ||
36 | callNames := make([]string, 0, len(calls)) | ||
37 | for k := range calls { | ||
38 | callNames = append(callNames, k) | ||
39 | } | ||
40 | sort.Strings(callNames) | ||
41 | |||
42 | for _, callName := range callNames { | ||
43 | call := calls[callName] | ||
44 | path := make([]string, len(parent.Path)+1) | ||
45 | copy(path, parent.Path) | ||
46 | path[len(path)-1] = call.Name | ||
47 | |||
48 | req := ModuleRequest{ | ||
49 | Name: call.Name, | ||
50 | Path: path, | ||
51 | SourceAddr: call.SourceAddr, | ||
52 | SourceAddrRange: call.SourceAddrRange, | ||
53 | VersionConstraint: call.Version, | ||
54 | Parent: parent, | ||
55 | CallRange: call.DeclRange, | ||
56 | } | ||
57 | |||
58 | mod, ver, modDiags := walker.LoadModule(&req) | ||
59 | diags = append(diags, modDiags...) | ||
60 | if mod == nil { | ||
61 | // nil can be returned if the source address was invalid and so | ||
62 | // nothing could be loaded whatsoever. LoadModule should've | ||
63 | // returned at least one error diagnostic in that case. | ||
64 | continue | ||
65 | } | ||
66 | |||
67 | child := &Config{ | ||
68 | Parent: parent, | ||
69 | Root: parent.Root, | ||
70 | Path: path, | ||
71 | Module: mod, | ||
72 | CallRange: call.DeclRange, | ||
73 | SourceAddr: call.SourceAddr, | ||
74 | SourceAddrRange: call.SourceAddrRange, | ||
75 | Version: ver, | ||
76 | } | ||
77 | |||
78 | child.Children, modDiags = buildChildModules(child, walker) | ||
79 | |||
80 | ret[call.Name] = child | ||
81 | } | ||
82 | |||
83 | return ret, diags | ||
84 | } | ||
85 | |||
86 | // A ModuleWalker knows how to find and load a child module given details about | ||
87 | // the module to be loaded and a reference to its partially-loaded parent | ||
88 | // Config. | ||
89 | type ModuleWalker interface { | ||
90 | // LoadModule finds and loads a requested child module. | ||
91 | // | ||
92 | // If errors are detected during loading, implementations should return them | ||
93 | // in the diagnostics object. If the diagnostics object contains any errors | ||
94 | // then the caller will tolerate the returned module being nil or incomplete. | ||
95 | // If no errors are returned, it should be non-nil and complete. | ||
96 | // | ||
97 | // Full validation need not have been performed but an implementation should | ||
98 | // ensure that the basic file- and module-validations performed by the | ||
99 | // LoadConfigDir function (valid syntax, no namespace collisions, etc) have | ||
100 | // been performed before returning a module. | ||
101 | LoadModule(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) | ||
102 | } | ||
103 | |||
104 | // ModuleWalkerFunc is an implementation of ModuleWalker that directly wraps | ||
105 | // a callback function, for more convenient use of that interface. | ||
106 | type ModuleWalkerFunc func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) | ||
107 | |||
108 | // LoadModule implements ModuleWalker. | ||
109 | func (f ModuleWalkerFunc) LoadModule(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) { | ||
110 | return f(req) | ||
111 | } | ||
112 | |||
113 | // ModuleRequest is used with the ModuleWalker interface to describe a child | ||
114 | // module that must be loaded. | ||
115 | type ModuleRequest struct { | ||
116 | // Name is the "logical name" of the module call within configuration. | ||
117 | // This is provided in case the name is used as part of a storage key | ||
118 | // for the module, but implementations must otherwise treat it as an | ||
119 | // opaque string. It is guaranteed to have already been validated as an | ||
120 | // HCL identifier and UTF-8 encoded. | ||
121 | Name string | ||
122 | |||
123 | // Path is a list of logical names that traverse from the root module to | ||
124 | // this module. This can be used, for example, to form a lookup key for | ||
125 | // each distinct module call in a configuration, allowing for multiple | ||
126 | // calls with the same name at different points in the tree. | ||
127 | Path addrs.Module | ||
128 | |||
129 | // SourceAddr is the source address string provided by the user in | ||
130 | // configuration. | ||
131 | SourceAddr string | ||
132 | |||
133 | // SourceAddrRange is the source range for the SourceAddr value as it | ||
134 | // was provided in configuration. This can and should be used to generate | ||
135 | // diagnostics about the source address having invalid syntax, referring | ||
136 | // to a non-existent object, etc. | ||
137 | SourceAddrRange hcl.Range | ||
138 | |||
139 | // VersionConstraint is the version constraint applied to the module in | ||
140 | // configuration. This data structure includes the source range for | ||
141 | // the constraint, which can and should be used to generate diagnostics | ||
142 | // about constraint-related issues, such as constraints that eliminate all | ||
143 | // available versions of a module whose source is otherwise valid. | ||
144 | VersionConstraint VersionConstraint | ||
145 | |||
146 | // Parent is the partially-constructed module tree node that the loaded | ||
147 | // module will be added to. Callers may refer to any field of this | ||
148 | // structure except Children, which is still under construction when | ||
149 | // ModuleRequest objects are created and thus has undefined content. | ||
150 | // The main reason this is provided is so that full module paths can | ||
151 | // be constructed for uniqueness. | ||
152 | Parent *Config | ||
153 | |||
154 | // CallRange is the source range for the header of the "module" block | ||
155 | // in configuration that prompted this request. This can be used as the | ||
156 | // subject of an error diagnostic that relates to the module call itself, | ||
157 | // rather than to either its source address or its version number. | ||
158 | CallRange hcl.Range | ||
159 | } | ||
160 | |||
161 | // DisabledModuleWalker is a ModuleWalker that doesn't support | ||
162 | // child modules at all, and so will return an error if asked to load one. | ||
163 | // | ||
164 | // This is provided primarily for testing. There is no good reason to use this | ||
165 | // in the main application. | ||
166 | var DisabledModuleWalker ModuleWalker | ||
167 | |||
168 | func init() { | ||
169 | DisabledModuleWalker = ModuleWalkerFunc(func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) { | ||
170 | return nil, nil, hcl.Diagnostics{ | ||
171 | { | ||
172 | Severity: hcl.DiagError, | ||
173 | Summary: "Child modules are not supported", | ||
174 | Detail: "Child module calls are not allowed in this context.", | ||
175 | Subject: &req.CallRange, | ||
176 | }, | ||
177 | } | ||
178 | }) | ||
179 | } | ||