blob: fe905c9a7a7c2bf09d6ba855ad5b0245b8cdaf64 [file] [log] [blame] [edit]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package stackstate
import (
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/collections"
"github.com/hashicorp/terraform/internal/stacks/stackaddrs"
"github.com/hashicorp/terraform/internal/states"
)
// StateBuilder wraps State, and provides some write-only methods to update the
// state.
//
// This is generally used to build up a new state from scratch during tests.
type StateBuilder struct {
state *State
}
func NewStateBuilder() *StateBuilder {
return &StateBuilder{
state: NewState(),
}
}
// Build returns the state and invalidates the StateBuilder.
//
// You will get nil pointer exceptions if you attempt to use the builder after
// calling Build.
func (s *StateBuilder) Build() *State {
ret := s.state
s.state = nil
return ret
}
// AddResourceInstance adds a resource instance to the state.
func (s *StateBuilder) AddResourceInstance(builder *ResourceInstanceBuilder) *StateBuilder {
if builder.addr == nil || builder.src == nil || builder.providerAddr == nil {
panic("ResourceInstanceBuilder is missing required fields")
}
s.state.addResourceInstanceObject(*builder.addr, builder.src, *builder.providerAddr)
return s
}
// AddComponentInstance adds a component instance to the state.
func (s *StateBuilder) AddComponentInstance(builder *ComponentInstanceBuilder) *StateBuilder {
component := s.state.ensureComponentInstanceState(builder.addr)
component.outputValues = builder.outputValues
component.inputVariables = builder.inputVariables
for dep := range builder.dependencies.All() {
component.dependencies.Add(dep)
}
for dep := range builder.dependents.All() {
component.dependents.Add(dep)
}
return s
}
// AddOutput adds an output to the state.
func (s *StateBuilder) AddOutput(name string, value cty.Value) *StateBuilder {
s.state.outputs[stackaddrs.OutputValue{Name: name}] = value
return s
}
// AddInput adds an input variable to the state.
func (s *StateBuilder) AddInput(name string, value cty.Value) *StateBuilder {
s.state.inputs[stackaddrs.InputVariable{Name: name}] = value
return s
}
type ResourceInstanceBuilder struct {
addr *stackaddrs.AbsResourceInstanceObject
src *states.ResourceInstanceObjectSrc
providerAddr *addrs.AbsProviderConfig
}
func NewResourceInstanceBuilder() *ResourceInstanceBuilder {
return &ResourceInstanceBuilder{}
}
func (b *ResourceInstanceBuilder) SetAddr(addr stackaddrs.AbsResourceInstanceObject) *ResourceInstanceBuilder {
b.addr = &addr
return b
}
func (b *ResourceInstanceBuilder) SetResourceInstanceObjectSrc(src states.ResourceInstanceObjectSrc) *ResourceInstanceBuilder {
b.src = &src
return b
}
func (b *ResourceInstanceBuilder) SetProviderAddr(addr addrs.AbsProviderConfig) *ResourceInstanceBuilder {
b.providerAddr = &addr
return b
}
type ComponentInstanceBuilder struct {
addr stackaddrs.AbsComponentInstance
dependencies collections.Set[stackaddrs.AbsComponent]
dependents collections.Set[stackaddrs.AbsComponent]
outputValues map[addrs.OutputValue]cty.Value
inputVariables map[addrs.InputVariable]cty.Value
}
func NewComponentInstanceBuilder(instance stackaddrs.AbsComponentInstance) *ComponentInstanceBuilder {
return &ComponentInstanceBuilder{
addr: instance,
dependencies: collections.NewSet[stackaddrs.AbsComponent](),
dependents: collections.NewSet[stackaddrs.AbsComponent](),
outputValues: make(map[addrs.OutputValue]cty.Value),
inputVariables: make(map[addrs.InputVariable]cty.Value),
}
}
func (b *ComponentInstanceBuilder) AddDependency(addr stackaddrs.AbsComponent) *ComponentInstanceBuilder {
b.dependencies.Add(addr)
return b
}
func (b *ComponentInstanceBuilder) AddDependent(addr stackaddrs.AbsComponent) *ComponentInstanceBuilder {
b.dependents.Add(addr)
return b
}
func (b *ComponentInstanceBuilder) AddOutputValue(name string, value cty.Value) *ComponentInstanceBuilder {
b.outputValues[addrs.OutputValue{Name: name}] = value
return b
}
func (b *ComponentInstanceBuilder) AddInputVariable(name string, value cty.Value) *ComponentInstanceBuilder {
b.inputVariables[addrs.InputVariable{Name: name}] = value
return b
}