cobra.go 3.5 KB

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