github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/cli/cobra.go (about)

     1  package cli
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/docker/docker/pkg/term"
     8  	"github.com/pkg/errors"
     9  	"github.com/spf13/cobra"
    10  )
    11  
    12  // SetupRootCommand sets default usage, help, and error handling for the
    13  // root command.
    14  func SetupRootCommand(rootCmd *cobra.Command) {
    15  	cobra.AddTemplateFunc("hasSubCommands", hasSubCommands)
    16  	cobra.AddTemplateFunc("hasManagementSubCommands", hasManagementSubCommands)
    17  	cobra.AddTemplateFunc("operationSubCommands", operationSubCommands)
    18  	cobra.AddTemplateFunc("managementSubCommands", managementSubCommands)
    19  	cobra.AddTemplateFunc("wrappedFlagUsages", wrappedFlagUsages)
    20  
    21  	rootCmd.SetUsageTemplate(usageTemplate)
    22  	rootCmd.SetHelpTemplate(helpTemplate)
    23  	rootCmd.SetFlagErrorFunc(FlagErrorFunc)
    24  	rootCmd.SetHelpCommand(helpCommand)
    25  	rootCmd.SetVersionTemplate("Docker version {{.Version}}\n")
    26  
    27  	rootCmd.PersistentFlags().BoolP("help", "h", false, "Print usage")
    28  	rootCmd.PersistentFlags().MarkShorthandDeprecated("help", "please use --help")
    29  	rootCmd.PersistentFlags().Lookup("help").Hidden = true
    30  }
    31  
    32  // FlagErrorFunc prints an error message which matches the format of the
    33  // docker/cli/cli error messages
    34  func FlagErrorFunc(cmd *cobra.Command, err error) error {
    35  	if err == nil {
    36  		return nil
    37  	}
    38  
    39  	usage := ""
    40  	if cmd.HasSubCommands() {
    41  		usage = "\n\n" + cmd.UsageString()
    42  	}
    43  	return StatusError{
    44  		Status:     fmt.Sprintf("%s\nSee '%s --help'.%s", err, cmd.CommandPath(), usage),
    45  		StatusCode: 125,
    46  	}
    47  }
    48  
    49  var helpCommand = &cobra.Command{
    50  	Use:               "help [command]",
    51  	Short:             "Help about the command",
    52  	PersistentPreRun:  func(cmd *cobra.Command, args []string) {},
    53  	PersistentPostRun: func(cmd *cobra.Command, args []string) {},
    54  	RunE: func(c *cobra.Command, args []string) error {
    55  		cmd, args, e := c.Root().Find(args)
    56  		if cmd == nil || e != nil || len(args) > 0 {
    57  			return errors.Errorf("unknown help topic: %v", strings.Join(args, " "))
    58  		}
    59  
    60  		helpFunc := cmd.HelpFunc()
    61  		helpFunc(cmd, args)
    62  		return nil
    63  	},
    64  }
    65  
    66  func hasSubCommands(cmd *cobra.Command) bool {
    67  	return len(operationSubCommands(cmd)) > 0
    68  }
    69  
    70  func hasManagementSubCommands(cmd *cobra.Command) bool {
    71  	return len(managementSubCommands(cmd)) > 0
    72  }
    73  
    74  func operationSubCommands(cmd *cobra.Command) []*cobra.Command {
    75  	cmds := []*cobra.Command{}
    76  	for _, sub := range cmd.Commands() {
    77  		if sub.IsAvailableCommand() && !sub.HasSubCommands() {
    78  			cmds = append(cmds, sub)
    79  		}
    80  	}
    81  	return cmds
    82  }
    83  
    84  func wrappedFlagUsages(cmd *cobra.Command) string {
    85  	width := 80
    86  	if ws, err := term.GetWinsize(0); err == nil {
    87  		width = int(ws.Width)
    88  	}
    89  	return cmd.Flags().FlagUsagesWrapped(width - 1)
    90  }
    91  
    92  func managementSubCommands(cmd *cobra.Command) []*cobra.Command {
    93  	cmds := []*cobra.Command{}
    94  	for _, sub := range cmd.Commands() {
    95  		if sub.IsAvailableCommand() && sub.HasSubCommands() {
    96  			cmds = append(cmds, sub)
    97  		}
    98  	}
    99  	return cmds
   100  }
   101  
   102  var usageTemplate = `Usage:
   103  
   104  {{- if not .HasSubCommands}}	{{.UseLine}}{{end}}
   105  {{- if .HasSubCommands}}	{{ .CommandPath}}{{- if .HasAvailableFlags}} [OPTIONS]{{end}} COMMAND{{end}}
   106  
   107  {{if ne .Long ""}}{{ .Long | trim }}{{ else }}{{ .Short | trim }}{{end}}
   108  
   109  {{- if gt .Aliases 0}}
   110  
   111  Aliases:
   112    {{.NameAndAliases}}
   113  
   114  {{- end}}
   115  {{- if .HasExample}}
   116  
   117  Examples:
   118  {{ .Example }}
   119  
   120  {{- end}}
   121  {{- if .HasAvailableFlags}}
   122  
   123  Options:
   124  {{ wrappedFlagUsages . | trimRightSpace}}
   125  
   126  {{- end}}
   127  {{- if hasManagementSubCommands . }}
   128  
   129  Management Commands:
   130  
   131  {{- range managementSubCommands . }}
   132    {{rpad .Name .NamePadding }} {{.Short}}
   133  {{- end}}
   134  
   135  {{- end}}
   136  {{- if hasSubCommands .}}
   137  
   138  Commands:
   139  
   140  {{- range operationSubCommands . }}
   141    {{rpad .Name .NamePadding }} {{.Short}}
   142  {{- end}}
   143  {{- end}}
   144  
   145  {{- if .HasSubCommands }}
   146  
   147  Run '{{.CommandPath}} COMMAND --help' for more information on a command.
   148  {{- end}}
   149  `
   150  
   151  var helpTemplate = `
   152  {{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`