-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Relax ordering requirements for flags/commands to improve upon cli ergonomics #1113
Comments
I'm tentatively in favor of this, we would just have to think about any potential unexpected impacts.
☝️ In practice this is how I've solved this problem, I really didn't consider it to be a huge issue. I agree that it's not elegant, though. |
For my use case, I actually prefer the behavior that flags must be placed specifically next to their declaration site. To give an example of why this is important—I have an application called # Run tusk in verbose mode, tests in normal mode
tusk --verbose test
# Run tests in verbose mode, tusk in normal mode
tusk test --verbose
# Run both tusk and tests in verbose mode
tusk --verbose test --verbose I am not opposed to adding this as an option, but it is an option that I would personally keep toggled off in my applications. |
@rliebz I have thought about that problem but to even distinguish between which levels a given flag is defined in v2 you have to go thru hoops. I'm not sure whether that's even intended behaviour but I had to do something like this: app := &cli.App{
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "verbose1",
Aliases:[]string{"verbose"},
},
},
Commands: []*cli.Command{
{
Name: "l1",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "verbose2",
Aliases:[]string{"verbose"},
},
},
Subcommands: []*cli.Command{
{
Name: "l2",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "verbose3",
Aliases:[]string{"verbose"},
},
},
Action: func(c *cli.Context) error {
fmt.Printf("v %+v\n",c.Bool("verbose"))
fmt.Printf("v1 %+v\n",c.Bool("verbose1"))
fmt.Printf("v2 %+v\n",c.Bool("verbose2"))
fmt.Printf("v3 %+v\n",c.Bool("verbose3"))
fmt.Println("new task template: ", c.Args().First())
return nil
},
},
},
},
},
} to even find a way to do it and considering using duplicate flag names is not even documented it looks like an implementation quirk rather than intended feature (or I am doing it wrong?). v1 had distinction between flag and global flag but honestly I made more errors in using them than actual useful functionality... |
I'm actually still on v1. I'm not sure what the current behavior is for this, or what the impetus for changing it was. |
@rliebz in v2 it would change some edge cases with using cli.GlobalType vs just cli.Type but v2 has no differentiation of that. |
I would love if this ordering requirement were relaxed, its my primary complaint about this library. |
I'd be interested in implementing it. Haven't looked at code yet but I'd probably also add a flag to opt in for "strict" ordering if it won't mess up code too much. |
In principle it should be as easy as replacing
|
In #1233 we upgraded github.com/urfave/cli from v1 to v2. There was no functional need for the upgrade, it was just about bumping our dependencies and continuing to slowly adopt go modules. However, I overlooked that v2 changed some rules for ordering of flags and arguments. From the [upgrade guide](https://github.com/urfave/cli/blob/master/docs/migrate-v1-to-v2.md): > In v2 flags must come before args. This is more POSIX-compliant. You may need to update scripts, user documentation, etc. > > This will work: > > cli hello --shout rick > > This will not: > > cli hello rick --shout We're not keen on breaking our users scripts, so let's rollback to v1. There's an [open issue upstream](urfave/cli#1113) about the new ordering rules. We'll keep an eye on that, and maybe re-try the upgrade if it becomes possible to do so in a non-breaking way This is mostly a revert of PR #1233, but with a few extra changes to things that happened after that PR (like adding the `artifact search` subcommand).
We recently upgraded from v1 to v2, and discovered this broke some customer scripts that were using flags after arguments. For now, we've reverted to v1 to avoid the breaking change (buildkite/agent#1286). We don't have a strong view on whether the v1 or v2 behaviour is preferable, but the change in behaviour is a blocker for us. It'd be great if there was a way to opt-in to the v1 behaviour with v2, purely for backwards compatibility. |
In #1233 we upgraded github.com/urfave/cli from v1 to v2. There was no functional need for the upgrade, it was just about bumping our dependencies and continuing to slowly adopt go modules. However, I overlooked that v2 changed some rules for ordering of flags and arguments. From the [upgrade guide](https://github.com/urfave/cli/blob/master/docs/migrate-v1-to-v2.md): > In v2 flags must come before args. This is more POSIX-compliant. You may need to update scripts, user documentation, etc. > > This will work: > > cli hello --shout rick > > This will not: > > cli hello rick --shout We're not keen on breaking our users scripts, so let's rollback to v1. There's an [open issue upstream](urfave/cli#1113) about the new ordering rules. We'll keep an eye on that, and maybe re-try the upgrade if it becomes possible to do so in a non-breaking way This is mostly a revert of PR #1233 and #1250, but with a few extra changes to things that happened after that PR (like adding the `artifact search` subcommand).
In #1233 we upgraded github.com/urfave/cli from v1 to v2. There was no functional need for the upgrade, it was just about bumping our dependencies and continuing to slowly adopt go modules. However, I overlooked that v2 changed some rules for ordering of flags and arguments. From the [upgrade guide](https://github.com/urfave/cli/blob/master/docs/migrate-v1-to-v2.md): > In v2 flags must come before args. This is more POSIX-compliant. You may need to update scripts, user documentation, etc. > > This will work: > > cli hello --shout rick > > This will not: > > cli hello rick --shout We're not keen on breaking our users scripts, so let's rollback to v1. There's an [open issue upstream](urfave/cli#1113) about the new ordering rules. We'll keep an eye on that, and maybe re-try the upgrade if it becomes possible to do so in a non-breaking way This is mostly a revert of PR #1233 and #1250, but with a few extra changes to things that happened after that PR (like adding the `artifact search` subcommand).
This issue or PR has been automatically marked as stale because it has not had recent activity. Please add a comment bumping this if you're still interested in it's resolution! Thanks for your help, please let us know if you need anything else. |
I'm in the same boat too, avoiding upgrading because of the breaking change in behavior. |
This issue or PR has been bumped and is no longer marked as stale! Feel free to bump it again in the future, if it's still relevant. |
I've wrote a bit of code to "merge" flags on each step (and remove duplicates if same) But I'm not sure how to make |
This issue or PR has been automatically marked as stale because it has not had recent activity. Please add a comment bumping this if you're still interested in it's resolution! Thanks for your help, please let us know if you need anything else. |
I'm definitely still interested in the resolution of this issue, and still sticking with v1 for now because of the drastic change in behavior. |
This issue or PR has been bumped and is no longer marked as stale! Feel free to bump it again in the future, if it's still relevant. |
I'm migrating from v2 -> v1 for this, thanks for opening this ticket. I'm moving all global flags to normal flags so I can get the same flexible support. Folks are complaining a lot about this in our cli. It's a major usability concern imho. #1113 (comment) seems like a good step forward for v2. |
Mentioned errors solved:
Problem: Parser loops multiple times and goes a level lower in (p)flag, that is normally expected. |
@jtagcat Thank you for working on this problem! I admit that I'm more than a bit nervous about depending on spf13/pflag 😅 because it was forked from https://github.com/ogier/pflag for whatever reason, but diverged (?) enough that it's not being kept up to date, and is not being directly maintained with much regularity (last commit at time of this writing was over a year ago). That being said, switching away from stdlib No matter what route we take with an alternate parser, I think that it will greatly reduce backward-compatibility pains by targeting the |
To be honest, I'm not a fan of pflag either. The concern we have with making it v3, as mentioned above, is that the change would be ready, but not available (waiting indefinitely on other v3 features). From my perspective, v2 behavior is utterly unusable on the CLI. If I could, instead of large major version iterations, I'd ship many major versions with a feature or two each, but it's leaving users behind, if anyone cares. A few weeks ago, I explored the idea of writing a fork from zero, adopting a few ideas. Among them, pre-run variable validation-sanitization, shared and inheritable/-d flags (improving documentation generation, ordering, and overall complexity). Supporting the base, and few core ideas sounds more attractive than accepting less-used features. Being conservative makes it easier to maintain. Forks exist for a reason. Thanks for mentioning argh, I'll look in to it sometime. |
@jtagcat I'm happy to start publishing releases in the |
@meatballhat: Yeah, that'd work. Though, that doesn't change the fact I don't have the time to contribute meaningfully. I'm mostly booked(, and this is work for me). Every now and then I can take 1-2 day spurt chunks/bites. My priority would be to:
Footnotes
|
@meatballhat I looked at argh. I don't really have any comments. I sat down for https://github.com/jtagcat/harg (going crazy noises). Looks surprisingly promising. reinventing™ a golang argument parser. a day-night or 2 days of work is expected to reach v1:
|
@jtagcat Love your effort. Please make sure to add unit tests. In fact I would write the test code first and then keep coding !!!!! |
- Move '--config' flag from global options to 'web' subcommand. - Set default '--config' flag value to 'fyj.ini'. [cli](github.com/urfave/cli) library requires global flags before subcommands/arguments. For refer to urfave/cli#1113, urfave/cli#1268 and urfave/cli#1391.
Moar #1928 |
Checklist
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
to
vs
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:
Let's say app has a subcommand to query systems state
Which has
--filter
string option, and this command have subcommands for various parts of systemwith 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 itUser now wants to see who has access to that project. But we have options just for that
So far so good. Let's see which of them can deploy the application
Okay, now let's compare it with another project...
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 ?Okay, we can't. Bit annoying but it is only few commands.
Right, it does what we wanted. Now onto writing that report. There is a
csv
output format so it should be trivial.Oh, right, go C-b NINE times because that needs to be after a command but before subcommand.
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'sls -la /tmp
andls /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 rootso
should be equivalent. Sometimes even having options before subcommand makes sense, like
Describe alternatives you've considered
Copying every flag to local "works" but it isn't exactly elegant, and messes up with generated help.
The text was updated successfully, but these errors were encountered: