mirror of
https://github.com/golang/go
synced 2024-11-21 15:24:45 -07:00
flags: allow distinct sets of flags.
A FlagSet is an independent set of flags that may be used, for example, to provide flag processing for subcommands in a CLI. The standard, os.Args-derived set of flags is a global but non-exported FlagSet and the standard functions are wrappers for methods of that FlagSet. Allow the programmer to control whether the program exits if there is a parse error. For the default set, the behavior remains to exit on error. The handling of Usage is odd due to backward compatibility. R=golang-dev, bradfitz, r, bradfitz CC=golang-dev https://golang.org/cl/4517092
This commit is contained in:
parent
648f25b237
commit
f4fe688b09
@ -9,24 +9,14 @@ import "os"
|
||||
// Additional routines compiled into the package only during testing.
|
||||
|
||||
// ResetForTesting clears all flag state and sets the usage function as directed.
|
||||
// After calling ResetForTesting, parse errors in flag handling will panic rather
|
||||
// than exit the program.
|
||||
// After calling ResetForTesting, parse errors in flag handling will not
|
||||
// exit the program.
|
||||
func ResetForTesting(usage func()) {
|
||||
flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), os.Args[1:]}
|
||||
commandLine = NewFlagSet(os.Args[0], ContinueOnError)
|
||||
Usage = usage
|
||||
panicOnError = true
|
||||
}
|
||||
|
||||
// ParseForTesting parses the flag state using the provided arguments. It
|
||||
// should be called after 1) ResetForTesting and 2) setting up the new flags.
|
||||
// The return value reports whether the parse was error-free.
|
||||
func ParseForTesting(args []string) (result bool) {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
result = false
|
||||
}
|
||||
}()
|
||||
os.Args = args
|
||||
Parse()
|
||||
return true
|
||||
// CommandLine returns the default FlagSet.
|
||||
func CommandLine() *FlagSet {
|
||||
return commandLine
|
||||
}
|
||||
|
@ -50,18 +50,12 @@
|
||||
Integer flags accept 1234, 0664, 0x1234 and may be negative.
|
||||
Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False.
|
||||
|
||||
It is safe to call flag.Parse multiple times, possibly after changing
|
||||
os.Args. This makes it possible to implement command lines with
|
||||
subcommands that enable additional flags, as in:
|
||||
|
||||
flag.Bool(...) // global options
|
||||
flag.Parse() // parse leading command
|
||||
subcmd := flag.Arg(0)
|
||||
switch subcmd {
|
||||
// add per-subcommand options
|
||||
}
|
||||
os.Args = flag.Args()
|
||||
flag.Parse()
|
||||
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 flag
|
||||
|
||||
@ -190,6 +184,30 @@ type Value interface {
|
||||
Set(string) bool
|
||||
}
|
||||
|
||||
// ErrorHandling defines how to handle flag parsing errors.
|
||||
type ErrorHandling int
|
||||
|
||||
const (
|
||||
ContinueOnError ErrorHandling = iota
|
||||
ExitOnError
|
||||
PanicOnError
|
||||
)
|
||||
|
||||
// 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()
|
||||
|
||||
name string
|
||||
actual map[string]*Flag
|
||||
formal map[string]*Flag
|
||||
args []string // arguments after flags
|
||||
exitOnError bool // does the program exit if there's an error?
|
||||
errorHandling ErrorHandling
|
||||
}
|
||||
|
||||
// A Flag represents the state of a flag.
|
||||
type Flag struct {
|
||||
Name string // name as it appears on command line
|
||||
@ -198,14 +216,6 @@ type Flag struct {
|
||||
DefValue string // default value (as text); for usage message
|
||||
}
|
||||
|
||||
type allFlags struct {
|
||||
actual map[string]*Flag
|
||||
formal map[string]*Flag
|
||||
args []string // arguments after flags
|
||||
}
|
||||
|
||||
var flags *allFlags
|
||||
|
||||
// sortFlags returns the flags as a slice in lexicographical sorted order.
|
||||
func sortFlags(flags map[string]*Flag) []*Flag {
|
||||
list := make(sort.StringArray, len(flags))
|
||||
@ -224,43 +234,67 @@ func sortFlags(flags map[string]*Flag) []*Flag {
|
||||
|
||||
// VisitAll visits the flags in lexicographical order, calling fn for each.
|
||||
// It visits all flags, even those not set.
|
||||
func VisitAll(fn func(*Flag)) {
|
||||
for _, f := range sortFlags(flags.formal) {
|
||||
fn(f)
|
||||
func (f *FlagSet) VisitAll(fn func(*Flag)) {
|
||||
for _, flag := range sortFlags(f.formal) {
|
||||
fn(flag)
|
||||
}
|
||||
}
|
||||
|
||||
// VisitAll visits the command-line flags in lexicographical order, 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, calling fn for each.
|
||||
// It visits only those flags that have been set.
|
||||
func Visit(fn func(*Flag)) {
|
||||
for _, f := range sortFlags(flags.actual) {
|
||||
fn(f)
|
||||
func (f *FlagSet) Visit(fn func(*Flag)) {
|
||||
for _, flag := range sortFlags(f.actual) {
|
||||
fn(flag)
|
||||
}
|
||||
}
|
||||
|
||||
// Visit visits the command-line flags in lexicographical order, 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.formal[name]
|
||||
}
|
||||
|
||||
// Lookup returns the Flag structure of the named command-line flag,
|
||||
// returning nil if none exists.
|
||||
func Lookup(name string) *Flag {
|
||||
return flags.formal[name]
|
||||
return commandLine.formal[name]
|
||||
}
|
||||
|
||||
// Set sets the value of the named flag. It returns true if the set succeeded; false if
|
||||
// there is no such flag defined.
|
||||
func Set(name, value string) bool {
|
||||
f, ok := flags.formal[name]
|
||||
func (f *FlagSet) Set(name, value string) bool {
|
||||
flag, ok := f.formal[name]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
ok = f.Value.Set(value)
|
||||
ok = flag.Value.Set(value)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
flags.actual[name] = f
|
||||
f.actual[name] = flag
|
||||
return true
|
||||
}
|
||||
|
||||
// PrintDefaults prints to standard error the default values of all defined flags.
|
||||
func PrintDefaults() {
|
||||
VisitAll(func(f *Flag) {
|
||||
// Set sets the value of the named command-line flag. It returns true if the
|
||||
// set succeeded; false if there is no such flag defined.
|
||||
func Set(name, value string) bool {
|
||||
return commandLine.Set(name, value)
|
||||
}
|
||||
|
||||
// PrintDefaults prints to standard error the default values of all defined flags in the set.
|
||||
func (f *FlagSet) PrintDefaults() {
|
||||
f.VisitAll(func(f *Flag) {
|
||||
format := " -%s=%s: %s\n"
|
||||
if _, ok := f.Value.(*stringValue); ok {
|
||||
// put quotes on the value
|
||||
@ -270,141 +304,255 @@ func PrintDefaults() {
|
||||
})
|
||||
}
|
||||
|
||||
// Usage prints to standard error a default usage message documenting all defined flags.
|
||||
// The function is a variable that may be changed to point to a custom function.
|
||||
var Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
|
||||
PrintDefaults()
|
||||
// PrintDefaults prints to standard error the default values of all defined command-line flags.
|
||||
func PrintDefaults() {
|
||||
commandLine.PrintDefaults()
|
||||
}
|
||||
|
||||
var panicOnError = false
|
||||
// defaultUsage is the default function to print a usage message.
|
||||
func defaultUsage(f *FlagSet) {
|
||||
fmt.Fprintf(os.Stderr, "Usage of %s:\n", f.name)
|
||||
f.PrintDefaults()
|
||||
}
|
||||
|
||||
// failf prints to standard error a formatted error and Usage, and then exits the program.
|
||||
func failf(format string, a ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, format, a...)
|
||||
Usage()
|
||||
if panicOnError {
|
||||
panic("flag parse error")
|
||||
}
|
||||
os.Exit(2)
|
||||
// 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.
|
||||
var Usage = func() {
|
||||
defaultUsage(commandLine)
|
||||
}
|
||||
|
||||
// NFlag returns the number of flags that have been set.
|
||||
func NFlag() int { return len(flags.actual) }
|
||||
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 {
|
||||
if i < 0 || i >= len(flags.args) {
|
||||
return ""
|
||||
}
|
||||
return flags.args[i]
|
||||
return commandLine.Arg(i)
|
||||
}
|
||||
|
||||
// NArg is the number of arguments remaining after flags have been processed.
|
||||
func NArg() int { return len(flags.args) }
|
||||
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 flags.args }
|
||||
func Args() []string { return commandLine.args }
|
||||
|
||||
// BoolVar defines a bool flag with specified name, default value, and usage string.
|
||||
// The argument p points to a bool variable in which to store the value of the flag.
|
||||
func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) {
|
||||
f.Var(newBoolValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// BoolVar defines a bool flag with specified name, default value, and usage string.
|
||||
// The argument p points to a bool variable in which to store the value of the flag.
|
||||
func BoolVar(p *bool, name string, value bool, usage string) {
|
||||
Var(newBoolValue(value, p), name, usage)
|
||||
commandLine.Var(newBoolValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Bool defines a bool flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a bool variable that stores the value of the flag.
|
||||
func (f *FlagSet) Bool(name string, value bool, usage string) *bool {
|
||||
p := new(bool)
|
||||
f.BoolVar(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Bool defines a bool flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a bool variable that stores the value of the flag.
|
||||
func Bool(name string, value bool, usage string) *bool {
|
||||
p := new(bool)
|
||||
BoolVar(p, name, value, usage)
|
||||
return p
|
||||
return commandLine.Bool(name, value, usage)
|
||||
}
|
||||
|
||||
// IntVar defines an int flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int variable in which to store the value of the flag.
|
||||
func (f *FlagSet) IntVar(p *int, name string, value int, usage string) {
|
||||
f.Var(newIntValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// IntVar defines an int flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int variable in which to store the value of the flag.
|
||||
func IntVar(p *int, name string, value int, usage string) {
|
||||
Var(newIntValue(value, p), name, usage)
|
||||
commandLine.Var(newIntValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Int defines an int flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int variable that stores the value of the flag.
|
||||
func (f *FlagSet) Int(name string, value int, usage string) *int {
|
||||
p := new(int)
|
||||
f.IntVar(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Int defines an int flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int variable that stores the value of the flag.
|
||||
func Int(name string, value int, usage string) *int {
|
||||
p := new(int)
|
||||
IntVar(p, name, value, usage)
|
||||
return p
|
||||
return commandLine.Int(name, value, usage)
|
||||
}
|
||||
|
||||
// Int64Var defines an int64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int64 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) {
|
||||
f.Var(newInt64Value(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Int64Var defines an int64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int64 variable in which to store the value of the flag.
|
||||
func Int64Var(p *int64, name string, value int64, usage string) {
|
||||
Var(newInt64Value(value, p), name, usage)
|
||||
commandLine.Var(newInt64Value(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Int64 defines an int64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int64 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Int64(name string, value int64, usage string) *int64 {
|
||||
p := new(int64)
|
||||
f.Int64Var(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Int64 defines an int64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int64 variable that stores the value of the flag.
|
||||
func Int64(name string, value int64, usage string) *int64 {
|
||||
p := new(int64)
|
||||
Int64Var(p, name, value, usage)
|
||||
return p
|
||||
return commandLine.Int64(name, value, usage)
|
||||
}
|
||||
|
||||
// UintVar defines a uint flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint variable in which to store the value of the flag.
|
||||
func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) {
|
||||
f.Var(newUintValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// UintVar defines a uint flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint variable in which to store the value of the flag.
|
||||
func UintVar(p *uint, name string, value uint, usage string) {
|
||||
Var(newUintValue(value, p), name, usage)
|
||||
commandLine.Var(newUintValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Uint defines a uint flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint variable that stores the value of the flag.
|
||||
func Uint(name string, value uint, usage string) *uint {
|
||||
// The return value is the address of a uint variable that stores the value of the flag.
|
||||
func (f *FlagSet) Uint(name string, value uint, usage string) *uint {
|
||||
p := new(uint)
|
||||
UintVar(p, name, value, usage)
|
||||
f.UintVar(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint defines a uint flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint variable that stores the value of the flag.
|
||||
func Uint(name string, value uint, usage string) *uint {
|
||||
return commandLine.Uint(name, value, usage)
|
||||
}
|
||||
|
||||
// Uint64Var defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint64 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string) {
|
||||
f.Var(newUint64Value(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Uint64Var defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint64 variable in which to store the value of the flag.
|
||||
func Uint64Var(p *uint64, name string, value uint64, usage string) {
|
||||
Var(newUint64Value(value, p), name, usage)
|
||||
commandLine.Var(newUint64Value(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Uint64 defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint64 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 {
|
||||
p := new(uint64)
|
||||
f.Uint64Var(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint64 defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint64 variable that stores the value of the flag.
|
||||
func Uint64(name string, value uint64, usage string) *uint64 {
|
||||
p := new(uint64)
|
||||
Uint64Var(p, name, value, usage)
|
||||
return p
|
||||
return commandLine.Uint64(name, value, usage)
|
||||
}
|
||||
|
||||
// StringVar defines a string flag with specified name, default value, and usage string.
|
||||
// The argument p points to a string variable in which to store the value of the flag.
|
||||
func StringVar(p *string, name, value string, usage string) {
|
||||
Var(newStringValue(value, p), name, usage)
|
||||
func (f *FlagSet) StringVar(p *string, name string, value string, usage string) {
|
||||
f.Var(newStringValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// StringVar defines a string flag with specified name, default value, and usage string.
|
||||
// The argument p points to a string variable in which to store the value of the flag.
|
||||
func StringVar(p *string, name string, value string, usage string) {
|
||||
commandLine.Var(newStringValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// String defines a string flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a string variable that stores the value of the flag.
|
||||
func String(name, value string, usage string) *string {
|
||||
func (f *FlagSet) String(name string, value string, usage string) *string {
|
||||
p := new(string)
|
||||
StringVar(p, name, value, usage)
|
||||
f.StringVar(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// String defines a string flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a string variable that stores the value of the flag.
|
||||
func String(name string, value string, usage string) *string {
|
||||
return commandLine.String(name, value, usage)
|
||||
}
|
||||
|
||||
// Float64Var defines a float64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a float64 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) {
|
||||
f.Var(newFloat64Value(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Float64Var defines a float64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a float64 variable in which to store the value of the flag.
|
||||
func Float64Var(p *float64, name string, value float64, usage string) {
|
||||
Var(newFloat64Value(value, p), name, usage)
|
||||
commandLine.Var(newFloat64Value(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Float64 defines a float64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a float64 variable that stores the value of the flag.
|
||||
func Float64(name string, value float64, usage string) *float64 {
|
||||
func (f *FlagSet) Float64(name string, value float64, usage string) *float64 {
|
||||
p := new(float64)
|
||||
Float64Var(p, name, value, usage)
|
||||
f.Float64Var(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Float64 defines an int flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a float64 variable that stores the value of the flag.
|
||||
func Float64(name string, value float64, usage string) *float64 {
|
||||
return commandLine.Float64(name, value, usage)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// Remember the default value as a string; it won't change.
|
||||
flag := &Flag{name, usage, value, value.String()}
|
||||
_, alreadythere := f.formal[name]
|
||||
if alreadythere {
|
||||
fmt.Fprintf(os.Stderr, "%s flag redefined: %s\n", f.name, name)
|
||||
panic("flag redefinition") // Happens only if flags are declared with identical names
|
||||
}
|
||||
f.formal[name] = 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
|
||||
@ -412,36 +560,42 @@ func Float64(name string, value float64, usage string) *float64 {
|
||||
// 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) {
|
||||
// Remember the default value as a string; it won't change.
|
||||
f := &Flag{name, usage, value, value.String()}
|
||||
_, alreadythere := flags.formal[name]
|
||||
if alreadythere {
|
||||
fmt.Fprintln(os.Stderr, "flag redefined:", name)
|
||||
panic("flag redefinition") // Happens only if flags are declared with identical names
|
||||
}
|
||||
flags.formal[name] = f
|
||||
commandLine.Var(value, name, usage)
|
||||
}
|
||||
|
||||
// failf prints to standard error a formatted error and usage message and
|
||||
// returns the error.
|
||||
func (f *FlagSet) failf(format string, a ...interface{}) os.Error {
|
||||
err := fmt.Errorf(format, a...)
|
||||
fmt.Println(errc)
|
||||
if f == commandLine {
|
||||
Usage()
|
||||
} else {
|
||||
f.Usage()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *allFlags) parseOne() (ok bool) {
|
||||
// parseOne parses one flag. It returns whether a flag was seen.
|
||||
func (f *FlagSet) parseOne() (bool, os.Error) {
|
||||
if len(f.args) == 0 {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
s := f.args[0]
|
||||
if len(s) == 0 || s[0] != '-' || len(s) == 1 {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
num_minuses := 1
|
||||
if s[1] == '-' {
|
||||
num_minuses++
|
||||
if len(s) == 2 { // "--" terminates the flags
|
||||
f.args = f.args[1:]
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
name := s[num_minuses:]
|
||||
if len(name) == 0 || name[0] == '-' || name[0] == '=' {
|
||||
failf("bad flag syntax: %s\n", s)
|
||||
return false, f.failf("bad flag syntax: %s", s)
|
||||
}
|
||||
|
||||
// it's a flag. does it have an argument?
|
||||
@ -456,15 +610,15 @@ func (f *allFlags) parseOne() (ok bool) {
|
||||
break
|
||||
}
|
||||
}
|
||||
m := flags.formal
|
||||
m := f.formal
|
||||
flag, alreadythere := m[name] // BUG
|
||||
if !alreadythere {
|
||||
failf("flag provided but not defined: -%s\n", name)
|
||||
return false, f.failf("flag provided but not defined: -%s", name)
|
||||
}
|
||||
if fv, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg
|
||||
if has_value {
|
||||
if !fv.Set(value) {
|
||||
failf("invalid boolean value %q for flag: -%s\n", value, name)
|
||||
f.failf("invalid boolean value %q for flag: -%s", value, name)
|
||||
}
|
||||
} else {
|
||||
fv.Set("true")
|
||||
@ -477,25 +631,61 @@ func (f *allFlags) parseOne() (ok bool) {
|
||||
value, f.args = f.args[0], f.args[1:]
|
||||
}
|
||||
if !has_value {
|
||||
failf("flag needs an argument: -%s\n", name)
|
||||
return false, f.failf("flag needs an argument: -%s", name)
|
||||
}
|
||||
ok = flag.Value.Set(value)
|
||||
if !ok {
|
||||
failf("invalid value %q for flag: -%s\n", value, name)
|
||||
return false, f.failf("invalid value %q for flag: -%s", value, name)
|
||||
}
|
||||
}
|
||||
flags.actual[name] = flag
|
||||
return true
|
||||
f.actual[name] = flag
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Parse parses the command-line flags. Must be called after all flags are defined
|
||||
// and before any are accessed by the program.
|
||||
func Parse() {
|
||||
flags.args = os.Args[1:]
|
||||
for flags.parseOne() {
|
||||
// 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.
|
||||
func (f *FlagSet) Parse(arguments []string) os.Error {
|
||||
f.args = arguments
|
||||
for {
|
||||
seen, err := f.parseOne()
|
||||
if seen {
|
||||
continue
|
||||
}
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
switch f.errorHandling {
|
||||
case ContinueOnError:
|
||||
return err
|
||||
case ExitOnError:
|
||||
os.Exit(2)
|
||||
case PanicOnError:
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), os.Args[1:]}
|
||||
// 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:])
|
||||
}
|
||||
|
||||
// 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 and
|
||||
// error handling property.
|
||||
func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
|
||||
f := &FlagSet{
|
||||
name: name,
|
||||
actual: make(map[string]*Flag),
|
||||
formal: make(map[string]*Flag),
|
||||
errorHandling: errorHandling,
|
||||
}
|
||||
f.Usage = func() { defaultUsage(f) }
|
||||
return f
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ func TestEverything(t *testing.T) {
|
||||
func TestUsage(t *testing.T) {
|
||||
called := false
|
||||
ResetForTesting(func() { called = true })
|
||||
if ParseForTesting([]string{"a.out", "-x"}) {
|
||||
if CommandLine().Parse([]string{"-x"}) == nil {
|
||||
t.Error("parse did not fail for unknown flag")
|
||||
}
|
||||
if !called {
|
||||
@ -97,19 +97,17 @@ func TestUsage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
ResetForTesting(func() { t.Error("bad parse") })
|
||||
boolFlag := Bool("bool", false, "bool value")
|
||||
bool2Flag := Bool("bool2", false, "bool2 value")
|
||||
intFlag := Int("int", 0, "int value")
|
||||
int64Flag := Int64("int64", 0, "int64 value")
|
||||
uintFlag := Uint("uint", 0, "uint value")
|
||||
uint64Flag := Uint64("uint64", 0, "uint64 value")
|
||||
stringFlag := String("string", "0", "string value")
|
||||
float64Flag := Float64("float64", 0, "float64 value")
|
||||
func testParse(f *FlagSet, t *testing.T) {
|
||||
boolFlag := f.Bool("bool", false, "bool value")
|
||||
bool2Flag := f.Bool("bool2", false, "bool2 value")
|
||||
intFlag := f.Int("int", 0, "int value")
|
||||
int64Flag := f.Int64("int64", 0, "int64 value")
|
||||
uintFlag := f.Uint("uint", 0, "uint value")
|
||||
uint64Flag := f.Uint64("uint64", 0, "uint64 value")
|
||||
stringFlag := f.String("string", "0", "string value")
|
||||
float64Flag := f.Float64("float64", 0, "float64 value")
|
||||
extra := "one-extra-argument"
|
||||
args := []string{
|
||||
"a.out",
|
||||
"-bool",
|
||||
"-bool2=true",
|
||||
"--int", "22",
|
||||
@ -120,8 +118,8 @@ func TestParse(t *testing.T) {
|
||||
"-float64", "2718e28",
|
||||
extra,
|
||||
}
|
||||
if !ParseForTesting(args) {
|
||||
t.Fatal("parse failed")
|
||||
if err := f.Parse(args); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if *boolFlag != true {
|
||||
t.Error("bool flag should be true, is ", *boolFlag)
|
||||
@ -147,14 +145,23 @@ func TestParse(t *testing.T) {
|
||||
if *float64Flag != 2718e28 {
|
||||
t.Error("float64 flag should be 2718e28, is ", *float64Flag)
|
||||
}
|
||||
if len(Args()) != 1 {
|
||||
t.Error("expected one argument, got", len(Args()))
|
||||
} else if Args()[0] != extra {
|
||||
t.Errorf("expected argument %q got %q", extra, Args()[0])
|
||||
if len(f.Args()) != 1 {
|
||||
t.Error("expected one argument, got", len(f.Args()))
|
||||
} else if f.Args()[0] != extra {
|
||||
t.Errorf("expected argument %q got %q", extra, f.Args()[0])
|
||||
}
|
||||
}
|
||||
|
||||
// Declare a user-defined flag.
|
||||
func TestParse(t *testing.T) {
|
||||
ResetForTesting(func() { t.Error("bad parse") })
|
||||
testParse(CommandLine(), t)
|
||||
}
|
||||
|
||||
func TestFlagSetParse(t *testing.T) {
|
||||
testParse(NewFlagSet("test", ContinueOnError), t)
|
||||
}
|
||||
|
||||
// Declare a user-defined flag type.
|
||||
type flagVar []string
|
||||
|
||||
func (f *flagVar) String() string {
|
||||
@ -167,11 +174,11 @@ func (f *flagVar) Set(value string) bool {
|
||||
}
|
||||
|
||||
func TestUserDefined(t *testing.T) {
|
||||
ResetForTesting(func() { t.Fatal("bad parse") })
|
||||
flags := NewFlagSet("test", ContinueOnError)
|
||||
var v flagVar
|
||||
Var(&v, "v", "usage")
|
||||
if !ParseForTesting([]string{"a.out", "-v", "1", "-v", "2", "-v=3"}) {
|
||||
t.Error("parse failed")
|
||||
flags.Var(&v, "v", "usage")
|
||||
if err := flags.Parse([]string{"-v", "1", "-v", "2", "-v=3"}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(v) != 3 {
|
||||
t.Fatal("expected 3 args; got ", len(v))
|
||||
@ -182,13 +189,17 @@ func TestUserDefined(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// This tests that one can reset the flags. This still works but not well, and is
|
||||
// superseded by FlagSet.
|
||||
func TestChangingArgs(t *testing.T) {
|
||||
ResetForTesting(func() { t.Fatal("bad parse") })
|
||||
oldArgs := os.Args
|
||||
defer func() { os.Args = oldArgs }()
|
||||
os.Args = []string{"cmd", "-before", "subcmd", "-after", "args"}
|
||||
before := Bool("before", false, "")
|
||||
Parse()
|
||||
if err := CommandLine().Parse(os.Args[1:]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cmd := Arg(0)
|
||||
os.Args = Args()
|
||||
after := Bool("after", false, "")
|
||||
|
Loading…
Reference in New Issue
Block a user