Files
steampipe/pkg/steampipeconfig/modconfig/variable.go
kaidaguerre 91436fafba Support resolution of variables for transitive dependencies using parent mod 'args' property
`steampipe mod update` now updates transitive mods
It is now be possible to set values for variables in the current mod using fully qualified variable names. 
Only variables for root mod and top level dependency mods can be set by user
Closes #3533. Closes #3547. Closes #3548. Closes #3549
2023-06-09 16:22:09 +01:00

144 lines
4.4 KiB
Go

package modconfig
import (
"fmt"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/terraform/tfdiags"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig/var_config"
"github.com/turbot/steampipe/pkg/type_conversion"
"github.com/turbot/steampipe/pkg/utils"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/convert"
)
// TODO check DescriptionSet - still required?
// Variable is a struct representing a Variable resource
type Variable struct {
ResourceWithMetadataImpl
ModTreeItemImpl
// required to allow partial decoding
Remain hcl.Body `hcl:",remain" json:"-"`
Default cty.Value `column:"default_value,jsonb" json:"-"`
Type cty.Type `column:"var_type,text" json:"-"`
TypeString string `json:"type"`
DefaultGo any `json:"value_default"`
ValueGo any `json:"value"`
ModName string `json:"mod_name"`
// set after value resolution `column:"value,jsonb"`
Value cty.Value `column:"value,jsonb" json:"-"`
ValueSourceType string `column:"value_source,text" json:"-"`
ValueSourceFileName string `column:"value_source_file_name,text" json:"-"`
ValueSourceStartLineNumber int `column:"value_source_start_line_number,integer" json:"-"`
ValueSourceEndLineNumber int `column:"value_source_end_line_number,integer" json:"-"`
ParsingMode var_config.VariableParsingMode `json:"-"`
metadata *ResourceMetadata
}
func NewVariable(v *var_config.Variable, mod *Mod) *Variable {
var defaultGo interface{} = nil
if !v.Default.IsNull() {
defaultGo, _ = type_conversion.CtyToGo(v.Default)
}
fullName := fmt.Sprintf("%s.var.%s", mod.ShortName, v.Name)
res := &Variable{
ModTreeItemImpl: ModTreeItemImpl{
HclResourceImpl: HclResourceImpl{
ShortName: v.Name,
Description: &v.Description,
FullName: fullName,
DeclRange: v.DeclRange,
UnqualifiedName: fmt.Sprintf("var.%s", v.Name),
blockType: BlockTypeVariable,
},
Mod: mod,
},
Default: v.Default,
DefaultGo: defaultGo,
// initialise the value to the default - may be set later
Value: v.Default,
ValueGo: defaultGo,
Type: v.Type,
ParsingMode: v.ParsingMode,
ModName: mod.ShortName,
TypeString: type_conversion.CtyTypeToHclType(v.Type, v.Default.Type()),
}
// if no type is set and a default _is_ set, use default to set the type
if res.Type.Equals(cty.DynamicPseudoType) && !res.Default.IsNull() {
res.Type = res.Default.Type()
}
return res
}
func (v *Variable) Equals(other *Variable) bool {
return v.ShortName == other.ShortName &&
v.FullName == other.FullName &&
v.Description == other.Description &&
v.Default.RawEquals(other.Default) &&
v.Value.RawEquals(other.Value)
}
// OnDecoded implements HclResource
func (v *Variable) OnDecoded(block *hcl.Block, _ ResourceMapsProvider) hcl.Diagnostics {
return nil
}
// Required returns true if this variable is required to be set by the caller,
// or false if there is a default value that will be used when it isn't set.
func (v *Variable) Required() bool {
return v.Default == cty.NilVal
}
func (v *Variable) SetInputValue(value cty.Value, sourceType string, sourceRange tfdiags.SourceRange) error {
// if the value type is a tuple with no elem type, and we have a type, set the variable to have our type
if value.Type().Equals(cty.Tuple(nil)) && !v.Type.Equals(cty.DynamicPseudoType) {
var err error
value, err = convert.Convert(value, v.Type)
if err != nil {
return err
}
}
v.Value = value
v.ValueSourceType = sourceType
v.ValueSourceFileName = sourceRange.Filename
v.ValueSourceStartLineNumber = sourceRange.Start.Line
v.ValueSourceEndLineNumber = sourceRange.End.Line
v.ValueGo, _ = type_conversion.CtyToGo(value)
// if type string is not set, derive from the type of value
if v.TypeString == "" {
v.TypeString = type_conversion.CtyTypeToHclType(value.Type())
}
return nil
}
func (v *Variable) Diff(other *Variable) *DashboardTreeItemDiffs {
res := &DashboardTreeItemDiffs{
Item: v,
Name: v.Name(),
}
if !utils.SafeStringsEqual(v.FullName, other.FullName) {
res.AddPropertyDiff("Name")
}
if !utils.SafeStringsEqual(v.Value, other.Value) {
res.AddPropertyDiff("Value")
}
res.populateChildDiffs(v, other)
return res
}
// CtyValue implements CtyValueProvider
func (v *Variable) CtyValue() (cty.Value, error) {
return GetCtyValue(v)
}