Checklist
- [X ] Are you running the latest v2 release? The list of releases is here.
- [X ] Did you check the manual for your release? The v2 manual is here
- [ X] Did you perform a search about this feature? Here's the Github guide about searching.
What problem does this solve?
CLI ergonomics when editing/adding flags to command are very bad.
Quick example, consider how many times you have to move cursor back in commandline to go from
$ cmd query users
to
$ cmd --out=csv query --filter "project=kittens" users --with-permission=Deploy
vs
$ cmd query users --with-permission=Deploy --filter "project=kittens", --out=csv
It also "reads" worse:
"output CSV on query project kittens on users with permissions to deploy:
vs
" query users that can deploy in project kittens, output csv"
Without forced ordering you can add a flag at the end at any point so ad-hoc usage of commands is much more streamlined, it also allows writing CLI scripts with arguments grouped by what makes more sense, not by how program author structured it.
Now the long winded example, consider the following:
- App has global flags applicable to all subcommands like
- change output type (for example switch between machine-parseable and user-frien
- server address
- config/credentials pass
- environment
- etc
- Application has subcommand with their own flags user might want to iterate
Let's say app has a subcommand to query systems state
cmd query
Which has --filter
string option, and this command have subcommands for various parts of system
cmd query nodes
cmd query services
cmd query users
with various sub-subcommand specific switches.
Let's say user wants to only see stuff about a certain project. No worries, we have --filter
flag for it
$ cmd query --filter project=kittens
User now wants to see who has access to that project. But we have options just for that
$ cmd query --filter project=kittens users
So far so good. Let's see which of them can deploy the application
$ cmd query --filter project=kittens users --with-permission=Deploy
Okay, now let's compare it with another project...
$ cmd query --filter project=dogs users --with-permission=Deploy
Now we need to go back 4 words (4x C-b
) and we can start changing it. But we have few more projects to check? How about just move filter at the end ?
$ cmd query users --with-permission=Deploy --filter project=dogs
flag provided but not defined: -filter
Okay, we can't. Bit annoying but it is only few commands.
$ for project in kittens dogs otters ducks ; do cmd query --filter "project=$project" users --with-permission=Deploy ; done
Right, it does what we wanted. Now onto writing that report. There is a csv
output format so it should be trivial.
$ for project in kittens dogs otters ducks ; do cmd query --filter "project=$project" users --with-permission=Deploy --out=csv; done
flag provided but not defined: -out
Oh, right, go C-b NINE times because that needs to be after a command but before subcommand.
$ for project in kittens dogs otters ducks ; do cmd --out=csv query --filter "project=$project" users --with-permission=Deploy ; done
Want to bump it to verbose or enable debug ? Go back nearly to the start of the line. Want to set environment or target server ? Same. Only real option to have convenient ability to change the parameters used in whole app is duplicating them as command-local variables.
The migration manual mentions something that "it is more POSIX-like" but POSIX conventions never had a notion of subcommands in the first place, the "stuff after options" was not a subcommand but also command's parameters (usually file to operate on), and even now most of the say coreutils
tools allow for having options in any place just for convenience (GNU's ls -la /tmp
and ls /tmt -la
have same effect for example)
Solution description
Every --option
in commandline should be considered for a flag, from closest "leaf" subcommand to the root
so
$ cmd --env=dev query --filter type=sqldb
$ cmd query --filter type=sqldb --env=dev
should be equivalent. Sometimes even having options before subcommand makes sense, like
$ cmd --filter="type=sqldb" query users
$ cmd --filter="type=sqldb" query nodes
$ cmd --filter="type=sqldb" query services
Describe alternatives you've considered
Copying every flag to local "works" but it isn't exactly elegant, and messes up with generated help.