123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- package cli
- import (
- "fmt"
- "io"
- "os"
- "strings"
- )
- // OsExiter is the function used when the app exits. If not set defaults to os.Exit.
- var OsExiter = os.Exit
- // ErrWriter is used to write errors to the user. This can be anything
- // implementing the io.Writer interface and defaults to os.Stderr.
- var ErrWriter io.Writer = os.Stderr
- // MultiError is an error that wraps multiple errors.
- type MultiError struct {
- Errors []error
- }
- // NewMultiError creates a new MultiError. Pass in one or more errors.
- func NewMultiError(err ...error) MultiError {
- return MultiError{Errors: err}
- }
- // Error implements the error interface.
- func (m MultiError) Error() string {
- errs := make([]string, len(m.Errors))
- for i, err := range m.Errors {
- errs[i] = err.Error()
- }
- return strings.Join(errs, "\n")
- }
- type ErrorFormatter interface {
- Format(s fmt.State, verb rune)
- }
- // ExitCoder is the interface checked by `App` and `Command` for a custom exit
- // code
- type ExitCoder interface {
- error
- ExitCode() int
- }
- // ExitError fulfills both the builtin `error` interface and `ExitCoder`
- type ExitError struct {
- exitCode int
- message interface{}
- }
- // NewExitError makes a new *ExitError
- func NewExitError(message interface{}, exitCode int) *ExitError {
- return &ExitError{
- exitCode: exitCode,
- message: message,
- }
- }
- // Error returns the string message, fulfilling the interface required by
- // `error`
- func (ee *ExitError) Error() string {
- return fmt.Sprintf("%v", ee.message)
- }
- // ExitCode returns the exit code, fulfilling the interface required by
- // `ExitCoder`
- func (ee *ExitError) ExitCode() int {
- return ee.exitCode
- }
- // HandleExitCoder checks if the error fulfills the ExitCoder interface, and if
- // so prints the error to stderr (if it is non-empty) and calls OsExiter with the
- // given exit code. If the given error is a MultiError, then this func is
- // called on all members of the Errors slice and calls OsExiter with the last exit code.
- func HandleExitCoder(err error) {
- if err == nil {
- return
- }
- if exitErr, ok := err.(ExitCoder); ok {
- if err.Error() != "" {
- if _, ok := exitErr.(ErrorFormatter); ok {
- fmt.Fprintf(ErrWriter, "%+v\n", err)
- } else {
- fmt.Fprintln(ErrWriter, err)
- }
- }
- OsExiter(exitErr.ExitCode())
- return
- }
- if multiErr, ok := err.(MultiError); ok {
- code := handleMultiError(multiErr)
- OsExiter(code)
- return
- }
- }
- func handleMultiError(multiErr MultiError) int {
- code := 1
- for _, merr := range multiErr.Errors {
- if multiErr2, ok := merr.(MultiError); ok {
- code = handleMultiError(multiErr2)
- } else {
- fmt.Fprintln(ErrWriter, merr)
- if exitErr, ok := merr.(ExitCoder); ok {
- code = exitErr.ExitCode()
- }
- }
- }
- return code
- }
|