135 lines
3.7 KiB
Go
135 lines
3.7 KiB
Go
package hcl
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/hcl/v2"
|
|
"github.com/hashicorp/hcl/v2/hclsyntax"
|
|
"github.com/jinzhu/copier"
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
"code.icb4dc0.de/buildr/buildr/modules"
|
|
)
|
|
|
|
func (s ModulesSpec) prepareBlockForParsing(
|
|
block GenericBlock,
|
|
modType modules.Category,
|
|
evalCtx *hcl.EvalContext,
|
|
outDir string,
|
|
) (blockPreparationResult, error) {
|
|
syntaxBlock, ok := block.BlockBody.(*hclsyntax.Body)
|
|
if !ok {
|
|
return blockPreparationResult{
|
|
Specs: []blockParsingSpec{
|
|
parsingSpecOf(modType, block, nil),
|
|
},
|
|
ParsingRepresentation: cty.EmptyObjectVal,
|
|
}, nil
|
|
}
|
|
|
|
forEachAttr, ok := syntaxBlock.Attributes["for_each"]
|
|
if !ok {
|
|
initBlock(syntaxBlock, modType, block.BlockName, outDir)
|
|
bodyAsValue, _ := s.parseSyntaxBodyToObject(syntaxBlock, evalCtx, true)
|
|
return blockPreparationResult{
|
|
Specs: []blockParsingSpec{parsingSpecOf(modType, block, nil)},
|
|
ParsingRepresentation: cty.ObjectVal(bodyAsValue),
|
|
}, nil
|
|
}
|
|
|
|
delete(syntaxBlock.Attributes, "for_each")
|
|
|
|
val, diags := forEachAttr.Expr.Value(evalCtx)
|
|
if diags.HasErrors() {
|
|
return blockPreparationResult{}, diags
|
|
}
|
|
|
|
if !val.Type().IsCollectionType() {
|
|
return blockPreparationResult{}, fmt.Errorf("cannot for_each over non-collection value")
|
|
}
|
|
|
|
forEachTarget := make(map[string]cty.Value)
|
|
elementType := val.Type().ElementType()
|
|
|
|
switch {
|
|
case val.Type().IsSetType():
|
|
if !elementType.Equals(cty.String) {
|
|
return blockPreparationResult{}, fmt.Errorf("cannot use non-string type as set/list element type: %v", elementType)
|
|
}
|
|
|
|
for _, val := range val.AsValueSet().Values() {
|
|
forEachTarget[val.AsString()] = cty.StringVal("")
|
|
}
|
|
case val.Type().IsListType():
|
|
if !elementType.Equals(cty.String) {
|
|
return blockPreparationResult{}, fmt.Errorf("cannot use non-string type as set/list element type: %v", elementType)
|
|
}
|
|
|
|
for _, val := range val.AsValueSet().Values() {
|
|
forEachTarget[val.AsString()] = cty.StringVal("")
|
|
}
|
|
case val.Type().IsMapType():
|
|
forEachTarget = val.AsValueMap()
|
|
}
|
|
|
|
result := blockPreparationResult{
|
|
Specs: make([]blockParsingSpec, 0, len(forEachTarget)),
|
|
}
|
|
|
|
parsingRepresentation := make(map[string]cty.Value, len(forEachTarget))
|
|
|
|
for k, v := range forEachTarget {
|
|
vals := map[string]cty.Value{
|
|
"each": cty.ObjectVal(map[string]cty.Value{
|
|
"key": cty.StringVal(k),
|
|
"value": v,
|
|
}),
|
|
}
|
|
|
|
blockCopy := new(hclsyntax.Body)
|
|
|
|
if err := copier.CopyWithOption(blockCopy, syntaxBlock, copier.Option{DeepCopy: true}); err != nil {
|
|
return blockPreparationResult{}, err
|
|
}
|
|
|
|
blockName := fmt.Sprintf("%s_%s", block.BlockName, k)
|
|
|
|
gb := GenericBlock{
|
|
ModuleName: block.ModuleName,
|
|
BlockName: blockName,
|
|
BlockBody: initBlock(blockCopy, modType, blockName, outDir),
|
|
}
|
|
|
|
result.Specs = append(result.Specs, parsingSpecOf(modType, gb, vals))
|
|
bodyAsValue, _ := s.parseSyntaxBodyToObject(blockCopy, evalCtx, true)
|
|
parsingRepresentation[k] = cty.ObjectVal(bodyAsValue)
|
|
}
|
|
|
|
result.ParsingRepresentation = cty.MapVal(parsingRepresentation)
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func parsingSpecOf(modType modules.Category, block GenericBlock, additionalVariables map[string]cty.Value) blockParsingSpec {
|
|
if additionalVariables == nil {
|
|
additionalVariables = make(map[string]cty.Value)
|
|
}
|
|
|
|
return blockParsingSpec{
|
|
Type: modType,
|
|
Block: block,
|
|
AdditionalParsingVariables: additionalVariables,
|
|
}
|
|
}
|
|
|
|
type blockParsingSpec struct {
|
|
AdditionalParsingVariables map[string]cty.Value
|
|
Block GenericBlock
|
|
Type modules.Category
|
|
}
|
|
|
|
type blockPreparationResult struct {
|
|
ParsingRepresentation cty.Value
|
|
Specs []blockParsingSpec
|
|
}
|