opentofu/terraform/eval_local.go
Martin Atkins 3a30bfe845 core: evaluate locals and return them for interpolation
We stash the locals in the module state in a map that is ignored for JSON
serialization. We don't include locals in the persisted state because they
can be trivially recomputed and this allows us to assume that they will
pass through verbatim, without any normalization or other transforms
caused by the JSON serialization.

From a user standpoint a local is just a named alias for an expression,
so it's desirable that the result passes through here in as raw a form
as possible, so it behaves as closely as possible to simply using the
given expression directly.
2017-08-21 15:15:25 -07:00

59 lines
1.2 KiB
Go

package terraform
import (
"fmt"
"github.com/hashicorp/terraform/config"
)
// EvalLocal is an EvalNode implementation that evaluates the
// expression for a local value and writes it into a transient part of
// the state.
type EvalLocal struct {
Name string
Value *config.RawConfig
}
func (n *EvalLocal) Eval(ctx EvalContext) (interface{}, error) {
cfg, err := ctx.Interpolate(n.Value, nil)
if err != nil {
return nil, fmt.Errorf("local.%s: %s", n.Name, err)
}
state, lock := ctx.State()
if state == nil {
return nil, fmt.Errorf("cannot write local value to nil state")
}
// Get a write lock so we can access the state
lock.Lock()
defer lock.Unlock()
// Look for the module state. If we don't have one, create it.
mod := state.ModuleByPath(ctx.Path())
if mod == nil {
mod = state.AddModule(ctx.Path())
}
// Get the value from the config
var valueRaw interface{} = config.UnknownVariableValue
if cfg != nil {
var ok bool
valueRaw, ok = cfg.Get("value")
if !ok {
valueRaw = ""
}
if cfg.IsComputed("value") {
valueRaw = config.UnknownVariableValue
}
}
if mod.Locals == nil {
// initialize
mod.Locals = map[string]interface{}{}
}
mod.Locals[n.Name] = valueRaw
return nil, nil
}