package terraform import ( "fmt" "github.com/hashicorp/hcl/v2" "github.com/zclconf/go-cty/cty" "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/lang" "github.com/hashicorp/terraform/tfdiags" ) // 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 { Addr addrs.LocalValue Expr hcl.Expression } func (n *EvalLocal) Eval(ctx EvalContext) (interface{}, error) { var diags tfdiags.Diagnostics // We ignore diags here because any problems we might find will be found // again in EvaluateExpr below. refs, _ := lang.ReferencesInExpr(n.Expr) for _, ref := range refs { if ref.Subject == n.Addr { diags = diags.Append(&hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "Self-referencing local value", Detail: fmt.Sprintf("Local value %s cannot use its own result as part of its expression.", n.Addr), Subject: ref.SourceRange.ToHCL().Ptr(), Context: n.Expr.Range().Ptr(), }) } } if diags.HasErrors() { return nil, diags.Err() } val, moreDiags := ctx.EvaluateExpr(n.Expr, cty.DynamicPseudoType, nil) diags = diags.Append(moreDiags) if moreDiags.HasErrors() { return nil, diags.Err() } state := ctx.State() if state == nil { return nil, fmt.Errorf("cannot write local value to nil state") } state.SetLocalValue(n.Addr.Absolute(ctx.Path()), val) return nil, nil } // EvalDeleteLocal is an EvalNode implementation that deletes a Local value // from the state. Locals aren't persisted, but we don't need to evaluate them // during destroy. type EvalDeleteLocal struct { Addr addrs.LocalValue } func (n *EvalDeleteLocal) Eval(ctx EvalContext) (interface{}, error) { state := ctx.State() if state == nil { return nil, nil } state.RemoveLocalValue(n.Addr.Absolute(ctx.Path())) return nil, nil }