From 9f59c34ce684320207e3e0cc4779d02935310641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1ximo=20Cuadros?= Date: Tue, 24 Mar 2020 06:36:10 +0100 Subject: [PATCH] starlark/types: standarization contructors and interface checks --- starlark/runtime/runtime.go | 2 +- starlark/types/backend.go | 23 +++++++--- starlark/types/collection.go | 25 ++++++----- starlark/types/computed.go | 10 +++++ starlark/types/provider.go | 60 +++++++++++++++++--------- starlark/types/provider_test.go | 2 +- starlark/types/provisioner.go | 4 +- starlark/types/resource.go | 7 ++- starlark/types/terraform.go | 12 +++--- starlark/types/testdata/terraform.star | 3 ++ 10 files changed, 100 insertions(+), 48 deletions(-) diff --git a/starlark/runtime/runtime.go b/starlark/runtime/runtime.go index 137225c..e07f77a 100644 --- a/starlark/runtime/runtime.go +++ b/starlark/runtime/runtime.go @@ -39,7 +39,7 @@ type Runtime struct { } func NewRuntime(pm *terraform.PluginManager) *Runtime { - tf := types.MakeTerraform(pm) + tf := types.NewTerraform(pm) return &Runtime{ Terraform: tf, diff --git a/starlark/types/backend.go b/starlark/types/backend.go index 362e4f6..0760efa 100644 --- a/starlark/types/backend.go +++ b/starlark/types/backend.go @@ -44,7 +44,7 @@ func BuiltinBackend(pm *terraform.PluginManager) starlark.Value { return nil, fmt.Errorf("unexpected positional arguments count") } - p, err := MakeBackend(pm, name.GoString()) + p, err := NewBackend(pm, name.GoString()) if err != nil { return nil, err } @@ -89,8 +89,12 @@ type Backend struct { *Resource } -// MakeBackend returns a new Backend instance based on given arguments, -func MakeBackend(pm *terraform.PluginManager, typ string) (*Backend, error) { +var _ starlark.Value = &Backend{} +var _ starlark.HasAttrs = &Backend{} +var _ starlark.Comparable = &Backend{} + +// NewBackend returns a new Backend instance based on given arguments, +func NewBackend(pm *terraform.PluginManager, typ string) (*Backend, error) { fn := binit.Backend(typ) if fn == nil { return nil, fmt.Errorf("unable to find backend %q", typ) @@ -105,6 +109,7 @@ func MakeBackend(pm *terraform.PluginManager, typ string) (*Backend, error) { }, nil } +// Attr honors the starlark.HasAttrs interface. func (b *Backend) Attr(name string) (starlark.Value, error) { switch name { case "state": @@ -176,7 +181,7 @@ func (b *Backend) state( return starlark.None, nil } - return MakeState(b.pm, module, state) + return NewState(b.pm, module, state) } @@ -218,8 +223,12 @@ type State struct { pm *terraform.PluginManager } -// MakeState returns a new instance of State based on the given arguments, -func MakeState(pm *terraform.PluginManager, module string, state *states.State) (*State, error) { +var _ starlark.Value = &State{} +var _ starlark.HasAttrs = &State{} +var _ starlark.Comparable = &State{} + +// NewState returns a new instance of State based on the given arguments, +func NewState(pm *terraform.PluginManager, module string, state *states.State) (*State, error) { var mod *states.Module for _, m := range state.Modules { if m.Addr.String() == module { @@ -244,7 +253,7 @@ func (s *State) initialize(state *states.State, mod *states.Module) error { addrs := state.ProviderAddrs() for _, addr := range addrs { typ := addr.ProviderConfig.Type.Type - p, err := MakeProvider(s.pm, typ, "", addr.ProviderConfig.Alias) + p, err := NewProvider(s.pm, typ, "", addr.ProviderConfig.Alias) if err != nil { return err } diff --git a/starlark/types/collection.go b/starlark/types/collection.go index bfce5a4..b6b4b26 100644 --- a/starlark/types/collection.go +++ b/starlark/types/collection.go @@ -18,6 +18,11 @@ type ResourceCollection struct { *starlark.List } +var _ starlark.Value = &ResourceCollection{} +var _ starlark.HasAttrs = &ResourceCollection{} +var _ starlark.Callable = &ResourceCollection{} +var _ starlark.Comparable = &ResourceCollection{} + func NewResourceCollection( typ string, k Kind, block *configschema.Block, provider *Provider, parent *Resource, ) *ResourceCollection { @@ -78,12 +83,12 @@ func (c *ResourceCollection) Freeze() {} // Hash honors the starlark.Value interface. func (c *ResourceCollection) Hash() (uint32, error) { - return 0, fmt.Errorf("unhashable type: ResourceCollection") + return 0, fmt.Errorf("unhashable type: %s", c.Type()) } // Name honors the starlark.Callable interface. func (c *ResourceCollection) Name() string { - return c.typ + return c.Type() } // CallInternal honors the starlark.Callable interface. @@ -279,6 +284,11 @@ type ProviderCollection struct { *Dict } +var _ starlark.Value = &ProviderCollection{} +var _ starlark.HasAttrs = &ProviderCollection{} +var _ starlark.Callable = &ProviderCollection{} +var _ starlark.Comparable = &ProviderCollection{} + func NewProviderCollection(pm *terraform.PluginManager) *ProviderCollection { return &ProviderCollection{ pm: pm, @@ -286,11 +296,6 @@ func NewProviderCollection(pm *terraform.PluginManager) *ProviderCollection { } } -// String honors the starlark.Value interface. -func (c *ProviderCollection) String() string { - return "foo" -} - // Type honors the starlark.Value interface. func (c *ProviderCollection) Type() string { return "ProviderCollection" @@ -306,12 +311,12 @@ func (c *ProviderCollection) Freeze() {} // Hash honors the starlark.Value interface. func (c *ProviderCollection) Hash() (uint32, error) { - return 0, fmt.Errorf("unhashable type: ProviderCollection") + return 0, fmt.Errorf("unhashable type: %s", c.Type()) } // Name honors the starlark.Callable interface. func (c *ProviderCollection) Name() string { - return "foo" + return c.Type() } // CallInternal honors the starlark.Callable interface. @@ -336,7 +341,7 @@ func (c *ProviderCollection) MakeProvider(name, version, alias string, kwargs [] return nil, fmt.Errorf("already exists a provider %q with the alias %q", name, alias) } - p, err := MakeProvider(c.pm, name, version, alias) + p, err := NewProvider(c.pm, name, version, alias) if err != nil { return nil, err } diff --git a/starlark/types/computed.go b/starlark/types/computed.go index d0b98b0..c7baf72 100644 --- a/starlark/types/computed.go +++ b/starlark/types/computed.go @@ -18,6 +18,11 @@ type Computed struct { 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 @@ -62,6 +67,7 @@ func NewComputedWithPath(r *Resource, t cty.Type, name, path string) *Computed { } } +// Type honors the starlark.Value interface. func (c *Computed) Type() string { return fmt.Sprintf("Computed<%s>", MustTypeFromCty(c.t).Starlark()) } @@ -71,6 +77,7 @@ func (c *Computed) InnerType() *Type { return t } +// Attr honors the starlark.HasAttrs interface. func (c *Computed) Attr(name string) (starlark.Value, error) { switch name { case "__resource__": @@ -91,6 +98,7 @@ func (c *Computed) Attr(name string) (starlark.Value, error) { 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__"} } @@ -104,6 +112,7 @@ func (c *Computed) doNested(name, path string, t cty.Type, index int) *Computed } +// Index honors the starlark.Indexable interface. func (c *Computed) Index(i int) starlark.Value { path := fmt.Sprintf("%s.%d", c.path, i) @@ -118,6 +127,7 @@ func (c *Computed) Index(i int) starlark.Value { return starlark.None } +// Len honors the starlark.Indexable interface. func (c *Computed) Len() int { if !c.t.IsSetType() && !c.t.IsListType() { return 0 diff --git a/starlark/types/provider.go b/starlark/types/provider.go index e72d305..aba4522 100644 --- a/starlark/types/provider.go +++ b/starlark/types/provider.go @@ -41,7 +41,7 @@ func BuiltinProvider(pm *terraform.PluginManager) starlark.Value { return nil, fmt.Errorf("unexpected positional arguments count") } - p, err := MakeProvider(pm, typ.GoString(), version.GoString(), name.GoString()) + p, err := NewProvider(pm, typ.GoString(), version.GoString(), name.GoString()) if err != nil { return nil, err } @@ -99,8 +99,12 @@ type Provider struct { *Resource } -// MakeProvider returns a new Provider instance from a given type, version and name. -func MakeProvider(pm *terraform.PluginManager, typ, version, name string) (*Provider, error) { +var _ starlark.Value = &Provider{} +var _ starlark.HasAttrs = &Provider{} +var _ starlark.Comparable = &Provider{} + +// NewProvider returns a new Provider instance from a given type, version and name. +func NewProvider(pm *terraform.PluginManager, typ, version, name string) (*Provider, error) { cli, meta, err := pm.Provider(typ, version, false) if err != nil { return nil, err @@ -164,7 +168,7 @@ func (p *Provider) AttrNames() []string { return append(p.Resource.AttrNames(), "data", "resource", "__version__") } -// CompareSameType honors starlark.Comprable interface. +// CompareSameType honors starlark.Comparable interface. func (x *Provider) CompareSameType(op syntax.Token, y_ starlark.Value, depth int) (bool, error) { y := y_.(*Provider) switch op { @@ -184,6 +188,9 @@ type ResourceCollectionGroup struct { collections map[string]*ResourceCollection } +var _ starlark.Value = &ResourceCollectionGroup{} +var _ starlark.HasAttrs = &ResourceCollectionGroup{} + func NewResourceCollectionGroup(p *Provider, k Kind, schemas map[string]providers.Schema) *ResourceCollectionGroup { return &ResourceCollectionGroup{ provider: p, @@ -194,42 +201,53 @@ func NewResourceCollectionGroup(p *Provider, k Kind, schemas map[string]provider } // Path returns the path of the ResourceCollectionGroup. -func (r *ResourceCollectionGroup) Path() string { - return fmt.Sprintf("%s.%s", r.provider.typ, r.kind) +func (g *ResourceCollectionGroup) Path() string { + return fmt.Sprintf("%s.%s", g.provider.typ, g.kind) } -func (r *ResourceCollectionGroup) String() string { - return fmt.Sprintf("ResourceCollectionGroup<%s>", r.Path()) +// String honors the starlark.String interface. +func (g *ResourceCollectionGroup) String() string { + return fmt.Sprintf("ResourceCollectionGroup<%s>", g.Path()) } -func (r *ResourceCollectionGroup) Type() string { +// Type honors the starlark.Value interface. +func (*ResourceCollectionGroup) Type() string { return "ResourceCollectionGroup" } -func (m *ResourceCollectionGroup) Freeze() {} -func (m *ResourceCollectionGroup) Truth() starlark.Bool { return true } -func (m *ResourceCollectionGroup) Hash() (uint32, error) { return 1, nil } +// Freeze honors the starlark.Value interface. +func (*ResourceCollectionGroup) Freeze() {} -func (m *ResourceCollectionGroup) Attr(name string) (starlark.Value, error) { - name = m.provider.typ + "_" + name +// Truth honors the starlark.Value interface. True even if empty. +func (*ResourceCollectionGroup) Truth() starlark.Bool { return true } - if c, ok := m.collections[name]; ok { +// Hash honors the starlark.Value interface. +func (g *ResourceCollectionGroup) Hash() (uint32, error) { + return 0, fmt.Errorf("unhashable type: %s", g.Type()) +} + +// Attr honors the starlark.HasAttrs interface. +func (g *ResourceCollectionGroup) Attr(name string) (starlark.Value, error) { + name = g.provider.typ + "_" + name + + if c, ok := g.collections[name]; ok { return c, nil } - if schema, ok := m.schemas[name]; ok { - m.collections[name] = NewResourceCollection(name, m.kind, schema.Block, m.provider, m.provider.Resource) - return m.collections[name], nil + if schema, ok := g.schemas[name]; ok { + g.collections[name] = NewResourceCollection(name, g.kind, schema.Block, g.provider, g.provider.Resource) + return g.collections[name], nil } return starlark.None, nil } -func (s *ResourceCollectionGroup) AttrNames() []string { - names := make([]string, len(s.schemas)) +// AttrNames honors the starlark.HasAttrs interface. +func (g *ResourceCollectionGroup) AttrNames() []string { + names := make([]string, len(g.schemas)) var i int - for k := range s.schemas { + for k := range g.schemas { parts := strings.SplitN(k, "_", 2) names[i] = parts[1] i++ diff --git a/starlark/types/provider_test.go b/starlark/types/provider_test.go index 72a3a5d..c6eeaba 100644 --- a/starlark/types/provider_test.go +++ b/starlark/types/provider_test.go @@ -73,7 +73,7 @@ func doTestPrint(t *testing.T, filename string, print func(*starlark.Thread, str "hcl": BuiltinHCL(), "fn": BuiltinFunctionComputed(), "evaluate": BuiltinEvaluate(), - "tf": MakeTerraform(pm), + "tf": NewTerraform(pm), } _, err := starlark.ExecFile(thread, filename, nil, predeclared) diff --git a/starlark/types/provisioner.go b/starlark/types/provisioner.go index 22e4987..b36c1bc 100644 --- a/starlark/types/provisioner.go +++ b/starlark/types/provisioner.go @@ -23,7 +23,7 @@ func BuiltinProvisioner(pm *terraform.PluginManager) starlark.Value { return nil, fmt.Errorf("unexpected positional arguments count") } - p, err := MakeProvisioner(pm, name.GoString()) + p, err := NewProvisioner(pm, name.GoString()) if err != nil { return nil, err } @@ -38,7 +38,7 @@ type Provisioner struct { *Resource } -func MakeProvisioner(pm *terraform.PluginManager, typ string) (*Provisioner, error) { +func NewProvisioner(pm *terraform.PluginManager, typ string) (*Provisioner, error) { cli, meta, err := pm.Provisioner(typ) if err != nil { return nil, err diff --git a/starlark/types/resource.go b/starlark/types/resource.go index c0ca263..fa68d4b 100644 --- a/starlark/types/resource.go +++ b/starlark/types/resource.go @@ -127,6 +127,11 @@ type Resource struct { provisioners []*Provisioner } +var _ starlark.Value = &Resource{} +var _ starlark.HasAttrs = &Resource{} +var _ starlark.HasSetField = &Resource{} +var _ starlark.Comparable = &Resource{} + // MakeResource returns a new resource of the given kind, type based on the // given configschema.Block. func MakeResource(name, typ string, k Kind, b *configschema.Block, provider *Provider, parent *Resource) *Resource { @@ -418,7 +423,7 @@ func (r *Resource) addProvisioner(_ *starlark.Thread, _ *starlark.Builtin, args return starlark.None, nil } -// CompareSameType honors starlark.Comprable interface. +// CompareSameType honors starlark.Comparable interface. func (x *Resource) CompareSameType(op syntax.Token, y_ starlark.Value, depth int) (bool, error) { y := y_.(*Resource) switch op { diff --git a/starlark/types/terraform.go b/starlark/types/terraform.go index b73c895..173c19b 100644 --- a/starlark/types/terraform.go +++ b/starlark/types/terraform.go @@ -51,13 +51,17 @@ type Terraform struct { p *ProviderCollection } -// MakeTerraform returns a new instance of Terraform -func MakeTerraform(pm *terraform.PluginManager) *Terraform { +// NewTerraform returns a new instance of Terraform +func NewTerraform(pm *terraform.PluginManager) *Terraform { return &Terraform{ p: NewProviderCollection(pm), } } +var _ starlark.Value = &Terraform{} +var _ starlark.HasAttrs = &Terraform{} +var _ starlark.HasSetField = &Terraform{} + // Attr honors the starlark.HasAttrs interface. func (t *Terraform) Attr(name string) (starlark.Value, error) { switch name { @@ -101,7 +105,7 @@ func (t *Terraform) Freeze() {} // immutable // Hash honors the starlark.Value interface. func (t *Terraform) Hash() (uint32, error) { - return 0, fmt.Errorf("unhashable type: Terraform") + return 0, fmt.Errorf("unhashable type: %s", t.Type()) } // String honors the starlark.Value interface. @@ -118,5 +122,3 @@ func (t *Terraform) Truth() starlark.Bool { func (t *Terraform) Type() string { return "Terraform" } - -var _ starlark.Value = &Terraform{} diff --git a/starlark/types/testdata/terraform.star b/starlark/types/testdata/terraform.star index 6272c18..e44411a 100644 --- a/starlark/types/testdata/terraform.star +++ b/starlark/types/testdata/terraform.star @@ -20,6 +20,9 @@ assert.eq(tf.provider["aws"]["bar"] == None, False) assert.eq(tf.provider["aws"]["bar"], bar) assert.eq(tf.provider["aws"]["bar"].region, "bar") +# type +assert.eq(type(tf.provider), "ProviderCollection") + # backend assert.eq(tf.backend, None)