github.com/thajeztah/cli@v0.0.0-20240223162942-dc6bfac81a8b/cli-plugins/manager/cobra.go (about) 1 package manager 2 3 import ( 4 "fmt" 5 "os" 6 "sync" 7 8 "github.com/docker/cli/cli/command" 9 "github.com/spf13/cobra" 10 ) 11 12 const ( 13 // CommandAnnotationPlugin is added to every stub command added by 14 // AddPluginCommandStubs with the value "true" and so can be 15 // used to distinguish plugin stubs from regular commands. 16 CommandAnnotationPlugin = "com.docker.cli.plugin" 17 18 // CommandAnnotationPluginVendor is added to every stub command 19 // added by AddPluginCommandStubs and contains the vendor of 20 // that plugin. 21 CommandAnnotationPluginVendor = "com.docker.cli.plugin.vendor" 22 23 // CommandAnnotationPluginVersion is added to every stub command 24 // added by AddPluginCommandStubs and contains the version of 25 // that plugin. 26 CommandAnnotationPluginVersion = "com.docker.cli.plugin.version" 27 28 // CommandAnnotationPluginInvalid is added to any stub command 29 // added by AddPluginCommandStubs for an invalid command (that 30 // is, one which failed it's candidate test) and contains the 31 // reason for the failure. 32 CommandAnnotationPluginInvalid = "com.docker.cli.plugin-invalid" 33 ) 34 35 var pluginCommandStubsOnce sync.Once 36 37 // AddPluginCommandStubs adds a stub cobra.Commands for each valid and invalid 38 // plugin. The command stubs will have several annotations added, see 39 // `CommandAnnotationPlugin*`. 40 func AddPluginCommandStubs(dockerCli command.Cli, rootCmd *cobra.Command) (err error) { 41 pluginCommandStubsOnce.Do(func() { 42 var plugins []Plugin 43 plugins, err = ListPlugins(dockerCli, rootCmd) 44 if err != nil { 45 return 46 } 47 for _, p := range plugins { 48 p := p 49 vendor := p.Vendor 50 if vendor == "" { 51 vendor = "unknown" 52 } 53 annotations := map[string]string{ 54 CommandAnnotationPlugin: "true", 55 CommandAnnotationPluginVendor: vendor, 56 CommandAnnotationPluginVersion: p.Version, 57 } 58 if p.Err != nil { 59 annotations[CommandAnnotationPluginInvalid] = p.Err.Error() 60 } 61 rootCmd.AddCommand(&cobra.Command{ 62 Use: p.Name, 63 Short: p.ShortDescription, 64 Run: func(_ *cobra.Command, _ []string) {}, 65 Annotations: annotations, 66 DisableFlagParsing: true, 67 RunE: func(cmd *cobra.Command, args []string) error { 68 flags := rootCmd.PersistentFlags() 69 flags.SetOutput(nil) 70 perr := flags.Parse(args) 71 if perr != nil { 72 return err 73 } 74 if flags.Changed("help") { 75 cmd.HelpFunc()(rootCmd, args) 76 return nil 77 } 78 return fmt.Errorf("docker: '%s' is not a docker command.\nSee 'docker --help'", cmd.Name()) 79 }, 80 ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 81 // Delegate completion to plugin 82 cargs := []string{p.Path, cobra.ShellCompRequestCmd, p.Name} 83 cargs = append(cargs, args...) 84 cargs = append(cargs, toComplete) 85 os.Args = cargs 86 runCommand, runErr := PluginRunCommand(dockerCli, p.Name, cmd) 87 if runErr != nil { 88 return nil, cobra.ShellCompDirectiveError 89 } 90 runErr = runCommand.Run() 91 if runErr == nil { 92 os.Exit(0) // plugin already rendered complete data 93 } 94 return nil, cobra.ShellCompDirectiveError 95 }, 96 }) 97 } 98 }) 99 return err 100 }