...

Source file src/github.com/urfave/cli/v2/errors.go

Documentation: github.com/urfave/cli/v2

     1  package cli
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"strings"
     8  )
     9  
    10  // OsExiter is the function used when the app exits. If not set defaults to os.Exit.
    11  var OsExiter = os.Exit
    12  
    13  // ErrWriter is used to write errors to the user. This can be anything
    14  // implementing the io.Writer interface and defaults to os.Stderr.
    15  var ErrWriter io.Writer = os.Stderr
    16  
    17  // MultiError is an error that wraps multiple errors.
    18  type MultiError interface {
    19  	error
    20  	Errors() []error
    21  }
    22  
    23  // newMultiError creates a new MultiError. Pass in one or more errors.
    24  func newMultiError(err ...error) MultiError {
    25  	ret := multiError(err)
    26  	return &ret
    27  }
    28  
    29  type multiError []error
    30  
    31  // Error implements the error interface.
    32  func (m *multiError) Error() string {
    33  	errs := make([]string, len(*m))
    34  	for i, err := range *m {
    35  		errs[i] = err.Error()
    36  	}
    37  
    38  	return strings.Join(errs, "\n")
    39  }
    40  
    41  // Errors returns a copy of the errors slice
    42  func (m *multiError) Errors() []error {
    43  	errs := make([]error, len(*m))
    44  	for _, err := range *m {
    45  		errs = append(errs, err)
    46  	}
    47  	return errs
    48  }
    49  
    50  type requiredFlagsErr interface {
    51  	error
    52  	getMissingFlags() []string
    53  }
    54  
    55  type errRequiredFlags struct {
    56  	missingFlags []string
    57  }
    58  
    59  func (e *errRequiredFlags) Error() string {
    60  	numberOfMissingFlags := len(e.missingFlags)
    61  	if numberOfMissingFlags == 1 {
    62  		return fmt.Sprintf("Required flag %q not set", e.missingFlags[0])
    63  	}
    64  	joinedMissingFlags := strings.Join(e.missingFlags, ", ")
    65  	return fmt.Sprintf("Required flags %q not set", joinedMissingFlags)
    66  }
    67  
    68  func (e *errRequiredFlags) getMissingFlags() []string {
    69  	return e.missingFlags
    70  }
    71  
    72  // ErrorFormatter is the interface that will suitably format the error output
    73  type ErrorFormatter interface {
    74  	Format(s fmt.State, verb rune)
    75  }
    76  
    77  // ExitCoder is the interface checked by `App` and `Command` for a custom exit
    78  // code
    79  type ExitCoder interface {
    80  	error
    81  	ExitCode() int
    82  }
    83  
    84  type exitError struct {
    85  	exitCode int
    86  	err      error
    87  }
    88  
    89  // NewExitError calls Exit to create a new ExitCoder.
    90  //
    91  // Deprecated: This function is a duplicate of Exit and will eventually be removed.
    92  func NewExitError(message interface{}, exitCode int) ExitCoder {
    93  	return Exit(message, exitCode)
    94  }
    95  
    96  // Exit wraps a message and exit code into an error, which by default is
    97  // handled with a call to os.Exit during default error handling.
    98  //
    99  // This is the simplest way to trigger a non-zero exit code for an App without
   100  // having to call os.Exit manually. During testing, this behavior can be avoided
   101  // by overriding the ExitErrHandler function on an App or the package-global
   102  // OsExiter function.
   103  func Exit(message interface{}, exitCode int) ExitCoder {
   104  	var err error
   105  
   106  	switch e := message.(type) {
   107  	case ErrorFormatter:
   108  		err = fmt.Errorf("%+v", message)
   109  	case error:
   110  		err = e
   111  	default:
   112  		err = fmt.Errorf("%+v", message)
   113  	}
   114  
   115  	return &exitError{
   116  		err:      err,
   117  		exitCode: exitCode,
   118  	}
   119  }
   120  
   121  func (ee *exitError) Error() string {
   122  	return ee.err.Error()
   123  }
   124  
   125  func (ee *exitError) ExitCode() int {
   126  	return ee.exitCode
   127  }
   128  
   129  func (ee *exitError) Unwrap() error {
   130  	return ee.err
   131  }
   132  
   133  // HandleExitCoder handles errors implementing ExitCoder by printing their
   134  // message and calling OsExiter with the given exit code.
   135  //
   136  // If the given error instead implements MultiError, each error will be checked
   137  // for the ExitCoder interface, and OsExiter will be called with the last exit
   138  // code found, or exit code 1 if no ExitCoder is found.
   139  //
   140  // This function is the default error-handling behavior for an App.
   141  func HandleExitCoder(err error) {
   142  	if err == nil {
   143  		return
   144  	}
   145  
   146  	if exitErr, ok := err.(ExitCoder); ok {
   147  		if err.Error() != "" {
   148  			if _, ok := exitErr.(ErrorFormatter); ok {
   149  				_, _ = fmt.Fprintf(ErrWriter, "%+v\n", err)
   150  			} else {
   151  				_, _ = fmt.Fprintln(ErrWriter, err)
   152  			}
   153  		}
   154  		OsExiter(exitErr.ExitCode())
   155  		return
   156  	}
   157  
   158  	if multiErr, ok := err.(MultiError); ok {
   159  		code := handleMultiError(multiErr)
   160  		OsExiter(code)
   161  		return
   162  	}
   163  }
   164  
   165  func handleMultiError(multiErr MultiError) int {
   166  	code := 1
   167  	for _, merr := range multiErr.Errors() {
   168  		if multiErr2, ok := merr.(MultiError); ok {
   169  			code = handleMultiError(multiErr2)
   170  		} else if merr != nil {
   171  			fmt.Fprintln(ErrWriter, merr)
   172  			if exitErr, ok := merr.(ExitCoder); ok {
   173  				code = exitErr.ExitCode()
   174  			}
   175  		}
   176  	}
   177  	return code
   178  }
   179  

View as plain text