errlist.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. Copyright 2017 Google Inc.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. // Package errlist implents an error type that contains a list of other errors.
  14. // The provided Add function correctly handles nil so it may be unconditionally
  15. // called with an error, even if the error is nil.
  16. //
  17. // Package errlist exports two types, List and Error. List is always used to
  18. // construct a list of errors, and Error is used when introspecting an error.
  19. // List does not implement the error interface to prevent an empty list from
  20. // being returned.
  21. //
  22. // EXAMPLE
  23. //
  24. // func checkStrings(source []string) error {
  25. // var errs errlist.List
  26. // for _, s := range source {
  27. // errs.Add(check(s))
  28. // }
  29. // return errs.Err()
  30. // }
  31. //
  32. // func check(s string) error {
  33. // if len(s) < 1 || len(s) > 5 {
  34. // return fmt.Errorf("bad string: %q", s)
  35. // }
  36. // return nil
  37. // }
  38. //
  39. //
  40. // func errHasPrefix(err error, prefix string) bool {
  41. // switch errs := err.(type) {
  42. // case errlist.Error:
  43. // for _, err := range errs.Errors() {
  44. // if errHasPrefix(err, prefix) {
  45. // return true
  46. // }
  47. // }
  48. // default:
  49. // return strings.HasPrefix(err.Error(), prefix)
  50. // }
  51. // return false
  52. // }
  53. package errlist
  54. import (
  55. "reflect"
  56. "strings"
  57. )
  58. // Separator is used to separate error messages when calling Error on a list.
  59. // Only package main should set Separator. It should only be set in an init
  60. // function defined in the main package.
  61. var Separator = ", "
  62. // An Error is a list of errors and implements the error interface. An Error
  63. // should never be declared directly, use a List and then it's Err
  64. // method to return a proper error.
  65. type Error struct {
  66. List
  67. }
  68. // List is the working representation of an Error, it does not implement
  69. // the error interface. Use the Add method to add errors to a List.
  70. //
  71. // Separator may optionally be set as the string to separate errors when
  72. // displayed. If not set, it defaults to the global Separator value.
  73. type List struct {
  74. Separator string
  75. errors []error
  76. }
  77. // Errors is implemented by error types that can return lists of errors.
  78. type Errors interface {
  79. // Errors returns the list of errors associated with the recevier. It
  80. // returns nil if there are no errors associated with the recevier.
  81. Errors() []error
  82. }
  83. // etype is used for detecting types that are simply slices of error.
  84. var etype = reflect.TypeOf([]error{})
  85. // Add adds all non-nil errs to the list of errors in e and returns true if errs
  86. // contains a non-nil error. If no non-nil errors are passed Add does nothing
  87. // and returns false. Add will never add a nil error to the List. If err
  88. // implementes the Errors interface or its underlying type is a slice of errors
  89. // then e.Add is called on each individual error.
  90. func (e *List) Add(errs ...error) bool {
  91. added := false
  92. for _, err := range errs {
  93. if err != nil {
  94. if el, ok := err.(Errors); ok {
  95. errs := el.Errors()
  96. if len(errs) == 0 {
  97. continue
  98. }
  99. e.errors = append(e.errors, errs...)
  100. added = true
  101. continue
  102. }
  103. if rv := reflect.ValueOf(err); rv.Type().AssignableTo(etype) {
  104. a := false
  105. n := rv.Len()
  106. for i := 0; i < n; i++ {
  107. errI, ok := rv.Index(i).Interface().(error)
  108. if ok {
  109. a = e.Add(errI) || a
  110. }
  111. }
  112. added = added || a
  113. continue
  114. }
  115. e.errors = append(e.errors, err)
  116. added = true
  117. }
  118. }
  119. return added
  120. }
  121. // Reset resets the error list in e to nil.
  122. func (e *List) Reset() {
  123. e.errors = nil
  124. }
  125. // Append implements the deprecated usage of the previous errlist package.
  126. // Use Add instead.
  127. func (e *List) Append(err error) {
  128. e.Add(err)
  129. }
  130. // Err returns e as an error of type Error if e has errors, or nil.
  131. func (e List) Err() error {
  132. if len(e.errors) == 0 {
  133. return nil
  134. }
  135. return Error{e}
  136. }
  137. // Error implements the error interface.
  138. func (e Error) Error() string {
  139. sep := e.Separator
  140. if sep == "" {
  141. sep = Separator
  142. }
  143. msgs := make([]string, len(e.errors))
  144. for x, err := range e.errors {
  145. msgs[x] = err.Error()
  146. }
  147. return strings.Join(msgs, sep)
  148. }
  149. // Errors returns the list of errors in e, or nil if e has no errors.
  150. func (e Error) Errors() []error {
  151. if len(e.errors) > 0 {
  152. return e.errors
  153. }
  154. return nil
  155. }