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