diff --git a/cli/command/completion/functions.go b/cli/command/completion/functions.go index 7cebeac921..6026ef7692 100644 --- a/cli/command/completion/functions.go +++ b/cli/command/completion/functions.go @@ -3,23 +3,33 @@ package completion import ( "os" - "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/formatter" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/image" "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/volume" + "github.com/docker/docker/client" "github.com/spf13/cobra" ) // ValidArgsFn a function to be used by cobra command as `ValidArgsFunction` to offer command line completion type ValidArgsFn func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) +// APIClientProvider provides a method to get an [client.APIClient], initializing +// it if needed. +// +// It's a smaller interface than [command.Cli], and used in situations where an +// APIClient is needed, but we want to postpone initializing the client until +// it's used. +type APIClientProvider interface { + Client() client.APIClient +} + // ImageNames offers completion for images present within the local store -func ImageNames(dockerCli command.Cli) ValidArgsFn { +func ImageNames(dockerCLI APIClientProvider) ValidArgsFn { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, err := dockerCli.Client().ImageList(cmd.Context(), image.ListOptions{}) + list, err := dockerCLI.Client().ImageList(cmd.Context(), image.ListOptions{}) if err != nil { return nil, cobra.ShellCompDirectiveError } @@ -34,9 +44,9 @@ func ImageNames(dockerCli command.Cli) ValidArgsFn { // ContainerNames offers completion for container names and IDs // By default, only names are returned. // Set DOCKER_COMPLETION_SHOW_CONTAINER_IDS=yes to also complete IDs. -func ContainerNames(dockerCli command.Cli, all bool, filters ...func(types.Container) bool) ValidArgsFn { +func ContainerNames(dockerCLI APIClientProvider, all bool, filters ...func(types.Container) bool) ValidArgsFn { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, err := dockerCli.Client().ContainerList(cmd.Context(), container.ListOptions{ + list, err := dockerCLI.Client().ContainerList(cmd.Context(), container.ListOptions{ All: all, }) if err != nil { @@ -67,9 +77,9 @@ func ContainerNames(dockerCli command.Cli, all bool, filters ...func(types.Conta } // VolumeNames offers completion for volumes -func VolumeNames(dockerCli command.Cli) ValidArgsFn { +func VolumeNames(dockerCLI APIClientProvider) ValidArgsFn { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, err := dockerCli.Client().VolumeList(cmd.Context(), volume.ListOptions{}) + list, err := dockerCLI.Client().VolumeList(cmd.Context(), volume.ListOptions{}) if err != nil { return nil, cobra.ShellCompDirectiveError } @@ -82,9 +92,9 @@ func VolumeNames(dockerCli command.Cli) ValidArgsFn { } // NetworkNames offers completion for networks -func NetworkNames(dockerCli command.Cli) ValidArgsFn { +func NetworkNames(dockerCLI APIClientProvider) ValidArgsFn { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, err := dockerCli.Client().NetworkList(cmd.Context(), network.ListOptions{}) + list, err := dockerCLI.Client().NetworkList(cmd.Context(), network.ListOptions{}) if err != nil { return nil, cobra.ShellCompDirectiveError } diff --git a/cli/command/config/cmd.go b/cli/command/config/cmd.go index 86ad1cc09c..b8e84037cb 100644 --- a/cli/command/config/cmd.go +++ b/cli/command/config/cmd.go @@ -30,9 +30,9 @@ func NewConfigCommand(dockerCli command.Cli) *cobra.Command { } // completeNames offers completion for swarm configs -func completeNames(dockerCli command.Cli) completion.ValidArgsFn { +func completeNames(dockerCLI completion.APIClientProvider) completion.ValidArgsFn { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, err := dockerCli.Client().ConfigList(cmd.Context(), types.ConfigListOptions{}) + list, err := dockerCLI.Client().ConfigList(cmd.Context(), types.ConfigListOptions{}) if err != nil { return nil, cobra.ShellCompDirectiveError } diff --git a/cli/command/secret/cmd.go b/cli/command/secret/cmd.go index ec0643b054..4b5dc26332 100644 --- a/cli/command/secret/cmd.go +++ b/cli/command/secret/cmd.go @@ -30,9 +30,9 @@ func NewSecretCommand(dockerCli command.Cli) *cobra.Command { } // completeNames offers completion for swarm secrets -func completeNames(dockerCli command.Cli) completion.ValidArgsFn { +func completeNames(dockerCLI completion.APIClientProvider) completion.ValidArgsFn { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, err := dockerCli.Client().SecretList(cmd.Context(), types.SecretListOptions{}) + list, err := dockerCLI.Client().SecretList(cmd.Context(), types.SecretListOptions{}) if err != nil { return nil, cobra.ShellCompDirectiveError } diff --git a/cli/command/service/cmd.go b/cli/command/service/cmd.go index 2c0b8fca9d..aa54d54e11 100644 --- a/cli/command/service/cmd.go +++ b/cli/command/service/cmd.go @@ -35,9 +35,9 @@ func NewServiceCommand(dockerCli command.Cli) *cobra.Command { } // CompletionFn offers completion for swarm services -func CompletionFn(dockerCli command.Cli) completion.ValidArgsFn { +func CompletionFn(dockerCLI completion.APIClientProvider) completion.ValidArgsFn { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, err := dockerCli.Client().ServiceList(cmd.Context(), types.ServiceListOptions{}) + list, err := dockerCLI.Client().ServiceList(cmd.Context(), types.ServiceListOptions{}) if err != nil { return nil, cobra.ShellCompDirectiveError } diff --git a/cli/command/stack/cmd.go b/cli/command/stack/cmd.go index bf4dc79955..dba4e2929d 100644 --- a/cli/command/stack/cmd.go +++ b/cli/command/stack/cmd.go @@ -46,9 +46,9 @@ func NewStackCommand(dockerCli command.Cli) *cobra.Command { } // completeNames offers completion for swarm stacks -func completeNames(dockerCli command.Cli) completion.ValidArgsFn { +func completeNames(dockerCLI completion.APIClientProvider) completion.ValidArgsFn { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, err := swarm.GetStacks(cmd.Context(), dockerCli) + list, err := swarm.GetStacks(cmd.Context(), dockerCLI.Client()) if err != nil { return nil, cobra.ShellCompDirectiveError } diff --git a/cli/command/stack/list.go b/cli/command/stack/list.go index d737b8771e..d440d95839 100644 --- a/cli/command/stack/list.go +++ b/cli/command/stack/list.go @@ -2,6 +2,7 @@ package stack import ( "context" + "io" "sort" "github.com/docker/cli/cli" @@ -36,22 +37,22 @@ func newListCommand(dockerCli command.Cli) *cobra.Command { // RunList performs a stack list against the specified swarm cluster func RunList(ctx context.Context, dockerCli command.Cli, opts options.List) error { - ss, err := swarm.GetStacks(ctx, dockerCli) + ss, err := swarm.GetStacks(ctx, dockerCli.Client()) if err != nil { return err } stacks := make([]*formatter.Stack, 0, len(ss)) stacks = append(stacks, ss...) - return format(dockerCli, opts, stacks) + return format(dockerCli.Out(), opts, stacks) } -func format(dockerCli command.Cli, opts options.List, stacks []*formatter.Stack) error { +func format(out io.Writer, opts options.List, stacks []*formatter.Stack) error { fmt := formatter.Format(opts.Format) if fmt == "" || fmt == formatter.TableFormatKey { fmt = formatter.SwarmStackTableFormat } stackCtx := formatter.Context{ - Output: dockerCli.Out(), + Output: out, Format: fmt, } sort.Slice(stacks, func(i, j int) bool { diff --git a/cli/command/stack/swarm/list.go b/cli/command/stack/swarm/list.go index 983ea5e201..4c58b3de93 100644 --- a/cli/command/stack/swarm/list.go +++ b/cli/command/stack/swarm/list.go @@ -3,16 +3,16 @@ package swarm import ( "context" - "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/stack/formatter" "github.com/docker/cli/cli/compose/convert" "github.com/docker/docker/api/types" + "github.com/docker/docker/client" "github.com/pkg/errors" ) // GetStacks lists the swarm stacks. -func GetStacks(ctx context.Context, dockerCli command.Cli) ([]*formatter.Stack, error) { - services, err := dockerCli.Client().ServiceList( +func GetStacks(ctx context.Context, apiClient client.ServiceAPIClient) ([]*formatter.Stack, error) { + services, err := apiClient.ServiceList( ctx, types.ServiceListOptions{Filters: getAllStacksFilter()}) if err != nil {