1// Copyright 2009 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5/* 6Package pflag is a drop-in replacement for Go's flag package, implementing 7POSIX/GNU-style --flags. 8 9pflag is compatible with the GNU extensions to the POSIX recommendations 10for command-line options. See 11http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html 12 13Usage: 14 15pflag is a drop-in replacement of Go's native flag package. If you import 16pflag under the name "flag" then all code should continue to function 17with no changes. 18 19 import flag "github.com/ogier/pflag" 20 21 There is one exception to this: if you directly instantiate the Flag struct 22there is one more field "Shorthand" that you will need to set. 23Most code never instantiates this struct directly, and instead uses 24functions such as String(), BoolVar(), and Var(), and is therefore 25unaffected. 26 27Define flags using flag.String(), Bool(), Int(), etc. 28 29This declares an integer flag, -flagname, stored in the pointer ip, with type *int. 30 var ip = flag.Int("flagname", 1234, "help message for flagname") 31If you like, you can bind the flag to a variable using the Var() functions. 32 var flagvar int 33 func init() { 34 flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") 35 } 36Or you can create custom flags that satisfy the Value interface (with 37pointer receivers) and couple them to flag parsing by 38 flag.Var(&flagVal, "name", "help message for flagname") 39For such flags, the default value is just the initial value of the variable. 40 41After all flags are defined, call 42 flag.Parse() 43to parse the command line into the defined flags. 44 45Flags may then be used directly. If you're using the flags themselves, 46they are all pointers; if you bind to variables, they're values. 47 fmt.Println("ip has value ", *ip) 48 fmt.Println("flagvar has value ", flagvar) 49 50After parsing, the arguments after the flag are available as the 51slice flag.Args() or individually as flag.Arg(i). 52The arguments are indexed from 0 through flag.NArg()-1. 53 54The pflag package also defines some new functions that are not in flag, 55that give one-letter shorthands for flags. You can use these by appending 56'P' to the name of any function that defines a flag. 57 var ip = flag.IntP("flagname", "f", 1234, "help message") 58 var flagvar bool 59 func init() { 60 flag.BoolVarP("boolname", "b", true, "help message") 61 } 62 flag.VarP(&flagVar, "varname", "v", 1234, "help message") 63Shorthand letters can be used with single dashes on the command line. 64Boolean shorthand flags can be combined with other shorthand flags. 65 66Command line flag syntax: 67 --flag // boolean flags only 68 --flag=x 69 70Unlike the flag package, a single dash before an option means something 71different than a double dash. Single dashes signify a series of shorthand 72letters for flags. All but the last shorthand letter must be boolean flags. 73 // boolean flags 74 -f 75 -abc 76 // non-boolean flags 77 -n 1234 78 -Ifile 79 // mixed 80 -abcs "hello" 81 -abcn1234 82 83Flag parsing stops after the terminator "--". Unlike the flag package, 84flags can be interspersed with arguments anywhere on the command line 85before this terminator. 86 87Integer flags accept 1234, 0664, 0x1234 and may be negative. 88Boolean flags (in their long form) accept 1, 0, t, f, true, false, 89TRUE, FALSE, True, False. 90Duration flags accept any input valid for time.ParseDuration. 91 92The default set of command-line flags is controlled by 93top-level functions. The FlagSet type allows one to define 94independent sets of flags, such as to implement subcommands 95in a command-line interface. The methods of FlagSet are 96analogous to the top-level functions for the command-line 97flag set. 98*/ 99package pflag 100 101import ( 102 "bytes" 103 "errors" 104 "fmt" 105 "io" 106 "os" 107 "sort" 108 "strings" 109) 110 111// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined. 112var ErrHelp = errors.New("pflag: help requested") 113 114// ErrorHandling defines how to handle flag parsing errors. 115type ErrorHandling int 116 117const ( 118 // ContinueOnError will return an err from Parse() if an error is found 119 ContinueOnError ErrorHandling = iota 120 // ExitOnError will call os.Exit(2) if an error is found when parsing 121 ExitOnError 122 // PanicOnError will panic() if an error is found when parsing flags 123 PanicOnError 124) 125 126// NormalizedName is a flag name that has been normalized according to rules 127// for the FlagSet (e.g. making '-' and '_' equivalent). 128type NormalizedName string 129 130// A FlagSet represents a set of defined flags. 131type FlagSet struct { 132 // Usage is the function called when an error occurs while parsing flags. 133 // The field is a function (not a method) that may be changed to point to 134 // a custom error handler. 135 Usage func() 136 137 name string 138 parsed bool 139 actual map[NormalizedName]*Flag 140 formal map[NormalizedName]*Flag 141 shorthands map[byte]*Flag 142 args []string // arguments after flags 143 argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no -- 144 exitOnError bool // does the program exit if there's an error? 145 errorHandling ErrorHandling 146 output io.Writer // nil means stderr; use out() accessor 147 interspersed bool // allow interspersed option/non-option args 148 normalizeNameFunc func(f *FlagSet, name string) NormalizedName 149} 150 151// A Flag represents the state of a flag. 152type Flag struct { 153 Name string // name as it appears on command line 154 Shorthand string // one-letter abbreviated flag 155 Usage string // help message 156 Value Value // value as set 157 DefValue string // default value (as text); for usage message 158 Changed bool // If the user set the value (or if left to default) 159 NoOptDefVal string //default value (as text); if the flag is on the command line without any options 160 Deprecated string // If this flag is deprecated, this string is the new or now thing to use 161 Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text 162 ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use 163 Annotations map[string][]string // used by cobra.Command bash autocomple code 164} 165 166// Value is the interface to the dynamic value stored in a flag. 167// (The default value is represented as a string.) 168type Value interface { 169 String() string 170 Set(string) error 171 Type() string 172} 173 174// sortFlags returns the flags as a slice in lexicographical sorted order. 175func sortFlags(flags map[NormalizedName]*Flag) []*Flag { 176 list := make(sort.StringSlice, len(flags)) 177 i := 0 178 for k := range flags { 179 list[i] = string(k) 180 i++ 181 } 182 list.Sort() 183 result := make([]*Flag, len(list)) 184 for i, name := range list { 185 result[i] = flags[NormalizedName(name)] 186 } 187 return result 188} 189 190// SetNormalizeFunc allows you to add a function which can translate flag names. 191// Flags added to the FlagSet will be translated and then when anything tries to 192// look up the flag that will also be translated. So it would be possible to create 193// a flag named "getURL" and have it translated to "geturl". A user could then pass 194// "--getUrl" which may also be translated to "geturl" and everything will work. 195func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) { 196 f.normalizeNameFunc = n 197 for k, v := range f.formal { 198 delete(f.formal, k) 199 nname := f.normalizeFlagName(string(k)) 200 f.formal[nname] = v 201 v.Name = string(nname) 202 } 203} 204 205// GetNormalizeFunc returns the previously set NormalizeFunc of a function which 206// does no translation, if not set previously. 207func (f *FlagSet) GetNormalizeFunc() func(f *FlagSet, name string) NormalizedName { 208 if f.normalizeNameFunc != nil { 209 return f.normalizeNameFunc 210 } 211 return func(f *FlagSet, name string) NormalizedName { return NormalizedName(name) } 212} 213 214func (f *FlagSet) normalizeFlagName(name string) NormalizedName { 215 n := f.GetNormalizeFunc() 216 return n(f, name) 217} 218 219func (f *FlagSet) out() io.Writer { 220 if f.output == nil { 221 return os.Stderr 222 } 223 return f.output 224} 225 226// SetOutput sets the destination for usage and error messages. 227// If output is nil, os.Stderr is used. 228func (f *FlagSet) SetOutput(output io.Writer) { 229 f.output = output 230} 231 232// VisitAll visits the flags in lexicographical order, calling fn for each. 233// It visits all flags, even those not set. 234func (f *FlagSet) VisitAll(fn func(*Flag)) { 235 for _, flag := range sortFlags(f.formal) { 236 fn(flag) 237 } 238} 239 240// HasFlags returns a bool to indicate if the FlagSet has any flags definied. 241func (f *FlagSet) HasFlags() bool { 242 return len(f.formal) > 0 243} 244 245// HasAvailableFlags returns a bool to indicate if the FlagSet has any flags 246// definied that are not hidden or deprecated. 247func (f *FlagSet) HasAvailableFlags() bool { 248 for _, flag := range f.formal { 249 if !flag.Hidden && len(flag.Deprecated) == 0 { 250 return true 251 } 252 } 253 return false 254} 255 256// VisitAll visits the command-line flags in lexicographical order, calling 257// fn for each. It visits all flags, even those not set. 258func VisitAll(fn func(*Flag)) { 259 CommandLine.VisitAll(fn) 260} 261 262// Visit visits the flags in lexicographical order, calling fn for each. 263// It visits only those flags that have been set. 264func (f *FlagSet) Visit(fn func(*Flag)) { 265 for _, flag := range sortFlags(f.actual) { 266 fn(flag) 267 } 268} 269 270// Visit visits the command-line flags in lexicographical order, calling fn 271// for each. It visits only those flags that have been set. 272func Visit(fn func(*Flag)) { 273 CommandLine.Visit(fn) 274} 275 276// Lookup returns the Flag structure of the named flag, returning nil if none exists. 277func (f *FlagSet) Lookup(name string) *Flag { 278 return f.lookup(f.normalizeFlagName(name)) 279} 280 281// lookup returns the Flag structure of the named flag, returning nil if none exists. 282func (f *FlagSet) lookup(name NormalizedName) *Flag { 283 return f.formal[name] 284} 285 286// func to return a given type for a given flag name 287func (f *FlagSet) getFlagType(name string, ftype string, convFunc func(sval string) (interface{}, error)) (interface{}, error) { 288 flag := f.Lookup(name) 289 if flag == nil { 290 err := fmt.Errorf("flag accessed but not defined: %s", name) 291 return nil, err 292 } 293 294 if flag.Value.Type() != ftype { 295 err := fmt.Errorf("trying to get %s value of flag of type %s", ftype, flag.Value.Type()) 296 return nil, err 297 } 298 299 sval := flag.Value.String() 300 result, err := convFunc(sval) 301 if err != nil { 302 return nil, err 303 } 304 return result, nil 305} 306 307// ArgsLenAtDash will return the length of f.Args at the moment when a -- was 308// found during arg parsing. This allows your program to know which args were 309// before the -- and which came after. 310func (f *FlagSet) ArgsLenAtDash() int { 311 return f.argsLenAtDash 312} 313 314// MarkDeprecated indicated that a flag is deprecated in your program. It will 315// continue to function but will not show up in help or usage messages. Using 316// this flag will also print the given usageMessage. 317func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error { 318 flag := f.Lookup(name) 319 if flag == nil { 320 return fmt.Errorf("flag %q does not exist", name) 321 } 322 if len(usageMessage) == 0 { 323 return fmt.Errorf("deprecated message for flag %q must be set", name) 324 } 325 flag.Deprecated = usageMessage 326 return nil 327} 328 329// MarkShorthandDeprecated will mark the shorthand of a flag deprecated in your 330// program. It will continue to function but will not show up in help or usage 331// messages. Using this flag will also print the given usageMessage. 332func (f *FlagSet) MarkShorthandDeprecated(name string, usageMessage string) error { 333 flag := f.Lookup(name) 334 if flag == nil { 335 return fmt.Errorf("flag %q does not exist", name) 336 } 337 if len(usageMessage) == 0 { 338 return fmt.Errorf("deprecated message for flag %q must be set", name) 339 } 340 flag.ShorthandDeprecated = usageMessage 341 return nil 342} 343 344// MarkHidden sets a flag to 'hidden' in your program. It will continue to 345// function but will not show up in help or usage messages. 346func (f *FlagSet) MarkHidden(name string) error { 347 flag := f.Lookup(name) 348 if flag == nil { 349 return fmt.Errorf("flag %q does not exist", name) 350 } 351 flag.Hidden = true 352 return nil 353} 354 355// Lookup returns the Flag structure of the named command-line flag, 356// returning nil if none exists. 357func Lookup(name string) *Flag { 358 return CommandLine.Lookup(name) 359} 360 361// Set sets the value of the named flag. 362func (f *FlagSet) Set(name, value string) error { 363 normalName := f.normalizeFlagName(name) 364 flag, ok := f.formal[normalName] 365 if !ok { 366 return fmt.Errorf("no such flag -%v", name) 367 } 368 err := flag.Value.Set(value) 369 if err != nil { 370 return err 371 } 372 if f.actual == nil { 373 f.actual = make(map[NormalizedName]*Flag) 374 } 375 f.actual[normalName] = flag 376 flag.Changed = true 377 if len(flag.Deprecated) > 0 { 378 fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated) 379 } 380 return nil 381} 382 383// SetAnnotation allows one to set arbitrary annotations on a flag in the FlagSet. 384// This is sometimes used by spf13/cobra programs which want to generate additional 385// bash completion information. 386func (f *FlagSet) SetAnnotation(name, key string, values []string) error { 387 normalName := f.normalizeFlagName(name) 388 flag, ok := f.formal[normalName] 389 if !ok { 390 return fmt.Errorf("no such flag -%v", name) 391 } 392 if flag.Annotations == nil { 393 flag.Annotations = map[string][]string{} 394 } 395 flag.Annotations[key] = values 396 return nil 397} 398 399// Changed returns true if the flag was explicitly set during Parse() and false 400// otherwise 401func (f *FlagSet) Changed(name string) bool { 402 flag := f.Lookup(name) 403 // If a flag doesn't exist, it wasn't changed.... 404 if flag == nil { 405 return false 406 } 407 return flag.Changed 408} 409 410// Set sets the value of the named command-line flag. 411func Set(name, value string) error { 412 return CommandLine.Set(name, value) 413} 414 415// PrintDefaults prints, to standard error unless configured 416// otherwise, the default values of all defined flags in the set. 417func (f *FlagSet) PrintDefaults() { 418 usages := f.FlagUsages() 419 fmt.Fprintf(f.out(), "%s", usages) 420} 421 422// isZeroValue guesses whether the string represents the zero 423// value for a flag. It is not accurate but in practice works OK. 424func isZeroValue(value string) bool { 425 switch value { 426 case "false": 427 return true 428 case "<nil>": 429 return true 430 case "": 431 return true 432 case "0": 433 return true 434 } 435 return false 436} 437 438// UnquoteUsage extracts a back-quoted name from the usage 439// string for a flag and returns it and the un-quoted usage. 440// Given "a `name` to show" it returns ("name", "a name to show"). 441// If there are no back quotes, the name is an educated guess of the 442// type of the flag's value, or the empty string if the flag is boolean. 443func UnquoteUsage(flag *Flag) (name string, usage string) { 444 // Look for a back-quoted name, but avoid the strings package. 445 usage = flag.Usage 446 for i := 0; i < len(usage); i++ { 447 if usage[i] == '`' { 448 for j := i + 1; j < len(usage); j++ { 449 if usage[j] == '`' { 450 name = usage[i+1 : j] 451 usage = usage[:i] + name + usage[j+1:] 452 return name, usage 453 } 454 } 455 break // Only one back quote; use type name. 456 } 457 } 458 // No explicit name, so use type if we can find one. 459 name = "value" 460 switch flag.Value.(type) { 461 case boolFlag: 462 name = "" 463 case *durationValue: 464 name = "duration" 465 case *float64Value: 466 name = "float" 467 case *intValue, *int64Value: 468 name = "int" 469 case *stringValue: 470 name = "string" 471 case *uintValue, *uint64Value: 472 name = "uint" 473 } 474 return 475} 476 477// FlagUsages Returns a string containing the usage information for all flags in 478// the FlagSet 479func (f *FlagSet) FlagUsages() string { 480 x := new(bytes.Buffer) 481 482 lines := make([]string, 0, len(f.formal)) 483 484 maxlen := 0 485 f.VisitAll(func(flag *Flag) { 486 if len(flag.Deprecated) > 0 || flag.Hidden { 487 return 488 } 489 490 line := "" 491 if len(flag.Shorthand) > 0 && len(flag.ShorthandDeprecated) == 0 { 492 line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name) 493 } else { 494 line = fmt.Sprintf(" --%s", flag.Name) 495 } 496 497 varname, usage := UnquoteUsage(flag) 498 if len(varname) > 0 { 499 line += " " + varname 500 } 501 if len(flag.NoOptDefVal) > 0 { 502 switch flag.Value.Type() { 503 case "string": 504 line += fmt.Sprintf("[=%q]", flag.NoOptDefVal) 505 case "bool": 506 if flag.NoOptDefVal != "true" { 507 line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) 508 } 509 default: 510 line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) 511 } 512 } 513 514 // This special character will be replaced with spacing once the 515 // correct alignment is calculated 516 line += "\x00" 517 if len(line) > maxlen { 518 maxlen = len(line) 519 } 520 521 line += usage 522 if !isZeroValue(flag.DefValue) { 523 if flag.Value.Type() == "string" { 524 line += fmt.Sprintf(" (default %q)", flag.DefValue) 525 } else { 526 line += fmt.Sprintf(" (default %s)", flag.DefValue) 527 } 528 } 529 530 lines = append(lines, line) 531 }) 532 533 for _, line := range lines { 534 sidx := strings.Index(line, "\x00") 535 spacing := strings.Repeat(" ", maxlen-sidx) 536 fmt.Fprintln(x, line[:sidx], spacing, line[sidx+1:]) 537 } 538 539 return x.String() 540} 541 542// PrintDefaults prints to standard error the default values of all defined command-line flags. 543func PrintDefaults() { 544 CommandLine.PrintDefaults() 545} 546 547// defaultUsage is the default function to print a usage message. 548func defaultUsage(f *FlagSet) { 549 fmt.Fprintf(f.out(), "Usage of %s:\n", f.name) 550 f.PrintDefaults() 551} 552 553// NOTE: Usage is not just defaultUsage(CommandLine) 554// because it serves (via godoc flag Usage) as the example 555// for how to write your own usage function. 556 557// Usage prints to standard error a usage message documenting all defined command-line flags. 558// The function is a variable that may be changed to point to a custom function. 559// By default it prints a simple header and calls PrintDefaults; for details about the 560// format of the output and how to control it, see the documentation for PrintDefaults. 561var Usage = func() { 562 fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) 563 PrintDefaults() 564} 565 566// NFlag returns the number of flags that have been set. 567func (f *FlagSet) NFlag() int { return len(f.actual) } 568 569// NFlag returns the number of command-line flags that have been set. 570func NFlag() int { return len(CommandLine.actual) } 571 572// Arg returns the i'th argument. Arg(0) is the first remaining argument 573// after flags have been processed. 574func (f *FlagSet) Arg(i int) string { 575 if i < 0 || i >= len(f.args) { 576 return "" 577 } 578 return f.args[i] 579} 580 581// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument 582// after flags have been processed. 583func Arg(i int) string { 584 return CommandLine.Arg(i) 585} 586 587// NArg is the number of arguments remaining after flags have been processed. 588func (f *FlagSet) NArg() int { return len(f.args) } 589 590// NArg is the number of arguments remaining after flags have been processed. 591func NArg() int { return len(CommandLine.args) } 592 593// Args returns the non-flag arguments. 594func (f *FlagSet) Args() []string { return f.args } 595 596// Args returns the non-flag command-line arguments. 597func Args() []string { return CommandLine.args } 598 599// Var defines a flag with the specified name and usage string. The type and 600// value of the flag are represented by the first argument, of type Value, which 601// typically holds a user-defined implementation of Value. For instance, the 602// caller could create a flag that turns a comma-separated string into a slice 603// of strings by giving the slice the methods of Value; in particular, Set would 604// decompose the comma-separated string into the slice. 605func (f *FlagSet) Var(value Value, name string, usage string) { 606 f.VarP(value, name, "", usage) 607} 608 609// VarPF is like VarP, but returns the flag created 610func (f *FlagSet) VarPF(value Value, name, shorthand, usage string) *Flag { 611 // Remember the default value as a string; it won't change. 612 flag := &Flag{ 613 Name: name, 614 Shorthand: shorthand, 615 Usage: usage, 616 Value: value, 617 DefValue: value.String(), 618 } 619 f.AddFlag(flag) 620 return flag 621} 622 623// VarP is like Var, but accepts a shorthand letter that can be used after a single dash. 624func (f *FlagSet) VarP(value Value, name, shorthand, usage string) { 625 _ = f.VarPF(value, name, shorthand, usage) 626} 627 628// AddFlag will add the flag to the FlagSet 629func (f *FlagSet) AddFlag(flag *Flag) { 630 // Call normalizeFlagName function only once 631 normalizedFlagName := f.normalizeFlagName(flag.Name) 632 633 _, alreadythere := f.formal[normalizedFlagName] 634 if alreadythere { 635 msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name) 636 fmt.Fprintln(f.out(), msg) 637 panic(msg) // Happens only if flags are declared with identical names 638 } 639 if f.formal == nil { 640 f.formal = make(map[NormalizedName]*Flag) 641 } 642 643 flag.Name = string(normalizedFlagName) 644 f.formal[normalizedFlagName] = flag 645 646 if len(flag.Shorthand) == 0 { 647 return 648 } 649 if len(flag.Shorthand) > 1 { 650 fmt.Fprintf(f.out(), "%s shorthand more than ASCII character: %s\n", f.name, flag.Shorthand) 651 panic("shorthand is more than one character") 652 } 653 if f.shorthands == nil { 654 f.shorthands = make(map[byte]*Flag) 655 } 656 c := flag.Shorthand[0] 657 old, alreadythere := f.shorthands[c] 658 if alreadythere { 659 fmt.Fprintf(f.out(), "%s shorthand reused: %q for %s already used for %s\n", f.name, c, flag.Name, old.Name) 660 panic("shorthand redefinition") 661 } 662 f.shorthands[c] = flag 663} 664 665// AddFlagSet adds one FlagSet to another. If a flag is already present in f 666// the flag from newSet will be ignored 667func (f *FlagSet) AddFlagSet(newSet *FlagSet) { 668 if newSet == nil { 669 return 670 } 671 newSet.VisitAll(func(flag *Flag) { 672 if f.Lookup(flag.Name) == nil { 673 f.AddFlag(flag) 674 } 675 }) 676} 677 678// Var defines a flag with the specified name and usage string. The type and 679// value of the flag are represented by the first argument, of type Value, which 680// typically holds a user-defined implementation of Value. For instance, the 681// caller could create a flag that turns a comma-separated string into a slice 682// of strings by giving the slice the methods of Value; in particular, Set would 683// decompose the comma-separated string into the slice. 684func Var(value Value, name string, usage string) { 685 CommandLine.VarP(value, name, "", usage) 686} 687 688// VarP is like Var, but accepts a shorthand letter that can be used after a single dash. 689func VarP(value Value, name, shorthand, usage string) { 690 CommandLine.VarP(value, name, shorthand, usage) 691} 692 693// failf prints to standard error a formatted error and usage message and 694// returns the error. 695func (f *FlagSet) failf(format string, a ...interface{}) error { 696 err := fmt.Errorf(format, a...) 697 fmt.Fprintln(f.out(), err) 698 f.usage() 699 return err 700} 701 702// usage calls the Usage method for the flag set, or the usage function if 703// the flag set is CommandLine. 704func (f *FlagSet) usage() { 705 if f == CommandLine { 706 Usage() 707 } else if f.Usage == nil { 708 defaultUsage(f) 709 } else { 710 f.Usage() 711 } 712} 713 714func (f *FlagSet) setFlag(flag *Flag, value string, origArg string) error { 715 if err := flag.Value.Set(value); err != nil { 716 return f.failf("invalid argument %q for %s: %v", value, origArg, err) 717 } 718 // mark as visited for Visit() 719 if f.actual == nil { 720 f.actual = make(map[NormalizedName]*Flag) 721 } 722 f.actual[f.normalizeFlagName(flag.Name)] = flag 723 flag.Changed = true 724 if len(flag.Deprecated) > 0 { 725 fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated) 726 } 727 if len(flag.ShorthandDeprecated) > 0 && containsShorthand(origArg, flag.Shorthand) { 728 fmt.Fprintf(os.Stderr, "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated) 729 } 730 return nil 731} 732 733func containsShorthand(arg, shorthand string) bool { 734 // filter out flags --<flag_name> 735 if strings.HasPrefix(arg, "-") { 736 return false 737 } 738 arg = strings.SplitN(arg, "=", 2)[0] 739 return strings.Contains(arg, shorthand) 740} 741 742func (f *FlagSet) parseLongArg(s string, args []string) (a []string, err error) { 743 a = args 744 name := s[2:] 745 if len(name) == 0 || name[0] == '-' || name[0] == '=' { 746 err = f.failf("bad flag syntax: %s", s) 747 return 748 } 749 split := strings.SplitN(name, "=", 2) 750 name = split[0] 751 flag, alreadythere := f.formal[f.normalizeFlagName(name)] 752 if !alreadythere { 753 if name == "help" { // special case for nice help message. 754 f.usage() 755 return a, ErrHelp 756 } 757 err = f.failf("unknown flag: --%s", name) 758 return 759 } 760 var value string 761 if len(split) == 2 { 762 // '--flag=arg' 763 value = split[1] 764 } else if len(flag.NoOptDefVal) > 0 { 765 // '--flag' (arg was optional) 766 value = flag.NoOptDefVal 767 } else if len(a) > 0 { 768 // '--flag arg' 769 value = a[0] 770 a = a[1:] 771 } else { 772 // '--flag' (arg was required) 773 err = f.failf("flag needs an argument: %s", s) 774 return 775 } 776 err = f.setFlag(flag, value, s) 777 return 778} 779 780func (f *FlagSet) parseSingleShortArg(shorthands string, args []string) (outShorts string, outArgs []string, err error) { 781 if strings.HasPrefix(shorthands, "test.") { 782 return 783 } 784 outArgs = args 785 outShorts = shorthands[1:] 786 c := shorthands[0] 787 788 flag, alreadythere := f.shorthands[c] 789 if !alreadythere { 790 if c == 'h' { // special case for nice help message. 791 f.usage() 792 err = ErrHelp 793 return 794 } 795 //TODO continue on error 796 err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands) 797 return 798 } 799 var value string 800 if len(shorthands) > 2 && shorthands[1] == '=' { 801 value = shorthands[2:] 802 outShorts = "" 803 } else if len(flag.NoOptDefVal) > 0 { 804 value = flag.NoOptDefVal 805 } else if len(shorthands) > 1 { 806 value = shorthands[1:] 807 outShorts = "" 808 } else if len(args) > 0 { 809 value = args[0] 810 outArgs = args[1:] 811 } else { 812 err = f.failf("flag needs an argument: %q in -%s", c, shorthands) 813 return 814 } 815 err = f.setFlag(flag, value, shorthands) 816 return 817} 818 819func (f *FlagSet) parseShortArg(s string, args []string) (a []string, err error) { 820 a = args 821 shorthands := s[1:] 822 823 for len(shorthands) > 0 { 824 shorthands, a, err = f.parseSingleShortArg(shorthands, args) 825 if err != nil { 826 return 827 } 828 } 829 830 return 831} 832 833func (f *FlagSet) parseArgs(args []string) (err error) { 834 for len(args) > 0 { 835 s := args[0] 836 args = args[1:] 837 if len(s) == 0 || s[0] != '-' || len(s) == 1 { 838 if !f.interspersed { 839 f.args = append(f.args, s) 840 f.args = append(f.args, args...) 841 return nil 842 } 843 f.args = append(f.args, s) 844 continue 845 } 846 847 if s[1] == '-' { 848 if len(s) == 2 { // "--" terminates the flags 849 f.argsLenAtDash = len(f.args) 850 f.args = append(f.args, args...) 851 break 852 } 853 args, err = f.parseLongArg(s, args) 854 } else { 855 args, err = f.parseShortArg(s, args) 856 } 857 if err != nil { 858 return 859 } 860 } 861 return 862} 863 864// Parse parses flag definitions from the argument list, which should not 865// include the command name. Must be called after all flags in the FlagSet 866// are defined and before flags are accessed by the program. 867// The return value will be ErrHelp if -help was set but not defined. 868func (f *FlagSet) Parse(arguments []string) error { 869 f.parsed = true 870 f.args = make([]string, 0, len(arguments)) 871 err := f.parseArgs(arguments) 872 if err != nil { 873 switch f.errorHandling { 874 case ContinueOnError: 875 return err 876 case ExitOnError: 877 os.Exit(2) 878 case PanicOnError: 879 panic(err) 880 } 881 } 882 return nil 883} 884 885// Parsed reports whether f.Parse has been called. 886func (f *FlagSet) Parsed() bool { 887 return f.parsed 888} 889 890// Parse parses the command-line flags from os.Args[1:]. Must be called 891// after all flags are defined and before flags are accessed by the program. 892func Parse() { 893 // Ignore errors; CommandLine is set for ExitOnError. 894 CommandLine.Parse(os.Args[1:]) 895} 896 897// SetInterspersed sets whether to support interspersed option/non-option arguments. 898func SetInterspersed(interspersed bool) { 899 CommandLine.SetInterspersed(interspersed) 900} 901 902// Parsed returns true if the command-line flags have been parsed. 903func Parsed() bool { 904 return CommandLine.Parsed() 905} 906 907// CommandLine is the default set of command-line flags, parsed from os.Args. 908var CommandLine = NewFlagSet(os.Args[0], ExitOnError) 909 910// NewFlagSet returns a new, empty flag set with the specified name and 911// error handling property. 912func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { 913 f := &FlagSet{ 914 name: name, 915 errorHandling: errorHandling, 916 argsLenAtDash: -1, 917 interspersed: true, 918 } 919 return f 920} 921 922// SetInterspersed sets whether to support interspersed option/non-option arguments. 923func (f *FlagSet) SetInterspersed(interspersed bool) { 924 f.interspersed = interspersed 925} 926 927// Init sets the name and error handling property for a flag set. 928// By default, the zero FlagSet uses an empty name and the 929// ContinueOnError error handling policy. 930func (f *FlagSet) Init(name string, errorHandling ErrorHandling) { 931 f.name = name 932 f.errorHandling = errorHandling 933 f.argsLenAtDash = -1 934} 935