]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/hcl2/ext/dynblock/expand_spec.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / hcl2 / ext / dynblock / expand_spec.go
1 package dynblock
2
3 import (
4 "fmt"
5
6 "github.com/hashicorp/hcl2/hcl"
7 "github.com/zclconf/go-cty/cty"
8 "github.com/zclconf/go-cty/cty/convert"
9 )
10
11 type expandSpec struct {
12 blockType string
13 blockTypeRange hcl.Range
14 defRange hcl.Range
15 forEachVal cty.Value
16 iteratorName string
17 labelExprs []hcl.Expression
18 contentBody hcl.Body
19 inherited map[string]*iteration
20 }
21
22 func (b *expandBody) decodeSpec(blockS *hcl.BlockHeaderSchema, rawSpec *hcl.Block) (*expandSpec, hcl.Diagnostics) {
23 var diags hcl.Diagnostics
24
25 var schema *hcl.BodySchema
26 if len(blockS.LabelNames) != 0 {
27 schema = dynamicBlockBodySchemaLabels
28 } else {
29 schema = dynamicBlockBodySchemaNoLabels
30 }
31
32 specContent, specDiags := rawSpec.Body.Content(schema)
33 diags = append(diags, specDiags...)
34 if specDiags.HasErrors() {
35 return nil, diags
36 }
37
38 //// for_each attribute
39
40 eachAttr := specContent.Attributes["for_each"]
41 eachVal, eachDiags := eachAttr.Expr.Value(b.forEachCtx)
42 diags = append(diags, eachDiags...)
43
44 if !eachVal.CanIterateElements() && eachVal.Type() != cty.DynamicPseudoType {
45 // We skip this error for DynamicPseudoType because that means we either
46 // have a null (which is checked immediately below) or an unknown
47 // (which is handled in the expandBody Content methods).
48 diags = append(diags, &hcl.Diagnostic{
49 Severity: hcl.DiagError,
50 Summary: "Invalid dynamic for_each value",
51 Detail: fmt.Sprintf("Cannot use a %s value in for_each. An iterable collection is required.", eachVal.Type().FriendlyName()),
52 Subject: eachAttr.Expr.Range().Ptr(),
53 Expression: eachAttr.Expr,
54 EvalContext: b.forEachCtx,
55 })
56 return nil, diags
57 }
58 if eachVal.IsNull() {
59 diags = append(diags, &hcl.Diagnostic{
60 Severity: hcl.DiagError,
61 Summary: "Invalid dynamic for_each value",
62 Detail: "Cannot use a null value in for_each.",
63 Subject: eachAttr.Expr.Range().Ptr(),
64 Expression: eachAttr.Expr,
65 EvalContext: b.forEachCtx,
66 })
67 return nil, diags
68 }
69
70 //// iterator attribute
71
72 iteratorName := blockS.Type
73 if iteratorAttr := specContent.Attributes["iterator"]; iteratorAttr != nil {
74 itTraversal, itDiags := hcl.AbsTraversalForExpr(iteratorAttr.Expr)
75 diags = append(diags, itDiags...)
76 if itDiags.HasErrors() {
77 return nil, diags
78 }
79
80 if len(itTraversal) != 1 {
81 diags = append(diags, &hcl.Diagnostic{
82 Severity: hcl.DiagError,
83 Summary: "Invalid dynamic iterator name",
84 Detail: "Dynamic iterator must be a single variable name.",
85 Subject: itTraversal.SourceRange().Ptr(),
86 })
87 return nil, diags
88 }
89
90 iteratorName = itTraversal.RootName()
91 }
92
93 var labelExprs []hcl.Expression
94 if labelsAttr := specContent.Attributes["labels"]; labelsAttr != nil {
95 var labelDiags hcl.Diagnostics
96 labelExprs, labelDiags = hcl.ExprList(labelsAttr.Expr)
97 diags = append(diags, labelDiags...)
98 if labelDiags.HasErrors() {
99 return nil, diags
100 }
101
102 if len(labelExprs) > len(blockS.LabelNames) {
103 diags = append(diags, &hcl.Diagnostic{
104 Severity: hcl.DiagError,
105 Summary: "Extraneous dynamic block label",
106 Detail: fmt.Sprintf("Blocks of type %q require %d label(s).", blockS.Type, len(blockS.LabelNames)),
107 Subject: labelExprs[len(blockS.LabelNames)].Range().Ptr(),
108 })
109 return nil, diags
110 } else if len(labelExprs) < len(blockS.LabelNames) {
111 diags = append(diags, &hcl.Diagnostic{
112 Severity: hcl.DiagError,
113 Summary: "Insufficient dynamic block labels",
114 Detail: fmt.Sprintf("Blocks of type %q require %d label(s).", blockS.Type, len(blockS.LabelNames)),
115 Subject: labelsAttr.Expr.Range().Ptr(),
116 })
117 return nil, diags
118 }
119 }
120
121 // Since our schema requests only blocks of type "content", we can assume
122 // that all entries in specContent.Blocks are content blocks.
123 if len(specContent.Blocks) == 0 {
124 diags = append(diags, &hcl.Diagnostic{
125 Severity: hcl.DiagError,
126 Summary: "Missing dynamic content block",
127 Detail: "A dynamic block must have a nested block of type \"content\" to describe the body of each generated block.",
128 Subject: &specContent.MissingItemRange,
129 })
130 return nil, diags
131 }
132 if len(specContent.Blocks) > 1 {
133 diags = append(diags, &hcl.Diagnostic{
134 Severity: hcl.DiagError,
135 Summary: "Extraneous dynamic content block",
136 Detail: "Only one nested content block is allowed for each dynamic block.",
137 Subject: &specContent.Blocks[1].DefRange,
138 })
139 return nil, diags
140 }
141
142 return &expandSpec{
143 blockType: blockS.Type,
144 blockTypeRange: rawSpec.LabelRanges[0],
145 defRange: rawSpec.DefRange,
146 forEachVal: eachVal,
147 iteratorName: iteratorName,
148 labelExprs: labelExprs,
149 contentBody: specContent.Blocks[0].Body,
150 }, diags
151 }
152
153 func (s *expandSpec) newBlock(i *iteration, ctx *hcl.EvalContext) (*hcl.Block, hcl.Diagnostics) {
154 var diags hcl.Diagnostics
155 var labels []string
156 var labelRanges []hcl.Range
157 lCtx := i.EvalContext(ctx)
158 for _, labelExpr := range s.labelExprs {
159 labelVal, labelDiags := labelExpr.Value(lCtx)
160 diags = append(diags, labelDiags...)
161 if labelDiags.HasErrors() {
162 return nil, diags
163 }
164
165 var convErr error
166 labelVal, convErr = convert.Convert(labelVal, cty.String)
167 if convErr != nil {
168 diags = append(diags, &hcl.Diagnostic{
169 Severity: hcl.DiagError,
170 Summary: "Invalid dynamic block label",
171 Detail: fmt.Sprintf("Cannot use this value as a dynamic block label: %s.", convErr),
172 Subject: labelExpr.Range().Ptr(),
173 Expression: labelExpr,
174 EvalContext: lCtx,
175 })
176 return nil, diags
177 }
178 if labelVal.IsNull() {
179 diags = append(diags, &hcl.Diagnostic{
180 Severity: hcl.DiagError,
181 Summary: "Invalid dynamic block label",
182 Detail: "Cannot use a null value as a dynamic block label.",
183 Subject: labelExpr.Range().Ptr(),
184 Expression: labelExpr,
185 EvalContext: lCtx,
186 })
187 return nil, diags
188 }
189 if !labelVal.IsKnown() {
190 diags = append(diags, &hcl.Diagnostic{
191 Severity: hcl.DiagError,
192 Summary: "Invalid dynamic block label",
193 Detail: "This value is not yet known. Dynamic block labels must be immediately-known values.",
194 Subject: labelExpr.Range().Ptr(),
195 Expression: labelExpr,
196 EvalContext: lCtx,
197 })
198 return nil, diags
199 }
200
201 labels = append(labels, labelVal.AsString())
202 labelRanges = append(labelRanges, labelExpr.Range())
203 }
204
205 block := &hcl.Block{
206 Type: s.blockType,
207 TypeRange: s.blockTypeRange,
208 Labels: labels,
209 LabelRanges: labelRanges,
210 DefRange: s.defRange,
211 Body: s.contentBody,
212 }
213
214 return block, diags
215 }