github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/lib/errors/errors.go (about)

     1  package errors
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  )
     8  
     9  // New returns an error that formats as the given text.
    10  func New(text string) error {
    11  	return errors.New(text)
    12  }
    13  
    14  // Errorf formats according to a format specifier and returns the string
    15  // as a value that satisfies error.
    16  func Errorf(format string, a ...interface{}) error {
    17  	return fmt.Errorf(format, a...)
    18  }
    19  
    20  // WalkFunc is the signature of the Walk callback function. The function gets the
    21  // current error in the chain and should return true if the chain processing
    22  // should be aborted.
    23  type WalkFunc func(error) bool
    24  
    25  // Walk invokes the given function for each error in the chain. If the
    26  // provided functions returns true or no further cause can be found, the process
    27  // is stopped and no further calls will be made.
    28  //
    29  // The next error in the chain is determined by the following rules:
    30  // - If the current error has a `Cause() error` method (github.com/pkg/errors),
    31  //   the return value of this method is used.
    32  // - If the current error has a `Unwrap() error` method (golang.org/x/xerrors),
    33  //   the return value of this method is used.
    34  // - Common errors in the Go runtime that contain an Err field will use this value.
    35  func Walk(err error, f WalkFunc) {
    36  	for prev := err; err != nil; prev = err {
    37  		if f(err) {
    38  			return
    39  		}
    40  
    41  		switch e := err.(type) {
    42  		case causer:
    43  			err = e.Cause()
    44  		case wrapper:
    45  			err = e.Unwrap()
    46  		default:
    47  			// Unpack any struct or *struct with a field of name Err which satisfies
    48  			// the error interface. This includes *url.Error, *net.OpError,
    49  			// *os.SyscallError and many others in the stdlib.
    50  			errType := reflect.TypeOf(err)
    51  			errValue := reflect.ValueOf(err)
    52  			if errValue.IsValid() && errType.Kind() == reflect.Ptr {
    53  				errType = errType.Elem()
    54  				errValue = errValue.Elem()
    55  			}
    56  			if errValue.IsValid() && errType.Kind() == reflect.Struct {
    57  				if errField := errValue.FieldByName("Err"); errField.IsValid() {
    58  					errFieldValue := errField.Interface()
    59  					if newErr, ok := errFieldValue.(error); ok {
    60  						err = newErr
    61  					}
    62  				}
    63  			}
    64  		}
    65  		if reflect.DeepEqual(err, prev) {
    66  			break
    67  		}
    68  	}
    69  }
    70  
    71  type causer interface {
    72  	Cause() error
    73  }
    74  type wrapper interface {
    75  	Unwrap() error
    76  }