-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Allow plugins to have --flags which are the same as the top-level #1722
Conversation
One small linting error;
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
left one suggestion for the test, but LGTM, thanks!
|
||
// TestClashWithGlobalArgs ensures correct behaviour when a plugin | ||
// has an argument with the same name as one of the globals. | ||
func TestClashWithGlobalArgs(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(not a blocker for this PR); we should evaluate the naming of these tests, so make them easier to "grep" (which can be useful to run a subset of tests), i.e. give them a consistent prefix (e.g. TestPluginGlobalArgsClash
, TestPluginGlobalArgsUnknown
)
e585336
to
88a1249
Compare
Codecov Report
@@ Coverage Diff @@
## master #1722 +/- ##
==========================================
- Coverage 56.13% 56.04% -0.09%
==========================================
Files 306 306
Lines 21038 21050 +12
==========================================
- Hits 11809 11798 -11
- Misses 8374 8399 +25
+ Partials 855 853 -2 |
I'm going to add an e2e for this case here too once I'm done with the feedback so far |
88a1249
to
5dce8a6
Compare
Test failure ends with
Which I don't think can be due to my changes here... I'm about to push an update so if this was a flake it'll go away then I guess. |
1fce752
to
9457f1f
Compare
// flags.Args() and then continuing on and finding other | ||
// arguments which we try and treat as globals (when they are | ||
// actually arguments to the subcommand). | ||
flags.SetInterspersed(false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is smelly, but the only other way I see is to clone the flags, and then set the interspersed, add the flag set with persistent flags... so HandleGlobalFlags
has no side effects anymore.
That said, the effort may not be worth it...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, no, that's a good idea actually. I shall investigate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hrm, looks like cloning the flags is not as trivial as I would have hoped :-/ at least there is no handy looking method I can see and I'm not sure if a simple copy of the pointed to object is sufficient (but I think probably not).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I remember, there's a VisitAll
on flags but yep it's not trivial. Maybe we can add
a Clone
method upstream?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@silvin-lubecki Please have a look at 73f5adb and see if you think it is ok.
It doesn't try to copy all of the settings from the flagset to our local one, but I think it does enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, you found a nice way to construct another flag set 👍
73f5adb
to
7f18a66
Compare
The validate task failed
|
It worked for me locally in about 7m. GH was having an outage earlier, it's probably that. |
7f18a66
to
33fc528
Compare
`TestRunGoodArgument` fits here. Signed-off-by: Ian Campbell <[email protected]>
These won't pass right now due to docker#1699 ("Plugins can't re-use the same flags as cli global flags") and the change in 935d47b ("Ignore unknown arguments on the top-level command."), but the intention is to fix them now. Signed-off-by: Ian Campbell <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thank you @ijc 👍
The issue with plugin options clashing with globals is that when cobra is parsing the command line and it comes across an argument which doesn't start with a `-` it (in the absence of plugins) distinguishes between "argument to current command" and "new subcommand" based on the list of registered sub commands. Plugins breaks that model. When presented with `docker -D plugin -c foo` cobra parses up to the `plugin`, sees it isn't a registered sub-command of the top-level docker (because it isn't, it's a plugin) so it accumulates it as an argument to the top-level `docker` command. Then it sees the `-c`, and thinks it is the global `-c` (for AKA `--context`) option and tries to treat it as that, which fails. In the specific case of the top-level `docker` subcommand we know that it has no arguments which aren't `--flags` (or `-f` short flags) and so anything which doesn't start with a `-` must either be a (known) subcommand or an attempt to execute a plugin. We could simply scan for and register all installed plugins at start of day, so that cobra can do the right thing, but we want to avoid that since it would involve executing each plugin to fetch the metadata, even if the command wasn't going to end up hitting a plugin. Instead we can parse the initial set of global arguments separately before hitting the main cobra `Execute` path, which works here exactly because we know that the top-level has no non-flag arguments. One slight wrinkle is that the top-level `PersistentPreRunE` is no longer called on the plugins path (since it no longer goes via `Execute`), so we arrange for the initialisation done there (which has to be done after global flags are parsed to handle e.g. `--config`) to happen explictly after the global flags are parsed. Rather than make `newDockerCommand` return the complicated set of results needed to make this happen, instead return a closure which achieves this. The new functionality is introduced via a common `TopLevelCommand` abstraction which lets us adjust the plugin entrypoint to use the same strategy for parsing the global arguments. This isn't strictly required (in this case the stuff in cobra's `Execute` works fine) but doing it this way avoids the possibility of subtle differences in behaviour. Fixes docker#1699, and also, as a side-effect, the first item in docker#1661. Signed-off-by: Ian Campbell <[email protected]>
Previous commits fixed the first issue on docker#1661, this simply adds a test for it. Note that this is testing the current behaviour, without regard for the second issue in docker#1661 which proposes a different behaviour. Signed-off-by: Ian Campbell <[email protected]>
This makes things more idempotent, rather than relying on undoing the interspersed settings. Note that the underlying `Flag`s remain shared, it's just the `FlagSet` which is duplicated. Signed-off-by: Ian Campbell <[email protected]>
33fc528
to
e824bc8
Compare
This was complicated. The final commit message explains it best: