buildr/internal/hcl/raw_spec.go
Peter 786578bc6f
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
feat: adapt new wire format
update to Go 1.21
2023-08-15 21:47:19 +02:00

156 lines
4 KiB
Go

package hcl
import (
"fmt"
"strings"
"github.com/hashicorp/hcl/v2"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/gocty"
"code.icb4dc0.de/buildr/buildr/modules"
)
type RepositoryOption func(evalCtx *hcl.EvalContext) error
func WithGlobalVariable(key string, value any) RepositoryOption {
return func(evalCtx *hcl.EvalContext) error {
ctyType, err := gocty.ImpliedType(value)
if err != nil {
return err
}
mapped, err := gocty.ToCtyValue(value, ctyType)
if err != nil {
return err
}
evalCtx.Variables[key] = mapped
return nil
}
}
type ModulesSpec struct {
diagsWriter hcl.DiagnosticWriter
Locals []LocalsBlock `hcl:"locals,block"`
Tools GenericBlocks `hcl:"tool,block"`
Tasks GenericBlocks `hcl:"task,block"`
Builds GenericBlocks `hcl:"build,block"`
Packages GenericBlocks `hcl:"package,block"`
}
func (s ModulesSpec) Repository(
evalCtx *hcl.EvalContext,
diagsWriter hcl.DiagnosticWriter,
registry *modules.TypeRegistry,
outDir string,
opts ...RepositoryOption,
) (*modules.Repository, error) {
repo := new(modules.Repository)
s.diagsWriter = diagsWriter
for _, opt := range opts {
if err := opt(evalCtx); err != nil {
return nil, err
}
}
if err := s.parseLocals(s.Locals, evalCtx); err != nil {
return nil, err
}
parsingSpecs := make([]blockParsingSpec, 0, len(s.Tools)+len(s.Tasks)+len(s.Builds))
if specs, err := s.buildParsingInventory(modules.CategoryTool, s.Tools, evalCtx, outDir); err != nil {
return nil, err
} else {
parsingSpecs = append(parsingSpecs, specs...)
}
if specs, err := s.buildParsingInventory(modules.CategoryTask, s.Tasks, evalCtx, outDir); err != nil {
return nil, err
} else {
parsingSpecs = append(parsingSpecs, specs...)
}
if specs, err := s.buildParsingInventory(modules.CategoryBuild, s.Builds, evalCtx, outDir); err != nil {
return nil, err
} else {
parsingSpecs = append(parsingSpecs, specs...)
}
if specs, err := s.buildParsingInventory(modules.CategoryPackage, s.Packages, evalCtx, outDir); err != nil {
return nil, err
} else {
parsingSpecs = append(parsingSpecs, specs...)
}
if parsedModules, err := s.parseBlocksToModules(parsingSpecs, registry, evalCtx, diagsWriter); err != nil {
return nil, err
} else {
repo.RegisterModules(parsedModules...)
}
return repo, nil
}
func (s ModulesSpec) buildParsingInventory(
modCategory modules.Category,
blocks []GenericBlock,
evalCtx *hcl.EvalContext,
outDir string,
) ([]blockParsingSpec, error) {
if len(blocks) == 0 {
return nil, nil
}
groupNameByCategory := func(c modules.Category) string {
return fmt.Sprintf("%ss", strings.Replace(strings.ToLower(c.String()), "category", "", -1))
}
groupName := groupNameByCategory(modCategory)
blockGroupRepresentation := make(map[string]cty.Value, len(blocks))
blockGroupParsingSpecs := make([]blockParsingSpec, 0)
for i := range blocks {
result, err := s.prepareBlockForParsing(blocks[i], modCategory, evalCtx, outDir)
if err != nil {
return nil, err
}
blockGroupRepresentation[blocks[i].BlockName] = result.ParsingRepresentation
blockGroupParsingSpecs = append(blockGroupParsingSpecs, result.Specs...)
}
evalCtx.Variables[groupName] = cty.ObjectVal(blockGroupRepresentation)
return blockGroupParsingSpecs, nil
}
func (s ModulesSpec) parseBlocksToModules(
specs []blockParsingSpec,
registry *modules.TypeRegistry,
evalCtx *hcl.EvalContext,
diagsWriter hcl.DiagnosticWriter,
) ([]modules.ModuleWithMeta, error) {
parsedModules := make([]modules.ModuleWithMeta, 0, len(specs))
for i := range specs {
spec := specs[i]
blockParseCtx := evalCtx
if len(spec.AdditionalParsingVariables) > 0 {
blockParseCtx = evalCtx.NewChild()
blockParseCtx.Variables = spec.AdditionalParsingVariables
}
if m, err := registry.CreateFromHCL(spec.Type, spec.Block.ModuleName, spec.Block.BlockBody, blockParseCtx, diagsWriter); err != nil {
return nil, err
} else {
parsedModules = append(parsedModules, m)
}
}
return parsedModules, nil
}