How to put generic arguments before flags in v2
I've been trying to place generic arguments first when running a cli command, like this:
testrun aaa -lang spanish
Following along the spanish example in the tutorial here
What I get back is everything has become an argument. If I do it the other way round, with the argument at the back everything works fine. Is there a flag I'm missing to set for it to work in the initial way. I put up a stackoverflow question up too but didn't get any responses to that.
urfave/cli version: v2.14.1
golang v: 1.18
stackoverflow question link: https://stackoverflow.com/questions/73587275/urfave-cli-argument-placement-prevents-flag-parsing
Hi @yirez-tc
Why would you put flags/options at the end ? The usual way of running a cli would be the other way around, flags/options first and then arguments.
I can think about few examples from the linux world:
mkdir.exe r --help
Usage: mkdir [OPTION]... DIRECTORY...
...
or
rmdir --help
Usage: rmdir [OPTION]... DIRECTORY...
or
ls --help
Usage: ls [OPTION]... [FILE]...
I'm not saying that it should not be possible, but the standard way is options first, then args.
Hey @abousselmi ,
We can make do with putting it at the end but there was a specific requirement for a cli tool we were building. It had several flags and one of the flags was to be the first argument implicitly since it will be used the most often. The intention was to be a bit like an sql command.
something like below where this,that argument could be used without explicitly typing -oftenUsedFlag instead.
find this,that -oftenUsedFlag value -otherflag value ...
Hey @yirez-tc ,
The CLI help is pretty clear about the order of flags and args. You cannot have args before global options or command options.
A dummy find cli would print the following:
NAME:
find - Usage of my cli
USAGE:
find [global options] command [command options] [arguments...]
To achieve what you are asking, you can do something like :
func main() {
app := &cli.App{
Name: "find",
Usage: "Usage of my cli",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "oftenUsedFlag",
Value: "val",
Usage: "My flag 1",
},
&cli.StringFlag{
Name: "otherflag",
Value: "other val",
Usage: "My flag 2",
},
&cli.StringFlag{
Name: "arg",
Value: "false arg",
Usage: "My false arg",
},
},
Action: func(cCtx *cli.Context) error {
fmt.Println(cCtx.String("oftenUsedFlag"))
fmt.Println(cCtx.String("otherflag"))
fmt.Println("Hello", cCtx.String("arg"))
return nil
},
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
Then you can create an alias and execute it like this:
$ alias find="./find -arg"
which gives you the requested behavior, using only flags, with no args around
$ find this,that -oftenUsedFlag f1 -otherflag f2
f1
f2
Hello this,that
Why would you put flags/options at the end ? The usual way of running a cli
Both
git push origin main --force
and
git push --force origin main
work equally well.
I guess the limitation in this package is due to the behavior of flagSet.Parse() (see also https://github.com/golang/go/issues/4513, https://github.com/golang/go/issues/24107, https://github.com/golang/go/issues/36744).
use gopkg.in/alecthomas/kingpin.v2
Duplicate of #1113