]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/configs/config_build.go
update vendor and go.mod
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / configs / config_build.go
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 diags = append(diags, modDiags...)
80
81 ret[call.Name] = child
82 }
83
84 return ret, diags
85 }
86
87 // A ModuleWalker knows how to find and load a child module given details about
88 // the module to be loaded and a reference to its partially-loaded parent
89 // Config.
90 type ModuleWalker interface {
91 // LoadModule finds and loads a requested child module.
92 //
93 // If errors are detected during loading, implementations should return them
94 // in the diagnostics object. If the diagnostics object contains any errors
95 // then the caller will tolerate the returned module being nil or incomplete.
96 // If no errors are returned, it should be non-nil and complete.
97 //
98 // Full validation need not have been performed but an implementation should
99 // ensure that the basic file- and module-validations performed by the
100 // LoadConfigDir function (valid syntax, no namespace collisions, etc) have
101 // been performed before returning a module.
102 LoadModule(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics)
103 }
104
105 // ModuleWalkerFunc is an implementation of ModuleWalker that directly wraps
106 // a callback function, for more convenient use of that interface.
107 type ModuleWalkerFunc func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics)
108
109 // LoadModule implements ModuleWalker.
110 func (f ModuleWalkerFunc) LoadModule(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
111 return f(req)
112 }
113
114 // ModuleRequest is used with the ModuleWalker interface to describe a child
115 // module that must be loaded.
116 type ModuleRequest struct {
117 // Name is the "logical name" of the module call within configuration.
118 // This is provided in case the name is used as part of a storage key
119 // for the module, but implementations must otherwise treat it as an
120 // opaque string. It is guaranteed to have already been validated as an
121 // HCL identifier and UTF-8 encoded.
122 Name string
123
124 // Path is a list of logical names that traverse from the root module to
125 // this module. This can be used, for example, to form a lookup key for
126 // each distinct module call in a configuration, allowing for multiple
127 // calls with the same name at different points in the tree.
128 Path addrs.Module
129
130 // SourceAddr is the source address string provided by the user in
131 // configuration.
132 SourceAddr string
133
134 // SourceAddrRange is the source range for the SourceAddr value as it
135 // was provided in configuration. This can and should be used to generate
136 // diagnostics about the source address having invalid syntax, referring
137 // to a non-existent object, etc.
138 SourceAddrRange hcl.Range
139
140 // VersionConstraint is the version constraint applied to the module in
141 // configuration. This data structure includes the source range for
142 // the constraint, which can and should be used to generate diagnostics
143 // about constraint-related issues, such as constraints that eliminate all
144 // available versions of a module whose source is otherwise valid.
145 VersionConstraint VersionConstraint
146
147 // Parent is the partially-constructed module tree node that the loaded
148 // module will be added to. Callers may refer to any field of this
149 // structure except Children, which is still under construction when
150 // ModuleRequest objects are created and thus has undefined content.
151 // The main reason this is provided is so that full module paths can
152 // be constructed for uniqueness.
153 Parent *Config
154
155 // CallRange is the source range for the header of the "module" block
156 // in configuration that prompted this request. This can be used as the
157 // subject of an error diagnostic that relates to the module call itself,
158 // rather than to either its source address or its version number.
159 CallRange hcl.Range
160 }
161
162 // DisabledModuleWalker is a ModuleWalker that doesn't support
163 // child modules at all, and so will return an error if asked to load one.
164 //
165 // This is provided primarily for testing. There is no good reason to use this
166 // in the main application.
167 var DisabledModuleWalker ModuleWalker
168
169 func init() {
170 DisabledModuleWalker = ModuleWalkerFunc(func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
171 return nil, nil, hcl.Diagnostics{
172 {
173 Severity: hcl.DiagError,
174 Summary: "Child modules are not supported",
175 Detail: "Child module calls are not allowed in this context.",
176 Subject: &req.CallRange,
177 },
178 }
179 })
180 }