Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overriding --version #171

Open
dyfet opened this issue Dec 30, 2021 · 5 comments · May be fixed by #224
Open

Overriding --version #171

dyfet opened this issue Dec 30, 2021 · 5 comments · May be fixed by #224

Comments

@dyfet
Copy link

dyfet commented Dec 30, 2021

I was tryng to make this library behave more closely to the behavior of the rust clap crate. They are similar in the way they present command line options, but with a key difference that I find annoying:

If you define a Version method in go-arg, it shows the version string in error: lines, too. My first thought was, well, why not just override Version and return it myself when I want it?

type args struct {
    Version bool `arg:"--version,-V"`
}

This almost works...However, --version always is processed internally and cannot be overridden, while -V does exit from MustParse with Version set to true...

Ultimately I came to doing this:

func (args) Version() string {
    if os.Args[1] == "--version" && len(os.Args) == 2 {
        return "Version: " + version
    }
    return ""
}

Which does what I want, but feels strange. I also go thru different paths if I also want the -V alternate, and do something like:

type args struct {
    ShowVersion bool `arg:"--version,-V" help:"display version and exit:"`
}

I think if there is an arg: --version flag the built-in --version option processing should be ignored.

The other problem is when I do my Version() function conditionally based on os.Args, the only way to get --help to show the --version option is to add the ShowVersion entry, too.

@alexflint
Copy link
Owner

Oh, interesting. Yeah I don't think we should print the version string in error lines. Do you mean that if you do something like

type args struct {
  N int
}
func (args) Version() string { return "something" }

func main() {
  var arg Args
  arg.MustParse(&args)
}

and then invoke the program with something that doesn't parse as an integer then it behaves like this?

$ ./program --n=not_a_number
Version: something
error: could not convert to an int not_a_number

@dyfet
Copy link
Author

dyfet commented Dec 30, 2021

Indeed, or get something like:

[dyfet@luna cardaver]$ ./target/debug/cardaver -x
version string + version 0.0.1
Usage: cardaver [--version]
error: unknown argument -x

With

 func (args) Version() string { return "version string + version " + version }

It also doesn't pre-append "Version:", it just spits out whatever you return... I prefer to add the "Version: " part myself in the func anyway, but it seems wrong to use version in error message responses, and wrong to have them in the -h too, since the
func (args) Description() is free-form as well.

@dyfet
Copy link
Author

dyfet commented Dec 30, 2021

This is the kind of help I want, and looks a lot like you can get with clap in rust:

./target/debug/cardaver -h
cardaver 0.0.1
David Sugar <tychosoft@gmail.com>
Provides carddav services for coventry

Usage: cardaver [--version]

Options:
  --version              display version and exit
  --help, -h             display this help and exit

But to get there I have to do this:

type args struct {
    ShowVersion bool `arg:"--version" help:"display version and exit"`
}

func (args) Version() string {
    if os.Args[1] == "--version" && len(os.Args) == 2 {
        return "Version: " + version + "\nConfig: " + etcPrefix + "/cardaver.conf\nPrefix: " + varPrefix
    }
    return ""
}

func (args) Description() string {
    return "cardaver " + version + "\nDavid Sugar <tychosoft@gmail.com>\nProvides carddav services for coventry\n"
}

This also gives:

./target/release/cardaver --version
Version: 0.0.1
Config: /usr/local/etc/cardaver.conf
Prefix: /usr/local/var/coventry

@hhromic
Copy link
Contributor

hhromic commented Jul 14, 2023

Not a complete solution to this issue, but I recently submitted PR #223 which allows to override the --version argument and go-arg will not use its builtin implementation in that case. For example:

package main

import (
	"fmt"
	"github.com/alexflint/go-arg"
)

type args struct {
	Version bool `arg:"-V,--version" help:"display version and exit"`
}

func main() {
	var args args
	arg.MustParse(&args)

	if args.Version {
		fmt.Println("Show version...")
	}
}

With the current version of go-arg:

$ go run main.go --version

$ go run main.go -V
Show version...

And with my PR applied:

$ go run main.go --version
Show version...

$ go run main.go -V
Show version...

If both, the destination struct is versioned with func (args) Version() string { return "something" } and has a custom --version argument defined, the custom --version flag takes precedence.

Therefore, when using a custom --version argument, you should not version the destination struct with Version(). This in turn makes go-arg to also not print the version in help and error messages.

@hhromic
Copy link
Contributor

hhromic commented Jul 14, 2023

Also, if there is no Version() function and the destination struct does not define a --version, the current go-arg will silently accept a --version argument and output an empty line. With my PR applied, go-arg will return an invalid argument error instead which is more correct. For example:

package main

import (
	"github.com/alexflint/go-arg"
)

type args struct {
}

func main() {
	var args args
	arg.MustParse(&args)
}

With the current version of go-arg:

$ go run main.go --version

And with my PR applied:

$ go run main.go --version
Usage: main
error: unknown argument --version
exit status 255

@hhromic hhromic linked a pull request Jul 15, 2023 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants