cobra.go 3.5 KB

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