Skip to content

Commit

Permalink
Tidy up errors package
Browse files Browse the repository at this point in the history
  • Loading branch information
babarot committed Mar 12, 2022
1 parent 74cddca commit c4810f2
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 364 deletions.
35 changes: 0 additions & 35 deletions pkg/errors/detail.go

This file was deleted.

182 changes: 48 additions & 134 deletions pkg/errors/errors.go
Original file line number Diff line number Diff line change
@@ -1,158 +1,72 @@
package errors

// https://github.com/upspin/upspin/tree/master/errors
// https://commandcenter.blogspot.com/2017/12/error-handling-in-upspin.html
// https://blog.golang.org/errors-are-values

import (
"bytes"
"fmt"
"log"
"runtime"

"github.com/hashicorp/hcl/v2"
"strings"
)

var (
_ error = (*Error)(nil)
)
// Errors is an error type to track multiple errors. This is used to
// accumulate errors in cases and return them as a single "error".
type Errors []error

// Error is the type that implements the error interface.
// It contains a number of fields, each of different type.
// An Error value may leave some values unset.
type Error struct {
Err error
Files map[string]*hcl.File
Diagnostics hcl.Diagnostics
}
func (e *Errors) Error() string {
format := func(text string) string {
var s string
lines := strings.Split(text, "\n")
switch len(lines) {
default:
s += lines[0]
for _, line := range lines[1:] {
s += fmt.Sprintf("\n\t %s", line)
}
case 0:
s = (*e)[0].Error()
}
return s
}

func (e *Error) Error() string {
switch {
case e.Diagnostics.HasErrors():
if len(e.Files) == 0 {
return e.Diagnostics.Error()
if len(*e) == 1 {
if (*e)[0] == nil {
return ""
}
var b bytes.Buffer
wr := hcl.NewDiagnosticTextWriter(
&b, // writer to send messages to
e.Files, // the parser's file cache, for source snippets
100, // wrapping width
true, // generate colored/highlighted output
)
wr.WriteDiagnostics(e.Diagnostics)
return b.String()
case e.Err != nil:
return e.Err.Error()
return fmt.Sprintf("1 error occurred:\n\t* %s\n\n", format((*e)[0].Error()))
}
return ""
}

func flatten(diags hcl.Diagnostics) hcl.Diagnostics {
m := make(map[string]bool)
var d hcl.Diagnostics
for _, diag := range diags {
err := diags.Error()
if !m[err] {
m[err] = true
d = append(d, diag)
var points []string
for _, err := range *e {
if err == nil {
continue
}
points = append(points, fmt.Sprintf("* %s", format(err.Error())))
}
return d

return fmt.Sprintf(
"%d errors occurred:\n\t%s\n\n",
len(points), strings.Join(points, "\n\t"))
}

// New is
func New(args ...interface{}) error {
if len(args) == 0 {
return nil
func (e *Errors) Append(errs ...error) {
if e == nil {
e = new(Errors)
}
e := &Error{}
for _, arg := range args {
switch arg := arg.(type) {
case string:
// Someone might accidentally call us with a user or path name
// that is not of the right type. Take care of that and log it.
// if strings.Contains(arg, "@") {
// _, file, line, _ := runtime.Caller(1)
// log.Printf("errors.E: unqualified type for %q from %s:%d", arg, file, line)
// if strings.Contains(arg, "/") {
// if e.Path == "" { // Don't overwrite a valid path.
// e.Path = upspin.PathName(arg)
// }
// } else {
// if e.User == "" { // Don't overwrite a valid user.
// e.User = upspin.UserName(arg)
// }
// }
// continue
// }
e.Err = &errorString{arg}
case *Error:
// Make a copy
copy := *arg
e.Err = &copy
case hcl.Diagnostics:
e.Diagnostics = flatten(arg)
case map[string]*hcl.File:
e.Files = arg
case error:
e.Err = arg
default:
_, file, line, _ := runtime.Caller(1)
log.Printf("errors.E: bad call from %s:%d: %v", file, line, args)
return Errorf("unknown type %T, value %v in error call", arg, arg)
for _, err := range errs {
if err != nil {
*e = append(*e, err)
}
}
}

// prev, ok := e.Err.(*Error)
// if !ok {
// return e
// }
//
// // The previous error was also one of ours. Suppress duplications
// // so the message won't contain the same kind, file name or user name
// // twice.
// if prev.Path == e.Path {
// prev.Path = ""
// }
// if prev.User == e.User {
// prev.User = ""
// }
// if prev.Kind == e.Kind {
// prev.Kind = Other
// }
// // If this error has Kind unset or Other, pull up the inner one.
// if e.Kind == Other {
// e.Kind = prev.Kind
// prev.Kind = Other
// }

if len(e.Diagnostics) == 0 && e.Err == nil {
// ErrorOrNil returns an error interface if this Error represents
// a list of errors, or returns nil if the list of errors is empty. This
// function is useful at the end of accumulation to make sure that the value
// returned represents the existence of errors.
func (e *Errors) ErrorOrNil() error {
if e == nil {
return nil
}
if len(*e) == 0 {
return nil
}

return e
}

// Recreate the errors.New functionality of the standard Go errors package
// so we can create simple text errors when needed.

// New returns an error that formats as the given text. It is intended to
// be used as the error-typed argument to the E function.
// func New(text string) error {
// return &errorString{text}
// }

// errorString is a trivial implementation of error.
type errorString struct {
s string
}

func (e *errorString) Error() string {
return e.s
}

// Errorf is equivalent to fmt.Errorf, but allows clients to import only this
// package for all error handling.
func Errorf(format string, args ...interface{}) error {
return &errorString{fmt.Sprintf(format, args...)}
}
62 changes: 0 additions & 62 deletions pkg/errors/kind.go

This file was deleted.

80 changes: 0 additions & 80 deletions pkg/errors/multierror.go

This file was deleted.

Loading

0 comments on commit c4810f2

Please sign in to comment.