stacks/stackaddrs: Initial address types for stacks

This serves a similar purpose to the "addrs" package for Terraform overall,
but deals with concepts that are unique to the stacks language.
pull/34738/head
Martin Atkins 3 years ago
parent 3bf1a5cf53
commit e667352553

@ -0,0 +1,35 @@
package stackaddrs
import "github.com/hashicorp/terraform/internal/addrs"
// Component is the address of a "component" block within a stack config.
type Component struct {
Name string
}
func (Component) referenceableSigil() {}
func (Component) inStackConfigSigil() {}
func (Component) inStackInstanceSigil() {}
// ConfigComponent places a [Component] in the context of a particular [Stack].
type ConfigComponent = InStackConfig[Component]
// AbsComponent places a [Component] in the context of a particular [StackInstance].
type AbsComponent = InStackInstance[Component]
// ComponentInstance is the address of a dynamic instance of a component.
type ComponentInstance struct {
Component Component
Key addrs.InstanceKey
}
func (ComponentInstance) inStackConfigSigil() {}
func (ComponentInstance) inStackInstanceSigil() {}
// ConfigComponentInstance places a [ComponentInstance] in the context of a
// particular [Stack].
type ConfigComponentInstance = InStackConfig[ComponentInstance]
// AbsComponentInstance places a [ComponentInstance] in the context of a
// particular [StackInstance].
type AbsComponentInstance = InStackInstance[ComponentInstance]

@ -0,0 +1,4 @@
// Package stackaddrs builds on the top-level "addrs" package to provide the
// addresses for the extra layer of concepts that the stacks configuration
// language and its runtime are concerned about.
package stackaddrs

@ -0,0 +1,42 @@
package stackaddrs
// StackItemConfig is a type set containing all of the address types that make
// sense to consider as belonging statically to a [Stack].
type StackItemConfig interface {
inStackConfigSigil()
}
// StackItemDynamic is a type set containing all of the address types that make
// sense to consider as belonging dynamically to a [StackInstance].
type StackItemDynamic interface {
inStackInstanceSigil()
}
// InStackConfig is the generic form of addresses representing configuration
// objects belonging to particular nodes in the static tree of stack
// configurations.
type InStackConfig[T StackItemConfig] struct {
Stack Stack
Item T
}
func Config[T StackItemConfig](stackAddr Stack, relAddr T) InStackConfig[T] {
return InStackConfig[T]{
Stack: stackAddr,
Item: relAddr,
}
}
// InStackInstance is the generic form of addresses representing dynamic
// instances of objects that exist within an instance of a stack.
type InStackInstance[T StackItemDynamic] struct {
Stack StackInstance
Item T
}
func Absolute[T StackItemDynamic](stackAddr StackInstance, relAddr T) InStackInstance[T] {
return InStackInstance[T]{
Stack: stackAddr,
Item: relAddr,
}
}

@ -0,0 +1,15 @@
package stackaddrs
type InputVariable struct {
Name string
}
func (InputVariable) referenceableSigil() {}
func (InputVariable) inStackConfigSigil() {}
func (InputVariable) inStackInstanceSigil() {}
// ConfigInputVariable places an [InputVariable] in the context of a particular [Stack].
type ConfigInputVariable = InStackConfig[InputVariable]
// AbsInputVariable places an [InputVariable] in the context of a particular [StackInstance].
type AbsInputVariable = InStackInstance[InputVariable]

@ -0,0 +1,15 @@
package stackaddrs
type LocalValue struct {
Name string
}
func (LocalValue) referenceableSigil() {}
func (LocalValue) inStackConfigSigil() {}
func (LocalValue) inStackInstanceSigil() {}
// ConfigLocalValue places a [LocalValue] in the context of a particular [Stack].
type ConfigLocalValue = InStackConfig[LocalValue]
// AbsLocalValue places a [LocalValue] in the context of a particular [StackInstance].
type AbsLocalValue = InStackInstance[LocalValue]

@ -0,0 +1,14 @@
package stackaddrs
type OutputValue struct {
Name string
}
func (OutputValue) inStackConfigSigil() {}
func (OutputValue) inStackInstanceSigil() {}
// ConfigOutputValue places an [OutputValue] in the context of a particular [Stack].
type ConfigOutputValue = InStackConfig[OutputValue]
// AbsOutputValue places an [OutputValue] in the context of a particular [StackInstance].
type AbsOutputValue = InStackInstance[OutputValue]

@ -0,0 +1,51 @@
package stackaddrs
import (
"github.com/hashicorp/terraform/internal/addrs"
)
// ProviderConfigRef is a reference-only address type representing a reference
// to a particular provider configuration using its local name, since local
// name is how we refer to providers when they appear in expressions.
//
// The referent of a ProviderConfigRef is a [ProviderConfig], so resolving
// the reference will always require a lookup table from local name to
// fully-qualified provider address.
type ProviderConfigRef struct {
ProviderLocalName string
Name string
}
func (ProviderConfigRef) referenceableSigil() {}
// ProviderConfig is the address of a "provider" block in a stack configuration.
type ProviderConfig struct {
Provider addrs.Provider
Name string
}
func (ProviderConfig) inStackConfigSigil() {}
func (ProviderConfig) inStackInstanceSigil() {}
// ConfigProviderConfig places a [ProviderConfig] in the context of a particular [Stack].
type ConfigProviderConfig = InStackConfig[ProviderConfig]
// AbsProviderConfig places a [ProviderConfig] in the context of a particular [StackInstance].
type AbsProviderConfig = InStackInstance[ProviderConfig]
// ProviderConfigInstance is the address of a specific provider configuration,
// of which there might potentially be many associated with a given
// [ProviderConfig] if that block uses the "for_each" argument.
type ProviderConfigInstance struct {
ProviderConfig ProviderConfig
Key addrs.InstanceKey
}
func (ProviderConfigInstance) inStackConfigSigil() {}
func (ProviderConfigInstance) inStackInstanceSigil() {}
// ConfigProviderConfigInstance places a [ProviderConfigInstance] in the context of a particular [Stack].
type ConfigProviderConfigInstance = InStackConfig[ProviderConfigInstance]
// AbsProviderConfigInstance places a [ProviderConfigInstance] in the context of a particular [StackInstance].
type AbsProviderConfigInstance = InStackInstance[ProviderConfigInstance]

@ -0,0 +1,13 @@
package stackaddrs
// Referenceable is a type set containing all address types that can be
// the target of an expression-based reference within a particular stack.
type Referenceable interface {
referenceableSigil()
}
var _ Referenceable = Component{}
var _ Referenceable = StackCall{}
var _ Referenceable = InputVariable{}
var _ Referenceable = LocalValue{}
var _ Referenceable = ProviderConfigRef{}

@ -0,0 +1,97 @@
package stackaddrs
import (
"github.com/hashicorp/terraform/internal/addrs"
)
// Stack represents the address of a stack within the tree of stacks.
//
// The root stack [RootStack] represents the top-level stack and then any
// other value of this type represents an embedded stack descending from it.
type Stack []StackStep
type StackStep struct {
Name string
}
var RootStack Stack
// IsRoot returns true if this object represents the root stack, or false
// otherwise.
func (s Stack) IsRoot() bool {
return len(s) == 0
}
// Parent returns the parent of the reciever, or panics if the receiver is
// representing the root stack.
func (s Stack) Parent() Stack {
newLen := len(s) - 1
if newLen < 0 {
panic("root stack has no parent")
}
return s[:newLen:newLen]
}
// Child constructs the address of an embedded stack that's a child of the
// receiver.
func (s Stack) Child(name string) Stack {
ret := make([]StackStep, len(s), len(s)+1)
copy(ret, s)
return append(ret, StackStep{name})
}
// StackInstance represents the address of an instance of a stack within
// the tree of stacks.
//
// [RootStackInstance] represents the singleton instance of the top-level stack
// and then any other value of this type represents an instance of an embedded
// stack descending from it.
type StackInstance []StackInstanceStep
type StackInstanceStep struct {
Name string
Key addrs.InstanceKey
}
var RootStackInstance StackInstance
// IsRoot returns true if this object represents the singleton instance of the
// root stack, or false otherwise.
func (s StackInstance) IsRoot() bool {
return len(s) == 0
}
// Parent returns the parent of the reciever, or panics if the receiver is
// representing the root stack.
func (s StackInstance) Parent() StackInstance {
newLen := len(s) - 1
if newLen < 0 {
panic("root stack has no parent")
}
return s[:newLen:newLen]
}
// Child constructs the address of an embedded stack that's a child of the
// receiver.
func (s StackInstance) Child(name string, key addrs.InstanceKey) StackInstance {
ret := make([]StackInstanceStep, len(s), len(s)+1)
copy(ret, s)
return append(ret, StackInstanceStep{
Name: name,
Key: key,
})
}
// Call returns the address of the embedded stack call that the receiever
// belongs to, or panics if the receiver is the root module since the root
// module is called only implicitly.
func (s StackInstance) Call() AbsStackCall {
last := s[len(s)-1]
si := s[: len(s)-1 : len(s)-1]
return AbsStackCall{
Stack: si,
Item: StackCall{
Name: last.Name,
},
}
}

@ -0,0 +1,30 @@
package stackaddrs
import "github.com/hashicorp/terraform/internal/addrs"
// StackCall represents a call to an embedded stack. This is essentially the
// address of a "stack" block in the configuration, before it's been fully
// expanded into zero or more instances.
type StackCall struct {
Name string
}
func (StackCall) referenceableSigil() {}
func (StackCall) inStackConfigSigil() {}
func (StackCall) inStackInstanceSigil() {}
// ConfigStackCall represents a static stack call inside a particular [Stack].
type ConfigStackCall = InStackConfig[StackCall]
// AbsStackCall represents an instance of a stack call inside a particular
// [StackInstance[.
type AbsStackCall = InStackInstance[StackCall]
func AbsStackCallInstance(call AbsStackCall, key addrs.InstanceKey) StackInstance {
ret := make(StackInstance, len(call.Stack), len(call.Stack)+1)
copy(ret, call.Stack)
return append(ret, StackInstanceStep{
Name: call.Item.Name,
Key: key,
})
}

@ -0,0 +1,24 @@
package stackaddrs
import (
"github.com/hashicorp/terraform/internal/addrs"
)
// Targetable is the stacks analog to [addrs.Targetable], representing something
// that can be "targeted" inside a stack configuration.
type Targetable interface {
targetableSigil()
}
// ComponentTargetable is an adapter type that makes everything that's
// targetable in the main Terraform language also targetable through a
// component instance when in a stack configuration.
//
// To represent targeting an entire component, place [addrs.RootModuleInstance]
// in field Item to describe targeting the component's root module.
type ComponentTargetable[T addrs.Targetable] struct {
Component AbsComponentInstance
Item T
}
func (ComponentTargetable[T]) targetableSigil() {}
Loading…
Cancel
Save