-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-
200
-
201
-
202
-
203
-
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
-
212
-
213
-
214
-
215
-
216
-
217
-
218
-
219
-
220
-
221
-
222
-
223
-
224
-
225
-
226
-
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
235
-
236
-
237
-
238
-
239
-
240
-
241
-
242
-
243
-
244
-
245
-
246
-
247
-
248
-
249
-
250
-
251
-
252
-
253
-
254
-
255
-
256
-
257
-
258
-
259
-
260
-
261
-
262
-
263
-
264
-
265
-
266
-
267
-
268
-
269
-
270
-
271
-
272
-
273
-
274
-
275
-
276
-
277
-
278
-
279
-
280
-
281
-
282
-
283
-
284
-
285
-
286
-
287
-
288
-
289
-
290
-
291
-
292
-
293
-
294
-
295
-
296
-
297
-
298
-
299
-
300
-
301
-
302
-
303
-
304
-
305
-
306
-
307
-
308
-
309
-
310
-
311
-
312
-
313
-
314
-
315
-
316
-
317
-
318
-
319
-
320
-
321
-
322
-
323
-
324
-
325
-
326
-
327
-
328
-
329
-
330
-
331
-
332
-
333
-
334
-
335
-
336
-
337
-
338
-
339
-
340
-
341
-
342
-
343
-
344
-
345
-
346
-
347
-
348
-
349
-
350
-
351
-
352
-
353
-
354
-
355
-
356
-
357
-
358
-
359
-
360
-
361
-
362
-
363
-
364
-
365
-
366
-
367
-
368
-
369
-
370
-
371
-
372
-
373
-
374
-
375
-
376
-
377
-
378
-
379
-
380
-
381
-
382
-
383
-
384
-
385
-
386
-
387
-
388
-
389
-
390
-
391
-
392
-
393
-
394
-
395
-
396
-
397
-
398
-
399
-
400
-
401
-
402
-
403
-
404
-
405
-
406
-
407
-
408
-
409
-
410
-
411
-
412
-
413
-
414
-
415
-
416
-
417
-
418
-
419
-
420
-
421
-
422
-
423
-
424
-
425
-
426
-
427
-
428
-
429
-
430
-
431
-
432
-
433
-
434
-
435
-
436
-
437
-
438
-
439
-
440
-
441
-
442
-
443
-
444
-
445
-
446
-
447
-
448
-
449
-
450
-
451
-
452
-
453
-
454
-
455
-
456
-
457
-
458
-
459
-
460
-
461
-
462
-
463
-
464
-
465
-
466
-
467
-
468
-
469
-
470
-
471
-
472
-
473
-
474
-
475
-
476
-
477
-
478
-
479
-
480
-
481
-
482
-
483
-
484
-
485
-
486
-
487
-
488
-
489
-
490
-
491
-
492
-
493
-
494
-
495
-
496
-
497
-
498
-
499
-
500
-
501
-
502
-
503
-
504
-
505
-
506
-
507
-
508
-
509
-
510
-
511
-
512
-
513
-
514
-
515
-
516
-
517
-
518
-
519
-
520
-
521
-
522
-
523
-
524
-
525
-
526
-
527
-
528
-
529
-
530
-
531
-
532
-
533
-
534
-
535
-
536
-
537
-
538
-
539
-
540
-
541
-
542
-
543
-
544
-
545
-
546
-
547
-
548
-
549
-
550
-
551
-
552
-
553
-
554
-
555
-
556
-
557
-
558
-
559
-
560
-
561
-
562
-
563
-
564
-
565
-
566
-
567
-
568
-
569
-
570
-
571
-
572
-
573
-
574
-
575
-
576
-
577
-
578
-
579
-
580
-
581
-
582
-
583
-
584
-
585
-
586
-
587
-
588
-
589
-
590
-
591
-
592
-
593
-
594
-
595
-
596
-
597
-
598
-
599
-
600
-
601
-
602
-
603
-
604
-
605
-
606
-
607
-
608
-
609
-
610
-
611
-
612
-
613
-
614
-
615
-
616
-
617
-
618
-
619
-
620
-
621
-
622
-
623
-
624
-
625
-
626
-
627
-
628
-
629
-
630
-
631
-
632
-
633
-
634
-
635
-
636
-
637
-
638
-
639
-
640
-
641
-
642
-
643
-
644
-
645
-
646
-
647
-
648
-
649
-
650
-
651
-
652
-
653
-
654
-
655
-
656
-
657
-
658
-
659
-
660
-
661
-
662
-
663
-
664
-
665
-
666
-
667
-
668
-
669
-
670
-
671
-
672
-
673
-
674
-
675
-
676
-
677
-
678
-
679
-
680
-
681
-
682
-
683
-
684
-
685
-
686
-
687
-
688
-
689
-
690
-
691
-
692
-
693
-
694
-
695
-
696
-
697
-
698
-
699
-
700
-
701
-
702
-
703
-
704
-
705
-
706
-
707
-
708
-
709
-
710
-
711
-
712
-
713
-
714
// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package flags
import (
"bytes"
"fmt"
"os"
"path"
"reflect"
"sort"
"strings"
"unicode/utf8"
)
// A Parser provides command line option parsing. It can contain several
// option groups each with their own set of options.
type Parser struct {
// Embedded, see Command for more information
*Command
// A usage string to be displayed in the help message.
Usage string
// Option flags changing the behavior of the parser.
Options Options
// NamespaceDelimiter separates group namespaces and option long names
NamespaceDelimiter string
// EnvNamespaceDelimiter separates group env namespaces and env keys
EnvNamespaceDelimiter string
// UnknownOptionsHandler is a function which gets called when the parser
// encounters an unknown option. The function receives the unknown option
// name, a SplitArgument which specifies its value if set with an argument
// separator, and the remaining command line arguments.
// It should return a new list of remaining arguments to continue parsing,
// or an error to indicate a parse failure.
UnknownOptionHandler func(option string, arg SplitArgument, args []string) ([]string, error)
// CompletionHandler is a function gets called to handle the completion of
// items. By default, the items are printed and the application is exited.
// You can override this default behavior by specifying a custom CompletionHandler.
CompletionHandler func(items []Completion)
// CommandHandler is a function that gets called to handle execution of a
// command. By default, the command will simply be executed. This can be
// overridden to perform certain actions (such as applying global flags)
// just before the command is executed. Note that if you override the
// handler it is your responsibility to call the command.Execute function.
//
// The command passed into CommandHandler may be nil in case there is no
// command to be executed when parsing has finished.
CommandHandler func(command Commander, args []string) error
internalError error
}
// SplitArgument represents the argument value of an option that was passed using
// an argument separator.
type SplitArgument interface {
// String returns the option's value as a string, and a boolean indicating
// if the option was present.
Value() (string, bool)
}
type strArgument struct {
value *string
}
func (s strArgument) Value() (string, bool) {
if s.value == nil {
return "", false
}
return *s.value, true
}
// Options provides parser options that change the behavior of the option
// parser.
type Options uint
const (
// None indicates no options.
None Options = 0
// HelpFlag adds a default Help Options group to the parser containing
// -h and --help options. When either -h or --help is specified on the
// command line, the parser will return the special error of type
// ErrHelp. When PrintErrors is also specified, then the help message
// will also be automatically printed to os.Stdout.
HelpFlag = 1 << iota
// PassDoubleDash passes all arguments after a double dash, --, as
// remaining command line arguments (i.e. they will not be parsed for
// flags).
PassDoubleDash
// IgnoreUnknown ignores any unknown options and passes them as
// remaining command line arguments instead of generating an error.
IgnoreUnknown
// PrintErrors prints any errors which occurred during parsing to
// os.Stderr. In the special case of ErrHelp, the message will be printed
// to os.Stdout.
PrintErrors
// PassAfterNonOption passes all arguments after the first non option
// as remaining command line arguments. This is equivalent to strict
// POSIX processing.
PassAfterNonOption
// Default is a convenient default set of options which should cover
// most of the uses of the flags package.
Default = HelpFlag | PrintErrors | PassDoubleDash
)
type parseState struct {
arg string
args []string
retargs []string
positional []*Arg
err error
command *Command
lookup lookup
}
// Parse is a convenience function to parse command line options with default
// settings. The provided data is a pointer to a struct representing the
// default option group (named "Application Options"). For more control, use
// flags.NewParser.
func Parse(data interface{}) ([]string, error) {
return NewParser(data, Default).Parse()
}
// ParseArgs is a convenience function to parse command line options with default
// settings. The provided data is a pointer to a struct representing the
// default option group (named "Application Options"). The args argument is
// the list of command line arguments to parse. If you just want to parse the
// default program command line arguments (i.e. os.Args), then use flags.Parse
// instead. For more control, use flags.NewParser.
func ParseArgs(data interface{}, args []string) ([]string, error) {
return NewParser(data, Default).ParseArgs(args)
}
// NewParser creates a new parser. It uses os.Args[0] as the application
// name and then calls Parser.NewNamedParser (see Parser.NewNamedParser for
// more details). The provided data is a pointer to a struct representing the
// default option group (named "Application Options"), or nil if the default
// group should not be added. The options parameter specifies a set of options
// for the parser.
func NewParser(data interface{}, options Options) *Parser {
p := NewNamedParser(path.Base(os.Args[0]), options)
if data != nil {
g, err := p.AddGroup("Application Options", "", data)
if err == nil {
g.parent = p
}
p.internalError = err
}
return p
}
// NewNamedParser creates a new parser. The appname is used to display the
// executable name in the built-in help message. Option groups and commands can
// be added to this parser by using AddGroup and AddCommand.
func NewNamedParser(appname string, options Options) *Parser {
p := &Parser{
Command: newCommand(appname, "", "", nil),
Options: options,
NamespaceDelimiter: ".",
EnvNamespaceDelimiter: "_",
}
p.Command.parent = p
return p
}
// Parse parses the command line arguments from os.Args using Parser.ParseArgs.
// For more detailed information see ParseArgs.
func (p *Parser) Parse() ([]string, error) {
return p.ParseArgs(os.Args[1:])
}
// ParseArgs parses the command line arguments according to the option groups that
// were added to the parser. On successful parsing of the arguments, the
// remaining, non-option, arguments (if any) are returned. The returned error
// indicates a parsing error and can be used with PrintError to display
// contextual information on where the error occurred exactly.
//
// When the common help group has been added (AddHelp) and either -h or --help
// was specified in the command line arguments, a help message will be
// automatically printed if the PrintErrors option is enabled.
// Furthermore, the special error type ErrHelp is returned.
// It is up to the caller to exit the program if so desired.
func (p *Parser) ParseArgs(args []string) ([]string, error) {
if p.internalError != nil {
return nil, p.internalError
}
p.eachOption(func(c *Command, g *Group, option *Option) {
option.clearReferenceBeforeSet = true
option.updateDefaultLiteral()
})
// Add built-in help group to all commands if necessary
if (p.Options & HelpFlag) != None {
p.addHelpGroups(p.showBuiltinHelp)
}
compval := os.Getenv("GO_FLAGS_COMPLETION")
if len(compval) != 0 {
comp := &completion{parser: p}
items := comp.complete(args)
if p.CompletionHandler != nil {
p.CompletionHandler(items)
} else {
comp.print(items, compval == "verbose")
os.Exit(0)
}
return nil, nil
}
s := &parseState{
args: args,
retargs: make([]string, 0, len(args)),
}
p.fillParseState(s)
for !s.eof() {
var err error
arg := s.pop()
// When PassDoubleDash is set and we encounter a --, then
// simply append all the rest as arguments and break out
if (p.Options&PassDoubleDash) != None && arg == "--" {
s.addArgs(s.args...)
break
}
if !argumentIsOption(arg) {
if (p.Options&PassAfterNonOption) != None && s.lookup.commands[arg] == nil {
// If PassAfterNonOption is set then all remaining arguments
// are considered positional
if err = s.addArgs(s.arg); err != nil {
break
}
if err = s.addArgs(s.args...); err != nil {
break
}
break
}
// Note: this also sets s.err, so we can just check for
// nil here and use s.err later
if p.parseNonOption(s) != nil {
break
}
continue
}
prefix, optname, islong := stripOptionPrefix(arg)
optname, _, argument := splitOption(prefix, optname, islong)
if islong {
err = p.parseLong(s, optname, argument)
} else {
err = p.parseShort(s, optname, argument)
}
if err != nil {
ignoreUnknown := (p.Options & IgnoreUnknown) != None
parseErr := wrapError(err)
if parseErr.Type != ErrUnknownFlag || (!ignoreUnknown && p.UnknownOptionHandler == nil) {
s.err = parseErr
break
}
if ignoreUnknown {
s.addArgs(arg)
} else if p.UnknownOptionHandler != nil {
modifiedArgs, err := p.UnknownOptionHandler(optname, strArgument{argument}, s.args)
if err != nil {
s.err = err
break
}
s.args = modifiedArgs
}
}
}
if s.err == nil {
p.eachOption(func(c *Command, g *Group, option *Option) {
err := option.clearDefault()
if err != nil {
if _, ok := err.(*Error); !ok {
err = p.marshalError(option, err)
}
s.err = err
}
})
s.checkRequired(p)
}
var reterr error
if s.err != nil {
reterr = s.err
} else if len(s.command.commands) != 0 && !s.command.SubcommandsOptional {
reterr = s.estimateCommand()
} else if cmd, ok := s.command.data.(Commander); ok {
if p.CommandHandler != nil {
reterr = p.CommandHandler(cmd, s.retargs)
} else {
reterr = cmd.Execute(s.retargs)
}
} else if p.CommandHandler != nil {
reterr = p.CommandHandler(nil, s.retargs)
}
if reterr != nil {
var retargs []string
if ourErr, ok := reterr.(*Error); !ok || ourErr.Type != ErrHelp {
retargs = append([]string{s.arg}, s.args...)
} else {
retargs = s.args
}
return retargs, p.printError(reterr)
}
return s.retargs, nil
}
func (p *parseState) eof() bool {
return len(p.args) == 0
}
func (p *parseState) pop() string {
if p.eof() {
return ""
}
p.arg = p.args[0]
p.args = p.args[1:]
return p.arg
}
func (p *parseState) peek() string {
if p.eof() {
return ""
}
return p.args[0]
}
func (p *parseState) checkRequired(parser *Parser) error {
c := parser.Command
var required []*Option
for c != nil {
c.eachGroup(func(g *Group) {
for _, option := range g.options {
if !option.isSet && option.Required {
required = append(required, option)
}
}
})
c = c.Active
}
if len(required) == 0 {
if len(p.positional) > 0 {
var reqnames []string
for _, arg := range p.positional {
argRequired := (!arg.isRemaining() && p.command.ArgsRequired) || arg.Required != -1 || arg.RequiredMaximum != -1
if !argRequired {
continue
}
if arg.isRemaining() {
if arg.value.Len() < arg.Required {
var arguments string
if arg.Required > 1 {
arguments = "arguments, but got only " + fmt.Sprintf("%d", arg.value.Len())
} else {
arguments = "argument"
}
reqnames = append(reqnames, "`"+arg.Name+" (at least "+fmt.Sprintf("%d", arg.Required)+" "+arguments+")`")
} else if arg.RequiredMaximum != -1 && arg.value.Len() > arg.RequiredMaximum {
if arg.RequiredMaximum == 0 {
reqnames = append(reqnames, "`"+arg.Name+" (zero arguments)`")
} else {
var arguments string
if arg.RequiredMaximum > 1 {
arguments = "arguments, but got " + fmt.Sprintf("%d", arg.value.Len())
} else {
arguments = "argument"
}
reqnames = append(reqnames, "`"+arg.Name+" (at most "+fmt.Sprintf("%d", arg.RequiredMaximum)+" "+arguments+")`")
}
}
} else {
reqnames = append(reqnames, "`"+arg.Name+"`")
}
}
if len(reqnames) == 0 {
return nil
}
var msg string
if len(reqnames) == 1 {
msg = fmt.Sprintf("the required argument %s was not provided", reqnames[0])
} else {
msg = fmt.Sprintf("the required arguments %s and %s were not provided",
strings.Join(reqnames[:len(reqnames)-1], ", "), reqnames[len(reqnames)-1])
}
p.err = newError(ErrRequired, msg)
return p.err
}
return nil
}
names := make([]string, 0, len(required))
for _, k := range required {
names = append(names, "`"+k.String()+"'")
}
sort.Strings(names)
var msg string
if len(names) == 1 {
msg = fmt.Sprintf("the required flag %s was not specified", names[0])
} else {
msg = fmt.Sprintf("the required flags %s and %s were not specified",
strings.Join(names[:len(names)-1], ", "), names[len(names)-1])
}
p.err = newError(ErrRequired, msg)
return p.err
}
func (p *parseState) estimateCommand() error {
commands := p.command.sortedVisibleCommands()
cmdnames := make([]string, len(commands))
for i, v := range commands {
cmdnames[i] = v.Name
}
var msg string
var errtype ErrorType
if len(p.retargs) != 0 {
c, l := closestChoice(p.retargs[0], cmdnames)
msg = fmt.Sprintf("Unknown command `%s'", p.retargs[0])
errtype = ErrUnknownCommand
if float32(l)/float32(len(c)) < 0.5 {
msg = fmt.Sprintf("%s, did you mean `%s'?", msg, c)
} else if len(cmdnames) == 1 {
msg = fmt.Sprintf("%s. You should use the %s command",
msg,
cmdnames[0])
} else if len(cmdnames) > 1 {
msg = fmt.Sprintf("%s. Please specify one command of: %s or %s",
msg,
strings.Join(cmdnames[:len(cmdnames)-1], ", "),
cmdnames[len(cmdnames)-1])
}
} else {
errtype = ErrCommandRequired
if len(cmdnames) == 1 {
msg = fmt.Sprintf("Please specify the %s command", cmdnames[0])
} else if len(cmdnames) > 1 {
msg = fmt.Sprintf("Please specify one command of: %s or %s",
strings.Join(cmdnames[:len(cmdnames)-1], ", "),
cmdnames[len(cmdnames)-1])
}
}
return newError(errtype, msg)
}
func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg bool, argument *string) (err error) {
if !option.canArgument() {
if argument != nil {
return newErrorf(ErrNoArgumentForBool, "bool flag `%s' cannot have an argument", option)
}
err = option.set(nil)
} else if argument != nil || (canarg && !s.eof()) {
var arg string
if argument != nil {
arg = *argument
} else {
arg = s.pop()
if validationErr := option.isValidValue(arg); validationErr != nil {
return newErrorf(ErrExpectedArgument, validationErr.Error())
} else if p.Options&PassDoubleDash != 0 && arg == "--" {
return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got double dash `--'", option)
}
}
if option.tag.Get("unquote") != "false" {
arg, err = unquoteIfPossible(arg)
}
if err == nil {
err = option.set(&arg)
}
} else if option.OptionalArgument {
option.empty()
for _, v := range option.OptionalValue {
err = option.set(&v)
if err != nil {
break
}
}
} else {
err = newErrorf(ErrExpectedArgument, "expected argument for flag `%s'", option)
}
if err != nil {
if _, ok := err.(*Error); !ok {
err = p.marshalError(option, err)
}
}
return err
}
func (p *Parser) marshalError(option *Option, err error) *Error {
s := "invalid argument for flag `%s'"
expected := p.expectedType(option)
if expected != "" {
s = s + " (expected " + expected + ")"
}
return newErrorf(ErrMarshal, s+": %s",
option,
err.Error())
}
func (p *Parser) expectedType(option *Option) string {
valueType := option.value.Type()
if valueType.Kind() == reflect.Func {
return ""
}
return valueType.String()
}
func (p *Parser) parseLong(s *parseState, name string, argument *string) error {
if option := s.lookup.longNames[name]; option != nil {
// Only long options that are required can consume an argument
// from the argument list
canarg := !option.OptionalArgument
return p.parseOption(s, name, option, canarg, argument)
}
return newErrorf(ErrUnknownFlag, "unknown flag `%s'", name)
}
func (p *Parser) splitShortConcatArg(s *parseState, optname string) (string, *string) {
c, n := utf8.DecodeRuneInString(optname)
if n == len(optname) {
return optname, nil
}
first := string(c)
if option := s.lookup.shortNames[first]; option != nil && option.canArgument() {
arg := optname[n:]
return first, &arg
}
return optname, nil
}
func (p *Parser) parseShort(s *parseState, optname string, argument *string) error {
if argument == nil {
optname, argument = p.splitShortConcatArg(s, optname)
}
for i, c := range optname {
shortname := string(c)
if option := s.lookup.shortNames[shortname]; option != nil {
// Only the last short argument can consume an argument from
// the arguments list, and only if it's non optional
canarg := (i+utf8.RuneLen(c) == len(optname)) && !option.OptionalArgument
if err := p.parseOption(s, shortname, option, canarg, argument); err != nil {
return err
}
} else {
return newErrorf(ErrUnknownFlag, "unknown flag `%s'", shortname)
}
// Only the first option can have a concatted argument, so just
// clear argument here
argument = nil
}
return nil
}
func (p *parseState) addArgs(args ...string) error {
for len(p.positional) > 0 && len(args) > 0 {
arg := p.positional[0]
if err := convert(args[0], arg.value, arg.tag); err != nil {
p.err = err
return err
}
if !arg.isRemaining() {
p.positional = p.positional[1:]
}
args = args[1:]
}
p.retargs = append(p.retargs, args...)
return nil
}
func (p *Parser) parseNonOption(s *parseState) error {
if len(s.positional) > 0 {
return s.addArgs(s.arg)
}
if len(s.command.commands) > 0 && len(s.retargs) == 0 {
if cmd := s.lookup.commands[s.arg]; cmd != nil {
s.command.Active = cmd
cmd.fillParseState(s)
return nil
} else if !s.command.SubcommandsOptional {
s.addArgs(s.arg)
return newErrorf(ErrUnknownCommand, "Unknown command `%s'", s.arg)
}
}
return s.addArgs(s.arg)
}
func (p *Parser) showBuiltinHelp() error {
var b bytes.Buffer
p.WriteHelp(&b)
return newError(ErrHelp, b.String())
}
func (p *Parser) printError(err error) error {
if err != nil && (p.Options&PrintErrors) != None {
flagsErr, ok := err.(*Error)
if ok && flagsErr.Type == ErrHelp {
fmt.Fprintln(os.Stdout, err)
} else {
fmt.Fprintln(os.Stderr, err)
}
}
return err
}