github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/cli/command/stack/list.go (about) 1 package stack 2 3 import ( 4 "fmt" 5 "io" 6 "strconv" 7 "text/tabwriter" 8 9 "golang.org/x/net/context" 10 11 "github.com/docker/docker/api/types" 12 "github.com/docker/docker/api/types/filters" 13 "github.com/docker/docker/cli" 14 "github.com/docker/docker/cli/command" 15 "github.com/docker/docker/client" 16 "github.com/spf13/cobra" 17 ) 18 19 const ( 20 listItemFmt = "%s\t%s\n" 21 ) 22 23 type listOptions struct { 24 } 25 26 func newListCommand(dockerCli *command.DockerCli) *cobra.Command { 27 opts := listOptions{} 28 29 cmd := &cobra.Command{ 30 Use: "ls", 31 Aliases: []string{"list"}, 32 Short: "List stacks", 33 Args: cli.NoArgs, 34 RunE: func(cmd *cobra.Command, args []string) error { 35 return runList(dockerCli, opts) 36 }, 37 } 38 39 return cmd 40 } 41 42 func runList(dockerCli *command.DockerCli, opts listOptions) error { 43 client := dockerCli.Client() 44 ctx := context.Background() 45 46 stacks, err := getStacks(ctx, client) 47 if err != nil { 48 return err 49 } 50 51 out := dockerCli.Out() 52 printTable(out, stacks) 53 return nil 54 } 55 56 func printTable(out io.Writer, stacks []*stack) { 57 writer := tabwriter.NewWriter(out, 0, 4, 2, ' ', 0) 58 59 // Ignore flushing errors 60 defer writer.Flush() 61 62 fmt.Fprintf(writer, listItemFmt, "NAME", "SERVICES") 63 for _, stack := range stacks { 64 fmt.Fprintf( 65 writer, 66 listItemFmt, 67 stack.Name, 68 strconv.Itoa(stack.Services), 69 ) 70 } 71 } 72 73 type stack struct { 74 // Name is the name of the stack 75 Name string 76 // Services is the number of the services 77 Services int 78 } 79 80 func getStacks( 81 ctx context.Context, 82 apiclient client.APIClient, 83 ) ([]*stack, error) { 84 85 filter := filters.NewArgs() 86 filter.Add("label", labelNamespace) 87 88 services, err := apiclient.ServiceList( 89 ctx, 90 types.ServiceListOptions{Filters: filter}) 91 if err != nil { 92 return nil, err 93 } 94 m := make(map[string]*stack, 0) 95 for _, service := range services { 96 labels := service.Spec.Labels 97 name, ok := labels[labelNamespace] 98 if !ok { 99 return nil, fmt.Errorf("cannot get label %s for service %s", 100 labelNamespace, service.ID) 101 } 102 ztack, ok := m[name] 103 if !ok { 104 m[name] = &stack{ 105 Name: name, 106 Services: 1, 107 } 108 } else { 109 ztack.Services++ 110 } 111 } 112 var stacks []*stack 113 for _, stack := range m { 114 stacks = append(stacks, stack) 115 } 116 return stacks, nil 117 }