From b1ec8c909335d0a72b6887aea5e7428f3cff60a8 Mon Sep 17 00:00:00 2001 From: Alex Flint Date: Mon, 18 Jan 2016 10:31:01 -0800 Subject: [PATCH] make it possible to override the name of the program --- parse.go | 26 +++++++++++++++++++++----- parse_test.go | 2 +- usage.go | 6 ++---- usage_test.go | 22 ++++++++++++++++++++-- 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/parse.go b/parse.go index 219a947..32b9b9d 100644 --- a/parse.go +++ b/parse.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "os" + "path/filepath" "reflect" "strconv" "strings" @@ -27,7 +28,7 @@ var ErrHelp = errors.New("help requested by user") // MustParse processes command line arguments and exits upon failure func MustParse(dest ...interface{}) *Parser { - p, err := NewParser(dest...) + p, err := NewParser(Config{}, dest...) if err != nil { fmt.Println(err) os.Exit(-1) @@ -45,20 +46,26 @@ func MustParse(dest ...interface{}) *Parser { // Parse processes command line arguments and stores them in dest func Parse(dest ...interface{}) error { - p, err := NewParser(dest...) + p, err := NewParser(Config{}, dest...) if err != nil { return err } 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 type Parser struct { - spec []*spec + spec []*spec + config Config } // 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 for _, dest := range dests { v := reflect.ValueOf(dest) @@ -138,7 +145,16 @@ func NewParser(dests ...interface{}) (*Parser, error) { 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 diff --git a/parse_test.go b/parse_test.go index 7fca76a..1189588 100644 --- a/parse_test.go +++ b/parse_test.go @@ -10,7 +10,7 @@ import ( ) func parse(cmdline string, dest interface{}) error { - p, err := NewParser(dest) + p, err := NewParser(Config{}, dest) if err != nil { return err } diff --git a/usage.go b/usage.go index 61f0ad6..f9d2eb9 100644 --- a/usage.go +++ b/usage.go @@ -4,7 +4,6 @@ import ( "fmt" "io" "os" - "path/filepath" "reflect" "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 for _, spec := range options { @@ -114,8 +113,7 @@ func printOption(w io.Writer, spec *spec) { } fmt.Fprint(w, spec.help) } - // Check if spec.dest is zero value or not - // If it isn't a default value have been added + // If spec.dest is not the zero value then a default value has been added. v := spec.dest if v.IsValid() { z := reflect.Zero(v.Type()) diff --git a/usage_test.go b/usage_test.go index 2375e81..130cd45 100644 --- a/usage_test.go +++ b/usage_test.go @@ -40,7 +40,7 @@ options: } args.Name = "Foo Bar" args.Value = 42 - p, err := NewParser(&args) + p, err := NewParser(Config{}, &args) require.NoError(t, err) os.Args[0] = "example" @@ -68,7 +68,25 @@ options: 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) os.Args[0] = "example"