You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
120 lines
2.5 KiB
120 lines
2.5 KiB
3 years ago
|
// Copyright (C) MongoDB, Inc. 2017-present.
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||
|
// not use this file except in compliance with the License. You may obtain
|
||
|
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
package internal
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
)
|
||
|
|
||
|
// WrappedError represents an error that contains another error.
|
||
|
type WrappedError interface {
|
||
|
// Message gets the basic message of the error.
|
||
|
Message() string
|
||
|
// Inner gets the inner error if one exists.
|
||
|
Inner() error
|
||
|
}
|
||
|
|
||
|
// RolledUpErrorMessage gets a flattened error message.
|
||
|
func RolledUpErrorMessage(err error) string {
|
||
|
if wrappedErr, ok := err.(WrappedError); ok {
|
||
|
inner := wrappedErr.Inner()
|
||
|
if inner != nil {
|
||
|
return fmt.Sprintf("%s: %s", wrappedErr.Message(), RolledUpErrorMessage(inner))
|
||
|
}
|
||
|
|
||
|
return wrappedErr.Message()
|
||
|
}
|
||
|
|
||
|
return err.Error()
|
||
|
}
|
||
|
|
||
|
//UnwrapError attempts to unwrap the error down to its root cause.
|
||
|
func UnwrapError(err error) error {
|
||
|
|
||
|
switch tErr := err.(type) {
|
||
|
case WrappedError:
|
||
|
return UnwrapError(tErr.Inner())
|
||
|
case *multiError:
|
||
|
return UnwrapError(tErr.errors[0])
|
||
|
}
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// WrapError wraps an error with a message.
|
||
|
func WrapError(inner error, message string) error {
|
||
|
return &wrappedError{message, inner}
|
||
|
}
|
||
|
|
||
|
// WrapErrorf wraps an error with a message.
|
||
|
func WrapErrorf(inner error, format string, args ...interface{}) error {
|
||
|
return &wrappedError{fmt.Sprintf(format, args...), inner}
|
||
|
}
|
||
|
|
||
|
// MultiError combines multiple errors into a single error. If there are no errors,
|
||
|
// nil is returned. If there is 1 error, it is returned. Otherwise, they are combined.
|
||
|
func MultiError(errors ...error) error {
|
||
|
|
||
|
// remove nils from the error list
|
||
|
var nonNils []error
|
||
|
for _, e := range errors {
|
||
|
if e != nil {
|
||
|
nonNils = append(nonNils, e)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch len(nonNils) {
|
||
|
case 0:
|
||
|
return nil
|
||
|
case 1:
|
||
|
return nonNils[0]
|
||
|
default:
|
||
|
return &multiError{
|
||
|
message: "multiple errors encountered",
|
||
|
errors: nonNils,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type multiError struct {
|
||
|
message string
|
||
|
errors []error
|
||
|
}
|
||
|
|
||
|
func (e *multiError) Message() string {
|
||
|
return e.message
|
||
|
}
|
||
|
|
||
|
func (e *multiError) Error() string {
|
||
|
result := e.message
|
||
|
for _, e := range e.errors {
|
||
|
result += fmt.Sprintf("\n %s", e)
|
||
|
}
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
func (e *multiError) Errors() []error {
|
||
|
return e.errors
|
||
|
}
|
||
|
|
||
|
type wrappedError struct {
|
||
|
message string
|
||
|
inner error
|
||
|
}
|
||
|
|
||
|
func (e *wrappedError) Message() string {
|
||
|
return e.message
|
||
|
}
|
||
|
|
||
|
func (e *wrappedError) Error() string {
|
||
|
return RolledUpErrorMessage(e)
|
||
|
}
|
||
|
|
||
|
func (e *wrappedError) Inner() error {
|
||
|
return e.inner
|
||
|
}
|