diff --git a/cli/cobra.go b/cli/cobra.go index 229303edab..930ae5531f 100644 --- a/cli/cobra.go +++ b/cli/cobra.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "path/filepath" + "sort" "strings" pluginmanager "github.com/docker/cli/cli-plugins/manager" @@ -12,6 +13,7 @@ import ( cliflags "github.com/docker/cli/cli/flags" "github.com/docker/docker/pkg/homedir" "github.com/docker/docker/registry" + "github.com/fvbommel/sortorder" "github.com/moby/term" "github.com/morikuni/aec" "github.com/pkg/errors" @@ -30,9 +32,11 @@ func setupCommonRootCommand(rootCmd *cobra.Command) (*cliflags.ClientOptions, *p cobra.AddTemplateFunc("add", func(a, b int) int { return a + b }) cobra.AddTemplateFunc("hasSubCommands", hasSubCommands) + cobra.AddTemplateFunc("hasTopCommands", hasTopCommands) cobra.AddTemplateFunc("hasManagementSubCommands", hasManagementSubCommands) cobra.AddTemplateFunc("hasOrchestratorSubCommands", hasOrchestratorSubCommands) cobra.AddTemplateFunc("hasInvalidPlugins", hasInvalidPlugins) + cobra.AddTemplateFunc("topCommands", topCommands) cobra.AddTemplateFunc("operationSubCommands", operationSubCommands) cobra.AddTemplateFunc("managementSubCommands", managementSubCommands) cobra.AddTemplateFunc("orchestratorSubCommands", orchestratorSubCommands) @@ -250,12 +254,43 @@ func hasInvalidPlugins(cmd *cobra.Command) bool { return len(invalidPlugins(cmd)) > 0 } +func hasTopCommands(cmd *cobra.Command) bool { + return len(topCommands(cmd)) > 0 +} + +func topCommands(cmd *cobra.Command) []*cobra.Command { + cmds := []*cobra.Command{} + if cmd.Parent() != nil { + // for now, only use top-commands for the root-command, and skip + // for sub-commands + return cmds + } + for _, sub := range cmd.Commands() { + if isPlugin(sub) || !sub.IsAvailableCommand() { + continue + } + if _, ok := sub.Annotations["category-top"]; ok { + cmds = append(cmds, sub) + } + } + sort.SliceStable(cmds, func(i, j int) bool { + return sortorder.NaturalLess(cmds[i].Annotations["category-top"], cmds[j].Annotations["category-top"]) + }) + return cmds +} + func operationSubCommands(cmd *cobra.Command) []*cobra.Command { cmds := []*cobra.Command{} for _, sub := range cmd.Commands() { if isPlugin(sub) { continue } + if _, ok := sub.Annotations["category-top"]; ok { + if cmd.Parent() == nil { + // for now, only use top-commands for the root-command + continue + } + } if sub.IsAvailableCommand() && !sub.HasSubCommands() { cmds = append(cmds, sub) } @@ -378,6 +413,13 @@ Examples: Options: {{ wrappedFlagUsages . | trimRightSpace}} +{{- end}} +{{- end}} +{{- if hasTopCommands .}} + +Common Commands: +{{- range topCommands .}} + {{rpad (decoratedName .) (add .NamePadding 1)}}{{.Short}} {{- end}} {{- end}} {{- if hasManagementSubCommands . }} diff --git a/cli/command/container/exec.go b/cli/command/container/exec.go index 9259e53d84..9dc00724f2 100644 --- a/cli/command/container/exec.go +++ b/cli/command/container/exec.go @@ -52,6 +52,9 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command { options.Command = args[1:] return RunExec(dockerCli, options) }, + Annotations: map[string]string{ + "category-top": "2", + }, } flags := cmd.Flags() diff --git a/cli/command/container/list.go b/cli/command/container/list.go index 99b5c7ef27..b24ce8b09c 100644 --- a/cli/command/container/list.go +++ b/cli/command/container/list.go @@ -37,6 +37,9 @@ func NewPsCommand(dockerCli command.Cli) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return runPs(dockerCli, &options) }, + Annotations: map[string]string{ + "category-top": "3", + }, } flags := cmd.Flags() diff --git a/cli/command/container/run.go b/cli/command/container/run.go index 38785129b8..480743611b 100644 --- a/cli/command/container/run.go +++ b/cli/command/container/run.go @@ -44,6 +44,9 @@ func NewRunCommand(dockerCli command.Cli) *cobra.Command { } return runRun(dockerCli, cmd.Flags(), &opts, copts) }, + Annotations: map[string]string{ + "category-top": "1", + }, } flags := cmd.Flags() diff --git a/cli/command/image/build.go b/cli/command/image/build.go index 6f5ea8828a..99307e256b 100644 --- a/cli/command/image/build.go +++ b/cli/command/image/build.go @@ -105,6 +105,9 @@ func NewBuildCommand(dockerCli command.Cli) *cobra.Command { options.context = args[0] return runBuild(dockerCli, options) }, + Annotations: map[string]string{ + "category-top": "4", + }, } flags := cmd.Flags() diff --git a/cli/command/image/list.go b/cli/command/image/list.go index 7f1a8df3a7..4771032cb0 100644 --- a/cli/command/image/list.go +++ b/cli/command/image/list.go @@ -37,6 +37,9 @@ func NewImagesCommand(dockerCli command.Cli) *cobra.Command { } return runImages(dockerCli, options) }, + Annotations: map[string]string{ + "category-top": "7", + }, } flags := cmd.Flags() diff --git a/cli/command/image/pull.go b/cli/command/image/pull.go index 242ad4a19c..391d397684 100644 --- a/cli/command/image/pull.go +++ b/cli/command/image/pull.go @@ -34,6 +34,9 @@ func NewPullCommand(dockerCli command.Cli) *cobra.Command { opts.remote = args[0] return RunPull(dockerCli, opts) }, + Annotations: map[string]string{ + "category-top": "5", + }, } flags := cmd.Flags() diff --git a/cli/command/image/push.go b/cli/command/image/push.go index 771a99592e..c422088ea2 100644 --- a/cli/command/image/push.go +++ b/cli/command/image/push.go @@ -35,6 +35,9 @@ func NewPushCommand(dockerCli command.Cli) *cobra.Command { opts.remote = args[0] return RunPush(dockerCli, opts) }, + Annotations: map[string]string{ + "category-top": "6", + }, } flags := cmd.Flags() diff --git a/cli/command/registry/login.go b/cli/command/registry/login.go index e949c00407..9df30db107 100644 --- a/cli/command/registry/login.go +++ b/cli/command/registry/login.go @@ -44,6 +44,9 @@ func NewLoginCommand(dockerCli command.Cli) *cobra.Command { } return runLogin(dockerCli, opts) }, + Annotations: map[string]string{ + "category-top": "8", + }, } flags := cmd.Flags() diff --git a/cli/command/registry/logout.go b/cli/command/registry/logout.go index 6bd6ae087c..844428d779 100644 --- a/cli/command/registry/logout.go +++ b/cli/command/registry/logout.go @@ -23,6 +23,9 @@ func NewLogoutCommand(dockerCli command.Cli) *cobra.Command { } return runLogout(dockerCli, serverAddress) }, + Annotations: map[string]string{ + "category-top": "9", + }, } return cmd diff --git a/cli/command/registry/search.go b/cli/command/registry/search.go index cabaad28ae..9efc1f3d5a 100644 --- a/cli/command/registry/search.go +++ b/cli/command/registry/search.go @@ -32,6 +32,9 @@ func NewSearchCommand(dockerCli command.Cli) *cobra.Command { options.term = args[0] return runSearch(dockerCli, options) }, + Annotations: map[string]string{ + "category-top": "10", + }, } flags := cmd.Flags() diff --git a/cli/command/system/info.go b/cli/command/system/info.go index 1d57f3f5ca..ff2f794221 100644 --- a/cli/command/system/info.go +++ b/cli/command/system/info.go @@ -54,6 +54,9 @@ func NewInfoCommand(dockerCli command.Cli) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return runInfo(cmd, dockerCli, &opts) }, + Annotations: map[string]string{ + "category-top": "12", + }, } flags := cmd.Flags() diff --git a/cli/command/system/version.go b/cli/command/system/version.go index 06b62ae763..bd56bb0998 100644 --- a/cli/command/system/version.go +++ b/cli/command/system/version.go @@ -96,6 +96,9 @@ func NewVersionCommand(dockerCli command.Cli) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return runVersion(dockerCli, &opts) }, + Annotations: map[string]string{ + "category-top": "10", + }, } flags := cmd.Flags()