|
|
|
@ -3,9 +3,7 @@ package arg |
|
|
|
import ( |
|
|
|
"errors" |
|
|
|
"fmt" |
|
|
|
"io" |
|
|
|
"os" |
|
|
|
"path/filepath" |
|
|
|
"reflect" |
|
|
|
"strconv" |
|
|
|
"strings" |
|
|
|
@ -23,10 +21,10 @@ type spec struct { |
|
|
|
wasPresent bool |
|
|
|
} |
|
|
|
|
|
|
|
// Parse returns this value to indicate that -h or --help were provided
|
|
|
|
// ErrHelp indicates that -h or --help were provided
|
|
|
|
var ErrHelp = errors.New("help requested by user") |
|
|
|
|
|
|
|
// MustParse processes command line arguments and exits upon failure.
|
|
|
|
// MustParse processes command line arguments and exits upon failure
|
|
|
|
func MustParse(dest ...interface{}) { |
|
|
|
p, err := NewParser(dest...) |
|
|
|
if err != nil { |
|
|
|
@ -34,19 +32,20 @@ func MustParse(dest ...interface{}) { |
|
|
|
os.Exit(1) |
|
|
|
} |
|
|
|
err = p.Parse(os.Args[1:]) |
|
|
|
if err == ErrHelp { |
|
|
|
p.WriteUsage(os.Stdout) |
|
|
|
os.Exit(0) |
|
|
|
} |
|
|
|
if err != nil { |
|
|
|
fmt.Println(err) |
|
|
|
writeUsage(os.Stdout, filepath.Base(os.Args[0]), p.spec) |
|
|
|
os.Exit(1) |
|
|
|
p.Fail(err.Error()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Parse processes command line arguments and stores them in dest.
|
|
|
|
// Parse processes command line arguments and stores them in dest
|
|
|
|
func Parse(dest ...interface{}) error { |
|
|
|
p, err := NewParser(dest...) |
|
|
|
if err != nil { |
|
|
|
fmt.Println(err) |
|
|
|
os.Exit(1) |
|
|
|
return err |
|
|
|
} |
|
|
|
return p.Parse(os.Args[1:]) |
|
|
|
} |
|
|
|
@ -57,44 +56,7 @@ type Parser struct { |
|
|
|
} |
|
|
|
|
|
|
|
// NewParser constructs a parser from a list of destination structs
|
|
|
|
func NewParser(dest ...interface{}) (*Parser, error) { |
|
|
|
spec, err := extractSpec(dest...) |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
return &Parser{spec: spec}, nil |
|
|
|
} |
|
|
|
|
|
|
|
// Parse processes the given command line option, storing the results in the field
|
|
|
|
// of the structs from which NewParser was constructed
|
|
|
|
func (p *Parser) Parse(args []string) error { |
|
|
|
// If -h or --help were specified then print usage
|
|
|
|
for _, arg := range args { |
|
|
|
if arg == "-h" || arg == "--help" { |
|
|
|
return ErrHelp |
|
|
|
} |
|
|
|
if arg == "--" { |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Process all command line arguments
|
|
|
|
err := process(p.spec, args) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
// Validate
|
|
|
|
return validate(p.spec) |
|
|
|
} |
|
|
|
|
|
|
|
// WriteUsage writes usage information to the given writer
|
|
|
|
func (p *Parser) WriteUsage(w io.Writer) { |
|
|
|
writeUsage(w, filepath.Base(os.Args[0]), p.spec) |
|
|
|
} |
|
|
|
|
|
|
|
// extractSpec gets specifications for each argument from the tags in a struct
|
|
|
|
func extractSpec(dests ...interface{}) ([]*spec, error) { |
|
|
|
func NewParser(dests ...interface{}) (*Parser, error) { |
|
|
|
var specs []*spec |
|
|
|
for _, dest := range dests { |
|
|
|
v := reflect.ValueOf(dest) |
|
|
|
@ -169,10 +131,33 @@ func extractSpec(dests ...interface{}) ([]*spec, error) { |
|
|
|
specs = append(specs, &spec) |
|
|
|
} |
|
|
|
} |
|
|
|
return specs, nil |
|
|
|
return &Parser{spec: specs}, nil |
|
|
|
} |
|
|
|
|
|
|
|
// Parse processes the given command line option, storing the results in the field
|
|
|
|
// of the structs from which NewParser was constructed
|
|
|
|
func (p *Parser) Parse(args []string) error { |
|
|
|
// If -h or --help were specified then print usage
|
|
|
|
for _, arg := range args { |
|
|
|
if arg == "-h" || arg == "--help" { |
|
|
|
return ErrHelp |
|
|
|
} |
|
|
|
if arg == "--" { |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Process all command line arguments
|
|
|
|
err := process(p.spec, args) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
// Validate
|
|
|
|
return validate(p.spec) |
|
|
|
} |
|
|
|
|
|
|
|
// process goes through arguments the arguments one-by-one, parses them, and assigns the result to
|
|
|
|
// process goes through arguments one-by-one, parses them, and assigns the result to
|
|
|
|
// the underlying struct field
|
|
|
|
func process(specs []*spec, args []string) error { |
|
|
|
// construct a map from --option to spec
|
|
|
|
|