Files
docker-cli/cli/command/stack/list.go
Boaz Shuster 1333b49194 Sort swarm stacks and nodes using natural sorting
This commit changes the order stacks and nodes are displayed.
For example, running "docker stack ls" is expected to
display the following list:

NAME          SERVICES
service-1     1
service-2     1
service-10    1

However, currently this is what is printed:

NAME          SERVICES
service-1     1
service-10    1
service-2     1

To fix this, "docker stack ls" and "docker node ls" are using
natural sorting to make it more human readable.

Signed-off-by: Boaz Shuster <ripcurld.github@gmail.com>
2017-07-13 14:33:02 +03:00

97 lines
2.3 KiB
Go

package stack
import (
"sort"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/cli/cli/compose/convert"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"golang.org/x/net/context"
"vbom.ml/util/sortorder"
)
type listOptions struct {
format string
}
func newListCommand(dockerCli command.Cli) *cobra.Command {
opts := listOptions{}
cmd := &cobra.Command{
Use: "ls",
Aliases: []string{"list"},
Short: "List stacks",
Args: cli.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli, opts)
},
}
flags := cmd.Flags()
flags.StringVar(&opts.format, "format", "", "Pretty-print stacks using a Go template")
return cmd
}
func runList(dockerCli command.Cli, opts listOptions) error {
client := dockerCli.Client()
ctx := context.Background()
stacks, err := getStacks(ctx, client)
if err != nil {
return err
}
format := opts.format
if len(format) == 0 {
format = formatter.TableFormatKey
}
stackCtx := formatter.Context{
Output: dockerCli.Out(),
Format: formatter.NewStackFormat(format),
}
sort.Sort(byName(stacks))
return formatter.StackWrite(stackCtx, stacks)
}
type byName []*formatter.Stack
func (n byName) Len() int { return len(n) }
func (n byName) Swap(i, j int) { n[i], n[j] = n[j], n[i] }
func (n byName) Less(i, j int) bool { return sortorder.NaturalLess(n[i].Name, n[j].Name) }
func getStacks(ctx context.Context, apiclient client.APIClient) ([]*formatter.Stack, error) {
services, err := apiclient.ServiceList(
ctx,
types.ServiceListOptions{Filters: getAllStacksFilter()})
if err != nil {
return nil, err
}
m := make(map[string]*formatter.Stack)
for _, service := range services {
labels := service.Spec.Labels
name, ok := labels[convert.LabelNamespace]
if !ok {
return nil, errors.Errorf("cannot get label %s for service %s",
convert.LabelNamespace, service.ID)
}
ztack, ok := m[name]
if !ok {
m[name] = &formatter.Stack{
Name: name,
Services: 1,
}
} else {
ztack.Services++
}
}
var stacks []*formatter.Stack
for _, stack := range m {
stacks = append(stacks, stack)
}
return stacks, nil
}