-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
57 additions
and
364 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 = © | ||
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...)} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.