--- /dev/null
+package errors
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+)
+
+// New returns an error that formats as the given text.
+func New(text string) error {
+ return errors.New(text)
+}
+
+// wrapperError satisfies the error interface.
+type wrapperError struct {
+ msg string
+ detail []string
+ data map[string]interface{}
+ stack []StackFrame
+ root error
+}
+
+// It satisfies the error interface.
+func (e wrapperError) Error() string {
+ return e.msg
+}
+
+// Root returns the original error that was wrapped by one or more
+// calls to Wrap. If e does not wrap other errors, it will be returned
+// as-is.
+func Root(e error) error {
+ if wErr, ok := e.(wrapperError); ok {
+ return wErr.root
+ }
+ return e
+}
+
+// wrap adds a context message and stack trace to err and returns a new error
+// containing the new context. This function is meant to be composed within
+// other exported functions, such as Wrap and WithDetail.
+// The argument stackSkip is the number of stack frames to ascend when
+// generating stack straces, where 0 is the caller of wrap.
+func wrap(err error, msg string, stackSkip int) error {
+ if err == nil {
+ return nil
+ }
+
+ werr, ok := err.(wrapperError)
+ if !ok {
+ werr.root = err
+ werr.msg = err.Error()
+ werr.stack = getStack(stackSkip+2, stackTraceSize)
+ }
+ if msg != "" {
+ werr.msg = msg + ": " + werr.msg
+ }
+
+ return werr
+}
+
+// Wrap adds a context message and stack trace to err and returns a new error
+// with the new context. Arguments are handled as in fmt.Print.
+// Use Root to recover the original error wrapped by one or more calls to Wrap.
+// Use Stack to recover the stack trace.
+// Wrap returns nil if err is nil.
+func Wrap(err error, a ...interface{}) error {
+ if err == nil {
+ return nil
+ }
+ return wrap(err, fmt.Sprint(a...), 1)
+}
+
+// Wrapf is like Wrap, but arguments are handled as in fmt.Printf.
+func Wrapf(err error, format string, a ...interface{}) error {
+ if err == nil {
+ return nil
+ }
+ return wrap(err, fmt.Sprintf(format, a...), 1)
+}
+
+// WithDetail returns a new error that wraps
+// err as a chain error messsage containing text
+// as its additional context.
+// Function Detail will return the given text
+// when called on the new error value.
+func WithDetail(err error, text string) error {
+ if err == nil {
+ return nil
+ }
+ if text == "" {
+ return err
+ }
+ e1 := wrap(err, text, 1).(wrapperError)
+ e1.detail = append(e1.detail, text)
+ return e1
+}
+
+// WithDetailf is like WithDetail, except it formats
+// the detail message as in fmt.Printf.
+// Function Detail will return the formatted text
+// when called on the new error value.
+func WithDetailf(err error, format string, v ...interface{}) error {
+ if err == nil {
+ return nil
+ }
+ text := fmt.Sprintf(format, v...)
+ e1 := wrap(err, text, 1).(wrapperError)
+ e1.detail = append(e1.detail, text)
+ return e1
+}
+
+// Detail returns the detail message contained in err, if any.
+// An error has a detail message if it was made by WithDetail
+// or WithDetailf.
+func Detail(err error) string {
+ wrapper, ok := err.(wrapperError)
+ if !ok {
+ return err.Error()
+ }
+ return strings.Join(wrapper.detail, "; ")
+}
+
+// withData returns a new error that wraps err
+// as a chain error message containing v as
+// an extra data item.
+// Calling Data on the returned error yields v.
+// Note that if err already has a data item,
+// it will not be accessible via the returned error value.
+func withData(err error, v map[string]interface{}) error {
+ if err == nil {
+ return nil
+ }
+ e1 := wrap(err, "", 1).(wrapperError)
+ e1.data = v
+ return e1
+}
+
+// WithData returns a new error that wraps err
+// as a chain error message containing a value of type
+// map[string]interface{} as an extra data item.
+// The map contains the values in the map in err,
+// if any, plus the items in keyval.
+// Keyval takes the form
+// k1, v1, k2, v2, ...
+// Values kN must be strings.
+// Calling Data on the returned error yields the map.
+// Note that if err already has a data item of any other type,
+// it will not be accessible via the returned error value.
+func WithData(err error, keyval ...interface{}) error {
+ if err == nil {
+ return nil
+ }
+ // TODO(kr): add vet check for odd-length keyval and non-string keys
+ newkv := make(map[string]interface{})
+ for k, v := range Data(err) {
+ newkv[k] = v
+ }
+ for i := 0; i < len(keyval); i += 2 {
+ newkv[keyval[i].(string)] = keyval[i+1]
+ }
+ return withData(err, newkv)
+}
+
+// Data returns the data item in err, if any.
+func Data(err error) map[string]interface{} {
+ wrapper, _ := err.(wrapperError)
+ return wrapper.data
+}
+
+// Sub returns an error containing root as its root and
+// taking all other metadata (stack trace, detail, message,
+// and data items) from err.
+//
+// Sub returns nil when either root or err is nil.
+//
+// Use this when you need to substitute a new root error in place
+// of an existing error that may already hold a stack trace
+// or other metadata.
+func Sub(root, err error) error {
+ if wrapper, ok := err.(wrapperError); ok && root != nil {
+ wrapper.root = Root(root)
+ wrapper.msg = root.Error()
+ root = wrapper
+ }
+ if err == nil {
+ return nil
+ }
+ return Wrap(root, err.Error())
+}