Files
steampipe/pkg/steampipeconfig/parse/decode_mod.go

139 lines
4.0 KiB
Go

package parse
import (
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/gocty"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
)
func decodeMod(block *hcl.Block, evalCtx *hcl.EvalContext, mod *modconfig.Mod) (*modconfig.Mod, *decodeResult) {
res := newDecodeResult()
// retrieve the body content which complies with modBlockSchema
// - this will be used to handle attributes which need manual decoding
// everything else will be implicitly decoded
content, remain, diags := block.Body.PartialContent(ModBlockSchema)
res.handleDecodeDiags(diags)
// decode the body to populate all properties that can be automatically decoded
diags = decodeHclBody(remain, evalCtx, mod, mod)
res.handleDecodeDiags(diags)
if !res.Success() {
return mod, res
}
// now decode the require block
require, requireRes := decodeRequireBlock(content, evalCtx)
res.Merge(requireRes)
if require != nil {
mod.Require = require
}
return mod, res
}
func decodeRequireBlock(content *hcl.BodyContent, evalCtx *hcl.EvalContext) (*modconfig.Require, *decodeResult) {
var res = newDecodeResult()
block := getFirstBlockOfType(content.Blocks, modconfig.BlockTypeRequire)
if block == nil {
return nil, res
}
// retrieve the body content which complies with modBlockSchema
// - this will be used to handle attributes which need manual decoding
// everything else will be implicitly decoded
content, remain, diags := block.Body.PartialContent(RequireBlockSchema)
res.handleDecodeDiags(diags)
// decode the body into 'modContainer' to populate all properties that can be automatically decoded
require := modconfig.NewRequire()
diags = gohcl.DecodeBody(remain, evalCtx, require)
// handle any resulting diags, which may specify dependencies
res.handleDecodeDiags(diags)
modversionConstraints, modRes := decodeRequireModVersionConstraintBlocks(content, evalCtx)
res.Merge(modRes)
if modversionConstraints != nil {
require.Mods = modversionConstraints
}
return require, res
}
func decodeRequireModVersionConstraintBlocks(content *hcl.BodyContent, evalCtx *hcl.EvalContext) ([]*modconfig.ModVersionConstraint, *decodeResult) {
var res = newDecodeResult()
var constraints []*modconfig.ModVersionConstraint
for _, block := range content.Blocks {
// we only expect mod blocks
if block.Type != modconfig.BlockTypeMod {
continue
}
// retrieve the body content which complies with modBlockSchema
// - this will be used to handle attributes which need manual decoding
// everything else will be implicitly decoded
requireModContent, remain, diags := block.Body.PartialContent(RequireModBlockSchema)
res.handleDecodeDiags(diags)
// decode the body into 'modContainer' to populate all properties that can be automatically decoded
constraint, _ := modconfig.NewModVersionConstraint(block.Labels[0])
diags = gohcl.DecodeBody(remain, evalCtx, constraint)
// handle any resulting diags, which may specify dependencies
res.handleDecodeDiags(diags)
args, modRes := decodeRequireModArgs(requireModContent, evalCtx)
res.Merge(modRes)
if args != nil {
constraint.Args = args
}
constraints = append(constraints, constraint)
}
return constraints, res
}
func decodeRequireModArgs(content *hcl.BodyContent, evalCtx *hcl.EvalContext) (map[string]cty.Value, *decodeResult) {
var res = newDecodeResult()
attr, ok := content.Attributes["args"]
if !ok {
return nil, res
}
// try to evaluate expression
val, diags := attr.Expr.Value(evalCtx)
// handle any resulting diags, which may specify dependencies
res.handleDecodeDiags(diags)
if diags.HasErrors() {
return nil, res
}
argMap, _ := ctyObjectToCtyArgMap(val)
return argMap, res
}
func ctyObjectToCtyArgMap(val cty.Value) (map[string]cty.Value, error) {
res := make(map[string]cty.Value)
it := val.ElementIterator()
for it.Next() {
k, v := it.Element()
// decode key
var key string
if err := gocty.FromCtyValue(k, &key); err != nil {
return nil, err
}
if v.IsKnown() {
res[key] = v
}
}
return res, nil
}