mirror of
https://github.com/mcuadros/ascode
synced 2024-11-26 06:01:08 +01:00
starlark/types: Computed renamed to Attribute, added documentation
This commit is contained in:
parent
be125c9f03
commit
c3cd97a5fc
@ -63,7 +63,7 @@ func NewRuntime(pm *terraform.PluginManager) *Runtime {
|
||||
"provisioner": types.BuiltinProvisioner(),
|
||||
"backend": types.BuiltinBackend(),
|
||||
"hcl": types.BuiltinHCL(),
|
||||
"fn": types.BuiltinFunctionComputed(),
|
||||
"fn": types.BuiltinFunctionAttribute(),
|
||||
"evaluate": types.BuiltinEvaluate(),
|
||||
"struct": starlark.NewBuiltin("struct", starlarkstruct.Make),
|
||||
"module": starlark.NewBuiltin("module", starlarkstruct.MakeModule),
|
||||
|
205
starlark/types/attribute.go
Normal file
205
starlark/types/attribute.go
Normal file
@ -0,0 +1,205 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"go.starlark.net/starlark"
|
||||
)
|
||||
|
||||
// sTring alias required to avoid name collision with the method String.
|
||||
type sString = starlark.String
|
||||
|
||||
// Attribute is a reference to an argument of a Resource. Used mainly
|
||||
// for Computed arguments of Resources.
|
||||
//
|
||||
// outline: types
|
||||
// types:
|
||||
// Attribute
|
||||
// Attribute is a reference to an argument of a Resource. Used mainly
|
||||
// for Computed arguments of Resources.
|
||||
//
|
||||
// Attribute behaves as type of the argument represented, this means
|
||||
// that their can be assigned to other resource arguments of the same
|
||||
// type. And, if the type is a list are indexables.
|
||||
//
|
||||
// examples:
|
||||
// attribute.star
|
||||
//
|
||||
// fields:
|
||||
// __resource__ Resource
|
||||
// Resource of the attribute.
|
||||
// __type__ string
|
||||
// Type of the attribute. Eg.: `string`
|
||||
type Attribute struct {
|
||||
r *Resource
|
||||
t cty.Type
|
||||
name string
|
||||
path string
|
||||
|
||||
sString
|
||||
}
|
||||
|
||||
var _ starlark.Value = &Attribute{}
|
||||
var _ starlark.HasAttrs = &Attribute{}
|
||||
var _ starlark.Indexable = &Attribute{}
|
||||
var _ starlark.Comparable = &Attribute{}
|
||||
|
||||
// NewAttribute returns a new Attribute for a given value or block of a Resource.
|
||||
func NewAttribute(r *Resource, t cty.Type, name string) *Attribute {
|
||||
var parts []string
|
||||
var path string
|
||||
|
||||
child := r
|
||||
|
||||
for {
|
||||
if child.parent.kind == ProviderKind {
|
||||
if child.kind == ResourceKind {
|
||||
path = fmt.Sprintf("%s.%s", child.typ, child.Name())
|
||||
} else {
|
||||
path = fmt.Sprintf("%s.%s.%s", child.kind, child.typ, child.Name())
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
parts = append(parts, child.typ)
|
||||
child = child.parent
|
||||
}
|
||||
|
||||
for i := len(parts) - 1; i >= 0; i-- {
|
||||
path += "." + parts[i]
|
||||
}
|
||||
|
||||
// handling of MaxItems equals 1
|
||||
block, ok := r.parent.block.BlockTypes[r.typ]
|
||||
if ok && block.MaxItems == 1 {
|
||||
name = "0." + name
|
||||
}
|
||||
|
||||
return NewAttributeWithPath(r, t, name, path+"."+name)
|
||||
}
|
||||
|
||||
func NewAttributeWithPath(r *Resource, t cty.Type, name, path string) *Attribute {
|
||||
return &Attribute{
|
||||
r: r,
|
||||
t: t,
|
||||
name: name,
|
||||
path: path,
|
||||
sString: starlark.String(fmt.Sprintf("${%s}", path)),
|
||||
}
|
||||
}
|
||||
|
||||
// Type honors the starlark.Value interface.
|
||||
func (c *Attribute) Type() string {
|
||||
return fmt.Sprintf("Attribute<%s>", MustTypeFromCty(c.t).Starlark())
|
||||
}
|
||||
|
||||
func (c *Attribute) InnerType() *Type {
|
||||
t, _ := NewTypeFromCty(c.t)
|
||||
return t
|
||||
}
|
||||
|
||||
// Attr honors the starlark.HasAttrs interface.
|
||||
func (c *Attribute) Attr(name string) (starlark.Value, error) {
|
||||
switch name {
|
||||
case "__resource__":
|
||||
return c.r, nil
|
||||
case "__type__":
|
||||
return starlark.String(MustTypeFromCty(c.t).Starlark()), nil
|
||||
}
|
||||
|
||||
if !c.t.IsObjectType() {
|
||||
return nil, fmt.Errorf("%s it's not a object", c.Type())
|
||||
}
|
||||
|
||||
if !c.t.HasAttribute(name) {
|
||||
errmsg := fmt.Sprintf("%s has no .%s field", c.Type(), name)
|
||||
return nil, starlark.NoSuchAttrError(errmsg)
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s.%s", c.path, name)
|
||||
return NewAttributeWithPath(c.r, c.t.AttributeType(name), name, path), nil
|
||||
}
|
||||
|
||||
// AttrNames honors the starlark.HasAttrs interface.
|
||||
func (c *Attribute) AttrNames() []string {
|
||||
return []string{"__resource__", "__type__"}
|
||||
}
|
||||
|
||||
func (c *Attribute) doNested(name, path string, t cty.Type, index int) *Attribute {
|
||||
return &Attribute{
|
||||
r: c.r,
|
||||
t: t,
|
||||
name: c.name,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Index honors the starlark.Indexable interface.
|
||||
func (c *Attribute) Index(i int) starlark.Value {
|
||||
path := fmt.Sprintf("%s.%d", c.path, i)
|
||||
|
||||
if c.t.IsSetType() {
|
||||
return NewAttributeWithPath(c.r, *c.t.SetElementType(), c.name, path)
|
||||
}
|
||||
|
||||
if c.t.IsListType() {
|
||||
return NewAttributeWithPath(c.r, *c.t.ListElementType(), c.name, path)
|
||||
}
|
||||
|
||||
return starlark.None
|
||||
}
|
||||
|
||||
// Len honors the starlark.Indexable interface.
|
||||
func (c *Attribute) Len() int {
|
||||
if !c.t.IsSetType() && !c.t.IsListType() {
|
||||
return 0
|
||||
}
|
||||
|
||||
return 1024
|
||||
}
|
||||
|
||||
// BuiltinFunctionAttribute returns a built-in function that wraps Attributes
|
||||
// in HCL functions.
|
||||
//
|
||||
// outline: types
|
||||
// functions:
|
||||
// fn(name, target) Attribute
|
||||
// Fn wraps an Attribute in a HCL function. Since the Attributes value
|
||||
// are only available in the `apply` phase of Terraform, the only method
|
||||
// to manipulate this values is using the Terraform
|
||||
// [HCL functions](https://www.terraform.io/docs/configuration/functions.html).
|
||||
//
|
||||
//
|
||||
// params:
|
||||
// name string
|
||||
// Name of the HCL function to be applied. Eg.: `base64encode`
|
||||
// target Attribute
|
||||
// Target Attribute of the HCL function.
|
||||
//
|
||||
func BuiltinFunctionAttribute() starlark.Value {
|
||||
// TODO(mcuadros): implement multiple arguments support.
|
||||
return starlark.NewBuiltin("fn", func(_ *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
|
||||
var function starlark.String
|
||||
var computed *Attribute
|
||||
switch len(args) {
|
||||
case 2:
|
||||
var ok bool
|
||||
function, ok = args.Index(0).(starlark.String)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected string, got %s", args.Index(0).Type())
|
||||
}
|
||||
|
||||
computed, ok = args.Index(1).(*Attribute)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected Attribute, got %s", args.Index(1).Type())
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected positional arguments count")
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s(%s)", function.GoString(), computed.path)
|
||||
return NewAttributeWithPath(computed.r, computed.t, computed.name, path), nil
|
||||
})
|
||||
}
|
9
starlark/types/attribute_test.go
Normal file
9
starlark/types/attribute_test.go
Normal file
@ -0,0 +1,9 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAttribute(t *testing.T) {
|
||||
doTest(t, "testdata/attribute.star")
|
||||
}
|
@ -68,6 +68,7 @@ var _ starlark.HasAttrs = &ResourceCollection{}
|
||||
var _ starlark.Callable = &ResourceCollection{}
|
||||
var _ starlark.Comparable = &ResourceCollection{}
|
||||
|
||||
// NewResourceCollection returns a new ResourceCollection for the given values.
|
||||
func NewResourceCollection(
|
||||
typ string, k Kind, block *configschema.Block, provider *Provider, parent *Resource,
|
||||
) *ResourceCollection {
|
||||
@ -271,6 +272,7 @@ var _ starlark.HasAttrs = &ProviderCollection{}
|
||||
var _ starlark.Callable = &ProviderCollection{}
|
||||
var _ starlark.Comparable = &ProviderCollection{}
|
||||
|
||||
// NewProviderCollection returns a new ProviderCollection.
|
||||
func NewProviderCollection(pm *terraform.PluginManager) *ProviderCollection {
|
||||
return &ProviderCollection{
|
||||
pm: pm,
|
||||
|
@ -1,162 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"go.starlark.net/starlark"
|
||||
)
|
||||
|
||||
type sString = starlark.String
|
||||
|
||||
type Computed struct {
|
||||
r *Resource
|
||||
t cty.Type
|
||||
name string
|
||||
path string
|
||||
|
||||
sString
|
||||
}
|
||||
|
||||
var _ starlark.Value = &Computed{}
|
||||
var _ starlark.HasAttrs = &Computed{}
|
||||
var _ starlark.Indexable = &Computed{}
|
||||
var _ starlark.Comparable = &Computed{}
|
||||
|
||||
func NewComputed(r *Resource, t cty.Type, name string) *Computed {
|
||||
var parts []string
|
||||
var path string
|
||||
|
||||
child := r
|
||||
|
||||
for {
|
||||
if child.parent.kind == ProviderKind {
|
||||
if child.kind == ResourceKind {
|
||||
path = fmt.Sprintf("%s.%s", child.typ, child.Name())
|
||||
} else {
|
||||
path = fmt.Sprintf("%s.%s.%s", child.kind, child.typ, child.Name())
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
parts = append(parts, child.typ)
|
||||
child = child.parent
|
||||
}
|
||||
|
||||
for i := len(parts) - 1; i >= 0; i-- {
|
||||
path += "." + parts[i]
|
||||
}
|
||||
|
||||
// handling of MaxItems equals 1
|
||||
block, ok := r.parent.block.BlockTypes[r.typ]
|
||||
if ok && block.MaxItems == 1 {
|
||||
name = "0." + name
|
||||
}
|
||||
|
||||
return NewComputedWithPath(r, t, name, path+"."+name)
|
||||
}
|
||||
|
||||
func NewComputedWithPath(r *Resource, t cty.Type, name, path string) *Computed {
|
||||
return &Computed{
|
||||
r: r,
|
||||
t: t,
|
||||
name: name,
|
||||
path: path,
|
||||
sString: starlark.String(fmt.Sprintf("${%s}", path)),
|
||||
}
|
||||
}
|
||||
|
||||
// Type honors the starlark.Value interface.
|
||||
func (c *Computed) Type() string {
|
||||
return fmt.Sprintf("Computed<%s>", MustTypeFromCty(c.t).Starlark())
|
||||
}
|
||||
|
||||
func (c *Computed) InnerType() *Type {
|
||||
t, _ := NewTypeFromCty(c.t)
|
||||
return t
|
||||
}
|
||||
|
||||
// Attr honors the starlark.HasAttrs interface.
|
||||
func (c *Computed) Attr(name string) (starlark.Value, error) {
|
||||
switch name {
|
||||
case "__resource__":
|
||||
return c.r, nil
|
||||
case "__type__":
|
||||
return starlark.String(MustTypeFromCty(c.t).Starlark()), nil
|
||||
}
|
||||
|
||||
if !c.t.IsObjectType() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if !c.t.HasAttribute(name) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s.%s", c.path, name)
|
||||
return NewComputedWithPath(c.r, c.t.AttributeType(name), name, path), nil
|
||||
}
|
||||
|
||||
// AttrNames honors the starlark.HasAttrs interface.
|
||||
func (c *Computed) AttrNames() []string {
|
||||
return []string{"__resource__", "__type__"}
|
||||
}
|
||||
|
||||
func (c *Computed) doNested(name, path string, t cty.Type, index int) *Computed {
|
||||
return &Computed{
|
||||
r: c.r,
|
||||
t: t,
|
||||
name: c.name,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Index honors the starlark.Indexable interface.
|
||||
func (c *Computed) Index(i int) starlark.Value {
|
||||
path := fmt.Sprintf("%s.%d", c.path, i)
|
||||
|
||||
if c.t.IsSetType() {
|
||||
return NewComputedWithPath(c.r, *c.t.SetElementType(), c.name, path)
|
||||
}
|
||||
|
||||
if c.t.IsListType() {
|
||||
return NewComputedWithPath(c.r, *c.t.ListElementType(), c.name, path)
|
||||
}
|
||||
|
||||
return starlark.None
|
||||
}
|
||||
|
||||
// Len honors the starlark.Indexable interface.
|
||||
func (c *Computed) Len() int {
|
||||
if !c.t.IsSetType() && !c.t.IsListType() {
|
||||
return 0
|
||||
}
|
||||
|
||||
return 1024
|
||||
}
|
||||
|
||||
func BuiltinFunctionComputed() starlark.Value {
|
||||
return starlark.NewBuiltin("fn", func(_ *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
|
||||
var function starlark.String
|
||||
var computed *Computed
|
||||
switch len(args) {
|
||||
case 2:
|
||||
var ok bool
|
||||
function, ok = args.Index(0).(starlark.String)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected string, got %s", args.Index(0).Type())
|
||||
}
|
||||
|
||||
computed, ok = args.Index(1).(*Computed)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected Computed, got %s", args.Index(1).Type())
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected positional arguments count")
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s(%s)", function.GoString(), computed.path)
|
||||
return NewComputedWithPath(computed.r, computed.t, computed.name, path), nil
|
||||
})
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestComputed(t *testing.T) {
|
||||
doTest(t, "testdata/computed.star")
|
||||
}
|
@ -11,6 +11,7 @@ import (
|
||||
"go.starlark.net/starlark"
|
||||
)
|
||||
|
||||
// HCLCompatible defines if the struct is suitable of by encoded in HCL.
|
||||
type HCLCompatible interface {
|
||||
ToHCL(b *hclwrite.Body)
|
||||
}
|
||||
@ -44,6 +45,7 @@ func BuiltinHCL() starlark.Value {
|
||||
})
|
||||
}
|
||||
|
||||
// ToHCL honors the HCLCompatible interface.
|
||||
func (s *Terraform) ToHCL(b *hclwrite.Body) {
|
||||
if s.b != nil {
|
||||
s.b.ToHCL(b)
|
||||
@ -52,6 +54,7 @@ func (s *Terraform) ToHCL(b *hclwrite.Body) {
|
||||
s.p.ToHCL(b)
|
||||
}
|
||||
|
||||
// ToHCL honors the HCLCompatible interface.
|
||||
func (s *Dict) ToHCL(b *hclwrite.Body) {
|
||||
for _, v := range s.Keys() {
|
||||
p, _, _ := s.Get(v)
|
||||
@ -64,6 +67,7 @@ func (s *Dict) ToHCL(b *hclwrite.Body) {
|
||||
}
|
||||
}
|
||||
|
||||
// ToHCL honors the HCLCompatible interface.
|
||||
func (s *Provider) ToHCL(b *hclwrite.Body) {
|
||||
block := b.AppendNewBlock("provider", []string{s.typ})
|
||||
|
||||
@ -76,11 +80,13 @@ func (s *Provider) ToHCL(b *hclwrite.Body) {
|
||||
b.AppendNewline()
|
||||
}
|
||||
|
||||
// ToHCL honors the HCLCompatible interface.
|
||||
func (s *Provisioner) ToHCL(b *hclwrite.Body) {
|
||||
block := b.AppendNewBlock("provisioner", []string{s.typ})
|
||||
s.Resource.doToHCLAttributes(block.Body())
|
||||
}
|
||||
|
||||
// ToHCL honors the HCLCompatible interface.
|
||||
func (s *Backend) ToHCL(b *hclwrite.Body) {
|
||||
parent := b.AppendNewBlock("terraform", nil)
|
||||
|
||||
@ -89,6 +95,7 @@ func (s *Backend) ToHCL(b *hclwrite.Body) {
|
||||
b.AppendNewline()
|
||||
}
|
||||
|
||||
// ToHCL honors the HCLCompatible interface.
|
||||
func (t *ResourceCollectionGroup) ToHCL(b *hclwrite.Body) {
|
||||
names := make(sort.StringSlice, len(t.collections))
|
||||
var i int
|
||||
@ -103,12 +110,14 @@ func (t *ResourceCollectionGroup) ToHCL(b *hclwrite.Body) {
|
||||
}
|
||||
}
|
||||
|
||||
// ToHCL honors the HCLCompatible interface.
|
||||
func (c *ResourceCollection) ToHCL(b *hclwrite.Body) {
|
||||
for i := 0; i < c.Len(); i++ {
|
||||
c.Index(i).(*Resource).ToHCL(b)
|
||||
}
|
||||
}
|
||||
|
||||
// ToHCL honors the HCLCompatible interface.
|
||||
func (r *Resource) ToHCL(b *hclwrite.Body) {
|
||||
if len(b.Blocks()) != 0 || len(b.Attributes()) != 0 {
|
||||
b.AppendNewline()
|
||||
@ -142,7 +151,7 @@ func (r *Resource) doToHCLAttributes(body *hclwrite.Body) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if c, ok := v.v.(*Computed); ok {
|
||||
if c, ok := v.v.(*Attribute); ok {
|
||||
body.SetAttributeTraversal(v.Name, hcl.Traversal{
|
||||
hcl.TraverseRoot{Name: c.String()},
|
||||
})
|
||||
@ -168,7 +177,7 @@ func (r *Resource) doToHCLAttributes(body *hclwrite.Body) {
|
||||
}
|
||||
|
||||
func (r *Resource) doToHCLDependencies(body *hclwrite.Body) {
|
||||
if len(r.dependenies) == 0 {
|
||||
if len(r.dependencies) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@ -184,8 +193,8 @@ func (r *Resource) doToHCLDependencies(body *hclwrite.Body) {
|
||||
Type: hclsyntax.TokenOBrack, Bytes: []byte{'['},
|
||||
})
|
||||
|
||||
l := len(r.dependenies)
|
||||
for i, dep := range r.dependenies {
|
||||
l := len(r.dependencies)
|
||||
for i, dep := range r.dependencies {
|
||||
name := fmt.Sprintf("%s.%s", dep.typ, dep.Name())
|
||||
toks = append(toks, &hclwrite.Token{
|
||||
Type: hclsyntax.TokenIdent, Bytes: []byte(name),
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// PluginManagerLocal is the key of the terraform.PluginManager in the thread.
|
||||
PluginManagerLocal = "plugin_manager"
|
||||
)
|
||||
|
||||
@ -206,15 +207,15 @@ func (p *Provider) AttrNames() []string {
|
||||
}
|
||||
|
||||
// CompareSameType honors starlark.Comparable interface.
|
||||
func (x *Provider) CompareSameType(op syntax.Token, y_ starlark.Value, depth int) (bool, error) {
|
||||
y := y_.(*Provider)
|
||||
func (p *Provider) CompareSameType(op syntax.Token, yv starlark.Value, depth int) (bool, error) {
|
||||
y := yv.(*Provider)
|
||||
switch op {
|
||||
case syntax.EQL:
|
||||
return x == y, nil
|
||||
return p == y, nil
|
||||
case syntax.NEQ:
|
||||
return x != y, nil
|
||||
return p != y, nil
|
||||
default:
|
||||
return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type())
|
||||
return false, fmt.Errorf("%s %s %s not implemented", p.Type(), op, y.Type())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ func doTestPrint(t *testing.T, filename string, print func(*starlark.Thread, str
|
||||
"provisioner": BuiltinProvisioner(),
|
||||
"backend": BuiltinBackend(),
|
||||
"hcl": BuiltinHCL(),
|
||||
"fn": BuiltinFunctionComputed(),
|
||||
"fn": BuiltinFunctionAttribute(),
|
||||
"evaluate": BuiltinEvaluate(),
|
||||
"tf": NewTerraform(pm),
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ func (k Kind) IsProviderRelated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Resource Kind constants.
|
||||
const (
|
||||
ProviderKind Kind = "provider"
|
||||
ProvisionerKind Kind = "provisioner"
|
||||
@ -188,7 +189,7 @@ type Resource struct {
|
||||
|
||||
provider *Provider
|
||||
parent *Resource
|
||||
dependenies []*Resource
|
||||
dependencies []*Resource
|
||||
provisioners []*Provisioner
|
||||
}
|
||||
|
||||
@ -329,7 +330,7 @@ func (r *Resource) attrBlock(name string, b *configschema.NestedBlock) (starlark
|
||||
func (r *Resource) attrValue(name string, attr *configschema.Attribute) (starlark.Value, error) {
|
||||
if attr.Computed {
|
||||
if !r.values.Has(name) {
|
||||
return NewComputed(r, attr.Type, name), nil
|
||||
return NewAttribute(r, attr.Type, name), nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -468,7 +469,7 @@ func (r *Resource) dependsOn(_ *starlark.Thread, _ *starlark.Builtin, args starl
|
||||
resources[i] = resource
|
||||
}
|
||||
|
||||
r.dependenies = append(r.dependenies, resources...)
|
||||
r.dependencies = append(r.dependencies, resources...)
|
||||
return starlark.None, nil
|
||||
}
|
||||
|
||||
@ -488,30 +489,30 @@ func (r *Resource) addProvisioner(_ *starlark.Thread, _ *starlark.Builtin, args
|
||||
}
|
||||
|
||||
// CompareSameType honors starlark.Comparable interface.
|
||||
func (x *Resource) CompareSameType(op syntax.Token, y_ starlark.Value, depth int) (bool, error) {
|
||||
y := y_.(*Resource)
|
||||
func (r *Resource) CompareSameType(op syntax.Token, yv starlark.Value, depth int) (bool, error) {
|
||||
y := yv.(*Resource)
|
||||
switch op {
|
||||
case syntax.EQL:
|
||||
ok, err := x.doCompareSameType(y, depth)
|
||||
ok, err := r.doCompareSameType(y, depth)
|
||||
return ok, err
|
||||
case syntax.NEQ:
|
||||
ok, err := x.doCompareSameType(y, depth)
|
||||
ok, err := r.doCompareSameType(y, depth)
|
||||
return !ok, err
|
||||
default:
|
||||
return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type())
|
||||
return false, fmt.Errorf("%s %s %s not implemented", r.Type(), op, y.Type())
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Resource) doCompareSameType(y *Resource, depth int) (bool, error) {
|
||||
if x.typ != y.typ {
|
||||
func (r *Resource) doCompareSameType(y *Resource, depth int) (bool, error) {
|
||||
if r.typ != y.typ {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if x.values.Len() != y.values.Len() {
|
||||
if r.values.Len() != y.values.Len() {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for _, xval := range x.values.List() {
|
||||
for _, xval := range r.values.List() {
|
||||
yval := y.values.Get(xval.Name)
|
||||
if yval == nil {
|
||||
return false, nil
|
||||
|
@ -4,10 +4,10 @@ aws = tf.provider("aws", "2.13.0")
|
||||
|
||||
ami = aws.data.ami()
|
||||
|
||||
# compute of scalar
|
||||
# attribute of scalar
|
||||
web = aws.resource.instance()
|
||||
web.ami = ami.id
|
||||
assert.eq(type(web.ami), "Computed<string>")
|
||||
assert.eq(type(web.ami), "Attribute<string>")
|
||||
assert.eq(str(web.ami), '"${data.aws_ami.id_2.id}"')
|
||||
assert.eq(web.ami.__resource__, ami)
|
||||
assert.eq(web.ami.__type__, "string")
|
||||
@ -16,33 +16,37 @@ assert.eq(web.ami.__type__, "string")
|
||||
assert.eq("__resource__" in dir(web.ami), True)
|
||||
assert.eq("__type__" in dir(web.ami), True)
|
||||
|
||||
# compute of set
|
||||
# attribute of set
|
||||
table = aws.data.dynamodb_table()
|
||||
assert.eq(str(table.ttl), '"${data.aws_dynamodb_table.id_4.ttl}"')
|
||||
assert.eq(str(table.ttl[0]), '"${data.aws_dynamodb_table.id_4.ttl.0}"')
|
||||
assert.eq(str(table.ttl[0].attribute_name), '"${data.aws_dynamodb_table.id_4.ttl.0.attribute_name}"')
|
||||
|
||||
# compute of list
|
||||
# attribute of list
|
||||
instance = aws.data.instance()
|
||||
assert.eq(str(instance.credit_specification), '"${data.aws_instance.id_5.credit_specification}"')
|
||||
assert.eq(str(instance.credit_specification[0]), '"${data.aws_instance.id_5.credit_specification.0}"')
|
||||
assert.eq(str(instance.credit_specification[0].cpu_credits), '"${data.aws_instance.id_5.credit_specification.0.cpu_credits}"')
|
||||
|
||||
# compute of map
|
||||
computed = str(aws.resource.instance().root_block_device.volume_size)
|
||||
assert.eq(computed, '"${aws_instance.id_6.root_block_device.0.volume_size}"')
|
||||
# attribute of block
|
||||
attribute = str(aws.resource.instance().root_block_device.volume_size)
|
||||
assert.eq(attribute, '"${aws_instance.id_6.root_block_device.0.volume_size}"')
|
||||
|
||||
# compute on data source
|
||||
# attribute on data source
|
||||
assert.eq(str(aws.resource.instance().id), '"${aws_instance.id_7.id}"')
|
||||
|
||||
# compute on resource
|
||||
# attribute on resource
|
||||
assert.eq(str(aws.data.ami().id), '"${data.aws_ami.id_8.id}"')
|
||||
|
||||
gcp = tf.provider("google", "3.13.0")
|
||||
|
||||
# computed on list with MaxItem:1
|
||||
# attribute on list with MaxItem:1
|
||||
cluster = gcp.resource.container_cluster("foo")
|
||||
assert.eq(str(cluster.master_auth.client_certificate), '"${google_container_cluster.foo.master_auth.0.client_certificate}"')
|
||||
|
||||
# attr non-object
|
||||
assert.fails(lambda: web.ami.foo, "Attribute<string> it's not a object")
|
||||
|
||||
|
||||
# fn wrapping
|
||||
assert.eq(str(fn("base64encode", web.ami)), '"${base64encode(data.aws_ami.id_2.id)}"')
|
14
starlark/types/testdata/examples/attribute.star
vendored
Normal file
14
starlark/types/testdata/examples/attribute.star
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
# When a Resource has an Attribute means that the value it's only available
|
||||
# during the `apply` phase of Terraform. So in, AsCode an attribute behaves
|
||||
# like a poor-man pointer.
|
||||
|
||||
aws = tf.provider("aws")
|
||||
|
||||
ami = aws.resource.ami("ubuntu")
|
||||
|
||||
instance = aws.resource.instance("foo")
|
||||
instance.ami = ami.id
|
||||
|
||||
print(instance.ami)
|
||||
# Output:
|
||||
# "${aws_ami.ubuntu.id}"
|
2
starlark/types/testdata/resource.star
vendored
2
starlark/types/testdata/resource.star
vendored
@ -31,7 +31,7 @@ assert.eq(qux.name, None)
|
||||
assert.fails(lambda: qux.foo, "Resource<data> has no .foo field or method")
|
||||
|
||||
# attr id
|
||||
assert.eq(type(qux.id), "Computed<string>")
|
||||
assert.eq(type(qux.id), "Attribute<string>")
|
||||
assert.eq(str(qux.id), '"${data.ignition_user.id_2.id}"')
|
||||
aws = tf.provider("aws", "2.13.0")
|
||||
|
||||
|
@ -46,7 +46,7 @@ func NewTypeFromStarlark(typ string) (*Type, error) {
|
||||
t.cty = cty.List(cty.NilType)
|
||||
case "dict", "Resource":
|
||||
t.cty = cty.Map(cty.NilType)
|
||||
case "Computed":
|
||||
case "Attribute":
|
||||
t.cty = cty.String
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected %q type", typ)
|
||||
@ -108,7 +108,7 @@ func (t *Type) Cty() cty.Type {
|
||||
return t.cty
|
||||
}
|
||||
|
||||
// Validate validates a value againts the type.
|
||||
// Validate validates a value against the type.
|
||||
func (t *Type) Validate(v starlark.Value) error {
|
||||
switch v.(type) {
|
||||
case starlark.String:
|
||||
@ -123,12 +123,12 @@ func (t *Type) Validate(v starlark.Value) error {
|
||||
if t.cty == cty.Bool {
|
||||
return nil
|
||||
}
|
||||
case *Computed:
|
||||
if t.cty == v.(*Computed).t {
|
||||
case *Attribute:
|
||||
if t.cty == v.(*Attribute).t {
|
||||
return nil
|
||||
}
|
||||
|
||||
vt := v.(*Computed).InnerType().Starlark()
|
||||
vt := v.(*Attribute).InnerType().Starlark()
|
||||
return fmt.Errorf("expected %s, got %s", t.typ, vt)
|
||||
case *starlark.List:
|
||||
if t.cty.IsListType() || t.cty.IsSetType() {
|
||||
|
@ -78,8 +78,8 @@ func (v *Value) Cty() cty.Value {
|
||||
}
|
||||
|
||||
return cty.MapVal(values)
|
||||
case "Computed":
|
||||
return cty.StringVal(v.v.(*Computed).GoString())
|
||||
case "Attribute":
|
||||
return cty.StringVal(v.v.(*Attribute).GoString())
|
||||
default:
|
||||
return cty.StringVal(fmt.Sprintf("unhandled: %s", v.t.typ))
|
||||
}
|
||||
@ -264,10 +264,12 @@ func (a Values) Cty(schema *configschema.Block) cty.Value {
|
||||
return cty.ObjectVal(values)
|
||||
}
|
||||
|
||||
// Dict is a starlark.Dict HCLCompatible.
|
||||
type Dict struct {
|
||||
*starlark.Dict
|
||||
}
|
||||
|
||||
// NewDict returns a new empty Dict.
|
||||
func NewDict() *Dict {
|
||||
return &Dict{starlark.NewDict(0)}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
// PluginManager is a wrapper arround the terraform tools to download and execute
|
||||
// PluginManager is a wrapper around the terraform tools to download and execute
|
||||
// terraform plugins, like providers and provisioners.
|
||||
type PluginManager struct {
|
||||
Path string
|
||||
@ -28,7 +28,7 @@ func (m *PluginManager) Provider(provider, version string, forceLocal bool) (*pl
|
||||
meta, ok := m.getLocal("provider", provider, version)
|
||||
if !ok && !forceLocal {
|
||||
var err error
|
||||
meta, ok, err = m.getProviderRemote(provider, version)
|
||||
meta, _, err = m.getProviderRemote(provider, version)
|
||||
if err != nil {
|
||||
return nil, discovery.PluginMeta{}, err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user