diff --git a/cli/command/manifest/util.go b/cli/command/manifest/util.go index 8d4bd30364..7464a1d183 100644 --- a/cli/command/manifest/util.go +++ b/cli/command/manifest/util.go @@ -18,6 +18,7 @@ type osArch struct { // list of valid os/arch values (see "Optional Environment Variables" section // of https://golang.org/doc/install/source // Added linux/s390x as we know System z support already exists +// Keep in sync with _docker_manifest_annotate in contrib/completion/bash/docker var validOSArches = map[osArch]bool{ {os: "darwin", arch: "386"}: true, {os: "darwin", arch: "amd64"}: true, diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker index f34aa7395a..f195a81ebd 100644 --- a/contrib/completion/bash/docker +++ b/contrib/completion/bash/docker @@ -563,23 +563,39 @@ __docker_append_to_completions() { COMPREPLY=( ${COMPREPLY[@]/%/"$1"} ) } -# __docker_daemon_is_experimental tests whether the currently configured Docker -# daemon runs in experimental mode. If so, the function exits with 0 (true). -# Otherwise, or if the result cannot be determined, the exit value is 1 (false). -__docker_daemon_is_experimental() { - [ "$(__docker_q version -f '{{.Server.Experimental}}')" = "true" ] +# __docker_fetch_info fetches information about the configured Docker server and updates +# several variables with the results. +# The result is cached for the duration of one invocation of bash completion. +__docker_fetch_info() { + if [ -z "$info_fetched" ] ; then + read -r client_experimental server_experimental server_os < <(__docker_q version -f '{{.Client.Experimental}} {{.Server.Experimental}} {{.Server.Os}}') + info_fetched=true + fi } -# __docker_daemon_os_is tests whether the currently configured Docker daemon runs +# __docker_client_is_experimental tests whether the Docker cli is configured to support +# experimental features. If so, the function exits with 0 (true). +# Otherwise, or if the result cannot be determined, the exit value is 1 (false). +__docker_client_is_experimental() { + __docker_fetch_info + [ "$client_experimental" = "true" ] +} + +# __docker_server_is_experimental tests whether the currently configured Docker +# server runs in experimental mode. If so, the function exits with 0 (true). +# Otherwise, or if the result cannot be determined, the exit value is 1 (false). +__docker_server_is_experimental() { + __docker_fetch_info + [ "$server_experimental" = "true" ] +} + +# __docker_server_os_is tests whether the currently configured Docker server runs # on the operating system passed in as the first argument. -# It does so by querying the daemon for its OS. The result is cached for the duration -# of one invocation of bash completion so that this function can be used to test for -# several different operating systems without additional costs. # Known operating systems: linux, windows. -__docker_daemon_os_is() { +__docker_server_os_is() { local expected_os="$1" - local actual_os=${daemon_os=$(__docker_q version -f '{{.Server.Os}}')} - [ "$actual_os" = "$expected_os" ] + __docker_fetch_info + [ "$server_os" = "$expected_os" ] } # __docker_stack_orchestrator_is tests whether the client is configured to use @@ -1128,7 +1144,8 @@ _docker_docker() { *) local counter=$( __docker_pos_first_nonflag "$(__docker_to_extglob "$global_options_with_args")" ) if [ "$cword" -eq "$counter" ]; then - __docker_daemon_is_experimental && commands+=(${experimental_commands[*]}) + __docker_client_is_experimental && commands+=(${experimental_client_commands[*]}) + __docker_server_is_experimental && commands+=(${experimental_server_commands[*]}) COMPREPLY=( $( compgen -W "${commands[*]} help" -- "$cur" ) ) fi ;; @@ -1837,14 +1854,14 @@ _docker_container_run_and_create() { --volume -v --workdir -w " - __docker_daemon_os_is windows && options_with_args+=" + __docker_server_os_is windows && options_with_args+=" --cpu-count --cpu-percent --io-maxbandwidth --io-maxiops --isolation " - __docker_daemon_is_experimental && options_with_args+=" + __docker_server_is_experimental && options_with_args+=" --platform " @@ -1960,7 +1977,7 @@ _docker_container_run_and_create() { return ;; --isolation) - if __docker_daemon_os_is windows ; then + if __docker_server_os_is windows ; then __docker_complete_isolation return fi @@ -2071,12 +2088,12 @@ _docker_container_start() { __docker_complete_detach_keys && return case "$prev" in --checkpoint) - if __docker_daemon_is_experimental ; then + if __docker_server_is_experimental ; then return fi ;; --checkpoint-dir) - if __docker_daemon_is_experimental ; then + if __docker_server_is_experimental ; then _filedir -d return fi @@ -2086,7 +2103,7 @@ _docker_container_start() { case "$cur" in -*) local options="--attach -a --detach-keys --help --interactive -i" - __docker_daemon_is_experimental && options+=" --checkpoint --checkpoint-dir" + __docker_server_is_experimental && options+=" --checkpoint --checkpoint-dir" COMPREPLY=( $( compgen -W "$options" -- "$cur" ) ) ;; *) @@ -2449,7 +2466,7 @@ _docker_daemon() { } _docker_deploy() { - __docker_daemon_is_experimental && _docker_stack_deploy + __docker_server_is_experimental && _docker_stack_deploy } _docker_diff() { @@ -2535,7 +2552,7 @@ _docker_image_build() { --target --ulimit " - __docker_daemon_os_is windows && options_with_args+=" + __docker_server_os_is windows && options_with_args+=" --isolation " @@ -2549,7 +2566,7 @@ _docker_image_build() { --quiet -q --rm " - if __docker_daemon_is_experimental ; then + if __docker_server_is_experimental ; then options_with_args+=" --platform " @@ -2584,7 +2601,7 @@ _docker_image_build() { return ;; --isolation) - if __docker_daemon_os_is windows ; then + if __docker_server_os_is windows ; then __docker_complete_isolation return fi @@ -2779,7 +2796,7 @@ _docker_image_pull() { case "$cur" in -*) local options="--all-tags -a --disable-content-trust=false --help" - __docker_daemon_is_experimental && options+=" --platform" + __docker_server_is_experimental && options+=" --platform" COMPREPLY=( $( compgen -W "$options" -- "$cur" ) ) ;; @@ -3430,7 +3447,7 @@ _docker_service_update_and_create() { --user -u --workdir -w " - __docker_daemon_os_is windows && options_with_args+=" + __docker_server_os_is windows && options_with_args+=" --credential-spec " @@ -3821,6 +3838,109 @@ _docker_swarm_update() { esac } +_docker_manifest() { + local subcommands=" + annotate + create + inspect + push + " + __docker_subcommands "$subcommands" && return + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) + ;; + esac +} + +_docker_manifest_annotate() { + case "$prev" in + --arch) + COMPREPLY=( $( compgen -W " + 386 + amd64 + arm + arm64 + mips64 + mips64le + ppc64le + s390x" -- "$cur" ) ) + return + ;; + --os) + COMPREPLY=( $( compgen -W " + darwin + dragonfly + freebsd + linux + netbsd + openbsd + plan9 + solaris + windows" -- "$cur" ) ) + return + ;; + --os-features|--variant) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--arch --help --os --os-features --variant" -- "$cur" ) ) + ;; + *) + local counter=$( __docker_pos_first_nonflag "--arch|--os|--os-features|--variant" ) + if [ "$cword" -eq "$counter" ] || [ "$cword" -eq "$((counter + 1))" ]; then + __docker_complete_images --force-tag --id + fi + ;; + esac +} + +_docker_manifest_create() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--amend -a --help --insecure" -- "$cur" ) ) + ;; + *) + __docker_complete_images --force-tag --id + ;; + esac +} + +_docker_manifest_inspect() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help --insecure --verbose -v" -- "$cur" ) ) + ;; + *) + local counter=$( __docker_pos_first_nonflag ) + if [ "$cword" -eq "$counter" ] || [ "$cword" -eq "$((counter + 1))" ]; then + __docker_complete_images --force-tag --id + fi + ;; + esac +} + +_docker_manifest_push() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help --insecure --purge -p" -- "$cur" ) ) + ;; + *) + local counter=$( __docker_pos_first_nonflag ) + if [ "$cword" -eq "$counter" ]; then + __docker_complete_images --force-tag --id + fi + ;; + esac +} + _docker_node() { local subcommands=" demote @@ -4455,7 +4575,7 @@ _docker_stack_deploy() { case "$cur" in -*) local options="--compose-file -c --help --orchestrator" - __docker_daemon_is_experimental && __docker_stack_orchestrator_is swarm && options+=" --bundle-file" + __docker_server_is_experimental && __docker_stack_orchestrator_is swarm && options+=" --bundle-file" __docker_stack_orchestrator_is kubernetes && options+=" --kubeconfig --namespace" __docker_stack_orchestrator_is swarm && options+=" --prune --resolve-image --with-registry-auth" COMPREPLY=( $( compgen -W "$options" -- "$cur" ) ) @@ -5078,7 +5198,11 @@ _docker() { wait ) - local experimental_commands=( + local experimental_client_commands=( + manifest + ) + + local experimental_server_commands=( checkpoint deploy ) @@ -5102,10 +5226,12 @@ _docker() { --tlskey " - local host config daemon_os - + # variables to cache server info, populated on demand for performance reasons + local info_fetched server_experimental server_os # variables to cache client info, populated on demand for performance reasons - local stack_orchestrator_is_kubernetes stack_orchestrator_is_swarm + local client_experimental stack_orchestrator_is_kubernetes stack_orchestrator_is_swarm + + local host config COMPREPLY=() local cur prev words cword