...
1 package cli
2
3 import (
4 "context"
5 "flag"
6 "fmt"
7 "strings"
8 )
9
10
11
12
13
14 type Context struct {
15 context.Context
16 App *App
17 Command *Command
18 shellComplete bool
19 flagSet *flag.FlagSet
20 parentContext *Context
21 }
22
23
24 func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
25 c := &Context{App: app, flagSet: set, parentContext: parentCtx}
26 if parentCtx != nil {
27 c.Context = parentCtx.Context
28 c.shellComplete = parentCtx.shellComplete
29 if parentCtx.flagSet == nil {
30 parentCtx.flagSet = &flag.FlagSet{}
31 }
32 }
33
34 c.Command = &Command{}
35
36 if c.Context == nil {
37 c.Context = context.Background()
38 }
39
40 return c
41 }
42
43
44 func (cCtx *Context) NumFlags() int {
45 return cCtx.flagSet.NFlag()
46 }
47
48
49 func (cCtx *Context) Set(name, value string) error {
50 if fs := cCtx.lookupFlagSet(name); fs != nil {
51 return fs.Set(name, value)
52 }
53
54 return fmt.Errorf("no such flag -%s", name)
55 }
56
57
58 func (cCtx *Context) IsSet(name string) bool {
59
60 if fs := cCtx.lookupFlagSet(name); fs != nil {
61 isSet := false
62 fs.Visit(func(f *flag.Flag) {
63 if f.Name == name {
64 isSet = true
65 }
66 })
67 if isSet {
68 return true
69 }
70
71 f := cCtx.lookupFlag(name)
72 if f == nil {
73 return false
74 }
75
76 if f.IsSet() {
77 return true
78 }
79
80
81 aliases := f.Names()
82 fs.Visit(func(f *flag.Flag) {
83 for _, alias := range aliases {
84 if f.Name == alias {
85 isSet = true
86 }
87 }
88 })
89
90 if isSet {
91 return true
92 }
93 }
94
95 return false
96 }
97
98
99 func (cCtx *Context) LocalFlagNames() []string {
100 var names []string
101 cCtx.flagSet.Visit(makeFlagNameVisitor(&names))
102
103 if cCtx.Command != nil && cCtx.Command.Flags != nil {
104 for _, f := range cCtx.Command.Flags {
105 if f.IsSet() {
106 names = append(names, f.Names()...)
107 }
108 }
109 }
110
111
112
113 m := map[string]struct{}{}
114 var unames []string
115 for _, name := range names {
116 if _, ok := m[name]; !ok {
117 m[name] = struct{}{}
118 unames = append(unames, name)
119 }
120 }
121
122 return unames
123 }
124
125
126
127 func (cCtx *Context) FlagNames() []string {
128 var names []string
129 for _, pCtx := range cCtx.Lineage() {
130 names = append(names, pCtx.LocalFlagNames()...)
131 }
132 return names
133 }
134
135
136
137 func (cCtx *Context) Lineage() []*Context {
138 var lineage []*Context
139
140 for cur := cCtx; cur != nil; cur = cur.parentContext {
141 lineage = append(lineage, cur)
142 }
143
144 return lineage
145 }
146
147
148 func (cCtx *Context) Count(name string) int {
149 if fs := cCtx.lookupFlagSet(name); fs != nil {
150 if cf, ok := fs.Lookup(name).Value.(Countable); ok {
151 return cf.Count()
152 }
153 }
154 return 0
155 }
156
157
158 func (cCtx *Context) Value(name string) interface{} {
159 if fs := cCtx.lookupFlagSet(name); fs != nil {
160 return fs.Lookup(name).Value.(flag.Getter).Get()
161 }
162 return nil
163 }
164
165
166 func (cCtx *Context) Args() Args {
167 ret := args(cCtx.flagSet.Args())
168 return &ret
169 }
170
171
172 func (cCtx *Context) NArg() int {
173 return cCtx.Args().Len()
174 }
175
176 func (cCtx *Context) lookupFlag(name string) Flag {
177 for _, c := range cCtx.Lineage() {
178 if c.Command == nil {
179 continue
180 }
181
182 for _, f := range c.Command.Flags {
183 for _, n := range f.Names() {
184 if n == name {
185 return f
186 }
187 }
188 }
189 }
190
191 if cCtx.App != nil {
192 for _, f := range cCtx.App.Flags {
193 for _, n := range f.Names() {
194 if n == name {
195 return f
196 }
197 }
198 }
199 }
200
201 return nil
202 }
203
204 func (cCtx *Context) lookupFlagSet(name string) *flag.FlagSet {
205 for _, c := range cCtx.Lineage() {
206 if c.flagSet == nil {
207 continue
208 }
209 if f := c.flagSet.Lookup(name); f != nil {
210 return c.flagSet
211 }
212 }
213 cCtx.onInvalidFlag(name)
214 return nil
215 }
216
217 func (cCtx *Context) checkRequiredFlags(flags []Flag) requiredFlagsErr {
218 var missingFlags []string
219 for _, f := range flags {
220 if rf, ok := f.(RequiredFlag); ok && rf.IsRequired() {
221 var flagPresent bool
222 var flagName string
223
224 flagNames := f.Names()
225 flagName = flagNames[0]
226
227 for _, key := range flagNames {
228 if cCtx.IsSet(strings.TrimSpace(key)) {
229 flagPresent = true
230 }
231 }
232
233 if !flagPresent && flagName != "" {
234 missingFlags = append(missingFlags, flagName)
235 }
236 }
237 }
238
239 if len(missingFlags) != 0 {
240 return &errRequiredFlags{missingFlags: missingFlags}
241 }
242
243 return nil
244 }
245
246 func (cCtx *Context) onInvalidFlag(name string) {
247 for cCtx != nil {
248 if cCtx.App != nil && cCtx.App.InvalidFlagAccessHandler != nil {
249 cCtx.App.InvalidFlagAccessHandler(cCtx, name)
250 break
251 }
252 cCtx = cCtx.parentContext
253 }
254 }
255
256 func makeFlagNameVisitor(names *[]string) func(*flag.Flag) {
257 return func(f *flag.Flag) {
258 nameParts := strings.Split(f.Name, ",")
259 name := strings.TrimSpace(nameParts[0])
260
261 for _, part := range nameParts {
262 part = strings.TrimSpace(part)
263 if len(part) > len(name) {
264 name = part
265 }
266 }
267
268 if name != "" {
269 *names = append(*names, name)
270 }
271 }
272 }
273
View as plain text