mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
rebase: vendor files required for kmip
Signed-off-by: Rakshith R <rar@redhat.com>
This commit is contained in:
334
vendor/github.com/ansel1/merry/v2/errors.go
generated
vendored
Normal file
334
vendor/github.com/ansel1/merry/v2/errors.go
generated
vendored
Normal file
@ -0,0 +1,334 @@
|
||||
package merry
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// New creates a new error, with a stack attached. The equivalent of golang's errors.New()
|
||||
func New(msg string, wrappers ...Wrapper) error {
|
||||
return WrapSkipping(errors.New(msg), 1, wrappers...)
|
||||
}
|
||||
|
||||
// Errorf creates a new error with a formatted message and a stack. The equivalent of golang's fmt.Errorf().
|
||||
// args may contain either arguments to format, or Wrapper options, which will be applied to the error.
|
||||
func Errorf(format string, args ...interface{}) error {
|
||||
fmtArgs, wrappers := splitWrappers(args)
|
||||
|
||||
return WrapSkipping(fmt.Errorf(format, fmtArgs...), 1, wrappers...)
|
||||
}
|
||||
|
||||
// Sentinel creates an error without running hooks or capturing a stack. It is intended
|
||||
// to create sentinel errors, which will be wrapped with a stack later from where the
|
||||
// error is returned. At that time, a stack will be captured and hooks will be run.
|
||||
//
|
||||
// var ErrNotFound = merry.Sentinel("not found", merry.WithHTTPCode(404))
|
||||
//
|
||||
// func FindUser(name string) (*User, error) {
|
||||
// // some db code which fails to find a user
|
||||
// return nil, merry.Wrap(ErrNotFound)
|
||||
// }
|
||||
//
|
||||
// func main() {
|
||||
// _, err := FindUser("bob")
|
||||
// fmt.Println(errors.Is(err, ErrNotFound) // "true"
|
||||
// fmt.Println(merry.Details(err)) // stacktrace will start at the return statement
|
||||
// // in FindUser()
|
||||
// }
|
||||
func Sentinel(msg string, wrappers ...Wrapper) error {
|
||||
return ApplySkipping(errors.New(msg), 1, wrappers...)
|
||||
}
|
||||
|
||||
// Sentinelf is like Sentinel, but takes a formatted message. args can be a mix of
|
||||
// format arguments and Wrappers.
|
||||
func Sentinelf(format string, args ...interface{}) error {
|
||||
fmtArgs, wrappers := splitWrappers(args)
|
||||
|
||||
return ApplySkipping(fmt.Errorf(format, fmtArgs...), 1, wrappers...)
|
||||
}
|
||||
|
||||
func splitWrappers(args []interface{}) ([]interface{}, []Wrapper) {
|
||||
var wrappers []Wrapper
|
||||
|
||||
// pull out the args which are wrappers
|
||||
n := 0
|
||||
for _, arg := range args {
|
||||
if w, ok := arg.(Wrapper); ok {
|
||||
wrappers = append(wrappers, w)
|
||||
} else {
|
||||
args[n] = arg
|
||||
n++
|
||||
}
|
||||
}
|
||||
args = args[:n]
|
||||
|
||||
return args, wrappers
|
||||
}
|
||||
|
||||
// Wrap adds context to errors by applying Wrappers. See WithXXX() functions for Wrappers supplied
|
||||
// by this package.
|
||||
//
|
||||
// If StackCaptureEnabled is true, a stack starting at the caller will be automatically captured
|
||||
// and attached to the error. This behavior can be overridden with wrappers which either capture
|
||||
// their own stacks, or suppress auto capture.
|
||||
//
|
||||
// If err is nil, returns nil.
|
||||
func Wrap(err error, wrappers ...Wrapper) error {
|
||||
return WrapSkipping(err, 1, wrappers...)
|
||||
}
|
||||
|
||||
// WrapSkipping is like Wrap, but the captured stacks will start `skip` frames
|
||||
// further up the call stack. If skip is 0, it behaves the same as Wrap.
|
||||
func WrapSkipping(err error, skip int, wrappers ...Wrapper) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(onceHooks) > 0 {
|
||||
if _, ok := Lookup(err, errKeyHooked); !ok {
|
||||
err = ApplySkipping(err, skip+1, onceHooks...)
|
||||
err = ApplySkipping(err, skip+1, WithValue(errKeyHooked, err))
|
||||
}
|
||||
}
|
||||
err = ApplySkipping(err, skip+1, hooks...)
|
||||
err = ApplySkipping(err, skip+1, wrappers...)
|
||||
return captureStack(err, skip+1, false)
|
||||
}
|
||||
|
||||
// Apply is like Wrap, but does not execute hooks or do automatic stack capture. It just
|
||||
// applies the wrappers to the error.
|
||||
func Apply(err error, wrappers ...Wrapper) error {
|
||||
return ApplySkipping(err, 1, wrappers...)
|
||||
}
|
||||
|
||||
// ApplySkipping is like WrapSkipping, but does not execute hooks or do automatic stack capture. It just
|
||||
// applies the wrappers to the error. It is useful in Wrapper implementations which
|
||||
// // want to apply other Wrappers without starting an infinite recursion.
|
||||
func ApplySkipping(err error, skip int, wrappers ...Wrapper) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, w := range wrappers {
|
||||
err = w.Wrap(err, skip+1)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Prepend is a convenience function for the PrependMessage wrapper. It eases migration
|
||||
// from merry v1. It accepts a varargs of additional Wrappers.
|
||||
func Prepend(err error, msg string, wrappers ...Wrapper) error {
|
||||
return WrapSkipping(err, 1, append(wrappers, PrependMessage(msg))...)
|
||||
}
|
||||
|
||||
// Prependf is a convenience function for the PrependMessagef wrapper. It eases migration
|
||||
// from merry v1. The args can be format arguments mixed with Wrappers.
|
||||
func Prependf(err error, format string, args ...interface{}) error {
|
||||
fmtArgs, wrappers := splitWrappers(args)
|
||||
|
||||
return WrapSkipping(err, 1, append(wrappers, PrependMessagef(format, fmtArgs...))...)
|
||||
}
|
||||
|
||||
// Append is a convenience function for the AppendMessage wrapper. It eases migration
|
||||
// from merry v1. It accepts a varargs of additional Wrappers.
|
||||
func Append(err error, msg string, wrappers ...Wrapper) error {
|
||||
return WrapSkipping(err, 1, append(wrappers, AppendMessage(msg))...)
|
||||
}
|
||||
|
||||
// Appendf is a convenience function for the AppendMessagef wrapper. It eases migration
|
||||
// from merry v1. The args can be format arguments mixed with Wrappers.
|
||||
func Appendf(err error, format string, args ...interface{}) error {
|
||||
fmtArgs, wrappers := splitWrappers(args)
|
||||
|
||||
return WrapSkipping(err, 1, append(wrappers, AppendMessagef(format, fmtArgs...))...)
|
||||
}
|
||||
|
||||
// Value returns the value for key, or nil if not set.
|
||||
// If e is nil, returns nil. Will not search causes.
|
||||
func Value(err error, key interface{}) interface{} {
|
||||
v, _ := Lookup(err, key)
|
||||
return v
|
||||
}
|
||||
|
||||
// Lookup returns the value for the key, and a boolean indicating
|
||||
// whether the value was set. Will not search causes.
|
||||
//
|
||||
// if err is nil, returns nil and false.
|
||||
func Lookup(err error, key interface{}) (interface{}, bool) {
|
||||
var merr interface {
|
||||
error
|
||||
isMerryError()
|
||||
}
|
||||
|
||||
// I've tried implementing this logic a few different ways. It's tricky:
|
||||
//
|
||||
// - Lookup should only search the current error, but not causes. errWithCause's
|
||||
// Unwrap() will eventually unwrap to the cause, so we don't want to just
|
||||
// search the entire stream of errors returned by Unwrap.
|
||||
// - We need to handle cases where error implementations created outside
|
||||
// this package are in the middle of the chain. We need to use Unwrap
|
||||
// in these cases to traverse those errors and dig down to the next
|
||||
// merry error.
|
||||
// - Some error packages, including our own, do funky stuff with Unwrap(),
|
||||
// returning shim types to control the unwrapping order, rather than
|
||||
// the actual, raw wrapped error. Typically, these shims implement
|
||||
// Is/As to delegate to the raw error they encapsulate, but implement
|
||||
// Unwrap by encapsulating the raw error in another shim. So if we're looking
|
||||
// for a raw error type, we can't just use Unwrap() and do type assertions
|
||||
// against the result. We have to use errors.As(), to allow the shims to delegate
|
||||
// the type assertion to the raw error correctly.
|
||||
//
|
||||
// Based on all these constraints, we use errors.As() with an internal interface
|
||||
// that can only be implemented by our internal error types. When one is found,
|
||||
// we handle each of our internal types as a special case. For errWithCause, we
|
||||
// traverse to the wrapped error, ignoring the cause and the funky Unwrap logic.
|
||||
// We could have just used errors.As(err, *errWithValue), but that would have
|
||||
// traversed into the causes.
|
||||
|
||||
for {
|
||||
switch t := err.(type) {
|
||||
case *errWithValue:
|
||||
if t.key == key {
|
||||
return t.value, true
|
||||
}
|
||||
err = t.err
|
||||
case *errWithCause:
|
||||
err = t.err
|
||||
default:
|
||||
if errors.As(err, &merr) {
|
||||
err = merr
|
||||
} else {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Values returns a map of all values attached to the error
|
||||
// If a key has been attached multiple times, the map will
|
||||
// contain the last value mapped
|
||||
// If e is nil, returns nil.
|
||||
func Values(err error) map[interface{}]interface{} {
|
||||
var values map[interface{}]interface{}
|
||||
|
||||
for err != nil {
|
||||
if e, ok := err.(*errWithValue); ok {
|
||||
if _, ok := values[e.key]; !ok {
|
||||
if values == nil {
|
||||
values = map[interface{}]interface{}{}
|
||||
}
|
||||
values[e.key] = e.value
|
||||
}
|
||||
}
|
||||
err = errors.Unwrap(err)
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
// Stack returns the stack attached to an error, or nil if one is not attached
|
||||
// If e is nil, returns nil.
|
||||
func Stack(err error) []uintptr {
|
||||
stack, _ := Value(err, errKeyStack).([]uintptr)
|
||||
return stack
|
||||
}
|
||||
|
||||
// HTTPCode converts an error to an http status code. All errors
|
||||
// map to 500, unless the error has an http code attached.
|
||||
// If e is nil, returns 200.
|
||||
func HTTPCode(err error) int {
|
||||
if err == nil {
|
||||
return 200
|
||||
}
|
||||
|
||||
code, _ := Value(err, errKeyHTTPCode).(int)
|
||||
if code == 0 {
|
||||
return 500
|
||||
}
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
// UserMessage returns the end-user safe message. Returns empty if not set.
|
||||
// If e is nil, returns "".
|
||||
func UserMessage(err error) string {
|
||||
msg, _ := Value(err, errKeyUserMessage).(string)
|
||||
return msg
|
||||
}
|
||||
|
||||
// Cause returns the cause of the argument. If e is nil, or has no cause,
|
||||
// nil is returned.
|
||||
func Cause(err error) error {
|
||||
var causer *errWithCause
|
||||
if errors.As(err, &causer) {
|
||||
return causer.cause
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisteredDetails extracts details registered with RegisterDetailFunc from an error, and
|
||||
// returns them as a map. Values may be nil.
|
||||
//
|
||||
// If err is nil or there are no registered details, nil is returned.
|
||||
func RegisteredDetails(err error) map[string]interface{} {
|
||||
detailsLock.Lock()
|
||||
defer detailsLock.Unlock()
|
||||
|
||||
if len(detailFields) == 0 || err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
dets := map[string]interface{}{}
|
||||
|
||||
for label, f := range detailFields {
|
||||
dets[label] = f(err)
|
||||
}
|
||||
|
||||
return dets
|
||||
}
|
||||
|
||||
// captureStack: return an error with a stack attached. Stack will skip
|
||||
// specified frames. skip = 0 will start at caller.
|
||||
// If the err already has a stack, to auto-stack-capture is disabled globally,
|
||||
// this is a no-op. Use force to override and force a stack capture
|
||||
// in all cases.
|
||||
func captureStack(err error, skip int, force bool) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var c interface {
|
||||
Callers() []uintptr
|
||||
}
|
||||
|
||||
switch {
|
||||
case force:
|
||||
// always capture
|
||||
case HasStack(err):
|
||||
return err
|
||||
case errors.As(err, &c):
|
||||
// if the go-errors already captured a stack
|
||||
// reuse it
|
||||
if stack := c.Callers(); len(stack) > 0 {
|
||||
return Set(err, errKeyStack, stack)
|
||||
}
|
||||
case !captureStacks:
|
||||
return err
|
||||
}
|
||||
|
||||
s := make([]uintptr, MaxStackDepth())
|
||||
length := runtime.Callers(2+skip, s[:])
|
||||
return Set(err, errKeyStack, s[:length])
|
||||
}
|
||||
|
||||
// HasStack returns true if a stack is already attached to the err.
|
||||
// If err == nil, returns false.
|
||||
//
|
||||
// If a stack capture was suppressed with NoCaptureStack(), this will
|
||||
// still return true, indicating that stack capture processing has already
|
||||
// occurred on this error.
|
||||
func HasStack(err error) bool {
|
||||
_, ok := Lookup(err, errKeyStack)
|
||||
return ok
|
||||
}
|
Reference in New Issue
Block a user