From ab97c7a63a9819fef6e2627f31e189fa7a1a06bd Mon Sep 17 00:00:00 2001 From: Andrey Kurilin Date: Tue, 14 Jun 2016 17:04:53 +0300 Subject: [PATCH] Sort commands by their names The slice of commands are sorted now automatically while Commands are called. To turn off this feature, EnableCommandSorting variable is added. --- cobra.go | 4 ++++ command.go | 18 +++++++++++++++++- command_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/cobra.go b/cobra.go index 0c4e2e5d..93a2c0f3 100644 --- a/cobra.go +++ b/cobra.go @@ -41,6 +41,10 @@ var initializers []func() // Set this to true to enable it var EnablePrefixMatching = false +//EnableCommandSorting controls sorting of the slice of commands, which is turned on by default. +//To disable sorting, set it to false. +var EnableCommandSorting = true + //AddTemplateFunc adds a template function that's available to Usage and Help //template generation. func AddTemplateFunc(name string, tmplFunc interface{}) { diff --git a/command.go b/command.go index dc57d630..a8b0fa56 100644 --- a/command.go +++ b/command.go @@ -21,6 +21,7 @@ import ( "io" "os" "path/filepath" + "sort" "strings" flag "github.com/spf13/pflag" @@ -103,6 +104,8 @@ type Command struct { commandsMaxUseLen int commandsMaxCommandPathLen int commandsMaxNameLen int + // is commands slice are sorted or not + commandsAreSorted bool flagErrorBuf *bytes.Buffer @@ -721,8 +724,20 @@ func (c *Command) ResetCommands() { c.helpCommand = nil } -//Commands returns a slice of child commands. +// Sorts commands by their names +type commandSorterByName []*Command + +func (c commandSorterByName) Len() int { return len(c) } +func (c commandSorterByName) Swap(i, j int) { c[i], c[j] = c[j], c[i] } +func (c commandSorterByName) Less(i, j int) bool { return c[i].Name() < c[j].Name() } + +// Commands returns a sorted slice of child commands. func (c *Command) Commands() []*Command { + // do not sort commands if it already sorted or sorting was disabled + if EnableCommandSorting && !c.commandsAreSorted{ + sort.Sort(commandSorterByName(c.commands)) + c.commandsAreSorted = true + } return c.commands } @@ -751,6 +766,7 @@ func (c *Command) AddCommand(cmds ...*Command) { x.SetGlobalNormalizationFunc(c.globNormFunc) } c.commands = append(c.commands, x) + c.commandsAreSorted = false } } diff --git a/command_test.go b/command_test.go index 291947f3..127ca0e6 100644 --- a/command_test.go +++ b/command_test.go @@ -133,3 +133,44 @@ func Test_DisableFlagParsing(t *testing.T) { t.Errorf("expected: %v, got: %v", as, targs) } } + +func TestCommandsAreSorted(t *testing.T) { + EnableCommandSorting = true + + originalNames := []string{"middle", "zlast", "afirst"} + expectedNames := []string{"afirst", "middle", "zlast"} + + var tmpCommand = &Command{Use: "tmp"} + + for _, name := range(originalNames) { + tmpCommand.AddCommand(&Command{Use: name}) + } + + for i, c := range(tmpCommand.Commands()) { + if expectedNames[i] != c.Name() { + t.Errorf("expected: %s, got: %s", expectedNames[i], c.Name()) + } + } + + EnableCommandSorting = true +} + +func TestEnableCommandSortingIsDisabled(t *testing.T) { + EnableCommandSorting = false + + originalNames := []string{"middle", "zlast", "afirst"} + + var tmpCommand = &Command{Use: "tmp"} + + for _, name := range(originalNames) { + tmpCommand.AddCommand(&Command{Use: name}) + } + + for i, c := range(tmpCommand.Commands()) { + if originalNames[i] != c.Name() { + t.Errorf("expected: %s, got: %s", originalNames[i], c.Name()) + } + } + + EnableCommandSorting = true +}