github.com/hashicorp/terraform-plugin-sdk@v1.17.2/internal/tfdiags/config_traversals.go (about)

     1  package tfdiags
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"strconv"
     7  
     8  	"github.com/zclconf/go-cty/cty"
     9  )
    10  
    11  // FormatCtyPath is a helper function to produce a user-friendly string
    12  // representation of a cty.Path. The result uses a syntax similar to the
    13  // HCL expression language in the hope of it being familiar to users.
    14  func FormatCtyPath(path cty.Path) string {
    15  	var buf bytes.Buffer
    16  	for _, step := range path {
    17  		switch ts := step.(type) {
    18  		case cty.GetAttrStep:
    19  			fmt.Fprintf(&buf, ".%s", ts.Name)
    20  		case cty.IndexStep:
    21  			buf.WriteByte('[')
    22  			key := ts.Key
    23  			keyTy := key.Type()
    24  			switch {
    25  			case key.IsNull():
    26  				buf.WriteString("null")
    27  			case !key.IsKnown():
    28  				buf.WriteString("(not yet known)")
    29  			case keyTy == cty.Number:
    30  				bf := key.AsBigFloat()
    31  				buf.WriteString(bf.Text('g', -1))
    32  			case keyTy == cty.String:
    33  				buf.WriteString(strconv.Quote(key.AsString()))
    34  			default:
    35  				buf.WriteString("...")
    36  			}
    37  			buf.WriteByte(']')
    38  		}
    39  	}
    40  	return buf.String()
    41  }
    42  
    43  // FormatError is a helper function to produce a user-friendly string
    44  // representation of certain special error types that we might want to
    45  // include in diagnostic messages.
    46  //
    47  // This currently has special behavior only for cty.PathError, where a
    48  // non-empty path is rendered in a HCL-like syntax as context.
    49  func FormatError(err error) string {
    50  	perr, ok := err.(cty.PathError)
    51  	if !ok || len(perr.Path) == 0 {
    52  		return err.Error()
    53  	}
    54  
    55  	return fmt.Sprintf("%s: %s", FormatCtyPath(perr.Path), perr.Error())
    56  }
    57  
    58  // FormatErrorPrefixed is like FormatError except that it presents any path
    59  // information after the given prefix string, which is assumed to contain
    60  // an HCL syntax representation of the value that errors are relative to.
    61  func FormatErrorPrefixed(err error, prefix string) string {
    62  	perr, ok := err.(cty.PathError)
    63  	if !ok || len(perr.Path) == 0 {
    64  		return fmt.Sprintf("%s: %s", prefix, err.Error())
    65  	}
    66  
    67  	return fmt.Sprintf("%s%s: %s", prefix, FormatCtyPath(perr.Path), perr.Error())
    68  }