move more stuff over to the parser struct

This commit is contained in:
Alex Flint 2015-11-01 00:13:23 -07:00
parent f427e9f317
commit 30befae91a
2 changed files with 40 additions and 75 deletions

View File

@ -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
}
// process goes through arguments the arguments one-by-one, parses them, and assigns the result to
// 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 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

View File

@ -9,37 +9,17 @@ import (
"strings"
)
// Usage prints usage information to stdout and exits with status zero
func Usage(dest ...interface{}) {
if err := WriteUsage(os.Stdout, dest...); err != nil {
fmt.Println(err)
}
os.Exit(0)
}
// Fail prints usage information to stdout and exits with non-zero status
func Fail(msg string, dest ...interface{}) {
func (p *Parser) Fail(msg string) {
fmt.Println(msg)
if err := WriteUsage(os.Stdout, dest...); err != nil {
fmt.Println(err)
}
p.WriteUsage(os.Stdout)
os.Exit(1)
}
// WriteUsage writes usage information to the given writer
func WriteUsage(w io.Writer, dest ...interface{}) error {
spec, err := extractSpec(dest...)
if err != nil {
return err
}
writeUsage(w, filepath.Base(os.Args[0]), spec)
return nil
}
// writeUsage writes usage information to the given writer
func writeUsage(w io.Writer, cmd string, specs []*spec) {
func (p *Parser) WriteUsage(w io.Writer) {
var positionals, options []*spec
for _, spec := range specs {
for _, spec := range p.spec {
if spec.positional {
positionals = append(positionals, spec)
} else {
@ -47,7 +27,7 @@ func writeUsage(w io.Writer, cmd string, specs []*spec) {
}
}
fmt.Fprint(w, "usage: %s ", cmd)
fmt.Fprintf(w, "usage: %s ", filepath.Base(os.Args[0]))
// write the option component of the one-line usage message
for _, spec := range options {