1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246 |
- // Copyright 2009 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- /*
- Package pflag is a drop-in replacement for Go's flag package, implementing
- POSIX/GNU-style --flags.
- pflag is compatible with the GNU extensions to the POSIX recommendations
- for command-line options. See
- http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
- Usage:
- pflag is a drop-in replacement of Go's native flag package. If you import
- pflag under the name "flag" then all code should continue to function
- with no changes.
- import flag "github.com/spf13/pflag"
- There is one exception to this: if you directly instantiate the Flag struct
- there is one more field "Shorthand" that you will need to set.
- Most code never instantiates this struct directly, and instead uses
- functions such as String(), BoolVar(), and Var(), and is therefore
- unaffected.
- Define flags using flag.String(), Bool(), Int(), etc.
- This declares an integer flag, -flagname, stored in the pointer ip, with type *int.
- var ip = flag.Int("flagname", 1234, "help message for flagname")
- If you like, you can bind the flag to a variable using the Var() functions.
- var flagvar int
- func init() {
- flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
- }
- Or you can create custom flags that satisfy the Value interface (with
- pointer receivers) and couple them to flag parsing by
- flag.Var(&flagVal, "name", "help message for flagname")
- For such flags, the default value is just the initial value of the variable.
- After all flags are defined, call
- flag.Parse()
- to parse the command line into the defined flags.
- Flags may then be used directly. If you're using the flags themselves,
- they are all pointers; if you bind to variables, they're values.
- fmt.Println("ip has value ", *ip)
- fmt.Println("flagvar has value ", flagvar)
- After parsing, the arguments after the flag are available as the
- slice flag.Args() or individually as flag.Arg(i).
- The arguments are indexed from 0 through flag.NArg()-1.
- The pflag package also defines some new functions that are not in flag,
- that give one-letter shorthands for flags. You can use these by appending
- 'P' to the name of any function that defines a flag.
- var ip = flag.IntP("flagname", "f", 1234, "help message")
- var flagvar bool
- func init() {
- flag.BoolVarP(&flagvar, "boolname", "b", true, "help message")
- }
- flag.VarP(&flagval, "varname", "v", "help message")
- Shorthand letters can be used with single dashes on the command line.
- Boolean shorthand flags can be combined with other shorthand flags.
- Command line flag syntax:
- --flag // boolean flags only
- --flag=x
- Unlike the flag package, a single dash before an option means something
- different than a double dash. Single dashes signify a series of shorthand
- letters for flags. All but the last shorthand letter must be boolean flags.
- // boolean flags
- -f
- -abc
- // non-boolean flags
- -n 1234
- -Ifile
- // mixed
- -abcs "hello"
- -abcn1234
- Flag parsing stops after the terminator "--". Unlike the flag package,
- flags can be interspersed with arguments anywhere on the command line
- before this terminator.
- Integer flags accept 1234, 0664, 0x1234 and may be negative.
- Boolean flags (in their long form) accept 1, 0, t, f, true, false,
- TRUE, FALSE, True, False.
- Duration flags accept any input valid for time.ParseDuration.
- The default set of command-line flags is controlled by
- top-level functions. The FlagSet type allows one to define
- independent sets of flags, such as to implement subcommands
- in a command-line interface. The methods of FlagSet are
- analogous to the top-level functions for the command-line
- flag set.
- */
- package pflag
- import (
- "bytes"
- "errors"
- goflag "flag"
- "fmt"
- "io"
- "os"
- "sort"
- "strings"
- )
- // ErrHelp is the error returned if the flag -help is invoked but no such flag is defined.
- var ErrHelp = errors.New("pflag: help requested")
- // ErrorHandling defines how to handle flag parsing errors.
- type ErrorHandling int
- const (
- // ContinueOnError will return an err from Parse() if an error is found
- ContinueOnError ErrorHandling = iota
- // ExitOnError will call os.Exit(2) if an error is found when parsing
- ExitOnError
- // PanicOnError will panic() if an error is found when parsing flags
- PanicOnError
- )
- // ParseErrorsWhitelist defines the parsing errors that can be ignored
- type ParseErrorsWhitelist struct {
- // UnknownFlags will ignore unknown flags errors and continue parsing rest of the flags
- UnknownFlags bool
- }
- // NormalizedName is a flag name that has been normalized according to rules
- // for the FlagSet (e.g. making '-' and '_' equivalent).
- type NormalizedName string
- // A FlagSet represents a set of defined flags.
- type FlagSet struct {
- // Usage is the function called when an error occurs while parsing flags.
- // The field is a function (not a method) that may be changed to point to
- // a custom error handler.
- Usage func()
- // SortFlags is used to indicate, if user wants to have sorted flags in
- // help/usage messages.
- SortFlags bool
- // ParseErrorsWhitelist is used to configure a whitelist of errors
- ParseErrorsWhitelist ParseErrorsWhitelist
- name string
- parsed bool
- actual map[NormalizedName]*Flag
- orderedActual []*Flag
- sortedActual []*Flag
- formal map[NormalizedName]*Flag
- orderedFormal []*Flag
- sortedFormal []*Flag
- shorthands map[byte]*Flag
- args []string // arguments after flags
- argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no --
- errorHandling ErrorHandling
- output io.Writer // nil means stderr; use Output() accessor
- interspersed bool // allow interspersed option/non-option args
- normalizeNameFunc func(f *FlagSet, name string) NormalizedName
- addedGoFlagSets []*goflag.FlagSet
- }
- // A Flag represents the state of a flag.
- type Flag struct {
- Name string // name as it appears on command line
- Shorthand string // one-letter abbreviated flag
- Usage string // help message
- Value Value // value as set
- DefValue string // default value (as text); for usage message
- Changed bool // If the user set the value (or if left to default)
- NoOptDefVal string // default value (as text); if the flag is on the command line without any options
- Deprecated string // If this flag is deprecated, this string is the new or now thing to use
- Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text
- ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use
- Annotations map[string][]string // used by cobra.Command bash autocomple code
- }
- // Value is the interface to the dynamic value stored in a flag.
- // (The default value is represented as a string.)
- type Value interface {
- String() string
- Set(string) error
- Type() string
- }
- // SliceValue is a secondary interface to all flags which hold a list
- // of values. This allows full control over the value of list flags,
- // and avoids complicated marshalling and unmarshalling to csv.
- type SliceValue interface {
- // Append adds the specified value to the end of the flag value list.
- Append(string) error
- // Replace will fully overwrite any data currently in the flag value list.
- Replace([]string) error
- // GetSlice returns the flag value list as an array of strings.
- GetSlice() []string
- }
- // sortFlags returns the flags as a slice in lexicographical sorted order.
- func sortFlags(flags map[NormalizedName]*Flag) []*Flag {
- list := make(sort.StringSlice, len(flags))
- i := 0
- for k := range flags {
- list[i] = string(k)
- i++
- }
- list.Sort()
- result := make([]*Flag, len(list))
- for i, name := range list {
- result[i] = flags[NormalizedName(name)]
- }
- return result
- }
- // SetNormalizeFunc allows you to add a function which can translate flag names.
- // Flags added to the FlagSet will be translated and then when anything tries to
- // look up the flag that will also be translated. So it would be possible to create
- // a flag named "getURL" and have it translated to "geturl". A user could then pass
- // "--getUrl" which may also be translated to "geturl" and everything will work.
- func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) {
- f.normalizeNameFunc = n
- f.sortedFormal = f.sortedFormal[:0]
- for fname, flag := range f.formal {
- nname := f.normalizeFlagName(flag.Name)
- if fname == nname {
- continue
- }
- flag.Name = string(nname)
- delete(f.formal, fname)
- f.formal[nname] = flag
- if _, set := f.actual[fname]; set {
- delete(f.actual, fname)
- f.actual[nname] = flag
- }
- }
- }
- // GetNormalizeFunc returns the previously set NormalizeFunc of a function which
- // does no translation, if not set previously.
- func (f *FlagSet) GetNormalizeFunc() func(f *FlagSet, name string) NormalizedName {
- if f.normalizeNameFunc != nil {
- return f.normalizeNameFunc
- }
- return func(f *FlagSet, name string) NormalizedName { return NormalizedName(name) }
- }
- func (f *FlagSet) normalizeFlagName(name string) NormalizedName {
- n := f.GetNormalizeFunc()
- return n(f, name)
- }
- // Output returns the destination for usage and error messages. os.Stderr is returned if
- // output was not set or was set to nil.
- func (f *FlagSet) Output() io.Writer {
- if f.output == nil {
- return os.Stderr
- }
- return f.output
- }
- // Name returns the name of the flag set.
- func (f *FlagSet) Name() string {
- return f.name
- }
- // SetOutput sets the destination for usage and error messages.
- // If output is nil, os.Stderr is used.
- func (f *FlagSet) SetOutput(output io.Writer) {
- f.output = output
- }
- // VisitAll visits the flags in lexicographical order or
- // in primordial order if f.SortFlags is false, calling fn for each.
- // It visits all flags, even those not set.
- func (f *FlagSet) VisitAll(fn func(*Flag)) {
- if len(f.formal) == 0 {
- return
- }
- var flags []*Flag
- if f.SortFlags {
- if len(f.formal) != len(f.sortedFormal) {
- f.sortedFormal = sortFlags(f.formal)
- }
- flags = f.sortedFormal
- } else {
- flags = f.orderedFormal
- }
- for _, flag := range flags {
- fn(flag)
- }
- }
- // HasFlags returns a bool to indicate if the FlagSet has any flags defined.
- func (f *FlagSet) HasFlags() bool {
- return len(f.formal) > 0
- }
- // HasAvailableFlags returns a bool to indicate if the FlagSet has any flags
- // that are not hidden.
- func (f *FlagSet) HasAvailableFlags() bool {
- for _, flag := range f.formal {
- if !flag.Hidden {
- return true
- }
- }
- return false
- }
- // VisitAll visits the command-line flags in lexicographical order or
- // in primordial order if f.SortFlags is false, calling fn for each.
- // It visits all flags, even those not set.
- func VisitAll(fn func(*Flag)) {
- CommandLine.VisitAll(fn)
- }
- // Visit visits the flags in lexicographical order or
- // in primordial order if f.SortFlags is false, calling fn for each.
- // It visits only those flags that have been set.
- func (f *FlagSet) Visit(fn func(*Flag)) {
- if len(f.actual) == 0 {
- return
- }
- var flags []*Flag
- if f.SortFlags {
- if len(f.actual) != len(f.sortedActual) {
- f.sortedActual = sortFlags(f.actual)
- }
- flags = f.sortedActual
- } else {
- flags = f.orderedActual
- }
- for _, flag := range flags {
- fn(flag)
- }
- }
- // Visit visits the command-line flags in lexicographical order or
- // in primordial order if f.SortFlags is false, calling fn for each.
- // It visits only those flags that have been set.
- func Visit(fn func(*Flag)) {
- CommandLine.Visit(fn)
- }
- // Lookup returns the Flag structure of the named flag, returning nil if none exists.
- func (f *FlagSet) Lookup(name string) *Flag {
- return f.lookup(f.normalizeFlagName(name))
- }
- // ShorthandLookup returns the Flag structure of the short handed flag,
- // returning nil if none exists.
- // It panics, if len(name) > 1.
- func (f *FlagSet) ShorthandLookup(name string) *Flag {
- if name == "" {
- return nil
- }
- if len(name) > 1 {
- msg := fmt.Sprintf("can not look up shorthand which is more than one ASCII character: %q", name)
- fmt.Fprintf(f.Output(), msg)
- panic(msg)
- }
- c := name[0]
- return f.shorthands[c]
- }
- // lookup returns the Flag structure of the named flag, returning nil if none exists.
- func (f *FlagSet) lookup(name NormalizedName) *Flag {
- return f.formal[name]
- }
- // func to return a given type for a given flag name
- func (f *FlagSet) getFlagType(name string, ftype string, convFunc func(sval string) (interface{}, error)) (interface{}, error) {
- flag := f.Lookup(name)
- if flag == nil {
- err := fmt.Errorf("flag accessed but not defined: %s", name)
- return nil, err
- }
- if flag.Value.Type() != ftype {
- err := fmt.Errorf("trying to get %s value of flag of type %s", ftype, flag.Value.Type())
- return nil, err
- }
- sval := flag.Value.String()
- result, err := convFunc(sval)
- if err != nil {
- return nil, err
- }
- return result, nil
- }
- // ArgsLenAtDash will return the length of f.Args at the moment when a -- was
- // found during arg parsing. This allows your program to know which args were
- // before the -- and which came after.
- func (f *FlagSet) ArgsLenAtDash() int {
- return f.argsLenAtDash
- }
- // MarkDeprecated indicated that a flag is deprecated in your program. It will
- // continue to function but will not show up in help or usage messages. Using
- // this flag will also print the given usageMessage.
- func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error {
- flag := f.Lookup(name)
- if flag == nil {
- return fmt.Errorf("flag %q does not exist", name)
- }
- if usageMessage == "" {
- return fmt.Errorf("deprecated message for flag %q must be set", name)
- }
- flag.Deprecated = usageMessage
- flag.Hidden = true
- return nil
- }
- // MarkShorthandDeprecated will mark the shorthand of a flag deprecated in your
- // program. It will continue to function but will not show up in help or usage
- // messages. Using this flag will also print the given usageMessage.
- func (f *FlagSet) MarkShorthandDeprecated(name string, usageMessage string) error {
- flag := f.Lookup(name)
- if flag == nil {
- return fmt.Errorf("flag %q does not exist", name)
- }
- if usageMessage == "" {
- return fmt.Errorf("deprecated message for flag %q must be set", name)
- }
- flag.ShorthandDeprecated = usageMessage
- return nil
- }
- // MarkHidden sets a flag to 'hidden' in your program. It will continue to
- // function but will not show up in help or usage messages.
- func (f *FlagSet) MarkHidden(name string) error {
- flag := f.Lookup(name)
- if flag == nil {
- return fmt.Errorf("flag %q does not exist", name)
- }
- flag.Hidden = true
- return nil
- }
- // Lookup returns the Flag structure of the named command-line flag,
- // returning nil if none exists.
- func Lookup(name string) *Flag {
- return CommandLine.Lookup(name)
- }
- // ShorthandLookup returns the Flag structure of the short handed flag,
- // returning nil if none exists.
- func ShorthandLookup(name string) *Flag {
- return CommandLine.ShorthandLookup(name)
- }
- // Set sets the value of the named flag.
- func (f *FlagSet) Set(name, value string) error {
- normalName := f.normalizeFlagName(name)
- flag, ok := f.formal[normalName]
- if !ok {
- return fmt.Errorf("no such flag -%v", name)
- }
- err := flag.Value.Set(value)
- if err != nil {
- var flagName string
- if flag.Shorthand != "" && flag.ShorthandDeprecated == "" {
- flagName = fmt.Sprintf("-%s, --%s", flag.Shorthand, flag.Name)
- } else {
- flagName = fmt.Sprintf("--%s", flag.Name)
- }
- return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err)
- }
- if !flag.Changed {
- if f.actual == nil {
- f.actual = make(map[NormalizedName]*Flag)
- }
- f.actual[normalName] = flag
- f.orderedActual = append(f.orderedActual, flag)
- flag.Changed = true
- }
- if flag.Deprecated != "" {
- fmt.Fprintf(f.Output(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
- }
- return nil
- }
- // SetAnnotation allows one to set arbitrary annotations on a flag in the FlagSet.
- // This is sometimes used by spf13/cobra programs which want to generate additional
- // bash completion information.
- func (f *FlagSet) SetAnnotation(name, key string, values []string) error {
- normalName := f.normalizeFlagName(name)
- flag, ok := f.formal[normalName]
- if !ok {
- return fmt.Errorf("no such flag -%v", name)
- }
- if flag.Annotations == nil {
- flag.Annotations = map[string][]string{}
- }
- flag.Annotations[key] = values
- return nil
- }
- // Changed returns true if the flag was explicitly set during Parse() and false
- // otherwise
- func (f *FlagSet) Changed(name string) bool {
- flag := f.Lookup(name)
- // If a flag doesn't exist, it wasn't changed....
- if flag == nil {
- return false
- }
- return flag.Changed
- }
- // Set sets the value of the named command-line flag.
- func Set(name, value string) error {
- return CommandLine.Set(name, value)
- }
- // PrintDefaults prints, to standard error unless configured
- // otherwise, the default values of all defined flags in the set.
- func (f *FlagSet) PrintDefaults() {
- usages := f.FlagUsages()
- fmt.Fprint(f.Output(), usages)
- }
- // defaultIsZeroValue returns true if the default value for this flag represents
- // a zero value.
- func (f *Flag) defaultIsZeroValue() bool {
- switch f.Value.(type) {
- case boolFlag:
- return f.DefValue == "false"
- case *durationValue:
- // Beginning in Go 1.7, duration zero values are "0s"
- return f.DefValue == "0" || f.DefValue == "0s"
- case *intValue, *int8Value, *int32Value, *int64Value, *uintValue, *uint8Value, *uint16Value, *uint32Value, *uint64Value, *countValue, *float32Value, *float64Value:
- return f.DefValue == "0"
- case *stringValue:
- return f.DefValue == ""
- case *ipValue, *ipMaskValue, *ipNetValue:
- return f.DefValue == "<nil>"
- case *intSliceValue, *stringSliceValue, *stringArrayValue:
- return f.DefValue == "[]"
- default:
- switch f.Value.String() {
- case "false":
- return true
- case "<nil>":
- return true
- case "":
- return true
- case "0":
- return true
- }
- return false
- }
- }
- // UnquoteUsage extracts a back-quoted name from the usage
- // string for a flag and returns it and the un-quoted usage.
- // Given "a `name` to show" it returns ("name", "a name to show").
- // If there are no back quotes, the name is an educated guess of the
- // type of the flag's value, or the empty string if the flag is boolean.
- func UnquoteUsage(flag *Flag) (name string, usage string) {
- // Look for a back-quoted name, but avoid the strings package.
- usage = flag.Usage
- for i := 0; i < len(usage); i++ {
- if usage[i] == '`' {
- for j := i + 1; j < len(usage); j++ {
- if usage[j] == '`' {
- name = usage[i+1 : j]
- usage = usage[:i] + name + usage[j+1:]
- return name, usage
- }
- }
- break // Only one back quote; use type name.
- }
- }
- name = flag.Value.Type()
- switch name {
- case "bool":
- name = ""
- case "float64":
- name = "float"
- case "int64":
- name = "int"
- case "uint64":
- name = "uint"
- case "stringSlice":
- name = "strings"
- case "intSlice":
- name = "ints"
- case "uintSlice":
- name = "uints"
- case "boolSlice":
- name = "bools"
- }
- return
- }
- // Splits the string `s` on whitespace into an initial substring up to
- // `i` runes in length and the remainder. Will go `slop` over `i` if
- // that encompasses the entire string (which allows the caller to
- // avoid short orphan words on the final line).
- func wrapN(i, slop int, s string) (string, string) {
- if i+slop > len(s) {
- return s, ""
- }
- w := strings.LastIndexAny(s[:i], " \t\n")
- if w <= 0 {
- return s, ""
- }
- nlPos := strings.LastIndex(s[:i], "\n")
- if nlPos > 0 && nlPos < w {
- return s[:nlPos], s[nlPos+1:]
- }
- return s[:w], s[w+1:]
- }
- // Wraps the string `s` to a maximum width `w` with leading indent
- // `i`. The first line is not indented (this is assumed to be done by
- // caller). Pass `w` == 0 to do no wrapping
- func wrap(i, w int, s string) string {
- if w == 0 {
- return strings.Replace(s, "\n", "\n"+strings.Repeat(" ", i), -1)
- }
- // space between indent i and end of line width w into which
- // we should wrap the text.
- wrap := w - i
- var r, l string
- // Not enough space for sensible wrapping. Wrap as a block on
- // the next line instead.
- if wrap < 24 {
- i = 16
- wrap = w - i
- r += "\n" + strings.Repeat(" ", i)
- }
- // If still not enough space then don't even try to wrap.
- if wrap < 24 {
- return strings.Replace(s, "\n", r, -1)
- }
- // Try to avoid short orphan words on the final line, by
- // allowing wrapN to go a bit over if that would fit in the
- // remainder of the line.
- slop := 5
- wrap = wrap - slop
- // Handle first line, which is indented by the caller (or the
- // special case above)
- l, s = wrapN(wrap, slop, s)
- r = r + strings.Replace(l, "\n", "\n"+strings.Repeat(" ", i), -1)
- // Now wrap the rest
- for s != "" {
- var t string
- t, s = wrapN(wrap, slop, s)
- r = r + "\n" + strings.Repeat(" ", i) + strings.Replace(t, "\n", "\n"+strings.Repeat(" ", i), -1)
- }
- return r
- }
- // FlagUsagesWrapped returns a string containing the usage information
- // for all flags in the FlagSet. Wrapped to `cols` columns (0 for no
- // wrapping)
- func (f *FlagSet) FlagUsagesWrapped(cols int) string {
- buf := new(bytes.Buffer)
- lines := make([]string, 0, len(f.formal))
- maxlen := 0
- f.VisitAll(func(flag *Flag) {
- if flag.Hidden {
- return
- }
- line := ""
- if flag.Shorthand != "" && flag.ShorthandDeprecated == "" {
- line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name)
- } else {
- line = fmt.Sprintf(" --%s", flag.Name)
- }
- varname, usage := UnquoteUsage(flag)
- if varname != "" {
- line += " " + varname
- }
- if flag.NoOptDefVal != "" {
- switch flag.Value.Type() {
- case "string":
- line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal)
- case "bool":
- if flag.NoOptDefVal != "true" {
- line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
- }
- case "count":
- if flag.NoOptDefVal != "+1" {
- line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
- }
- default:
- line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
- }
- }
- // This special character will be replaced with spacing once the
- // correct alignment is calculated
- line += "\x00"
- if len(line) > maxlen {
- maxlen = len(line)
- }
- line += usage
- if !flag.defaultIsZeroValue() {
- if flag.Value.Type() == "string" {
- line += fmt.Sprintf(" (default %q)", flag.DefValue)
- } else {
- line += fmt.Sprintf(" (default %s)", flag.DefValue)
- }
- }
- if len(flag.Deprecated) != 0 {
- line += fmt.Sprintf(" (DEPRECATED: %s)", flag.Deprecated)
- }
- lines = append(lines, line)
- })
- for _, line := range lines {
- sidx := strings.Index(line, "\x00")
- spacing := strings.Repeat(" ", maxlen-sidx)
- // maxlen + 2 comes from + 1 for the \x00 and + 1 for the (deliberate) off-by-one in maxlen-sidx
- fmt.Fprintln(buf, line[:sidx], spacing, wrap(maxlen+2, cols, line[sidx+1:]))
- }
- return buf.String()
- }
- // FlagUsages returns a string containing the usage information for all flags in
- // the FlagSet
- func (f *FlagSet) FlagUsages() string {
- return f.FlagUsagesWrapped(0)
- }
- // PrintDefaults prints to standard error the default values of all defined command-line flags.
- func PrintDefaults() {
- CommandLine.PrintDefaults()
- }
- // defaultUsage is the default function to print a usage message.
- func defaultUsage(f *FlagSet) {
- fmt.Fprintf(f.Output(), "Usage of %s:\n", f.name)
- f.PrintDefaults()
- }
- // NOTE: Usage is not just defaultUsage(CommandLine)
- // because it serves (via godoc flag Usage) as the example
- // for how to write your own usage function.
- // Usage prints to standard error a usage message documenting all defined command-line flags.
- // The function is a variable that may be changed to point to a custom function.
- // By default it prints a simple header and calls PrintDefaults; for details about the
- // format of the output and how to control it, see the documentation for PrintDefaults.
- var Usage = func() {
- fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
- PrintDefaults()
- }
- // NFlag returns the number of flags that have been set.
- func (f *FlagSet) NFlag() int { return len(f.actual) }
- // NFlag returns the number of command-line flags that have been set.
- func NFlag() int { return len(CommandLine.actual) }
- // Arg returns the i'th argument. Arg(0) is the first remaining argument
- // after flags have been processed.
- func (f *FlagSet) Arg(i int) string {
- if i < 0 || i >= len(f.args) {
- return ""
- }
- return f.args[i]
- }
- // Arg returns the i'th command-line argument. Arg(0) is the first remaining argument
- // after flags have been processed.
- func Arg(i int) string {
- return CommandLine.Arg(i)
- }
- // NArg is the number of arguments remaining after flags have been processed.
- func (f *FlagSet) NArg() int { return len(f.args) }
- // NArg is the number of arguments remaining after flags have been processed.
- func NArg() int { return len(CommandLine.args) }
- // Args returns the non-flag arguments.
- func (f *FlagSet) Args() []string { return f.args }
- // Args returns the non-flag command-line arguments.
- func Args() []string { return CommandLine.args }
- // Var defines a flag with the specified name and usage string. The type and
- // value of the flag are represented by the first argument, of type Value, which
- // typically holds a user-defined implementation of Value. For instance, the
- // caller could create a flag that turns a comma-separated string into a slice
- // of strings by giving the slice the methods of Value; in particular, Set would
- // decompose the comma-separated string into the slice.
- func (f *FlagSet) Var(value Value, name string, usage string) {
- f.VarP(value, name, "", usage)
- }
- // VarPF is like VarP, but returns the flag created
- func (f *FlagSet) VarPF(value Value, name, shorthand, usage string) *Flag {
- // Remember the default value as a string; it won't change.
- flag := &Flag{
- Name: name,
- Shorthand: shorthand,
- Usage: usage,
- Value: value,
- DefValue: value.String(),
- }
- f.AddFlag(flag)
- return flag
- }
- // VarP is like Var, but accepts a shorthand letter that can be used after a single dash.
- func (f *FlagSet) VarP(value Value, name, shorthand, usage string) {
- f.VarPF(value, name, shorthand, usage)
- }
- // AddFlag will add the flag to the FlagSet
- func (f *FlagSet) AddFlag(flag *Flag) {
- normalizedFlagName := f.normalizeFlagName(flag.Name)
- _, alreadyThere := f.formal[normalizedFlagName]
- if alreadyThere {
- msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name)
- fmt.Fprintln(f.Output(), msg)
- panic(msg) // Happens only if flags are declared with identical names
- }
- if f.formal == nil {
- f.formal = make(map[NormalizedName]*Flag)
- }
- flag.Name = string(normalizedFlagName)
- f.formal[normalizedFlagName] = flag
- f.orderedFormal = append(f.orderedFormal, flag)
- if flag.Shorthand == "" {
- return
- }
- if len(flag.Shorthand) > 1 {
- msg := fmt.Sprintf("%q shorthand is more than one ASCII character", flag.Shorthand)
- fmt.Fprintf(f.Output(), msg)
- panic(msg)
- }
- if f.shorthands == nil {
- f.shorthands = make(map[byte]*Flag)
- }
- c := flag.Shorthand[0]
- used, alreadyThere := f.shorthands[c]
- if alreadyThere {
- msg := fmt.Sprintf("unable to redefine %q shorthand in %q flagset: it's already used for %q flag", c, f.name, used.Name)
- fmt.Fprintf(f.Output(), msg)
- panic(msg)
- }
- f.shorthands[c] = flag
- }
- // AddFlagSet adds one FlagSet to another. If a flag is already present in f
- // the flag from newSet will be ignored.
- func (f *FlagSet) AddFlagSet(newSet *FlagSet) {
- if newSet == nil {
- return
- }
- newSet.VisitAll(func(flag *Flag) {
- if f.Lookup(flag.Name) == nil {
- f.AddFlag(flag)
- }
- })
- }
- // Var defines a flag with the specified name and usage string. The type and
- // value of the flag are represented by the first argument, of type Value, which
- // typically holds a user-defined implementation of Value. For instance, the
- // caller could create a flag that turns a comma-separated string into a slice
- // of strings by giving the slice the methods of Value; in particular, Set would
- // decompose the comma-separated string into the slice.
- func Var(value Value, name string, usage string) {
- CommandLine.VarP(value, name, "", usage)
- }
- // VarP is like Var, but accepts a shorthand letter that can be used after a single dash.
- func VarP(value Value, name, shorthand, usage string) {
- CommandLine.VarP(value, name, shorthand, usage)
- }
- // failf prints to standard error a formatted error and usage message and
- // returns the error.
- func (f *FlagSet) failf(format string, a ...interface{}) error {
- err := fmt.Errorf(format, a...)
- if f.errorHandling != ContinueOnError {
- fmt.Fprintln(f.Output(), err)
- f.usage()
- }
- return err
- }
- // usage calls the Usage method for the flag set, or the usage function if
- // the flag set is CommandLine.
- func (f *FlagSet) usage() {
- if f == CommandLine {
- Usage()
- } else if f.Usage == nil {
- defaultUsage(f)
- } else {
- f.Usage()
- }
- }
- //--unknown (args will be empty)
- //--unknown --next-flag ... (args will be --next-flag ...)
- //--unknown arg ... (args will be arg ...)
- func stripUnknownFlagValue(args []string) []string {
- if len(args) == 0 {
- //--unknown
- return args
- }
- first := args[0]
- if len(first) > 0 && first[0] == '-' {
- //--unknown --next-flag ...
- return args
- }
- //--unknown arg ... (args will be arg ...)
- if len(args) > 1 {
- return args[1:]
- }
- return nil
- }
- func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) {
- a = args
- name := s[2:]
- if len(name) == 0 || name[0] == '-' || name[0] == '=' {
- err = f.failf("bad flag syntax: %s", s)
- return
- }
- split := strings.SplitN(name, "=", 2)
- name = split[0]
- flag, exists := f.formal[f.normalizeFlagName(name)]
- if !exists {
- switch {
- case name == "help":
- f.usage()
- return a, ErrHelp
- case f.ParseErrorsWhitelist.UnknownFlags:
- // --unknown=unknownval arg ...
- // we do not want to lose arg in this case
- if len(split) >= 2 {
- return a, nil
- }
- return stripUnknownFlagValue(a), nil
- default:
- err = f.failf("unknown flag: --%s", name)
- return
- }
- }
- var value string
- if len(split) == 2 {
- // '--flag=arg'
- value = split[1]
- } else if flag.NoOptDefVal != "" {
- // '--flag' (arg was optional)
- value = flag.NoOptDefVal
- } else if len(a) > 0 {
- // '--flag arg'
- value = a[0]
- a = a[1:]
- } else {
- // '--flag' (arg was required)
- err = f.failf("flag needs an argument: %s", s)
- return
- }
- err = fn(flag, value)
- if err != nil {
- f.failf(err.Error())
- }
- return
- }
- func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) {
- outArgs = args
- if strings.HasPrefix(shorthands, "test.") {
- return
- }
- outShorts = shorthands[1:]
- c := shorthands[0]
- flag, exists := f.shorthands[c]
- if !exists {
- switch {
- case c == 'h':
- f.usage()
- err = ErrHelp
- return
- case f.ParseErrorsWhitelist.UnknownFlags:
- // '-f=arg arg ...'
- // we do not want to lose arg in this case
- if len(shorthands) > 2 && shorthands[1] == '=' {
- outShorts = ""
- return
- }
- outArgs = stripUnknownFlagValue(outArgs)
- return
- default:
- err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands)
- return
- }
- }
- var value string
- if len(shorthands) > 2 && shorthands[1] == '=' {
- // '-f=arg'
- value = shorthands[2:]
- outShorts = ""
- } else if flag.NoOptDefVal != "" {
- // '-f' (arg was optional)
- value = flag.NoOptDefVal
- } else if len(shorthands) > 1 {
- // '-farg'
- value = shorthands[1:]
- outShorts = ""
- } else if len(args) > 0 {
- // '-f arg'
- value = args[0]
- outArgs = args[1:]
- } else {
- // '-f' (arg was required)
- err = f.failf("flag needs an argument: %q in -%s", c, shorthands)
- return
- }
- if flag.ShorthandDeprecated != "" {
- fmt.Fprintf(f.Output(), "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated)
- }
- err = fn(flag, value)
- if err != nil {
- f.failf(err.Error())
- }
- return
- }
- func (f *FlagSet) parseShortArg(s string, args []string, fn parseFunc) (a []string, err error) {
- a = args
- shorthands := s[1:]
- // "shorthands" can be a series of shorthand letters of flags (e.g. "-vvv").
- for len(shorthands) > 0 {
- shorthands, a, err = f.parseSingleShortArg(shorthands, args, fn)
- if err != nil {
- return
- }
- }
- return
- }
- func (f *FlagSet) parseArgs(args []string, fn parseFunc) (err error) {
- for len(args) > 0 {
- s := args[0]
- args = args[1:]
- if len(s) == 0 || s[0] != '-' || len(s) == 1 {
- if !f.interspersed {
- f.args = append(f.args, s)
- f.args = append(f.args, args...)
- return nil
- }
- f.args = append(f.args, s)
- continue
- }
- if s[1] == '-' {
- if len(s) == 2 { // "--" terminates the flags
- f.argsLenAtDash = len(f.args)
- f.args = append(f.args, args...)
- break
- }
- args, err = f.parseLongArg(s, args, fn)
- } else {
- args, err = f.parseShortArg(s, args, fn)
- }
- if err != nil {
- return
- }
- }
- return
- }
- // Parse parses flag definitions from the argument list, which should not
- // include the command name. Must be called after all flags in the FlagSet
- // are defined and before flags are accessed by the program.
- // The return value will be ErrHelp if -help was set but not defined.
- func (f *FlagSet) Parse(arguments []string) error {
- if f.addedGoFlagSets != nil {
- for _, goFlagSet := range f.addedGoFlagSets {
- goFlagSet.Parse(nil)
- }
- }
- f.parsed = true
- if len(arguments) < 0 {
- return nil
- }
- f.args = make([]string, 0, len(arguments))
- set := func(flag *Flag, value string) error {
- return f.Set(flag.Name, value)
- }
- err := f.parseArgs(arguments, set)
- if err != nil {
- switch f.errorHandling {
- case ContinueOnError:
- return err
- case ExitOnError:
- fmt.Println(err)
- os.Exit(2)
- case PanicOnError:
- panic(err)
- }
- }
- return nil
- }
- type parseFunc func(flag *Flag, value string) error
- // ParseAll parses flag definitions from the argument list, which should not
- // include the command name. The arguments for fn are flag and value. Must be
- // called after all flags in the FlagSet are defined and before flags are
- // accessed by the program. The return value will be ErrHelp if -help was set
- // but not defined.
- func (f *FlagSet) ParseAll(arguments []string, fn func(flag *Flag, value string) error) error {
- f.parsed = true
- f.args = make([]string, 0, len(arguments))
- err := f.parseArgs(arguments, fn)
- if err != nil {
- switch f.errorHandling {
- case ContinueOnError:
- return err
- case ExitOnError:
- os.Exit(2)
- case PanicOnError:
- panic(err)
- }
- }
- return nil
- }
- // Parsed reports whether f.Parse has been called.
- func (f *FlagSet) Parsed() bool {
- return f.parsed
- }
- // Parse parses the command-line flags from os.Args[1:]. Must be called
- // after all flags are defined and before flags are accessed by the program.
- func Parse() {
- // Ignore errors; CommandLine is set for ExitOnError.
- CommandLine.Parse(os.Args[1:])
- }
- // ParseAll parses the command-line flags from os.Args[1:] and called fn for each.
- // The arguments for fn are flag and value. Must be called after all flags are
- // defined and before flags are accessed by the program.
- func ParseAll(fn func(flag *Flag, value string) error) {
- // Ignore errors; CommandLine is set for ExitOnError.
- CommandLine.ParseAll(os.Args[1:], fn)
- }
- // SetInterspersed sets whether to support interspersed option/non-option arguments.
- func SetInterspersed(interspersed bool) {
- CommandLine.SetInterspersed(interspersed)
- }
- // Parsed returns true if the command-line flags have been parsed.
- func Parsed() bool {
- return CommandLine.Parsed()
- }
- // CommandLine is the default set of command-line flags, parsed from os.Args.
- var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
- // NewFlagSet returns a new, empty flag set with the specified name,
- // error handling property and SortFlags set to true.
- func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
- f := &FlagSet{
- name: name,
- errorHandling: errorHandling,
- argsLenAtDash: -1,
- interspersed: true,
- SortFlags: true,
- }
- return f
- }
- // SetInterspersed sets whether to support interspersed option/non-option arguments.
- func (f *FlagSet) SetInterspersed(interspersed bool) {
- f.interspersed = interspersed
- }
- // Init sets the name and error handling property for a flag set.
- // By default, the zero FlagSet uses an empty name and the
- // ContinueOnError error handling policy.
- func (f *FlagSet) Init(name string, errorHandling ErrorHandling) {
- f.name = name
- f.errorHandling = errorHandling
- f.argsLenAtDash = -1
- }
|