tfdiags: helper functions for nicer display of cty.PathError

cty doesn't have a native string representation of a cty.Path because it
is the layer below any particular syntax, but up here in Terraform land
we know that we use HCL native syntax and so we can format a string in
a HCL-ish way for familiarity to the user.

We'll use this form automatically when such an error is used directly as a
diagnostic, but we also expose the function publicly so that other code
that incorporates errors into diagnostic detail strings can apply the
same formatting.
This commit is contained in:
Martin Atkins 2018-03-16 18:30:06 -07:00
parent e309675853
commit 9bd47bf17c
2 changed files with 57 additions and 1 deletions

View File

@ -0,0 +1,56 @@
package tfdiags
import (
"bytes"
"fmt"
"strconv"
"github.com/zclconf/go-cty/cty"
)
// FormatCtyPath is a helper function to produce a user-friendly string
// representation of a cty.Path. The result uses a syntax similar to the
// HCL expression language in the hope of it being familiar to users.
func FormatCtyPath(path cty.Path) string {
var buf bytes.Buffer
for _, step := range path {
switch ts := step.(type) {
case cty.GetAttrStep:
fmt.Fprintf(&buf, ".%s", ts.Name)
case cty.IndexStep:
buf.WriteByte('[')
key := ts.Key
keyTy := key.Type()
switch {
case key.IsNull():
buf.WriteString("null")
case !key.IsKnown():
buf.WriteString("(not yet known)")
case keyTy == cty.Number:
bf := key.AsBigFloat()
buf.WriteString(bf.Text('g', -1))
case keyTy == cty.String:
buf.WriteString(strconv.Quote(key.AsString()))
default:
buf.WriteString("...")
}
buf.WriteByte(']')
}
}
return buf.String()
}
// FormatError is a helper function to produce a user-friendly string
// representation of certain special error types that we might want to
// include in diagnostic messages.
//
// This currently has special behavior only for cty.PathError, where a
// non-empty path is rendered in a HCL-like syntax as context.
func FormatError(err error) string {
perr, ok := err.(cty.PathError)
if !ok || len(perr.Path) == 0 {
return err.Error()
}
return fmt.Sprintf("%s: %s", FormatCtyPath(perr.Path), perr.Error())
}

View File

@ -13,7 +13,7 @@ func (e nativeError) Severity() Severity {
func (e nativeError) Description() Description {
return Description{
Summary: e.err.Error(),
Summary: FormatError(e.err),
}
}