From 7e8ae90c3f9197cbcf7bd640c2240e0a7c1eb67c Mon Sep 17 00:00:00 2001 From: Jordan Keister Date: Mon, 14 Nov 2022 14:50:33 -0600 Subject: [PATCH 1/2] update render unmarshal failures Signed-off-by: Jordan Keister --- alpha/declcfg/load.go | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/alpha/declcfg/load.go b/alpha/declcfg/load.go index 65c289780..1be80a32f 100644 --- a/alpha/declcfg/load.go +++ b/alpha/declcfg/load.go @@ -135,7 +135,7 @@ func LoadReader(r io.Reader) (*DeclarativeConfig, error) { var in Meta if err := json.Unmarshal(doc, &in); err != nil { - return nil, err + return nil, fmt.Errorf("unmarshal error: %s", resolveUnmarshalErr(doc, err)) } switch in.Schema { @@ -186,3 +186,25 @@ func LoadFile(root fs.FS, path string) (*DeclarativeConfig, error) { return cfg, nil } + +func resolveUnmarshalErr(data []byte, err error) string { + if e, ok := err.(*json.UnmarshalTypeError); ok { + sb := new(strings.Builder) + _, _ = sb.WriteString(fmt.Sprintf("%s at offset %d (indicated by <==)\n ", e.Error(), e.Offset)) + for i := 0; i < int(e.Offset); i++ { + _ = sb.WriteByte(data[i]) + } + _, _ = sb.WriteString(" <==") + return sb.String() + } + if e, ok := err.(*json.UnmarshalFieldError); ok { + return e.Error() + } + if e, ok := err.(*json.InvalidUnmarshalError); ok { + return e.Error() + } + if e, ok := err.(*json.SyntaxError); ok { + return e.Error() + } + return err.Error() +} From 64888376f0753ded627936d1059964da8edf3187 Mon Sep 17 00:00:00 2001 From: Jordan Keister Date: Tue, 15 Nov 2022 16:02:04 -0600 Subject: [PATCH 2/2] revamp for pretty format, error.As approach Signed-off-by: Jordan Keister --- alpha/declcfg/load.go | 55 ++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/alpha/declcfg/load.go b/alpha/declcfg/load.go index 1be80a32f..98b25da02 100644 --- a/alpha/declcfg/load.go +++ b/alpha/declcfg/load.go @@ -1,6 +1,7 @@ package declcfg import ( + "bytes" "encoding/json" "errors" "fmt" @@ -188,23 +189,45 @@ func LoadFile(root fs.FS, path string) (*DeclarativeConfig, error) { } func resolveUnmarshalErr(data []byte, err error) string { - if e, ok := err.(*json.UnmarshalTypeError); ok { - sb := new(strings.Builder) - _, _ = sb.WriteString(fmt.Sprintf("%s at offset %d (indicated by <==)\n ", e.Error(), e.Offset)) - for i := 0; i < int(e.Offset); i++ { - _ = sb.WriteByte(data[i]) - } - _, _ = sb.WriteString(" <==") - return sb.String() - } - if e, ok := err.(*json.UnmarshalFieldError); ok { - return e.Error() + var te *json.UnmarshalTypeError + if errors.As(err, &te) { + return formatUnmarshallErrorString(data, te.Error(), te.Offset) } - if e, ok := err.(*json.InvalidUnmarshalError); ok { - return e.Error() - } - if e, ok := err.(*json.SyntaxError); ok { - return e.Error() + var se *json.SyntaxError + if errors.As(err, &se) { + return formatUnmarshallErrorString(data, se.Error(), se.Offset) } return err.Error() } + +func formatUnmarshallErrorString(data []byte, errmsg string, offset int64) string { + sb := new(strings.Builder) + _, _ = sb.WriteString(fmt.Sprintf("%s at offset %d (indicated by <==)\n ", errmsg, offset)) + // attempt to present the erroneous JSON in indented, human-readable format + // errors result in presenting the original, unformatted output + var pretty bytes.Buffer + err := json.Indent(&pretty, data, "", " ") + if err == nil { + pString := pretty.String() + // calc the prettified string offset which correlates to the original string offset + var pOffset, origOffset int64 + origOffset = 0 + for origOffset = 0; origOffset < offset; { + pOffset++ + if pString[pOffset] != '\n' && pString[pOffset] != ' ' { + origOffset++ + } + } + _, _ = sb.WriteString(pString[:pOffset]) + _, _ = sb.WriteString(" <== ") + _, _ = sb.WriteString(pString[pOffset:]) + } else { + for i := int64(0); i < offset; i++ { + _ = sb.WriteByte(data[i]) + } + _, _ = sb.WriteString(" <== ") + _, _ = sb.Write(data[offset:]) + } + + return sb.String() +}