DockerCLI/vendor/github.com/docker/licensing/lib/errors/wrap.go

107 lines
2.7 KiB
Go

package errors
import "fmt"
// Wrapf takes an originating "cause" error and annotates
// it with text and the source file & line of the wrap point.
func Wrapf(err error, fields Fields, format string, args ...interface{}) *Wrapped {
w := &Wrapped{
Base: NewBase(1, fmt.Sprintf(format, args...)),
cause: err,
}
w.AddFields(fields)
return w
}
// Wrap takes an originating "cause" error and annotates
// it just with the source file & line of the wrap point.
func Wrap(err error, fields Fields) *Wrapped {
w := &Wrapped{
Base: NewBase(1, err.Error()),
cause: err,
}
w.AddFields(fields)
return w
}
// WithMessage takes an originating cause and text description,
// returning a wrapped error with the text and stack.
func WithMessage(err error, text string) *Wrapped {
return &Wrapped{
Base: NewBase(1, text),
cause: err,
}
}
// WithStack takes an originating cause and returns
// a wrapped error that just records the stack.
func WithStack(err error) *Wrapped {
return &Wrapped{
Base: NewBase(1, err.Error()),
cause: err,
}
}
// Wrapped provides a way to add additional context when passing back
// an error to a caller. It inherits the useful features from Base
// (call stacks, structured text & data).
type Wrapped struct {
*Base
cause error
}
func (w *Wrapped) Error() string {
msg := textAndFields(w.Text, w.Fields)
return msg + ": " + w.cause.Error()
}
// With allows adding additional structured data fields.
func (w *Wrapped) With(fields Fields) *Wrapped {
w.AddFields(fields)
return w
}
// Unwrap extracts any layered Wrapped errors inside of this one,
// returning the first non-Wrapped error found as the original cause.
func (w *Wrapped) Unwrap() (wraps []*Base, cause error) {
for w != nil {
cause = w.cause
wraps = append(wraps, w.Base)
w, _ = w.cause.(*Wrapped)
}
// For consistency, wraps should be in same order as stacks:
// first element is from the innermost wrap
// Hence we need to reverse the append operation above.
for i := len(wraps)/2 - 1; i >= 0; i-- {
j := len(wraps) - 1 - i
wraps[i], wraps[j] = wraps[j], wraps[i]
}
return
}
// Cause checks if the passed in error is a Wrapped. If so, it will
// extract & return information about all the wrapped errors inside.
// It will return the CallStack of cause, if it supports the errors.Stack()
// interface, or the innermost wrap (which should be the closest wrap to cause.)
// If error is not a wrapped, cause is same as input err.
func Cause(err error) (stack CallStack, wraps []*Base, cause error) {
cause = err
if w, ok := err.(*Wrapped); ok {
wraps, cause = w.Unwrap()
}
type stacker interface {
Stack() CallStack
}
if s, ok := cause.(stacker); ok {
stack = s.Stack()
} else {
if len(wraps) > 0 {
stack = wraps[0].Stack()
}
}
return
}