@@ -4,18 +4,32 @@ import (
44 "encoding/json"
55 "fmt"
66 "os"
7- "sync"
87
98 "github.com/docker/cli/cli"
109 "github.com/docker/cli/cli-plugins/manager"
1110 "github.com/docker/cli/cli/command"
1211 "github.com/docker/cli/cli/connhelper"
13- cliflags "github.com/docker/cli/cli/flags"
1412 "github.com/docker/docker/client"
1513 "github.com/spf13/cobra"
16- "github.com/spf13/pflag"
1714)
1815
16+ func runPlugin (dockerCli * command.DockerCli , plugin * cobra.Command , meta manager.Metadata ) error {
17+ tcmd := newPluginCommand (dockerCli , plugin , meta )
18+
19+ // Doing this here avoids also calling it for the metadata
20+ // command which needlessly initializes the client and tries
21+ // to connect to the daemon.
22+ plugin .PersistentPreRunE = func (_ * cobra.Command , _ []string ) error {
23+ return tcmd .Initialize (withPluginClientConn (plugin .Name ()))
24+ }
25+
26+ cmd , _ , err := tcmd .HandleGlobalFlags ()
27+ if err != nil {
28+ return err
29+ }
30+ return cmd .Execute ()
31+ }
32+
1933// Run is the top-level entry point to the CLI plugin framework. It should be called from your plugin's `main()` function.
2034func Run (makeCmd func (command.Cli ) * cobra.Command , meta manager.Metadata ) {
2135 dockerCli , err := command .NewDockerCli ()
@@ -26,9 +40,7 @@ func Run(makeCmd func(command.Cli) *cobra.Command, meta manager.Metadata) {
2640
2741 plugin := makeCmd (dockerCli )
2842
29- cmd := newPluginCommand (dockerCli , plugin , meta )
30-
31- if err := cmd .Execute (); err != nil {
43+ if err := runPlugin (dockerCli , plugin , meta ); err != nil {
3244 if sterr , ok := err .(cli.StatusError ); ok {
3345 if sterr .Status != "" {
3446 fmt .Fprintln (dockerCli .Err (), sterr .Status )
@@ -45,40 +57,6 @@ func Run(makeCmd func(command.Cli) *cobra.Command, meta manager.Metadata) {
4557 }
4658}
4759
48- // options encapsulates the ClientOptions and FlagSet constructed by
49- // `newPluginCommand` such that they can be finalized by our
50- // `PersistentPreRunE`. This is necessary because otherwise a plugin's
51- // own use of that hook will shadow anything we add to the top-level
52- // command meaning the CLI is never Initialized.
53- var options struct {
54- name string
55- init , prerun sync.Once
56- opts * cliflags.ClientOptions
57- flags * pflag.FlagSet
58- dockerCli * command.DockerCli
59- }
60-
61- // PersistentPreRunE must be called by any plugin command (or
62- // subcommand) which uses the cobra `PersistentPreRun*` hook. Plugins
63- // which do not make use of `PersistentPreRun*` do not need to call
64- // this (although it remains safe to do so). Plugins are recommended
65- // to use `PersistenPreRunE` to enable the error to be
66- // returned. Should not be called outside of a commands
67- // PersistentPreRunE hook and must not be run unless Run has been
68- // called.
69- func PersistentPreRunE (cmd * cobra.Command , args []string ) error {
70- var err error
71- options .prerun .Do (func () {
72- if options .opts == nil || options .flags == nil || options .dockerCli == nil {
73- panic ("PersistentPreRunE called without Run successfully called first" )
74- }
75- // flags must be the original top-level command flags, not cmd.Flags()
76- options .opts .Common .SetDefaultOptions (options .flags )
77- err = options .dockerCli .Initialize (options .opts , withPluginClientConn (options .name ))
78- })
79- return err
80- }
81-
8260func withPluginClientConn (name string ) command.InitializeOpt {
8361 return command .WithInitializeClient (func (dockerCli * command.DockerCli ) (client.APIClient , error ) {
8462 cmd := "docker"
@@ -111,7 +89,7 @@ func withPluginClientConn(name string) command.InitializeOpt {
11189 })
11290}
11391
114- func newPluginCommand (dockerCli * command.DockerCli , plugin * cobra.Command , meta manager.Metadata ) * cobra. Command {
92+ func newPluginCommand (dockerCli * command.DockerCli , plugin * cobra.Command , meta manager.Metadata ) * cli. TopLevelCommand {
11593 name := plugin .Name ()
11694 fullname := manager .NamePrefix + name
11795
@@ -121,7 +99,6 @@ func newPluginCommand(dockerCli *command.DockerCli, plugin *cobra.Command, meta
12199 SilenceUsage : true ,
122100 SilenceErrors : true ,
123101 TraverseChildren : true ,
124- PersistentPreRunE : PersistentPreRunE ,
125102 DisableFlagsInUseLine : true ,
126103 }
127104 opts , flags := cli .SetupPluginRootCommand (cmd )
@@ -135,13 +112,7 @@ func newPluginCommand(dockerCli *command.DockerCli, plugin *cobra.Command, meta
135112
136113 cli .DisableFlagsInUseLine (cmd )
137114
138- options .init .Do (func () {
139- options .name = name
140- options .opts = opts
141- options .flags = flags
142- options .dockerCli = dockerCli
143- })
144- return cmd
115+ return cli .NewTopLevelCommand (cmd , dockerCli , opts , flags )
145116}
146117
147118func newMetadataSubcommand (plugin * cobra.Command , meta manager.Metadata ) * cobra.Command {
@@ -151,8 +122,6 @@ func newMetadataSubcommand(plugin *cobra.Command, meta manager.Metadata) *cobra.
151122 cmd := & cobra.Command {
152123 Use : manager .MetadataSubcommandName ,
153124 Hidden : true ,
154- // Suppress the global/parent PersistentPreRunE, which needlessly initializes the client and tries to connect to the daemon.
155- PersistentPreRun : func (cmd * cobra.Command , args []string ) {},
156125 RunE : func (cmd * cobra.Command , args []string ) error {
157126 enc := json .NewEncoder (os .Stdout )
158127 enc .SetEscapeHTML (false )
0 commit comments