mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-25 01:00:16 -05:00
Integrate provider functions (#1439)
Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
This commit is contained in:
@@ -7,10 +7,13 @@ package lang
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/ext/dynblock"
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/hashicorp/hcl/v2/hclsyntax"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/convert"
|
||||
|
||||
@@ -71,7 +74,7 @@ func (s *Scope) EvalBlock(body hcl.Body, schema *configschema.Block) (cty.Value,
|
||||
body = blocktoattr.FixUpBlockAttrs(body, schema)
|
||||
|
||||
val, evalDiags := hcldec.Decode(body, spec, ctx)
|
||||
diags = diags.Append(evalDiags)
|
||||
diags = diags.Append(s.enhanceFunctionDiags(evalDiags))
|
||||
|
||||
return val, diags
|
||||
}
|
||||
@@ -149,7 +152,7 @@ func (s *Scope) EvalSelfBlock(body hcl.Body, self cty.Value, schema *configschem
|
||||
}
|
||||
|
||||
val, decDiags := hcldec.Decode(body, schema.DecoderSpec(), ctx)
|
||||
diags = diags.Append(decDiags)
|
||||
diags = diags.Append(s.enhanceFunctionDiags(decDiags))
|
||||
return val, diags
|
||||
}
|
||||
|
||||
@@ -175,7 +178,7 @@ func (s *Scope) EvalExpr(expr hcl.Expression, wantType cty.Type) (cty.Value, tfd
|
||||
}
|
||||
|
||||
val, evalDiags := expr.Value(ctx)
|
||||
diags = diags.Append(evalDiags)
|
||||
diags = diags.Append(s.enhanceFunctionDiags(evalDiags))
|
||||
|
||||
if wantType != cty.DynamicPseudoType {
|
||||
var convErr error
|
||||
@@ -196,6 +199,62 @@ func (s *Scope) EvalExpr(expr hcl.Expression, wantType cty.Type) (cty.Value, tfd
|
||||
return val, diags
|
||||
}
|
||||
|
||||
// Common provider function namespace form
|
||||
var providerFuncNamespace = regexp.MustCompile("^([^:]*)::([^:]*)::$")
|
||||
|
||||
// Identify and enhance any function related dialogs produced by a hcl.EvalContext
|
||||
func (s *Scope) enhanceFunctionDiags(diags hcl.Diagnostics) hcl.Diagnostics {
|
||||
out := make(hcl.Diagnostics, len(diags))
|
||||
for i, diag := range diags {
|
||||
out[i] = diag
|
||||
|
||||
if funcExtra, ok := diag.Extra.(hclsyntax.FunctionCallUnknownDiagExtra); ok {
|
||||
funcName := funcExtra.CalledFunctionName()
|
||||
// prefix::stuff::
|
||||
fullNamespace := funcExtra.CalledFunctionNamespace()
|
||||
|
||||
if !strings.Contains(fullNamespace, "::") {
|
||||
// Not a namespaced function, no enhancements nessesary
|
||||
continue
|
||||
}
|
||||
|
||||
// Insert the enhanced copy of diag into diags
|
||||
enhanced := *diag
|
||||
out[i] = &enhanced
|
||||
|
||||
// Update enhanced with additional details
|
||||
|
||||
if fullNamespace == CoreNamespace {
|
||||
// Error is in core namespace, mirror non-core equivalent
|
||||
enhanced.Summary = "Call to unknown function"
|
||||
enhanced.Detail = fmt.Sprintf("There is no builtin (%s) function named %q.", CoreNamespace, funcName)
|
||||
continue
|
||||
}
|
||||
|
||||
match := providerFuncNamespace.FindSubmatch([]byte(fullNamespace))
|
||||
if match == nil || string(match[1]) != "provider" {
|
||||
// complete mismatch or invalid prefix
|
||||
enhanced.Summary = "Invalid function format"
|
||||
enhanced.Detail = fmt.Sprintf("Expected provider::<provider_name>::<function_name>, instead found \"%s%s\"", fullNamespace, funcName)
|
||||
continue
|
||||
}
|
||||
|
||||
providerName := string(match[2])
|
||||
addr, ok := s.ProviderNames[providerName]
|
||||
if !ok {
|
||||
// Provider not registered
|
||||
enhanced.Summary = "Unknown function provider"
|
||||
enhanced.Detail = fmt.Sprintf("Provider %q does not exist within the required_providers of this module", providerName)
|
||||
} else {
|
||||
// Func not in provider
|
||||
enhanced.Summary = "Function not found in provider"
|
||||
enhanced.Detail = fmt.Sprintf("Function %q was not registered by provider named %q of type %q", funcName, providerName, addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// EvalReference evaluates the given reference in the receiving scope and
|
||||
// returns the resulting value. The value will be converted to the given type before
|
||||
// it is returned if possible, or else an error diagnostic will be produced
|
||||
|
||||
Reference in New Issue
Block a user