github.com/panekj/cli@v0.0.0-20230304125325-467dd2f3797e/cli-plugins/manager/cobra.go (about)

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