...
1 package cli
2
3 import (
4 "fmt"
5 "io"
6 "os"
7 "strings"
8 )
9
10
11 var OsExiter = os.Exit
12
13
14
15 var ErrWriter io.Writer = os.Stderr
16
17
18 type MultiError interface {
19 error
20 Errors() []error
21 }
22
23
24 func newMultiError(err ...error) MultiError {
25 ret := multiError(err)
26 return &ret
27 }
28
29 type multiError []error
30
31
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
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
73 type ErrorFormatter interface {
74 Format(s fmt.State, verb rune)
75 }
76
77
78
79 type ExitCoder interface {
80 error
81 ExitCode() int
82 }
83
84 type exitError struct {
85 exitCode int
86 err error
87 }
88
89
90
91
92 func NewExitError(message interface{}, exitCode int) ExitCoder {
93 return Exit(message, exitCode)
94 }
95
96
97
98
99
100
101
102
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
134
135
136
137
138
139
140
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