mirror of https://github.com/grafana/grafana
Chore: Use x/xerrors instead of pkg/errors (#16668)
* Use xerrors instead of pkg/errors * Add Wrap util func * Move Wrap to errutil packagepull/16724/head
parent
54c1bf0cc9
commit
c429934a66
@ -0,0 +1,11 @@ |
||||
package errutil |
||||
|
||||
import "golang.org/x/xerrors" |
||||
|
||||
// Wrap is a simple wrapper around Errorf that is doing error wrapping. You can read how that works in
|
||||
// https://godoc.org/golang.org/x/xerrors#Errorf but its API is very implicit which is a reason for this wrapper.
|
||||
// There is also a discussion (https://github.com/golang/go/issues/29934) where many comments make arguments for such
|
||||
// wrapper so hopefully it will be added in the standard lib later.
|
||||
func Wrap(message string, err error) error { |
||||
return xerrors.Errorf("%v: %w", message, err) |
||||
} |
||||
@ -0,0 +1,27 @@ |
||||
Copyright (c) 2019 The Go Authors. All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are |
||||
met: |
||||
|
||||
* Redistributions of source code must retain the above copyright |
||||
notice, this list of conditions and the following disclaimer. |
||||
* Redistributions in binary form must reproduce the above |
||||
copyright notice, this list of conditions and the following disclaimer |
||||
in the documentation and/or other materials provided with the |
||||
distribution. |
||||
* Neither the name of Google Inc. nor the names of its |
||||
contributors may be used to endorse or promote products derived from |
||||
this software without specific prior written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
@ -0,0 +1,22 @@ |
||||
Additional IP Rights Grant (Patents) |
||||
|
||||
"This implementation" means the copyrightable works distributed by |
||||
Google as part of the Go project. |
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive, |
||||
no-charge, royalty-free, irrevocable (except as stated in this section) |
||||
patent license to make, have made, use, offer to sell, sell, import, |
||||
transfer and otherwise run, modify and propagate the contents of this |
||||
implementation of Go, where such license applies only to those patent |
||||
claims, both currently owned or controlled by Google and acquired in |
||||
the future, licensable by Google that are necessarily infringed by this |
||||
implementation of Go. This grant does not include claims that would be |
||||
infringed only as a consequence of further modification of this |
||||
implementation. If you or your agent or exclusive licensee institute or |
||||
order or agree to the institution of patent litigation against any |
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging |
||||
that this implementation of Go or any code incorporated within this |
||||
implementation of Go constitutes direct or contributory patent |
||||
infringement, or inducement of patent infringement, then any patent |
||||
rights granted to you under this License for this implementation of Go |
||||
shall terminate as of the date such litigation is filed. |
||||
@ -0,0 +1,2 @@ |
||||
This repository holds the transition packages for the new Go 1.13 error values. |
||||
See golang.org/design/29934-error-values. |
||||
@ -0,0 +1,195 @@ |
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.13
|
||||
|
||||
package xerrors |
||||
|
||||
import ( |
||||
"bytes" |
||||
"fmt" |
||||
"io" |
||||
"reflect" |
||||
"strconv" |
||||
) |
||||
|
||||
// FormatError calls the FormatError method of f with an errors.Printer
|
||||
// configured according to s and verb, and writes the result to s.
|
||||
func FormatError(f Formatter, s fmt.State, verb rune) { |
||||
// Assuming this function is only called from the Format method, and given
|
||||
// that FormatError takes precedence over Format, it cannot be called from
|
||||
// any package that supports errors.Formatter. It is therefore safe to
|
||||
// disregard that State may be a specific printer implementation and use one
|
||||
// of our choice instead.
|
||||
|
||||
// limitations: does not support printing error as Go struct.
|
||||
|
||||
var ( |
||||
sep = " " // separator before next error
|
||||
p = &state{State: s} |
||||
direct = true |
||||
) |
||||
|
||||
var err error = f |
||||
|
||||
switch verb { |
||||
// Note that this switch must match the preference order
|
||||
// for ordinary string printing (%#v before %+v, and so on).
|
||||
|
||||
case 'v': |
||||
if s.Flag('#') { |
||||
if stringer, ok := err.(fmt.GoStringer); ok { |
||||
io.WriteString(&p.buf, stringer.GoString()) |
||||
goto exit |
||||
} |
||||
// proceed as if it were %v
|
||||
} else if s.Flag('+') { |
||||
p.printDetail = true |
||||
sep = "\n - " |
||||
} |
||||
case 's': |
||||
case 'q', 'x', 'X': |
||||
// Use an intermediate buffer in the rare cases that precision,
|
||||
// truncation, or one of the alternative verbs (q, x, and X) are
|
||||
// specified.
|
||||
direct = false |
||||
|
||||
default: |
||||
p.buf.WriteString("%!") |
||||
p.buf.WriteRune(verb) |
||||
p.buf.WriteByte('(') |
||||
switch { |
||||
case err != nil: |
||||
p.buf.WriteString(reflect.TypeOf(f).String()) |
||||
default: |
||||
p.buf.WriteString("<nil>") |
||||
} |
||||
p.buf.WriteByte(')') |
||||
io.Copy(s, &p.buf) |
||||
return |
||||
} |
||||
|
||||
loop: |
||||
for { |
||||
switch v := err.(type) { |
||||
case Formatter: |
||||
err = v.FormatError((*printer)(p)) |
||||
case fmt.Formatter: |
||||
v.Format(p, 'v') |
||||
break loop |
||||
default: |
||||
io.WriteString(&p.buf, v.Error()) |
||||
break loop |
||||
} |
||||
if err == nil { |
||||
break |
||||
} |
||||
if p.needColon || !p.printDetail { |
||||
p.buf.WriteByte(':') |
||||
p.needColon = false |
||||
} |
||||
p.buf.WriteString(sep) |
||||
p.inDetail = false |
||||
p.needNewline = false |
||||
} |
||||
|
||||
exit: |
||||
width, okW := s.Width() |
||||
prec, okP := s.Precision() |
||||
|
||||
if !direct || (okW && width > 0) || okP { |
||||
// Construct format string from State s.
|
||||
format := []byte{'%'} |
||||
if s.Flag('-') { |
||||
format = append(format, '-') |
||||
} |
||||
if s.Flag('+') { |
||||
format = append(format, '+') |
||||
} |
||||
if s.Flag(' ') { |
||||
format = append(format, ' ') |
||||
} |
||||
if okW { |
||||
format = strconv.AppendInt(format, int64(width), 10) |
||||
} |
||||
if okP { |
||||
format = append(format, '.') |
||||
format = strconv.AppendInt(format, int64(prec), 10) |
||||
} |
||||
format = append(format, string(verb)...) |
||||
fmt.Fprintf(s, string(format), p.buf.String()) |
||||
} else { |
||||
io.Copy(s, &p.buf) |
||||
} |
||||
} |
||||
|
||||
var detailSep = []byte("\n ") |
||||
|
||||
// state tracks error printing state. It implements fmt.State.
|
||||
type state struct { |
||||
fmt.State |
||||
buf bytes.Buffer |
||||
|
||||
printDetail bool |
||||
inDetail bool |
||||
needColon bool |
||||
needNewline bool |
||||
} |
||||
|
||||
func (s *state) Write(b []byte) (n int, err error) { |
||||
if s.printDetail { |
||||
if len(b) == 0 { |
||||
return 0, nil |
||||
} |
||||
if s.inDetail && s.needColon { |
||||
s.needNewline = true |
||||
if b[0] == '\n' { |
||||
b = b[1:] |
||||
} |
||||
} |
||||
k := 0 |
||||
for i, c := range b { |
||||
if s.needNewline { |
||||
if s.inDetail && s.needColon { |
||||
s.buf.WriteByte(':') |
||||
s.needColon = false |
||||
} |
||||
s.buf.Write(detailSep) |
||||
s.needNewline = false |
||||
} |
||||
if c == '\n' { |
||||
s.buf.Write(b[k:i]) |
||||
k = i + 1 |
||||
s.needNewline = true |
||||
} |
||||
} |
||||
s.buf.Write(b[k:]) |
||||
if !s.inDetail { |
||||
s.needColon = true |
||||
} |
||||
} else if !s.inDetail { |
||||
s.buf.Write(b) |
||||
} |
||||
return len(b), nil |
||||
} |
||||
|
||||
// printer wraps a state to implement an xerrors.Printer.
|
||||
type printer state |
||||
|
||||
func (s *printer) Print(args ...interface{}) { |
||||
if !s.inDetail || s.printDetail { |
||||
fmt.Fprint((*state)(s), args...) |
||||
} |
||||
} |
||||
|
||||
func (s *printer) Printf(format string, args ...interface{}) { |
||||
if !s.inDetail || s.printDetail { |
||||
fmt.Fprintf((*state)(s), format, args...) |
||||
} |
||||
} |
||||
|
||||
func (s *printer) Detail() bool { |
||||
s.inDetail = true |
||||
return s.printDetail |
||||
} |
||||
@ -0,0 +1,55 @@ |
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.13
|
||||
|
||||
package xerrors |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"strconv" |
||||
) |
||||
|
||||
// A Frame contains part of a call stack.
|
||||
type Frame = errors.Frame |
||||
|
||||
// Caller returns a Frame that describes a frame on the caller's stack.
|
||||
// The argument skip is the number of frames to skip over.
|
||||
// Caller(0) returns the frame for the caller of Caller.
|
||||
var Caller func(skip int) Frame = errors.Caller |
||||
|
||||
// FormatError calls the FormatError method of f with an errors.Printer
|
||||
// configured according to s and verb, and writes the result to s.
|
||||
func FormatError(f Formatter, s fmt.State, verb rune) { |
||||
// Assuming this function is only called from the Format method, and given
|
||||
// that FormatError takes precedence over Format, it cannot be called from
|
||||
// any package that supports errors.Formatter. It is therefore safe to
|
||||
// disregard that State may be a specific printer implementation and use one
|
||||
// of our choice instead.
|
||||
|
||||
width, okW := s.Width() |
||||
prec, okP := s.Precision() |
||||
|
||||
// Construct format string from State s.
|
||||
format := []byte{'%'} |
||||
if s.Flag('-') { |
||||
format = append(format, '-') |
||||
} |
||||
if s.Flag('+') { |
||||
format = append(format, '+') |
||||
} |
||||
if s.Flag(' ') { |
||||
format = append(format, ' ') |
||||
} |
||||
if okW { |
||||
format = strconv.AppendInt(format, int64(width), 10) |
||||
} |
||||
if okP { |
||||
format = append(format, '.') |
||||
format = strconv.AppendInt(format, int64(prec), 10) |
||||
} |
||||
format = append(format, string(verb)...) |
||||
fmt.Fprintf(s, string(format), f) |
||||
} |
||||
@ -0,0 +1,25 @@ |
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package xerrors implements functions to manipulate errors.
|
||||
//
|
||||
// This package supports transitioning to the Go 2 proposal for error values:
|
||||
// https://golang.org/design/29934-error-values
|
||||
//
|
||||
// Most of the functions and types in this package will be incorporated into the
|
||||
// standard library's errors package in Go 1.13; the behavior of this package's
|
||||
// Errorf function will be incorporated into the standard library's fmt.Errorf.
|
||||
// Use this package to get equivalent behavior in all supported Go versions. For
|
||||
// example, create errors using
|
||||
//
|
||||
// xerrors.New("write failed")
|
||||
//
|
||||
// or
|
||||
//
|
||||
// xerrors.Errorf("while reading: %v", err)
|
||||
//
|
||||
// If you want your error type to participate in the new formatting
|
||||
// implementation for %v and %+v, provide it with a Format method that calls
|
||||
// xerrors.FormatError, as shown in the example for FormatError.
|
||||
package xerrors // import "golang.org/x/xerrors"
|
||||
@ -0,0 +1,33 @@ |
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xerrors |
||||
|
||||
import "fmt" |
||||
|
||||
// errorString is a trivial implementation of error.
|
||||
type errorString struct { |
||||
s string |
||||
frame Frame |
||||
} |
||||
|
||||
// New returns an error that formats as the given text.
|
||||
//
|
||||
// The returned error contains a Frame set to the caller's location and
|
||||
// implements Formatter to show this information when printed with details.
|
||||
func New(text string) error { |
||||
return &errorString{text, Caller(1)} |
||||
} |
||||
|
||||
func (e *errorString) Error() string { |
||||
return e.s |
||||
} |
||||
|
||||
func (e *errorString) Format(s fmt.State, v rune) { FormatError(e, s, v) } |
||||
|
||||
func (e *errorString) FormatError(p Printer) (next error) { |
||||
p.Print(e.s) |
||||
e.frame.Format(p) |
||||
return nil |
||||
} |
||||
@ -0,0 +1,109 @@ |
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xerrors |
||||
|
||||
import ( |
||||
"fmt" |
||||
"strings" |
||||
|
||||
"golang.org/x/xerrors/internal" |
||||
) |
||||
|
||||
// Errorf formats according to a format specifier and returns the string as a
|
||||
// value that satisfies error.
|
||||
//
|
||||
// The returned error includes the file and line number of the caller when
|
||||
// formatted with additional detail enabled. If the last argument is an error
|
||||
// the returned error's Format method will return it if the format string ends
|
||||
// with ": %s", ": %v", or ": %w". If the last argument is an error and the
|
||||
// format string ends with ": %w", the returned error implements Wrapper
|
||||
// with an Unwrap method returning it.
|
||||
func Errorf(format string, a ...interface{}) error { |
||||
err, wrap := lastError(format, a) |
||||
format = formatPlusW(format) |
||||
if err == nil { |
||||
return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)} |
||||
} |
||||
|
||||
// TODO: this is not entirely correct. The error value could be
|
||||
// printed elsewhere in format if it mixes numbered with unnumbered
|
||||
// substitutions. With relatively small changes to doPrintf we can
|
||||
// have it optionally ignore extra arguments and pass the argument
|
||||
// list in its entirety.
|
||||
msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...) |
||||
frame := Frame{} |
||||
if internal.EnableTrace { |
||||
frame = Caller(1) |
||||
} |
||||
if wrap { |
||||
return &wrapError{msg, err, frame} |
||||
} |
||||
return &noWrapError{msg, err, frame} |
||||
} |
||||
|
||||
// formatPlusW is used to avoid the vet check that will barf at %w.
|
||||
func formatPlusW(s string) string { |
||||
return s |
||||
} |
||||
|
||||
func lastError(format string, a []interface{}) (err error, wrap bool) { |
||||
wrap = strings.HasSuffix(format, ": %w") |
||||
if !wrap && |
||||
!strings.HasSuffix(format, ": %s") && |
||||
!strings.HasSuffix(format, ": %v") { |
||||
return nil, false |
||||
} |
||||
|
||||
if len(a) == 0 { |
||||
return nil, false |
||||
} |
||||
|
||||
err, ok := a[len(a)-1].(error) |
||||
if !ok { |
||||
return nil, false |
||||
} |
||||
|
||||
return err, wrap |
||||
} |
||||
|
||||
type noWrapError struct { |
||||
msg string |
||||
err error |
||||
frame Frame |
||||
} |
||||
|
||||
func (e *noWrapError) Error() string { |
||||
return fmt.Sprint(e) |
||||
} |
||||
|
||||
func (e *noWrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) } |
||||
|
||||
func (e *noWrapError) FormatError(p Printer) (next error) { |
||||
p.Print(e.msg) |
||||
e.frame.Format(p) |
||||
return e.err |
||||
} |
||||
|
||||
type wrapError struct { |
||||
msg string |
||||
err error |
||||
frame Frame |
||||
} |
||||
|
||||
func (e *wrapError) Error() string { |
||||
return fmt.Sprint(e) |
||||
} |
||||
|
||||
func (e *wrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) } |
||||
|
||||
func (e *wrapError) FormatError(p Printer) (next error) { |
||||
p.Print(e.msg) |
||||
e.frame.Format(p) |
||||
return e.err |
||||
} |
||||
|
||||
func (e *wrapError) Unwrap() error { |
||||
return e.err |
||||
} |
||||
@ -0,0 +1,36 @@ |
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.13
|
||||
|
||||
package xerrors |
||||
|
||||
// A Formatter formats error messages.
|
||||
type Formatter interface { |
||||
error |
||||
|
||||
// FormatError prints the receiver's first error and returns the next error in
|
||||
// the error chain, if any.
|
||||
FormatError(p Printer) (next error) |
||||
} |
||||
|
||||
// A Printer formats error messages.
|
||||
//
|
||||
// The most common implementation of Printer is the one provided by package fmt
|
||||
// during Printf (as of Go 1.13). Localization packages such as golang.org/x/text/message
|
||||
// typically provide their own implementations.
|
||||
type Printer interface { |
||||
// Print appends args to the message output.
|
||||
Print(args ...interface{}) |
||||
|
||||
// Printf writes a formatted string.
|
||||
Printf(format string, args ...interface{}) |
||||
|
||||
// Detail reports whether error detail is requested.
|
||||
// After the first call to Detail, all text written to the Printer
|
||||
// is formatted as additional detail, or ignored when
|
||||
// detail has not been requested.
|
||||
// If Detail returns false, the caller can avoid printing the detail at all.
|
||||
Detail() bool |
||||
} |
||||
@ -0,0 +1,19 @@ |
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.13
|
||||
|
||||
package xerrors |
||||
|
||||
import "errors" |
||||
|
||||
// A Formatter formats error messages.
|
||||
type Formatter = errors.Formatter |
||||
|
||||
// A Printer formats error messages.
|
||||
//
|
||||
// The most common implementation of Printer is the one provided by package fmt
|
||||
// during Printf (as of Go 1.13). Localization packages such as golang.org/x/text/message
|
||||
// typically provide their own implementations.
|
||||
type Printer = errors.Printer |
||||
@ -0,0 +1,58 @@ |
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.13
|
||||
|
||||
package xerrors |
||||
|
||||
import ( |
||||
"runtime" |
||||
) |
||||
|
||||
// A Frame contains part of a call stack.
|
||||
type Frame struct { |
||||
// Make room for three PCs: the one we were asked for, what it called,
|
||||
// and possibly a PC for skipPleaseUseCallersFrames. See:
|
||||
// https://go.googlesource.com/go/+/032678e0fb/src/runtime/extern.go#169
|
||||
frames [3]uintptr |
||||
} |
||||
|
||||
// Caller returns a Frame that describes a frame on the caller's stack.
|
||||
// The argument skip is the number of frames to skip over.
|
||||
// Caller(0) returns the frame for the caller of Caller.
|
||||
func Caller(skip int) Frame { |
||||
var s Frame |
||||
runtime.Callers(skip+1, s.frames[:]) |
||||
return s |
||||
} |
||||
|
||||
// location reports the file, line, and function of a frame.
|
||||
//
|
||||
// The returned function may be "" even if file and line are not.
|
||||
func (f Frame) location() (function, file string, line int) { |
||||
frames := runtime.CallersFrames(f.frames[:]) |
||||
if _, ok := frames.Next(); !ok { |
||||
return "", "", 0 |
||||
} |
||||
fr, ok := frames.Next() |
||||
if !ok { |
||||
return "", "", 0 |
||||
} |
||||
return fr.Function, fr.File, fr.Line |
||||
} |
||||
|
||||
// Format prints the stack as error detail.
|
||||
// It should be called from an error's Format implementation
|
||||
// after printing any other error detail.
|
||||
func (f Frame) Format(p Printer) { |
||||
if p.Detail() { |
||||
function, file, line := f.location() |
||||
if function != "" { |
||||
p.Printf("%s\n ", function) |
||||
} |
||||
if file != "" { |
||||
p.Printf("%s:%d\n", file, line) |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,3 @@ |
||||
module golang.org/x/xerrors |
||||
|
||||
go 1.11 |
||||
@ -0,0 +1,8 @@ |
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package internal |
||||
|
||||
// EnableTrace indicates whether stack information should be recorded in errors.
|
||||
var EnableTrace = true |
||||
@ -0,0 +1,104 @@ |
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package xerrors |
||||
|
||||
import ( |
||||
"reflect" |
||||
) |
||||
|
||||
// A Wrapper provides context around another error.
|
||||
type Wrapper interface { |
||||
// Unwrap returns the next error in the error chain.
|
||||
// If there is no next error, Unwrap returns nil.
|
||||
Unwrap() error |
||||
} |
||||
|
||||
// Opaque returns an error with the same error formatting as err
|
||||
// but that does not match err and cannot be unwrapped.
|
||||
func Opaque(err error) error { |
||||
return noWrapper{err} |
||||
} |
||||
|
||||
type noWrapper struct { |
||||
error |
||||
} |
||||
|
||||
func (e noWrapper) FormatError(p Printer) (next error) { |
||||
if f, ok := e.error.(Formatter); ok { |
||||
return f.FormatError(p) |
||||
} |
||||
p.Print(e.error) |
||||
return nil |
||||
} |
||||
|
||||
// Unwrap returns the result of calling the Unwrap method on err, if err implements
|
||||
// Unwrap. Otherwise, Unwrap returns nil.
|
||||
func Unwrap(err error) error { |
||||
u, ok := err.(Wrapper) |
||||
if !ok { |
||||
return nil |
||||
} |
||||
return u.Unwrap() |
||||
} |
||||
|
||||
// Is reports whether any error in err's chain matches target.
|
||||
//
|
||||
// An error is considered to match a target if it is equal to that target or if
|
||||
// it implements a method Is(error) bool such that Is(target) returns true.
|
||||
func Is(err, target error) bool { |
||||
if target == nil { |
||||
return err == target |
||||
} |
||||
for { |
||||
if err == target { |
||||
return true |
||||
} |
||||
if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) { |
||||
return true |
||||
} |
||||
// TODO: consider supporing target.Is(err). This would allow
|
||||
// user-definable predicates, but also may allow for coping with sloppy
|
||||
// APIs, thereby making it easier to get away with them.
|
||||
if err = Unwrap(err); err == nil { |
||||
return false |
||||
} |
||||
} |
||||
} |
||||
|
||||
// As finds the first error in err's chain that matches the type to which target
|
||||
// points, and if so, sets the target to its value and returns true. An error
|
||||
// matches a type if it is assignable to the target type, or if it has a method
|
||||
// As(interface{}) bool such that As(target) returns true. As will panic if target
|
||||
// is not a non-nil pointer to a type which implements error or is of interface type.
|
||||
//
|
||||
// The As method should set the target to its value and return true if err
|
||||
// matches the type to which target points.
|
||||
func As(err error, target interface{}) bool { |
||||
if target == nil { |
||||
panic("errors: target cannot be nil") |
||||
} |
||||
val := reflect.ValueOf(target) |
||||
typ := val.Type() |
||||
if typ.Kind() != reflect.Ptr || val.IsNil() { |
||||
panic("errors: target must be a non-nil pointer") |
||||
} |
||||
if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) { |
||||
panic("errors: *target must be interface or implement error") |
||||
} |
||||
targetType := typ.Elem() |
||||
for err != nil { |
||||
if reflect.TypeOf(err).AssignableTo(targetType) { |
||||
val.Elem().Set(reflect.ValueOf(err)) |
||||
return true |
||||
} |
||||
if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) { |
||||
return true |
||||
} |
||||
err = Unwrap(err) |
||||
} |
||||
return false |
||||
} |
||||
|
||||
var errorType = reflect.TypeOf((*error)(nil)).Elem() |
||||
Loading…
Reference in new issue