diff --git a/cli/command/completion/functions.go b/cli/command/completion/functions.go index 5665a274f..bc60668a0 100644 --- a/cli/command/completion/functions.go +++ b/cli/command/completion/functions.go @@ -116,14 +116,16 @@ func NetworkNames(dockerCLI APIClientProvider) cobra.CompletionFunc { // export MY_VAR=hello // docker run --rm --env MY_VAR alpine printenv MY_VAR // hello -func EnvVarNames(_ *cobra.Command, _ []string, _ string) (names []string, _ cobra.ShellCompDirective) { - envs := os.Environ() - names = make([]string, 0, len(envs)) - for _, env := range envs { - name, _, _ := strings.Cut(env, "=") - names = append(names, name) +func EnvVarNames() cobra.CompletionFunc { + return func(_ *cobra.Command, _ []string, _ string) (names []string, _ cobra.ShellCompDirective) { + envs := os.Environ() + names = make([]string, 0, len(envs)) + for _, env := range envs { + name, _, _ := strings.Cut(env, "=") + names = append(names, name) + } + return names, cobra.ShellCompDirectiveNoFileComp } - return names, cobra.ShellCompDirectiveNoFileComp } // FromList offers completion for the given list of options. @@ -134,8 +136,10 @@ func FromList(options ...string) cobra.CompletionFunc { // FileNames is a convenience function to use [cobra.ShellCompDirectiveDefault], // which indicates to let the shell perform its default behavior after // completions have been provided. -func FileNames(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) { - return nil, cobra.ShellCompDirectiveDefault +func FileNames() cobra.CompletionFunc { + return func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) { + return nil, cobra.ShellCompDirectiveDefault + } } var commonPlatforms = []string{ @@ -175,6 +179,8 @@ var commonPlatforms = []string{ // - we currently exclude architectures that may have unofficial builds, // but don't have wide adoption (and no support), such as loong64, mipsXXX, // ppc64 (non-le) to prevent confusion. -func Platforms(_ *cobra.Command, _ []string, _ string) (platforms []string, _ cobra.ShellCompDirective) { - return commonPlatforms, cobra.ShellCompDirectiveNoFileComp +func Platforms() cobra.CompletionFunc { + return func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) { + return commonPlatforms, cobra.ShellCompDirectiveNoFileComp + } } diff --git a/cli/command/completion/functions_test.go b/cli/command/completion/functions_test.go index ce675ebac..f651dde2f 100644 --- a/cli/command/completion/functions_test.go +++ b/cli/command/completion/functions_test.go @@ -176,7 +176,7 @@ func TestCompleteEnvVarNames(t *testing.T) { "ENV_A": "hello-a", "ENV_B": "hello-b", }) - values, directives := EnvVarNames(nil, nil, "") + values, directives := EnvVarNames()(nil, nil, "") assert.Check(t, is.Equal(directives&cobra.ShellCompDirectiveNoFileComp, cobra.ShellCompDirectiveNoFileComp), "Should not perform file completion") sort.Strings(values) @@ -185,7 +185,7 @@ func TestCompleteEnvVarNames(t *testing.T) { } func TestCompleteFileNames(t *testing.T) { - values, directives := FileNames(nil, nil, "") + values, directives := FileNames()(nil, nil, "") assert.Check(t, is.Equal(directives, cobra.ShellCompDirectiveDefault)) assert.Check(t, is.Len(values, 0)) } @@ -304,7 +304,7 @@ func TestCompleteNetworkNames(t *testing.T) { } func TestCompletePlatforms(t *testing.T) { - values, directives := Platforms(nil, nil, "") + values, directives := Platforms()(nil, nil, "") assert.Check(t, is.Equal(directives&cobra.ShellCompDirectiveNoFileComp, cobra.ShellCompDirectiveNoFileComp), "Should not perform file completion") assert.Check(t, is.DeepEqual(values, commonPlatforms)) } diff --git a/cli/command/container/completion.go b/cli/command/container/completion.go index 5cc45010f..37d598ceb 100644 --- a/cli/command/container/completion.go +++ b/cli/command/container/completion.go @@ -122,15 +122,15 @@ func addCompletions(cmd *cobra.Command, dockerCLI completion.APIClientProvider) _ = cmd.RegisterFlagCompletionFunc("cap-add", completeLinuxCapabilityNames) _ = cmd.RegisterFlagCompletionFunc("cap-drop", completeLinuxCapabilityNames) _ = cmd.RegisterFlagCompletionFunc("cgroupns", completeCgroupns()) - _ = cmd.RegisterFlagCompletionFunc("env", completion.EnvVarNames) - _ = cmd.RegisterFlagCompletionFunc("env-file", completion.FileNames) + _ = cmd.RegisterFlagCompletionFunc("env", completion.EnvVarNames()) + _ = cmd.RegisterFlagCompletionFunc("env-file", completion.FileNames()) _ = cmd.RegisterFlagCompletionFunc("ipc", completeIpc(dockerCLI)) _ = cmd.RegisterFlagCompletionFunc("link", completeLink(dockerCLI)) _ = cmd.RegisterFlagCompletionFunc("log-driver", completeLogDriver(dockerCLI)) _ = cmd.RegisterFlagCompletionFunc("log-opt", completeLogOpt) _ = cmd.RegisterFlagCompletionFunc("network", completion.NetworkNames(dockerCLI)) _ = cmd.RegisterFlagCompletionFunc("pid", completePid(dockerCLI)) - _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms) + _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms()) _ = cmd.RegisterFlagCompletionFunc("pull", completion.FromList(PullImageAlways, PullImageMissing, PullImageNever)) _ = cmd.RegisterFlagCompletionFunc("restart", completeRestartPolicies) _ = cmd.RegisterFlagCompletionFunc("security-opt", completeSecurityOpt) diff --git a/cli/command/container/create.go b/cli/command/container/create.go index 9b4129cd8..6d05c1962 100644 --- a/cli/command/container/create.go +++ b/cli/command/container/create.go @@ -88,7 +88,7 @@ func newCreateCommand(dockerCLI command.Cli) *cobra.Command { // TODO(thaJeztah): consider adding platform as "image create option" on containerOptions addPlatformFlag(flags, &options.platform) - _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms) + _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms()) flags.BoolVar(&options.untrusted, "disable-content-trust", !dockerCLI.ContentTrustEnabled(), "Skip image verification") copts = addFlags(flags) diff --git a/cli/command/container/exec.go b/cli/command/container/exec.go index 48c8d5f30..040c4099c 100644 --- a/cli/command/container/exec.go +++ b/cli/command/container/exec.go @@ -78,8 +78,8 @@ func newExecCommand(dockerCLI command.Cli) *cobra.Command { flags.StringVarP(&options.Workdir, "workdir", "w", "", "Working directory inside the container") flags.SetAnnotation("workdir", "version", []string{"1.35"}) - _ = cmd.RegisterFlagCompletionFunc("env", completion.EnvVarNames) - _ = cmd.RegisterFlagCompletionFunc("env-file", completion.FileNames) + _ = cmd.RegisterFlagCompletionFunc("env", completion.EnvVarNames()) + _ = cmd.RegisterFlagCompletionFunc("env-file", completion.FileNames()) return cmd } diff --git a/cli/command/context/import.go b/cli/command/context/import.go index d6a978c26..47c0bbcac 100644 --- a/cli/command/context/import.go +++ b/cli/command/context/import.go @@ -21,7 +21,7 @@ func newImportCommand(dockerCLI command.Cli) *cobra.Command { return runImport(dockerCLI, args[0], args[1]) }, // TODO(thaJeztah): this should also include "-" - ValidArgsFunction: completion.FileNames, + ValidArgsFunction: completion.FileNames(), DisableFlagsInUseLine: true, } return cmd diff --git a/cli/command/image/build.go b/cli/command/image/build.go index b2340168e..d98b21f49 100644 --- a/cli/command/image/build.go +++ b/cli/command/image/build.go @@ -157,7 +157,7 @@ func newBuildCommand(dockerCLI command.Cli) *cobra.Command { flags.SetAnnotation("squash", "experimental", nil) flags.SetAnnotation("squash", "version", []string{"1.25"}) - _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms) + _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms()) return cmd } diff --git a/cli/command/image/history.go b/cli/command/image/history.go index a8a4de8be..ef9be33a5 100644 --- a/cli/command/image/history.go +++ b/cli/command/image/history.go @@ -52,7 +52,7 @@ func newHistoryCommand(dockerCLI command.Cli) *cobra.Command { flags.StringVar(&opts.platform, "platform", "", `Show history for the given platform. Formatted as "os[/arch[/variant]]" (e.g., "linux/amd64")`) _ = flags.SetAnnotation("platform", "version", []string{"1.48"}) - _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms) + _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms()) return cmd } diff --git a/cli/command/image/import.go b/cli/command/image/import.go index bc1b31173..2a9f9d329 100644 --- a/cli/command/image/import.go +++ b/cli/command/image/import.go @@ -49,7 +49,7 @@ func newImportCommand(dockerCLI command.Cli) *cobra.Command { flags.VarP(&options.changes, "change", "c", "Apply Dockerfile instruction to the created image") flags.StringVarP(&options.message, "message", "m", "", "Set commit message for imported image") addPlatformFlag(flags, &options.platform) - _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms) + _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms()) return cmd } diff --git a/cli/command/image/inspect.go b/cli/command/image/inspect.go index 99784dd82..b899982f5 100644 --- a/cli/command/image/inspect.go +++ b/cli/command/image/inspect.go @@ -52,7 +52,7 @@ If the image or the server is not multi-platform capable, the command will error 'os[/arch[/variant]]': Explicit platform (eg. linux/amd64)`) flags.SetAnnotation("platform", "version", []string{"1.49"}) - _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms) + _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms()) return cmd } diff --git a/cli/command/image/load.go b/cli/command/image/load.go index 664d1fea5..11cb39e40 100644 --- a/cli/command/image/load.go +++ b/cli/command/image/load.go @@ -48,7 +48,7 @@ func newLoadCommand(dockerCLI command.Cli) *cobra.Command { flags.StringSliceVar(&opts.platform, "platform", []string{}, `Load only the given platform(s). Formatted as a comma-separated list of "os[/arch[/variant]]" (e.g., "linux/amd64,linux/arm64/v8").`) _ = flags.SetAnnotation("platform", "version", []string{"1.48"}) - _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms) + _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms()) return cmd } diff --git a/cli/command/image/pull.go b/cli/command/image/pull.go index 136fa14f4..00d3eb486 100644 --- a/cli/command/image/pull.go +++ b/cli/command/image/pull.go @@ -52,7 +52,7 @@ func newPullCommand(dockerCLI command.Cli) *cobra.Command { addPlatformFlag(flags, &opts.platform) flags.BoolVar(&opts.untrusted, "disable-content-trust", !dockerCLI.ContentTrustEnabled(), "Skip image verification") - _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms) + _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms()) return cmd } diff --git a/cli/command/image/push.go b/cli/command/image/push.go index 4ec8cd76e..62d565f24 100644 --- a/cli/command/image/push.go +++ b/cli/command/image/push.go @@ -69,7 +69,7 @@ Image index won't be pushed, meaning that other manifests, including attestation 'os[/arch[/variant]]': Explicit platform (eg. linux/amd64)`) flags.SetAnnotation("platform", "version", []string{"1.46"}) - _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms) + _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms()) return cmd } diff --git a/cli/command/image/remove.go b/cli/command/image/remove.go index a251a7658..90625e2c3 100644 --- a/cli/command/image/remove.go +++ b/cli/command/image/remove.go @@ -47,7 +47,7 @@ func newRemoveCommand(dockerCLI command.Cli) *cobra.Command { flags.StringSliceVar(&options.platforms, "platform", nil, `Remove only the given platform variant. Formatted as "os[/arch[/variant]]" (e.g., "linux/amd64")`) _ = flags.SetAnnotation("platform", "version", []string{"1.50"}) - _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms) + _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms()) return cmd } diff --git a/cli/command/image/save.go b/cli/command/image/save.go index 1309b4c95..f900cb1da 100644 --- a/cli/command/image/save.go +++ b/cli/command/image/save.go @@ -47,7 +47,7 @@ func newSaveCommand(dockerCLI command.Cli) *cobra.Command { flags.StringSliceVar(&opts.platform, "platform", []string{}, `Save only the given platform(s). Formatted as a comma-separated list of "os[/arch[/variant]]" (e.g., "linux/amd64,linux/arm64/v8")`) _ = flags.SetAnnotation("platform", "version", []string{"1.48"}) - _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms) + _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms()) return cmd } diff --git a/cli/command/service/create.go b/cli/command/service/create.go index 92aac5cde..d5830f5c9 100644 --- a/cli/command/service/create.go +++ b/cli/command/service/create.go @@ -82,8 +82,8 @@ func newCreateCommand(dockerCLI command.Cli) *cobra.Command { // _ = cmd.RegisterFlagCompletionFunc(flagStopSignal, completeSignals) _ = cmd.RegisterFlagCompletionFunc(flagMode, completion.FromList("replicated", "global", "replicated-job", "global-job")) - _ = cmd.RegisterFlagCompletionFunc(flagEnv, completion.EnvVarNames) // TODO(thaJeztah): flagEnvRemove (needs to read current env-vars on the service) - _ = cmd.RegisterFlagCompletionFunc(flagEnvFile, completion.FileNames) + _ = cmd.RegisterFlagCompletionFunc(flagEnv, completion.EnvVarNames()) // TODO(thaJeztah): flagEnvRemove (needs to read current env-vars on the service) + _ = cmd.RegisterFlagCompletionFunc(flagEnvFile, completion.FileNames()) _ = cmd.RegisterFlagCompletionFunc(flagNetwork, completion.NetworkNames(dockerCLI)) _ = cmd.RegisterFlagCompletionFunc(flagRestartCondition, completion.FromList("none", "on-failure", "any")) _ = cmd.RegisterFlagCompletionFunc(flagRollbackOrder, completion.FromList("start-first", "stop-first")) diff --git a/cli/command/service/update.go b/cli/command/service/update.go index bf999d76e..15e33419f 100644 --- a/cli/command/service/update.go +++ b/cli/command/service/update.go @@ -121,7 +121,7 @@ func newUpdateCommand(dockerCLI command.Cli) *cobra.Command { // _ = cmd.RegisterFlagCompletionFunc(flagCapDrop, completeLinuxCapabilityNames) // _ = cmd.RegisterFlagCompletionFunc(flagStopSignal, completeSignals) - _ = cmd.RegisterFlagCompletionFunc(flagEnvAdd, completion.EnvVarNames) + _ = cmd.RegisterFlagCompletionFunc(flagEnvAdd, completion.EnvVarNames()) // TODO(thaJeztah): flagEnvRemove (needs to read current env-vars on the service) _ = cmd.RegisterFlagCompletionFunc("image", completion.ImageNames(dockerCLI, -1)) _ = cmd.RegisterFlagCompletionFunc(flagNetworkAdd, completion.NetworkNames(dockerCLI))