Closed stevemil00 closed 2 months ago
Thanks for the detailed report @stevemil00
Sorry that this is not very intuitive, but the intended behavior of Parser.Parse is that it should return arg.ErrVersion when --version is provided on the command line. It is done this way so that "--help" and "--version" can terminate the processing of command line arguments as soon as they are encountered. If I was designing the library from scratch now, I wouldn't handle this by returning and error, but in the current implementation at the moment, that's how it works. The intention is that you catch these errors programmatically if you want to respond to --version and --help.
I just now added some notes to the README just now showing how to handle this all from outside the library, reproducing the exact same logic as MustParse. In your case, use code like this:
type args struct {
Something string
}
func (args) Version() string {
return "1.2.3"
}
func main() {
var args args
p, err := arg.NewParser(arg.Config{}, &args)
if err != nil {
log.Fatalf("there was an error in the definition of the Go struct: %v", err)
}
err = p.Parse(os.Args[1:])
switch {
case err == arg.ErrHelp: // found "--help" on command line
p.WriteHelp(os.Stdout)
os.Exit(0)
case err == arg.ErrVersion: // found "--version" on command line
fmt.Println(args.Version())
os.Exit(0)
case err != nil:
fmt.Printf("error: %v\n", err)
p.WriteUsage(os.Stdout)
os.Exit(1)
}
fmt.Printf("got %q\n", args.Something)
}
See also the full discussion, and in particular the second snippet in the README here.
Thanks again for the details report! Closing for now but do please re-open if I missed anything.
Hi -- it seems like if you're using
arg.NewParser
and thenparser.Parse
, somehow go-arg finds but does not seem to use theVersion
method defined on the Args struct.Actually, the TL;DR here might be that using
arg.NewParser
and thenparser.Parse
, there's no way to get the version string displayed, and you always get an error back. But if you callarg.MustParse
, orarg.NewParser
plusparser.MustParse
, that error gets caught internally and go-arg prints the version and exits (which seems legit ๐ ).Let's start by looking at this:
So that's just using
os.Args
internally, and it works just fine:If we use the relatively new
parser.MustParse
method, things work just fine, too:which gets you:
but if you use
NewParser
plusParse
, it blows up:and you get:
I tried stepping through this in the debugger, and it seemed like
NewParser
was recognizing that there was aVersion
method, running it, and storing its value in.version
. But thenparse
would run, and it would run into this:and since there isn't a version field in
Args
, it would blow up at:Looking at the code in
parser.MustParse
, it is following that same code path, and the help/version handling above blows up in the same way, but that code catches the error, prints the version, and exits:so if you do what the third bit of go does, call
NewParser
and then callParse
, thatMustParse
error interception never happens and there's no way to get the version string printed.It'd be nice if this was somehow consistent with
NewParser
+MustParse
or with the top-levelMustParse
, though now that I know what's going on (and now that I've upgraded to 1.51 ๐ ) it's an easy change to work around it.