diff --git a/Gopkg.lock b/Gopkg.lock index caa3a743830b..6734b7a0b0f1 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -326,12 +326,13 @@ revision = "279515615485b0f2d12f1421cc412fe2784e0190" [[projects]] - digest = "1:5cf3f025cbee5951a4ee961de067c8a89fc95a5adabead774f82822efabab121" + digest = "1:1ddea2d64730f05a189090d765b5108370acf83208d5074b2024a113096f4792" name = "github.com/pkg/errors" packages = ["."] pruneopts = "NUT" - revision = "645ef00459ed84a119197bfb8d8205042c6df63d" - version = "v0.8.0" + revision = "0c849bcccef2ad68bca21ce43782f28e68996375" + source = "https://github.com/pingcap/errors" + version = "v0.10.0" [[projects]] digest = "1:8d8f554bbb62fb7aecf661b85b25e227f6ab6cfe2b4395ea65ef478bfc174940" diff --git a/Gopkg.toml b/Gopkg.toml index 101eeb186738..5e0614737745 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -38,7 +38,8 @@ [[constraint]] name = "github.com/pkg/errors" - version = ">= 0.8.0" + version = ">= 0.9.0" + source = "https://github.com/pingcap/errors" [[override]] name = "github.com/BurntSushi/toml" diff --git a/vendor/github.com/pkg/errors/errors.go b/vendor/github.com/pkg/errors/errors.go index 842ee80456db..4e2e9673779c 100644 --- a/vendor/github.com/pkg/errors/errors.go +++ b/vendor/github.com/pkg/errors/errors.go @@ -13,24 +13,24 @@ // // Adding context to an error // -// The errors.Wrap function returns a new error that adds context to the -// original error by recording a stack trace at the point Wrap is called, +// The errors.Annotate function returns a new error that adds context to the +// original error by recording a stack trace at the point Annotate is called, // and the supplied message. For example // // _, err := ioutil.ReadAll(r) // if err != nil { -// return errors.Wrap(err, "read failed") +// return errors.Annotate(err, "read failed") // } // -// If additional control is required the errors.WithStack and errors.WithMessage -// functions destructure errors.Wrap into its component operations of annotating +// If additional control is required the errors.AddStack and errors.WithMessage +// functions destructure errors.Annotate into its component operations of annotating // an error with a stack trace and an a message, respectively. // // Retrieving the cause of an error // -// Using errors.Wrap constructs a stack of errors, adding context to the +// Using errors.Annotate constructs a stack of errors, adding context to the // preceding error. Depending on the nature of the error it may be necessary -// to reverse the operation of errors.Wrap to retrieve the original error +// to reverse the operation of errors.Annotate to retrieve the original error // for inspection. Any error value which implements this interface // // type causer interface { @@ -50,6 +50,7 @@ // // causer interface is not exported by this package, but is considered a part // of stable public API. +// errors.Unwrap is also available: this will retrieve the next error in the chain. // // Formatted printing of errors // @@ -64,14 +65,9 @@ // // Retrieving the stack trace of an error or wrapper // -// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are -// invoked. This information can be retrieved with the following interface. -// -// type stackTracer interface { -// StackTrace() errors.StackTrace -// } -// -// Where errors.StackTrace is defined as +// New, Errorf, Annotate, and Annotatef record a stack trace at the point they are invoked. +// This information can be retrieved with the StackTracer interface that returns +// a StackTrace. Where errors.StackTrace is defined as // // type StackTrace []Frame // @@ -79,16 +75,15 @@ // the fmt.Formatter interface that can be used for printing information about // the stack trace of this error. For example: // -// if err, ok := err.(stackTracer); ok { -// for _, f := range err.StackTrace() { +// if stacked := errors.GetStackTracer(err); stacked != nil { +// for _, f := range stacked.StackTrace() { // fmt.Printf("%+s:%d", f) // } // } // -// stackTracer interface is not exported by this package, but is considered a part -// of stable public API. -// // See the documentation for Frame.Format for more details. +// +// errors.Find can be used to search for an error in the error chain. package errors import ( @@ -115,6 +110,21 @@ func Errorf(format string, args ...interface{}) error { } } +// StackTraceAware is an optimization to avoid repetitive traversals of an error chain. +// HasStack checks for this marker first. +// Annotate/Wrap and Annotatef/Wrapf will produce this marker. +type StackTraceAware interface { + HasStack() bool +} + +// HasStack tells whether a StackTracer exists in the error chain +func HasStack(err error) bool { + if errWithStack, ok := err.(StackTraceAware); ok { + return errWithStack.HasStack() + } + return GetStackTracer(err) != nil +} + // fundamental is an error that has a message and a stack, but no caller. type fundamental struct { msg string @@ -141,16 +151,28 @@ func (f *fundamental) Format(s fmt.State, verb rune) { // WithStack annotates err with a stack trace at the point WithStack was called. // If err is nil, WithStack returns nil. +// +// Deprecated: use AddStack func WithStack(err error) error { if err == nil { return nil } + return &withStack{ err, callers(), } } +// AddStack is similar to WithStack. +// However, it will first check with HasStack to see if a stack trace already exists in the causer chain before creating another one. +func AddStack(err error) error { + if HasStack(err) { + return err + } + return WithStack(err) +} + type withStack struct { error *stack @@ -175,15 +197,19 @@ func (w *withStack) Format(s fmt.State, verb rune) { } // Wrap returns an error annotating err with a stack trace -// at the point Wrap is called, and the supplied message. -// If err is nil, Wrap returns nil. +// at the point Annotate is called, and the supplied message. +// If err is nil, Annotate returns nil. +// +// Deprecated: use Annotate instead func Wrap(err error, message string) error { if err == nil { return nil } + hasStack := HasStack(err) err = &withMessage{ - cause: err, - msg: message, + cause: err, + msg: message, + causeHasStack: hasStack, } return &withStack{ err, @@ -192,15 +218,19 @@ func Wrap(err error, message string) error { } // Wrapf returns an error annotating err with a stack trace -// at the point Wrapf is call, and the format specifier. -// If err is nil, Wrapf returns nil. +// at the point Annotatef is call, and the format specifier. +// If err is nil, Annotatef returns nil. +// +// Deprecated: use Annotatef instead func Wrapf(err error, format string, args ...interface{}) error { if err == nil { return nil } + hasStack := HasStack(err) err = &withMessage{ - cause: err, - msg: fmt.Sprintf(format, args...), + cause: err, + msg: fmt.Sprintf(format, args...), + causeHasStack: hasStack, } return &withStack{ err, @@ -215,18 +245,21 @@ func WithMessage(err error, message string) error { return nil } return &withMessage{ - cause: err, - msg: message, + cause: err, + msg: message, + causeHasStack: HasStack(err), } } type withMessage struct { - cause error - msg string + cause error + msg string + causeHasStack bool } -func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } -func (w *withMessage) Cause() error { return w.cause } +func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } +func (w *withMessage) Cause() error { return w.cause } +func (w *withMessage) HasStack() bool { return w.causeHasStack } func (w *withMessage) Format(s fmt.State, verb rune) { switch verb { @@ -254,16 +287,35 @@ func (w *withMessage) Format(s fmt.State, verb rune) { // be returned. If the error is nil, nil will be returned without further // investigation. func Cause(err error) error { + cause := Unwrap(err) + if cause == nil { + return err + } + return Cause(cause) +} + +// Unwrap uses causer to return the next error in the chain or nil. +// This goes one-level deeper, whereas Cause goes as far as possible +func Unwrap(err error) error { type causer interface { Cause() error } + if unErr, ok := err.(causer); ok { + return unErr.Cause() + } + return nil +} - for err != nil { - cause, ok := err.(causer) - if !ok { - break +// Find an error in the chain that matches a test function. +// returns nil if no error is found. +func Find(origErr error, test func(error) bool) error { + var foundErr error + WalkDeep(origErr, func(err error) bool { + if test(err) { + foundErr = err + return true } - err = cause.Cause() - } - return err + return false + }) + return foundErr } diff --git a/vendor/github.com/pkg/errors/stack.go b/vendor/github.com/pkg/errors/stack.go index 6b1f2891a5ac..bb1e6a84f339 100644 --- a/vendor/github.com/pkg/errors/stack.go +++ b/vendor/github.com/pkg/errors/stack.go @@ -1,13 +1,37 @@ package errors import ( + "bytes" "fmt" "io" "path" "runtime" + "strconv" "strings" ) +// StackTracer retrieves the StackTrace +// Generally you would want to use the GetStackTracer function to do that. +type StackTracer interface { + StackTrace() StackTrace +} + +// GetStackTracer will return the first StackTracer in the causer chain. +// This function is used by AddStack to avoid creating redundant stack traces. +// +// You can also use the StackTracer interface on the returned error to get the stack trace. +func GetStackTracer(origErr error) StackTracer { + var stacked StackTracer + WalkDeep(origErr, func(err error) bool { + if stackTracer, ok := err.(StackTracer); ok { + stacked = stackTracer + return true + } + return false + }) + return stacked +} + // Frame represents a program counter inside a stack frame. type Frame uintptr @@ -46,9 +70,15 @@ func (f Frame) line() int { // // Format accepts flags that alter the printing of some verbs, as follows: // -// %+s path of source file relative to the compile time GOPATH +// %+s function name and path of source file relative to the compile time +// GOPATH separated by \n\t (\n\t) // %+v equivalent to %+s:%d func (f Frame) Format(s fmt.State, verb rune) { + f.format(s, s, verb) +} + +// format allows stack trace printing calls to be made with a bytes.Buffer. +func (f Frame) format(w io.Writer, s fmt.State, verb rune) { switch verb { case 's': switch { @@ -56,47 +86,84 @@ func (f Frame) Format(s fmt.State, verb rune) { pc := f.pc() fn := runtime.FuncForPC(pc) if fn == nil { - io.WriteString(s, "unknown") + io.WriteString(w, "unknown") } else { file, _ := fn.FileLine(pc) - fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file) + io.WriteString(w, fn.Name()) + io.WriteString(w, "\n\t") + io.WriteString(w, file) } default: - io.WriteString(s, path.Base(f.file())) + io.WriteString(w, path.Base(f.file())) } case 'd': - fmt.Fprintf(s, "%d", f.line()) + io.WriteString(w, strconv.Itoa(f.line())) case 'n': name := runtime.FuncForPC(f.pc()).Name() - io.WriteString(s, funcname(name)) + io.WriteString(w, funcname(name)) case 'v': - f.Format(s, 's') - io.WriteString(s, ":") - f.Format(s, 'd') + f.format(w, s, 's') + io.WriteString(w, ":") + f.format(w, s, 'd') } } // StackTrace is stack of Frames from innermost (newest) to outermost (oldest). type StackTrace []Frame +// Format formats the stack of Frames according to the fmt.Formatter interface. +// +// %s lists source files for each Frame in the stack +// %v lists the source file and line number for each Frame in the stack +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+v Prints filename, function, and line number for each Frame in the stack. func (st StackTrace) Format(s fmt.State, verb rune) { + var b bytes.Buffer switch verb { case 'v': switch { case s.Flag('+'): - for _, f := range st { - fmt.Fprintf(s, "\n%+v", f) + b.Grow(len(st) * stackMinLen) + for _, fr := range st { + b.WriteByte('\n') + fr.format(&b, s, verb) } case s.Flag('#'): - fmt.Fprintf(s, "%#v", []Frame(st)) + fmt.Fprintf(&b, "%#v", []Frame(st)) default: - fmt.Fprintf(s, "%v", []Frame(st)) + st.formatSlice(&b, s, verb) } case 's': - fmt.Fprintf(s, "%s", []Frame(st)) + st.formatSlice(&b, s, verb) } + io.Copy(s, &b) } +// formatSlice will format this StackTrace into the given buffer as a slice of +// Frame, only valid when called with '%s' or '%v'. +func (st StackTrace) formatSlice(b *bytes.Buffer, s fmt.State, verb rune) { + b.WriteByte('[') + if len(st) == 0 { + b.WriteByte(']') + return + } + + b.Grow(len(st) * (stackMinLen / 4)) + st[0].format(b, s, verb) + for _, fr := range st[1:] { + b.WriteByte(' ') + fr.format(b, s, verb) + } + b.WriteByte(']') +} + +// stackMinLen is a best-guess at the minimum length of a stack trace. It +// doesn't need to be exact, just give a good enough head start for the buffer +// to avoid the expensive early growth. +const stackMinLen = 96 + // stack represents a stack of program counters. type stack []uintptr @@ -105,10 +172,14 @@ func (s *stack) Format(st fmt.State, verb rune) { case 'v': switch { case st.Flag('+'): + var b bytes.Buffer + b.Grow(len(*s) * stackMinLen) for _, pc := range *s { f := Frame(pc) - fmt.Fprintf(st, "\n%+v", f) + b.WriteByte('\n') + f.format(&b, st, 'v') } + io.Copy(st, &b) } } } @@ -122,9 +193,13 @@ func (s *stack) StackTrace() StackTrace { } func callers() *stack { + return callersSkip(4) +} + +func callersSkip(skip int) *stack { const depth = 32 var pcs [depth]uintptr - n := runtime.Callers(3, pcs[:]) + n := runtime.Callers(skip, pcs[:]) var st stack = pcs[0:n] return &st } @@ -137,42 +212,15 @@ func funcname(name string) string { return name[i+1:] } -func trimGOPATH(name, file string) string { - // Here we want to get the source file path relative to the compile time - // GOPATH. As of Go 1.6.x there is no direct way to know the compiled - // GOPATH at runtime, but we can infer the number of path segments in the - // GOPATH. We note that fn.Name() returns the function name qualified by - // the import path, which does not include the GOPATH. Thus we can trim - // segments from the beginning of the file path until the number of path - // separators remaining is one more than the number of path separators in - // the function name. For example, given: - // - // GOPATH /home/user - // file /home/user/src/pkg/sub/file.go - // fn.Name() pkg/sub.Type.Method - // - // We want to produce: - // - // pkg/sub/file.go - // - // From this we can easily see that fn.Name() has one less path separator - // than our desired output. We count separators from the end of the file - // path until it finds two more than in the function name and then move - // one character forward to preserve the initial path segment without a - // leading separator. - const sep = "/" - goal := strings.Count(name, sep) + 2 - i := len(file) - for n := 0; n < goal; n++ { - i = strings.LastIndex(file[:i], sep) - if i == -1 { - // not enough separators found, set i so that the slice expression - // below leaves file unmodified - i = -len(sep) - break - } - } - // get back to 0 or trim the leading separator - file = file[i+len(sep):] - return file +// NewStack is for library implementers that want to generate a stack trace. +// Normally you should insted use AddStack to get an error with a stack trace. +// +// The result of this function can be turned into a stack trace by calling .StackTrace() +// +// This function takes an argument for the number of stack frames to skip. +// This avoids putting stack generation function calls like this one in the stack trace. +// A value of 0 will give you the line that called NewStack(0) +// A library author wrapping this in their own function will want to use a value of at least 1. +func NewStack(skip int) StackTracer { + return callersSkip(skip + 3) }