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.
 
 

122 lines
3.4 KiB

  1. package multierror
  2. import (
  3. "errors"
  4. "fmt"
  5. )
  6. // Error is an error type to track multiple errors. This is used to
  7. // accumulate errors in cases and return them as a single "error".
  8. type Error struct {
  9. Errors []error
  10. ErrorFormat ErrorFormatFunc
  11. }
  12. func (e *Error) Error() string {
  13. fn := e.ErrorFormat
  14. if fn == nil {
  15. fn = ListFormatFunc
  16. }
  17. return fn(e.Errors)
  18. }
  19. // ErrorOrNil returns an error interface if this Error represents
  20. // a list of errors, or returns nil if the list of errors is empty. This
  21. // function is useful at the end of accumulation to make sure that the value
  22. // returned represents the existence of errors.
  23. func (e *Error) ErrorOrNil() error {
  24. if e == nil {
  25. return nil
  26. }
  27. if len(e.Errors) == 0 {
  28. return nil
  29. }
  30. return e
  31. }
  32. func (e *Error) GoString() string {
  33. return fmt.Sprintf("*%#v", *e)
  34. }
  35. // WrappedErrors returns the list of errors that this Error is wrapping. It is
  36. // an implementation of the errwrap.Wrapper interface so that multierror.Error
  37. // can be used with that library.
  38. //
  39. // This method is not safe to be called concurrently. Unlike accessing the
  40. // Errors field directly, this function also checks if the multierror is nil to
  41. // prevent a null-pointer panic. It satisfies the errwrap.Wrapper interface.
  42. func (e *Error) WrappedErrors() []error {
  43. if e == nil {
  44. return nil
  45. }
  46. return e.Errors
  47. }
  48. // Unwrap returns an error from Error (or nil if there are no errors).
  49. // This error returned will further support Unwrap to get the next error,
  50. // etc. The order will match the order of Errors in the multierror.Error
  51. // at the time of calling.
  52. //
  53. // The resulting error supports errors.As/Is/Unwrap so you can continue
  54. // to use the stdlib errors package to introspect further.
  55. //
  56. // This will perform a shallow copy of the errors slice. Any errors appended
  57. // to this error after calling Unwrap will not be available until a new
  58. // Unwrap is called on the multierror.Error.
  59. func (e *Error) Unwrap() error {
  60. // If we have no errors then we do nothing
  61. if e == nil || len(e.Errors) == 0 {
  62. return nil
  63. }
  64. // If we have exactly one error, we can just return that directly.
  65. if len(e.Errors) == 1 {
  66. return e.Errors[0]
  67. }
  68. // Shallow copy the slice
  69. errs := make([]error, len(e.Errors))
  70. copy(errs, e.Errors)
  71. return chain(errs)
  72. }
  73. // chain implements the interfaces necessary for errors.Is/As/Unwrap to
  74. // work in a deterministic way with multierror. A chain tracks a list of
  75. // errors while accounting for the current represented error. This lets
  76. // Is/As be meaningful.
  77. //
  78. // Unwrap returns the next error. In the cleanest form, Unwrap would return
  79. // the wrapped error here but we can't do that if we want to properly
  80. // get access to all the errors. Instead, users are recommended to use
  81. // Is/As to get the correct error type out.
  82. //
  83. // Precondition: []error is non-empty (len > 0)
  84. type chain []error
  85. // Error implements the error interface
  86. func (e chain) Error() string {
  87. return e[0].Error()
  88. }
  89. // Unwrap implements errors.Unwrap by returning the next error in the
  90. // chain or nil if there are no more errors.
  91. func (e chain) Unwrap() error {
  92. if len(e) == 1 {
  93. return nil
  94. }
  95. return e[1:]
  96. }
  97. // As implements errors.As by attempting to map to the current value.
  98. func (e chain) As(target interface{}) bool {
  99. return errors.As(e[0], target)
  100. }
  101. // Is implements errors.Is by comparing the current value directly.
  102. func (e chain) Is(target error) bool {
  103. return errors.Is(e[0], target)
  104. }