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

[cmd/*] Switch to pflag for all CLI flag parsing #10619

Merged
merged 6 commits into from
Jul 25, 2022

Conversation

ajm188
Copy link
Contributor

@ajm188 ajm188 commented Jun 29, 2022

Description

This PR begins the next step in the implementation of VEP-4, officially moving us to using pflag in all of our CLI flag parsing. It does not migrate any flag definitions (except one small proof-of-concept/example), or move any flags (at all) out of the global flagset, which can be done incrementally in follow-up PRs.

How to move a package's flags out of the global flagset — The Guide

(if you think of a good place to house this, let me know!)

For each flag in the package you are tackling, you are going to want to determine if it truly should be global and available to every binary (probably flags that control logging and tracing behavior are good candidates), or if they only make sense for a particular binary or particular subset of binaries.

To see which cmd entrypoints actually import your package at all (which doesn't actually tell you if the value that flag is set to has any impact on that binary), you can run:

go list -f '{{ .ImportPath }}| {{ join .Deps " " }} ' ./go/cmd/... | awk -F"|" '$2 ~ " <full import path of your package here> " {print $1}'

The spacing in the -f argument to go list might seem arbitrary, but it's specific and important here, as it lets us do an exact match in the awk (e.g. you want to know if vitess.io/vitess/go/vt/vtgate is imported, but not get false positives if someone imports vitess.io/vitess/go/vt/vtgate/buffer, or anything else underneath the go/vt/vtgate/* tree).

As an example, here are the cmds that import grpcvtgateservice:

$ go list -f '{{ .ImportPath }}| {{ join .Deps " " }} ' ./go/cmd/... | awk -F"|" '$2 ~ " vitess.io/vitess/go/vt/vtgate/grpcvtgateservice " {print $1}'
vitess.io/vitess/go/cmd/vtcombo
vitess.io/vitess/go/cmd/vtgate
vitess.io/vitess/go/cmd/vtgateclienttest

Armed with this list, you need to make a judgement call as to whether each of these commands actually needs the flags defined in your package. I don't have much to say in the way of guidance here, except to ask the domain experts of the package and the cmd entrypoint. This is also why we have endtoend tests, and release candidates :)

Once you've decided, you can move your flags to a function (RegisterFlags is a good name, as is InstallFlags, which takes a *pflag.FlagSet as input), for example:

var myCoolFlag int

- flag.IntVar(&myCoolFlag, "my-cool-flag", 0, "this is my cool flag, but it's in the global flagset")
+ func RegisterFlags(fs *pflag.FlagSet) {
+     fs.IntVar(&myCoolFlag, "my-cool-flag", 0, "this is my cool flag, and now it's only installed on this one flagset")
+ }

Now that you've done that, you'll hook into servenv's new hook points to ensure your flag gets installed in the right places. If you decided your flag should truly be global, you will do:

func init() {
    servenv.OnParse(RegisterFlags)
}

If you've decided your flag belongs only on one or two commands, you'll do:

func init() {
    servenv.OnParseFor("vttablet", RegisterFlags)
    servenv.OnParseFor("vtgate", RegisterFlags) // this is also why I suggest writing a function rather than inlining
}

Related Issue(s)

Checklist

  • "Backport me!" label has been added if this change should be backported
  • Tests were added or are not required
  • Documentation was added or is not required

Deployment Notes

@vitess-bot
Copy link
Contributor

vitess-bot bot commented Jun 29, 2022

Review Checklist

Hello reviewers! 👋 Please follow this checklist when reviewing this Pull Request.

General

  • Ensure that the Pull Request has a descriptive title.
  • If this is a change that users need to know about, please apply the release notes (needs details) label so that merging is blocked unless the summary release notes document is included.
  • If a new flag is being introduced, review whether it is really needed. The flag names should be clear and intuitive (as far as possible), and the flag's help should be descriptive. Additionally, flag names should use dashes (-) as word separators rather than underscores (_).
  • If a workflow is added or modified, each items in Jobs should be named in order to mark it as required. If the workflow should be required, the GitHub Admin should be notified.

Bug fixes

  • There should be at least one unit or end-to-end test.
  • The Pull Request description should either include a link to an issue that describes the bug OR an actual description of the bug and how to reproduce, along with a description of the fix.

Non-trivial changes

  • There should be some code comments as to why things are implemented the way they are.

New/Existing features

  • Should be documented, either by modifying the existing documentation or creating new documentation.
  • New features should have a link to a feature request issue or an RFC that documents the use cases, corner cases and test cases.

Backward compatibility

  • Protobuf changes should be wire-compatible.
  • Changes to _vt tables and RPCs need to be backward compatible.
  • vtctl command output order should be stable and awk-able.

@ajm188 ajm188 force-pushed the andrew/pflag branch 3 times, most recently from 9322f52 to e1c3867 Compare June 30, 2022 17:43
@deepthi deepthi self-requested a review July 8, 2022 04:57
@ajm188 ajm188 force-pushed the andrew/pflag branch 5 times, most recently from 968914a to c38f6d7 Compare July 13, 2022 13:27
@ajm188 ajm188 added Type: Enhancement Logical improvement (somewhere between a bug and feature) Component: General Changes throughout the code base Component: CLI labels Jul 13, 2022
@ajm188 ajm188 changed the title [do not merge] WIP: giving an initial pflag swap a pass through CI [cmd/*] Switch to pflag for all CLI flag parsing Jul 13, 2022
@ajm188 ajm188 marked this pull request as ready for review July 13, 2022 18:28
@deepthi
Copy link
Member

deepthi commented Jul 13, 2022

(if you think of a good place to house this, let me know!)

How about converting the TODOs in the tracking project to Issues?
Then the issue that this PR fixes (partially, I assume), can include a task list + the guide, and as we make progress we can check things off.

@ajm188
Copy link
Contributor Author

ajm188 commented Jul 14, 2022

(if you think of a good place to house this, let me know!)

How about converting the TODOs in the tracking project to Issues? Then the issue that this PR fixes (partially, I assume), can include a task list + the guide, and as we make progress we can check things off.

Let me know what you think!! #10697

Andrew Mason added 4 commits July 25, 2022 10:29
This transparently swaps the cli parsing library used by `internal/flag`
from the standard library `flag` package to `spf13/pflag`.

It also introduces hook points for packages throughout the vitess codebase
to register their flags for either all commands using `servenv` or a
particular subset of commands. This allows these packages to continue to
define their flag variables in a package-private way, but without
polluting the global flagset.

Signed-off-by: Andrew Mason <[email protected]>
tl;dr stdlib `flag` has [this][1] and `pflag` does not

[1]: golang/go@dcf0929

Signed-off-by: Andrew Mason <[email protected]>
Andrew Mason added 2 commits July 25, 2022 10:32
@ajm188
Copy link
Contributor Author

ajm188 commented Jul 25, 2022

rebased to pick up the help text change here

@ajm188 ajm188 merged commit c3f4a99 into vitessio:main Jul 25, 2022
@ajm188 ajm188 deleted the andrew/pflag branch July 25, 2022 19:12
dbussink added a commit to planetscale/vitess that referenced this pull request Jul 26, 2022
@shlomi-noach
Copy link
Contributor

👋 this PR seems to break vtctl/vtctlclient, who no longer accept any command-specific flags. For example:

$ vtctlclient ApplySchema --skip_preflight --ddl_strategy "online -allow-zero-in-date --allow-concurrent --postpone-completion" --sql "alter table corder engine=innodb" commerce
unknown flag: --skip_preflight

or

$ vtctlclient ApplySchema --ddl_strategy "online -allow-zero-in-date --allow-concurrent --postpone-completion" --sql "alter table corder engine=innodb" commerce
unknown flag: --ddl_strategy

or

$ vtctlclient ApplySchema --sql "alter table corder engine=innodb" commerce
unknown flag: --sql

I'm not sure how tests passed, as they ought to have captured this malfunction. At any case, right now main seems to be broken in this regard; we're going to revert this PR and re-examine it later on.

@ajm188
Copy link
Contributor Author

ajm188 commented Jul 26, 2022

(just closing the loop here) we discussed this in other fora, and the issue was a combination of being on different checkout and therefore needing the legacy -- as in v14 deprecation warnings.

timvaillancourt pushed a commit to slackhq/vitess that referenced this pull request Aug 16, 2023
* Switch to `pflag` for all parsing

This transparently swaps the cli parsing library used by `internal/flag`
from the standard library `flag` package to `spf13/pflag`.

It also introduces hook points for packages throughout the vitess codebase
to register their flags for either all commands using `servenv` or a
particular subset of commands. This allows these packages to continue to
define their flag variables in a package-private way, but without
polluting the global flagset.

Signed-off-by: Andrew Mason <[email protected]>

* Workaround exit code difference between stdlib `flag` and `pflag`

tl;dr stdlib `flag` has [this][1] and `pflag` does not

[1]: golang/go@dcf0929

Signed-off-by: Andrew Mason <[email protected]>

* adjust test data for difference in spacing between pflag/stdflag

Signed-off-by: Andrew Mason <[email protected]>

* update lingering legacy flag tests

Signed-off-by: Andrew Mason <[email protected]>

* Update vtgate/tabletgateway.go to use new interface to isolate flags, update test data

Signed-off-by: Andrew Mason <[email protected]>

* update flags in java test code

Signed-off-by: Andrew Mason <[email protected]>
timvaillancourt pushed a commit to slackhq/vitess that referenced this pull request Aug 28, 2023
* Switch to `pflag` for all parsing

This transparently swaps the cli parsing library used by `internal/flag`
from the standard library `flag` package to `spf13/pflag`.

It also introduces hook points for packages throughout the vitess codebase
to register their flags for either all commands using `servenv` or a
particular subset of commands. This allows these packages to continue to
define their flag variables in a package-private way, but without
polluting the global flagset.

Signed-off-by: Andrew Mason <[email protected]>

* Workaround exit code difference between stdlib `flag` and `pflag`

tl;dr stdlib `flag` has [this][1] and `pflag` does not

[1]: golang/go@dcf0929

Signed-off-by: Andrew Mason <[email protected]>

* adjust test data for difference in spacing between pflag/stdflag

Signed-off-by: Andrew Mason <[email protected]>

* update lingering legacy flag tests

Signed-off-by: Andrew Mason <[email protected]>

* Update vtgate/tabletgateway.go to use new interface to isolate flags, update test data

Signed-off-by: Andrew Mason <[email protected]>

* update flags in java test code

Signed-off-by: Andrew Mason <[email protected]>
timvaillancourt pushed a commit to slackhq/vitess that referenced this pull request Sep 1, 2023
* Switch to `pflag` for all parsing

This transparently swaps the cli parsing library used by `internal/flag`
from the standard library `flag` package to `spf13/pflag`.

It also introduces hook points for packages throughout the vitess codebase
to register their flags for either all commands using `servenv` or a
particular subset of commands. This allows these packages to continue to
define their flag variables in a package-private way, but without
polluting the global flagset.

Signed-off-by: Andrew Mason <[email protected]>

* Workaround exit code difference between stdlib `flag` and `pflag`

tl;dr stdlib `flag` has [this][1] and `pflag` does not

[1]: golang/go@dcf0929

Signed-off-by: Andrew Mason <[email protected]>

* adjust test data for difference in spacing between pflag/stdflag

Signed-off-by: Andrew Mason <[email protected]>

* update lingering legacy flag tests

Signed-off-by: Andrew Mason <[email protected]>

* Update vtgate/tabletgateway.go to use new interface to isolate flags, update test data

Signed-off-by: Andrew Mason <[email protected]>

* update flags in java test code

Signed-off-by: Andrew Mason <[email protected]>
timvaillancourt added a commit to slackhq/vitess that referenced this pull request Sep 4, 2023
* Switch to `pflag` for all parsing

This transparently swaps the cli parsing library used by `internal/flag`
from the standard library `flag` package to `spf13/pflag`.

It also introduces hook points for packages throughout the vitess codebase
to register their flags for either all commands using `servenv` or a
particular subset of commands. This allows these packages to continue to
define their flag variables in a package-private way, but without
polluting the global flagset.



* Workaround exit code difference between stdlib `flag` and `pflag`

tl;dr stdlib `flag` has [this][1] and `pflag` does not

[1]: golang/go@dcf0929



* adjust test data for difference in spacing between pflag/stdflag



* update lingering legacy flag tests



* Update vtgate/tabletgateway.go to use new interface to isolate flags, update test data



* update flags in java test code

Signed-off-by: Andrew Mason <[email protected]>
Co-authored-by: Andrew Mason <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: CLI Component: General Changes throughout the code base Type: Enhancement Logical improvement (somewhere between a bug and feature)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[VEP-4, phase 2] Switch flag parsing in cmd entrypoints to use pflag 
3 participants