mirror of https://github.com/coder/coder.git
69 lines
2.2 KiB
Go
69 lines
2.2 KiB
Go
package terraform
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
tfjson "github.com/hashicorp/terraform-json"
|
|
)
|
|
|
|
// This implementation bases on the original Terraform formatter, which unfortunately is internal:
|
|
// https://github.com/hashicorp/terraform/blob/6b35927cf0988262739a5f0acea4790ae58a16d3/internal/command/format/diagnostic.go#L125
|
|
|
|
func FormatDiagnostic(diag *tfjson.Diagnostic) string {
|
|
var buf bytes.Buffer
|
|
appendSourceSnippets(&buf, diag)
|
|
_, _ = buf.WriteString(diag.Detail)
|
|
return buf.String()
|
|
}
|
|
|
|
func appendSourceSnippets(buf *bytes.Buffer, diag *tfjson.Diagnostic) {
|
|
if diag.Range == nil {
|
|
return
|
|
}
|
|
|
|
if diag.Snippet == nil {
|
|
// This should generally not happen, as long as sources are always
|
|
// loaded through the main loader. We may load things in other
|
|
// ways in weird cases, so we'll tolerate it at the expense of
|
|
// a not-so-helpful error message.
|
|
_, _ = fmt.Fprintf(buf, "on %s line %d:\n (source code not available)\n", diag.Range.Filename, diag.Range.Start.Line)
|
|
} else {
|
|
snippet := diag.Snippet
|
|
code := snippet.Code
|
|
|
|
var contextStr string
|
|
if snippet.Context != nil {
|
|
contextStr = fmt.Sprintf(", in %s", *snippet.Context)
|
|
}
|
|
_, _ = fmt.Fprintf(buf, "on %s line %d%s:\n", diag.Range.Filename, diag.Range.Start.Line, contextStr)
|
|
|
|
// Split the snippet into lines and render one at a time
|
|
lines := strings.Split(code, "\n")
|
|
for i, line := range lines {
|
|
_, _ = fmt.Fprintf(buf, " %d: %s\n", snippet.StartLine+i, line)
|
|
}
|
|
|
|
if len(snippet.Values) > 0 {
|
|
// The diagnostic may also have information about the dynamic
|
|
// values of relevant variables at the point of evaluation.
|
|
// This is particularly useful for expressions that get evaluated
|
|
// multiple times with different values, such as blocks using
|
|
// "count" and "for_each", or within "for" expressions.
|
|
values := make([]tfjson.DiagnosticExpressionValue, len(snippet.Values))
|
|
copy(values, snippet.Values)
|
|
sort.Slice(values, func(i, j int) bool {
|
|
return values[i].Traversal < values[j].Traversal
|
|
})
|
|
|
|
_, _ = buf.WriteString(" ├────────────────\n")
|
|
for _, value := range values {
|
|
_, _ = fmt.Fprintf(buf, " │ %s %s\n", value.Traversal, value.Statement)
|
|
}
|
|
}
|
|
}
|
|
_ = buf.WriteByte('\n')
|
|
}
|