kingpin icon indicating copy to clipboard operation
kingpin copied to clipboard

ExistingDir() still checked when program run with --version

Open gebn opened this issue 5 years ago • 2 comments

When using kingpin.Version("..."), passing --version means .Required() arguments do not have to be provided. I have an argument with a .Default() that must be an .ExistingDir(). The default path does not exist on the system. When passing only --version, I get an error that the default directory doesn't exist, rather than the version. Passing --version --help means the version is printed correctly.

It would be very useful if kingpin did not check that .ExistingDir()s actually existed if the program is run with only the --version flag.

gebn avatar Jan 13 '19 19:01 gebn

Hit the same issue, reproduce:

package main

import (
	"github.com/alecthomas/kingpin"
)

var (
	foo = kingpin.Flag("foo", "Foo").Default("foo.txt").File()
)

func main() {
	kingpin.Version("0.1")
	kingpin.Parse()
}
[~/goprojects/ygersie/test]$ go run kingpin.go --version
kingpin: error: open foo.txt: no such file or directory, try --help
exit status 1

ygersie avatar Oct 18 '19 12:10 ygersie

I took a look at this and it's not easily fixable, AFAICT.

The issue is that internally --version is just yet another flag like all the others. When you call .Parse() the sequence always goes as follows:

  1. Do the raw CLI parsing so we know what flags & args were passed
  2. Set default values for flags
  3. Set values for all flags based on CLI (& env vars, I assume)
  4. Applies pre-actions, which is where --version is handled

The problem is that the pre-actions are able to see the flags from steps 2 & 3.

To fix this there would need to be some sort of pre-pre-action special case, maybe an "immediate action", where the presence of a particular flag can short circuit the normal processing.

This is doable, but I'm not sure what the best way to implement this in a non-hacky, extensible way would be.

autarch avatar Feb 16 '20 20:02 autarch