errors.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  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. }