Merge pull request #32 from alexflint/override_program_name

make it possible to override the name of the program
This commit is contained in:
Alex Flint 2016-02-22 06:39:41 -08:00
commit aaae1550b7
4 changed files with 44 additions and 12 deletions

View File

@ -4,6 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"os" "os"
"path/filepath"
"reflect" "reflect"
"strings" "strings"
) )
@ -28,7 +29,7 @@ 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{}) *Parser { func MustParse(dest ...interface{}) *Parser {
p, err := NewParser(dest...) p, err := NewParser(Config{}, dest...)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(-1) os.Exit(-1)
@ -46,20 +47,26 @@ func MustParse(dest ...interface{}) *Parser {
// 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 { func Parse(dest ...interface{}) error {
p, err := NewParser(dest...) p, err := NewParser(Config{}, dest...)
if err != nil { if err != nil {
return err return err
} }
return p.Parse(os.Args[1:]) return p.Parse(os.Args[1:])
} }
// Config represents configuration options for an argument parser
type Config struct {
Program string // Program is the name of the program used in the help text
}
// Parser represents a set of command line options with destination values // Parser represents a set of command line options with destination values
type Parser struct { type Parser struct {
spec []*spec spec []*spec
config Config
} }
// NewParser constructs a parser from a list of destination structs // NewParser constructs a parser from a list of destination structs
func NewParser(dests ...interface{}) (*Parser, error) { func NewParser(config Config, dests ...interface{}) (*Parser, error) {
var specs []*spec var specs []*spec
for _, dest := range dests { for _, dest := range dests {
v := reflect.ValueOf(dest) v := reflect.ValueOf(dest)
@ -134,7 +141,16 @@ func NewParser(dests ...interface{}) (*Parser, error) {
specs = append(specs, &spec) specs = append(specs, &spec)
} }
} }
return &Parser{spec: specs}, nil if config.Program == "" {
config.Program = "program"
if len(os.Args) > 0 {
config.Program = filepath.Base(os.Args[0])
}
}
return &Parser{
spec: specs,
config: config,
}, nil
} }
// Parse processes the given command line option, storing the results in the field // Parse processes the given command line option, storing the results in the field

View File

@ -13,7 +13,7 @@ import (
) )
func parse(cmdline string, dest interface{}) error { func parse(cmdline string, dest interface{}) error {
p, err := NewParser(dest) p, err := NewParser(Config{}, dest)
if err != nil { if err != nil {
return err return err
} }

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"path/filepath"
"reflect" "reflect"
"strings" "strings"
) )
@ -30,7 +29,7 @@ func (p *Parser) WriteUsage(w io.Writer) {
} }
} }
fmt.Fprintf(w, "usage: %s", filepath.Base(os.Args[0])) fmt.Fprintf(w, "usage: %s", p.config.Program)
// write the option component of the usage message // write the option component of the usage message
for _, spec := range options { for _, spec := range options {
@ -114,8 +113,7 @@ func printOption(w io.Writer, spec *spec) {
} }
fmt.Fprint(w, spec.help) fmt.Fprint(w, spec.help)
} }
// Check if spec.dest is zero value or not // If spec.dest is not the zero value then a default value has been added.
// If it isn't a default value have been added
v := spec.dest v := spec.dest
if v.IsValid() { if v.IsValid() {
z := reflect.Zero(v.Type()) z := reflect.Zero(v.Type())

View File

@ -43,7 +43,7 @@ options:
} }
args.Name = "Foo Bar" args.Name = "Foo Bar"
args.Value = 42 args.Value = 42
p, err := NewParser(&args) p, err := NewParser(Config{}, &args)
require.NoError(t, err) require.NoError(t, err)
os.Args[0] = "example" os.Args[0] = "example"
@ -71,7 +71,25 @@ options:
VeryLongPositionalWithHelp string `arg:"positional,help:this positional argument is very long"` VeryLongPositionalWithHelp string `arg:"positional,help:this positional argument is very long"`
} }
p, err := NewParser(&args) p, err := NewParser(Config{}, &args)
require.NoError(t, err)
os.Args[0] = "example"
var help bytes.Buffer
p.WriteHelp(&help)
assert.Equal(t, expectedHelp, help.String())
}
func TestUsageWithProgramName(t *testing.T) {
expectedHelp := `usage: myprogram
options:
--help, -h display this help and exit
`
config := Config{
Program: "myprogram",
}
p, err := NewParser(config, &struct{}{})
require.NoError(t, err) require.NoError(t, err)
os.Args[0] = "example" os.Args[0] = "example"