errors.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package cli
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "strings"
  7. )
  8. // OsExiter is the function used when the app exits. If not set defaults to os.Exit.
  9. var OsExiter = os.Exit
  10. // ErrWriter is used to write errors to the user. This can be anything
  11. // implementing the io.Writer interface and defaults to os.Stderr.
  12. var ErrWriter io.Writer = os.Stderr
  13. // MultiError is an error that wraps multiple errors.
  14. type MultiError struct {
  15. Errors []error
  16. }
  17. // NewMultiError creates a new MultiError. Pass in one or more errors.
  18. func NewMultiError(err ...error) MultiError {
  19. return MultiError{Errors: err}
  20. }
  21. // Error implents the error interface.
  22. func (m MultiError) Error() string {
  23. errs := make([]string, len(m.Errors))
  24. for i, err := range m.Errors {
  25. errs[i] = err.Error()
  26. }
  27. return strings.Join(errs, "\n")
  28. }
  29. // ExitCoder is the interface checked by `App` and `Command` for a custom exit
  30. // code
  31. type ExitCoder interface {
  32. error
  33. ExitCode() int
  34. }
  35. // ExitError fulfills both the builtin `error` interface and `ExitCoder`
  36. type ExitError struct {
  37. exitCode int
  38. message string
  39. }
  40. // NewExitError makes a new *ExitError
  41. func NewExitError(message string, exitCode int) *ExitError {
  42. return &ExitError{
  43. exitCode: exitCode,
  44. message: message,
  45. }
  46. }
  47. // Error returns the string message, fulfilling the interface required by
  48. // `error`
  49. func (ee *ExitError) Error() string {
  50. return ee.message
  51. }
  52. // ExitCode returns the exit code, fulfilling the interface required by
  53. // `ExitCoder`
  54. func (ee *ExitError) ExitCode() int {
  55. return ee.exitCode
  56. }
  57. // HandleExitCoder checks if the error fulfills the ExitCoder interface, and if
  58. // so prints the error to stderr (if it is non-empty) and calls OsExiter with the
  59. // given exit code. If the given error is a MultiError, then this func is
  60. // called on all members of the Errors slice.
  61. func HandleExitCoder(err error) {
  62. if err == nil {
  63. return
  64. }
  65. if exitErr, ok := err.(ExitCoder); ok {
  66. if err.Error() != "" {
  67. fmt.Fprintln(ErrWriter, err)
  68. }
  69. OsExiter(exitErr.ExitCode())
  70. return
  71. }
  72. if multiErr, ok := err.(MultiError); ok {
  73. for _, merr := range multiErr.Errors {
  74. HandleExitCoder(merr)
  75. }
  76. }
  77. }