From ae3816614de1c2a0c9ab9cd05afebc5b1dda6429 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Sun, 8 Nov 2020 21:50:51 +0100 Subject: [PATCH] Install the new shell completion logic Add a new make target (completion) to generate the shell completion scripts. This will generate the scripts for bash, zsh and fish for both podman and podman-remote with `podman completion`. The scripts are put into the completions directory and can be installed system wide with `sudo make install.completions`. This commit replaces the current handwritten scripts for bash and zsh. The `validate.completion` target has been adjusted to make sure nobody edits these scripts directly. Signed-off-by: Paul Holzinger --- Makefile | 28 +- completions/Readme.md | 7 + completions/bash/podman | 3830 ++----------------- completions/bash/podman-remote | 271 ++ completions/fish/podman-remote.fish | 182 + completions/fish/podman.fish | 182 + completions/zsh/_podman | 502 +-- completions/zsh/_podman-remote | 181 + contrib/spec/podman.spec.in | 1 + docs/source/markdown/podman-completion.1.md | 6 +- 10 files changed, 1256 insertions(+), 3934 deletions(-) create mode 100644 completions/Readme.md create mode 100644 completions/bash/podman-remote create mode 100644 completions/fish/podman-remote.fish create mode 100644 completions/fish/podman.fish create mode 100644 completions/zsh/_podman-remote diff --git a/Makefile b/Makefile index 726020cba056..5eeb3b2f7eef 100644 --- a/Makefile +++ b/Makefile @@ -48,6 +48,7 @@ OCI_RUNTIME ?= "" BASHINSTALLDIR=${PREFIX}/share/bash-completion/completions ZSHINSTALLDIR=${PREFIX}/share/zsh/site-functions +FISHINSTALLDIR=${PREFIX}/share/fish/vendor_completions.d SELINUXOPT ?= $(shell test -x /usr/sbin/selinuxenabled && selinuxenabled && echo -Z) @@ -474,6 +475,15 @@ changelog: ## Generate changelog $(shell cat $(TMPFILE) >> changelog.txt) $(shell rm $(TMPFILE)) +completions: binaries + install ${SELINUXOPT} -d -m 755 completions/{bash,zsh,fish} + ./bin/podman completion bash --no-desc -f completions/bash/podman + ./bin/podman-remote completion bash --no-desc -f completions/bash/podman-remote + ./bin/podman completion zsh -f completions/zsh/_podman + ./bin/podman-remote completion zsh -f completions/zsh/_podman-remote + ./bin/podman completion fish -f completions/fish/podman.fish + ./bin/podman-remote completion fish -f completions/fish/podman-remote.fish + .PHONY: install install: .gopathok install.bin install.remote install.man install.cni install.systemd ## Install binaries to system locations @@ -512,8 +522,13 @@ install.man: docs install.man-nobuild install.completions: install ${SELINUXOPT} -d -m 755 ${DESTDIR}${BASHINSTALLDIR} install ${SELINUXOPT} -m 644 completions/bash/podman ${DESTDIR}${BASHINSTALLDIR} + install ${SELINUXOPT} -m 644 completions/bash/podman-remote ${DESTDIR}${BASHINSTALLDIR} install ${SELINUXOPT} -d -m 755 ${DESTDIR}${ZSHINSTALLDIR} install ${SELINUXOPT} -m 644 completions/zsh/_podman ${DESTDIR}${ZSHINSTALLDIR} + install ${SELINUXOPT} -m 644 completions/zsh/_podman-remote ${DESTDIR}${ZSHINSTALLDIR} + install ${SELINUXOPT} -d -m 755 ${DESTDIR}${FISHINSTALLDIR} + install ${SELINUXOPT} -m 644 completions/fish/podman.fish ${DESTDIR}${FISHINSTALLDIR} + install ${SELINUXOPT} -m 644 completions/fish/podman-remote.fish ${DESTDIR}${FISHINSTALLDIR} .PHONY: install.cni install.cni: @@ -656,9 +671,20 @@ API.md: pkg/varlink/io.podman.varlink $(GO) generate ./docs/... .PHONY: validate.completions -validate.completions: completions/bash/podman +validate.completions: SHELL:=/usr/bin/env bash # Set shell to bash for this target +validate.completions: + # Check that nobody has manually edited the completion scripts + # If this check fails run make completions to restore the correct scripts + diff completions/bash/podman <(./bin/podman completion --no-desc bash) + diff completions/zsh/_podman <(./bin/podman completion zsh) + diff completions/fish/podman.fish <(./bin/podman completion fish) + diff completions/bash/podman-remote <(./bin/podman-remote completion --no-desc bash) + diff completions/zsh/_podman-remote <(./bin/podman-remote completion zsh) + diff completions/fish/podman-remote.fish <(./bin/podman-remote completion fish) + # Check if the files can be loaded by the shell . completions/bash/podman if [ -x /bin/zsh ]; then /bin/zsh completions/zsh/_podman; fi + if [ -x /bin/fish ]; then /bin/fish completions/fish/podman.fish; fi .PHONY: validate validate: gofmt lint .gitvalidation validate.completions man-page-check swagger-check diff --git a/completions/Readme.md b/completions/Readme.md new file mode 100644 index 000000000000..9a3eac480b29 --- /dev/null +++ b/completions/Readme.md @@ -0,0 +1,7 @@ +# Shell completion scripts + +Podman offers shell completion scripts for bash, zsh and fish. The completion scripts are available for both `podman` and `podman-remote`. + +The shell completion scripts are generated by `make completion`, do not edit these files directly. To install them you can run `sudo make install.completions`. + +For information about these sripts see [`man podman-completion`](../docs/source/markdown/podman-completion.1.md) diff --git a/completions/bash/podman b/completions/bash/podman index c08bb33527a9..17d1e86b7688 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -1,3601 +1,271 @@ -# -# This bash script was originally copied and converted from the upstream -# github.com:docker/docker project -# -: ${PROG:=$(basename ${BASH_SOURCE})} +# bash completion for podman -*- shell-script -*- - -__podman_previous_extglob_setting=$(shopt -p extglob) -shopt -s extglob - -__podman_q() { - podman ${host:+-H "$host"} ${config:+--config "$config"} 2>/dev/null "$@" -} - -# __podman_containers returns a list of containers. Additional options to -# `podman ps` may be specified in order to filter the list, e.g. -# `__podman_containers --filter status=running` -# By default, only names are returned. -# Set PODMAN_COMPLETION_SHOW_CONTAINER_IDS=yes to also complete IDs. -# An optional first option `--id|--name` may be used to limit the -# output to the IDs or names of matching items. This setting takes -# precedence over the environment setting. -__podman_containers() { - local format - if [ "$1" = "--id" ] ; then - format='{{.ID}}' - shift - elif [ "$1" = "--name" ] ; then - format='{{.Names}}' - shift - elif [ "${PODMAN_COMPLETION_SHOW_CONTAINER_IDS}" = yes ] ; then - format='{{.ID}} {{.Names}}' - else - format='{{.Names}}' - fi - __podman_q ps --format "$format" "$@" -} - -__podman_list_registries() { - sed -n -e '/registries.*=/ {s/.*\[\([^]]*\).*/\1/p;q}' /etc/containers/registries.conf | sed -e "s/[,']//g" -} - -# __podman_pods returns a list of pods. Additional options to -# `podman pod ps` may be specified in order to filter the list, e.g. -# `__podman_containers --filter status=running` -# By default, only names are returned. -# Set PODMAN_COMPLETION_SHOW_CONTAINER_IDS=yes to also complete IDs. -# An optional first option `--id|--name` may be used to limit the -# output to the IDs or names of matching items. This setting takes -# precedence over the environment setting. -__podman_pods() { - local format - if [ "$1" = "--id" ] ; then - format='{{.ID}}' - shift - elif [ "$1" = "--name" ] ; then - format='{{.Name}}' - shift - else - format='{{.Name}}' - fi - __podman_q pod ps --format "$format" "$@" -} - -# __podman_complete_containers applies completion of containers based on the current -# value of `$cur` or the value of the optional first option `--cur`, if given. -# Additional filters may be appended, see `__podman_containers`. -__podman_complete_containers() { - local current="$cur" - if [ "$1" = "--cur" ] ; then - current="$2" - shift 2 - fi - COMPREPLY=( $(compgen -W "$(__podman_containers "$@")" -- "$current") ) -} - -# __podman_complete_pods applies completion of pods based on the current -# value of `$cur` or the value of the optional first option `--cur`, if given. -# Additional filters may be appended, see `__podman_pods`. -__podman_complete_pods() { - local current="$cur" - if [ "$1" = "--cur" ] ; then - current="$2" - shift 2 - fi - COMPREPLY=( $(compgen -W "$(__podman_pods "$@")" -- "$current") ) -} - -__podman_complete_pod_names() { - local names=( $(__podman_q pod ps --format={{.Name}}) ) - COMPREPLY=( $(compgen -W "${names[*]}" -- "$cur") ) -} - -__podman_complete_containers_all() { - __podman_complete_containers "$@" --all -} - -__podman_complete_containers_created() { - __podman_complete_containers "$@" --all --filter status=created -} - -__podman_complete_containers_running() { - __podman_complete_containers "$@" --filter status=running -} - -__podman_complete_containers_stopped() { - __podman_complete_containers "$@" --all --filter status=exited -} - -__podman_complete_containers_unpauseable() { - __podman_complete_containers "$@" --all --filter status=paused -} - -__podman_complete_container_names() { - local containers=( $(__podman_q ps -aq --no-trunc) ) - local names=( $(__podman_q inspect --format '{{.Name}}' "${containers[@]}") ) - names=( "${names[@]#/}" ) # trim off the leading "/" from the container names - COMPREPLY=( $(compgen -W "${names[*]}" -- "$cur") ) -} - -__podman_complete_container_ids() { - local containers=( $(__podman_q ps -aq) ) - COMPREPLY=( $(compgen -W "${containers[*]}" -- "$cur") ) -} - -__podman_images() { - local images_args="" - - case "$PODMAN_COMPLETION_SHOW_IMAGE_IDS" in - all) - images_args="--no-trunc -a" - ;; - non-intermediate) - images_args="--no-trunc" - ;; - esac - - local repo_print_command - if [ "${PODMAN_COMPLETION_SHOW_TAGS:-yes}" = "yes" ]; then - repo_print_command='print $1; print $1":"$2' - else - repo_print_command='print $1' - fi - - local awk_script - case "$PODMAN_COMPLETION_SHOW_IMAGE_IDS" in - all|non-intermediate) - awk_script='NR>1 { print $3; if ($1 != "") { '"$repo_print_command"' } }' - ;; - none|*) - awk_script='NR>1 && $1 != "" { '"$repo_print_command"' }' - ;; - esac - - __podman_q images $images_args | awk "$awk_script" | grep -v '$' -} - -__podman_complete_images() { - COMPREPLY=( $(compgen -W "$(__podman_images)" -- "$cur") ) - __ltrim_colon_completions "$cur" -} - -__podman_complete_image_repos() { - local repos="$(__podman_q images | awk 'NR>1 && $1 != "" { print $1 }')" - COMPREPLY=( $(compgen -W "$repos" -- "$cur") ) -} - -__podman_complete_image_repos_and_tags() { - local reposAndTags="$(__podman_q images | awk 'NR>1 && $1 != "" { print $1; print $1":"$2 }')" - COMPREPLY=( $(compgen -W "$reposAndTags" -- "$cur") ) - __ltrim_colon_completions "$cur" -} - -# __podman_networks returns a list of all networks. Additional options to -# `podman network ls` may be specified in order to filter the list, e.g. -# `__podman_networks --filter type=custom` -# By default, only names are returned. -# Set PODMAN_COMPLETION_SHOW_NETWORK_IDS=yes to also complete IDs. -# An optional first option `--id|--name` may be used to limit the -# output to the IDs or names of matching items. This setting takes -# precedence over the environment setting. -__podman_networks() { - local format - if [ "$1" = "--id" ] ; then - format='{{.ID}}' - shift - elif [ "$1" = "--name" ] ; then - format='{{.Name}}' - shift - elif [ "${PODMAN_COMPLETION_SHOW_NETWORK_IDS}" = yes ] ; then - format='{{.ID}} {{.Name}}' - else - format='{{.Name}}' - fi - __podman_q network ls --format "$format" "$@" -} - -# __podman_complete_networks applies completion of networks based on the current -# value of `$cur` or the value of the optional first option `--cur`, if given. -# Additional filters may be appended, see `__podman_networks`. -__podman_complete_networks() { - local current="$cur" - if [ "$1" = "--cur" ] ; then - current="$2" - shift 2 - fi - COMPREPLY=( $(compgen -W "$(__podman_networks "$@")" -- "$current") ) -} - -__podman_complete_containers_in_network() { - local containers=$(__podman_q network inspect -f '{{range $i, $c := .Containers}}{{$i}} {{$c.Name}} {{end}}' "$1") - COMPREPLY=( $(compgen -W "$containers" -- "$cur") ) -} - -__podman_runtimes() { - __podman_q info | sed -n 's/^Runtimes: \(.*\)/\1/p' -} - -__podman_complete_runtimes() { - COMPREPLY=( $(compgen -W "$(__podman_runtimes)" -- "$cur") ) -} - -# __podman_services returns a list of all services. Additional options to -# `podman service ls` may be specified in order to filter the list, e.g. -# `__podman_services --filter name=xxx` -# By default, only node names are returned. -# Set PODMAN_COMPLETION_SHOW_SERVICE_IDS=yes to also complete IDs. -# An optional first option `--id|--name` may be used to limit the -# output to the IDs or names of matching items. This setting takes -# precedence over the environment setting. -__podman_services() { - local fields='$2' # default: service name only - [ "${PODMAN_COMPLETION_SHOW_SERVICE_IDS}" = yes ] && fields='$1,$2' # ID & name - - if [ "$1" = "--id" ] ; then - fields='$1' # IDs only - shift - elif [ "$1" = "--name" ] ; then - fields='$2' # names only - shift - fi - __podman_q service ls "$@" | awk "NR>1 {print $fields}" -} - -# __podman_complete_services applies completion of services based on the current -# value of `$cur` or the value of the optional first option `--cur`, if given. -# Additional filters may be appended, see `__podman_services`. -__podman_complete_services() { - local current="$cur" - if [ "$1" = "--cur" ] ; then - current="$2" - shift 2 - fi - COMPREPLY=( $(compgen -W "$(__podman_services "$@")" -- "$current") ) -} - -# __podman_append_to_completions appends the word passed as an argument to every -# word in `$COMPREPLY`. -# Normally you do this with `compgen -S` while generating the completions. -# This function allows you to append a suffix later. It allows you to use -# the __podman_complete_XXX functions in cases where you need a suffix. -__podman_append_to_completions() { - COMPREPLY=( ${COMPREPLY[@]/%/"$1"} ) -} - -# __podman_pos_first_nonflag finds the position of the first word that is neither -# option nor an option's argument. If there are options that require arguments, -# you should pass a glob describing those options, e.g. "--option1|-o|--option2" -# Use this function to restrict completions to exact positions after the argument list. -__podman_pos_first_nonflag() { - local argument_flags=$1 - - local counter=$((${subcommand_pos:-${command_pos}} + 1)) - while [ $counter -le $cword ]; do - if [ -n "$argument_flags" ] && eval "case '${words[$counter]}' in $argument_flags) true ;; *) false ;; esac"; then - (( counter++ )) - # eat "=" in case of --option=arg syntax - [ "${words[$counter]}" = "=" ] && (( counter++ )) - else - case "${words[$counter]}" in - -*) - ;; - *) - break - ;; - esac - fi - - # Bash splits words at "=", retaining "=" as a word, examples: - # "--debug=false" => 3 words, "--log-opt syslog-facility=daemon" => 4 words - while [ "${words[$counter + 1]}" = "=" ] ; do - counter=$(( counter + 2)) - done - - (( counter++ )) - done - - echo $counter -} - -# __podman_map_key_of_current_option returns `key` if we are currently completing the -# value of a map option (`key=value`) which matches the extglob given as an argument. -# This function is needed for key-specific completions. -__podman_map_key_of_current_option() { - local glob="$1" - - local key glob_pos - if [ "$cur" = "=" ] ; then # key= case - key="$prev" - glob_pos=$((cword - 2)) - elif [[ $cur == *=* ]] ; then # key=value case (OSX) - key=${cur%=*} - glob_pos=$((cword - 1)) - elif [ "$prev" = "=" ] ; then - key=${words[$cword - 2]} # key=value case - glob_pos=$((cword - 3)) - else - return - fi - - [ "${words[$glob_pos]}" = "=" ] && ((glob_pos--)) # --option=key=value syntax - - [[ ${words[$glob_pos]} == @($glob) ]] && echo "$key" -} - -# __podman_value_of_option returns the value of the first option matching `option_glob`. -# Valid values for `option_glob` are option names like `--log-level` and globs like -# `--log-level|-l` -# Only positions between the command and the current word are considered. -__podman_value_of_option() { - local option_extglob=$(__podman_to_extglob "$1") - - local counter=$((command_pos + 1)) - while [ $counter -lt $cword ]; do - case ${words[$counter]} in - $option_extglob ) - echo ${words[$counter + 1]} - break - ;; - esac - (( counter++ )) - done -} - -# __podman_to_alternatives transforms a multiline list of strings into a single line -# string with the words separated by `|`. -# This is used to prepare arguments to __podman_pos_first_nonflag(). -__podman_to_alternatives() { - local parts=( $1 ) - local IFS='|' - echo "${parts[*]}" -} - -# __podman_to_extglob transforms a multiline list of options into an extglob pattern -# suitable for use in case statements. -__podman_to_extglob() { - local extglob=$( __podman_to_alternatives "$1" ) - echo "@($extglob)" -} - -# __podman_subcommands processes subcommands -# Locates the first occurrence of any of the subcommands contained in the -# first argument. In case of a match, calls the corresponding completion -# function and returns 0. -# If no match is found, 1 is returned. The calling function can then -# continue processing its completion. -# -# TODO if the preceding command has options that accept arguments and an -# argument is equal to one of the subcommands, this is falsely detected as -# a match. -__podman_subcommands() { - local subcommands="$1" - - local counter=$(($command_pos + 1)) - - while [ $counter -lt $cword ]; do - case "${words[$counter]}" in - $(__podman_to_extglob "$subcommands") ) - subcommand_pos=$counter - local subcommand=${words[$counter]} - local completions_func=_podman_${command}_${subcommand} - declare -F $completions_func >/dev/null && $completions_func - return 0 - ;; - esac - (( counter++ )) - done - return 1 -} - -# __podman_nospace suppresses trailing whitespace -__podman_nospace() { - # compopt is not available in ancient bash versions - type compopt &>/dev/null && compopt -o nospace -} - -__podman_complete_resolved_hostname() { - command -v host >/dev/null 2>&1 || return - COMPREPLY=( $(host 2>/dev/null "${cur%:}" | awk '/has address/ {print $4}') ) -} - -__podman_local_interfaces() { - command -v ip >/dev/null 2>&1 || return - ip addr show scope global 2>/dev/null | sed -n 's| \+inet \([0-9.]\+\).* \([^ ]\+\)|\1 \2|p' -} - -__podman_complete_restart() { - case "$prev" in - --restart) - COMPREPLY=( $( compgen -W "always no on-failure unless-stopped" -- "$cur") ) - return - ;; - esac - return 1 -} - -__podman_complete_local_interfaces() { - local additional_interface - if [ "$1" = "--add" ] ; then - additional_interface="$2" - fi - - COMPREPLY=( $( compgen -W "$(__podman_local_interfaces) $additional_interface" -- "$cur" ) ) -} - -__podman_complete_capabilities() { - # The list of capabilities is defined in types.go, ALL was added manually. - COMPREPLY=( $( compgen -W " - ALL - AUDIT_CONTROL - AUDIT_WRITE - AUDIT_READ - BLOCK_SUSPEND - CHOWN - DAC_OVERRIDE - DAC_READ_SEARCH - FOWNER - FSETID - IPC_LOCK - IPC_OWNER - KILL - LEASE - LINUX_IMMUTABLE - MAC_ADMIN - MAC_OVERRIDE - MKNOD - NET_ADMIN - NET_BIND_SERVICE - NET_BROADCAST - NET_RAW - SETFCAP - SETGID - SETPCAP - SETUID - SYS_ADMIN - SYS_BOOT - SYS_CHROOT - SYSLOG - SYS_MODULE - SYS_NICE - SYS_PACCT - SYS_PTRACE - SYS_RAWIO - SYS_RESOURCE - SYS_TIME - SYS_TTY_CONFIG - WAKE_ALARM - " -- "$cur" ) ) -} - -__podman_complete_detach_keys() { - case "$prev" in - --detach-keys) - case "$cur" in - *,) - COMPREPLY=( $( compgen -W "${cur}ctrl-" -- "$cur" ) ) - ;; - *) - COMPREPLY=( $( compgen -W "ctrl-" -- "$cur" ) ) - ;; - esac - - __podman_nospace - return 0 - ;; - esac - return 1 -} - -__podman_complete_log_drivers() { - COMPREPLY=( $( compgen -W " - awslogs - etwlogs - fluentd - gcplogs - gelf - journald - json-file - logentries - none - splunk - syslog - k8s-file - " -- "$cur" ) ) -} - -__podman_complete_log_options() { - # see docs/reference/logging/index.md - local awslogs_options="awslogs-region awslogs-group awslogs-stream" - local fluentd_options="env fluentd-address fluentd-async-connect fluentd-buffer-limit fluentd-retry-wait fluentd-max-retries labels tag" - local gcplogs_options="env gcp-log-cmd gcp-project labels" - local gelf_options="env gelf-address gelf-compression-level gelf-compression-type labels tag" - local journald_options="env labels tag" - local json_file_options="env labels max-file max-size" - local logentries_options="logentries-token" - local syslog_options="env labels syslog-address syslog-facility syslog-format syslog-tls-ca-cert syslog-tls-cert syslog-tls-key syslog-tls-skip-verify tag" - local splunk_options="env labels splunk-caname splunk-capath splunk-format splunk-gzip splunk-gzip-level splunk-index splunk-insecureskipverify splunk-source splunk-sourcetype splunk-token splunk-url splunk-verify-connection tag" - local k8s_file_options="env labels max-file max-size" - - local all_options="$fluentd_options $gcplogs_options $gelf_options $journald_options $logentries_options $json_file_options $syslog_options $splunk_options" - - case $(__podman_value_of_option --log-driver) in - '') - COMPREPLY=( $( compgen -W "$all_options" -S = -- "$cur" ) ) - ;; - awslogs) - COMPREPLY=( $( compgen -W "$awslogs_options" -S = -- "$cur" ) ) - ;; - fluentd) - COMPREPLY=( $( compgen -W "$fluentd_options" -S = -- "$cur" ) ) - ;; - gcplogs) - COMPREPLY=( $( compgen -W "$gcplogs_options" -S = -- "$cur" ) ) - ;; - gelf) - COMPREPLY=( $( compgen -W "$gelf_options" -S = -- "$cur" ) ) - ;; - journald) - COMPREPLY=( $( compgen -W "$journald_options" -S = -- "$cur" ) ) - ;; - json-file) - COMPREPLY=( $( compgen -W "$json_file_options" -S = -- "$cur" ) ) - ;; - k8s-file) - COMPREPLY=( $( compgen -W "$k8s_file_options" -S = -- "$cur" ) ) - ;; - logentries) - COMPREPLY=( $( compgen -W "$logentries_options" -S = -- "$cur" ) ) - ;; - syslog) - COMPREPLY=( $( compgen -W "$syslog_options" -S = -- "$cur" ) ) - ;; - splunk) - COMPREPLY=( $( compgen -W "$splunk_options" -S = -- "$cur" ) ) - ;; - *) - return - ;; - esac - - __podman_nospace -} - -__podman_complete_log_driver_options() { - local key=$(__podman_map_key_of_current_option '--log-opt') - case "$key" in - fluentd-async-connect) - COMPREPLY=( $( compgen -W "false true" -- "${cur##*=}" ) ) - return - ;; - gelf-address) - COMPREPLY=( $( compgen -W "udp" -S "://" -- "${cur##*=}" ) ) - __podman_nospace - return - ;; - gelf-compression-level) - COMPREPLY=( $( compgen -W "1 2 3 4 5 6 7 8 9" -- "${cur##*=}" ) ) - return - ;; - gelf-compression-type) - COMPREPLY=( $( compgen -W "gzip none zlib" -- "${cur##*=}" ) ) - return - ;; - syslog-address) - COMPREPLY=( $( compgen -W "tcp:// tcp+tls:// udp:// unix://" -- "${cur##*=}" ) ) - __podman_nospace - __ltrim_colon_completions "${cur}" - return - ;; - syslog-facility) - COMPREPLY=( $( compgen -W " - auth - authpriv - cron - daemon - ftp - kern - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 - lpr - mail - news - syslog - user - uucp - " -- "${cur##*=}" ) ) - return - ;; - syslog-format) - COMPREPLY=( $( compgen -W "rfc3164 rfc5424 rfc5424micro" -- "${cur##*=}" ) ) - return - ;; - syslog-tls-ca-cert|syslog-tls-cert|syslog-tls-key) - _filedir - return - ;; - syslog-tls-skip-verify) - COMPREPLY=( $( compgen -W "true" -- "${cur##*=}" ) ) - return - ;; - splunk-url) - COMPREPLY=( $( compgen -W "http:// https://" -- "${cur##*=}" ) ) - __podman_nospace - __ltrim_colon_completions "${cur}" - return - ;; - splunk-gzip|splunk-insecureskipverify|splunk-verify-connection) - COMPREPLY=( $( compgen -W "false true" -- "${cur##*=}" ) ) - return - ;; - splunk-format) - COMPREPLY=( $( compgen -W "inline json raw" -- "${cur##*=}" ) ) - return - ;; - esac - return 1 -} - -__podman_complete_log_levels() { - COMPREPLY=( $( compgen -W "debug info warn error fatal" -- "$cur" ) ) -} - -# __podman_complete_signals returns a subset of the available signals that is most likely -# relevant in the context of podman containers -__podman_complete_signals() { - local signals=( - SIGCONT - SIGHUP - SIGINT - SIGKILL - SIGQUIT - SIGSTOP - SIGTERM - SIGUSR1 - SIGUSR2 - ) - COMPREPLY=( $( compgen -W "${signals[*]} ${signals[*]#SIG}" -- "$( echo $cur | tr '[:lower:]' '[:upper:]')" ) ) -} - -__podman_complete_user_group() { - if [[ $cur == *:* ]] ; then - COMPREPLY=( $(compgen -g -- "${cur#*:}") ) - else - COMPREPLY=( $(compgen -u -S : -- "$cur") ) - __podman_nospace - fi -} - -__podman_list_images() { - COMPREPLY=($(compgen -W "$(podman images -q)" -- $cur)) -} - -__podman_list_containers() { - COMPREPLY=($(compgen -W "$(podman ps -aq)" -- $cur)) -} - -__podman_images() { - local images_args="" - - case "$PODMAN_COMPLETION_SHOW_IMAGE_IDS" in - all) - images_args="--no-trunc -a" - ;; - non-intermediate) - images_args="--no-trunc" - ;; - esac - - local repo_print_command - if [ "${PODMAN_COMPLETION_SHOW_TAGS:-yes}" = "yes" ]; then - repo_print_command='print $1; print $1":"$2' - else - repo_print_command='print $1' - fi - - local awk_script - case "$PODMAN_COMPLETION_SHOW_IMAGE_IDS" in - all|non-intermediate) - awk_script='NR>1 { print $3; if ($1 != "") { '"$repo_print_command"' } }' - ;; - none|*) - awk_script='NR>1 && $1 != "" { '"$repo_print_command"' }' - ;; - esac - - __podman_q images $images_args | awk "$awk_script" | grep -v '$' -} - -_podman_auto_update() { - local options_with_args=" - --authfile - " - - local boolean_options=" - --help - -h - " - - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_volume_names - ;; - esac -} - -# __podman_complete_volumes applies completion of volumes based on the current -# value of `$cur` or the value of the optional first option `--cur`, if given. -__podman_complete_volumes() { - local current="$cur" - if [ "$1" = "--cur" ] ; then - current="$2" - shift 2 - fi - COMPREPLY=( $(compgen -W "$(__podman_volume "$@")" -- "$current") ) -} - -__podman_complete_volume_names() { - local names=( $(__podman_q volume ls --quiet) ) - COMPREPLY=( $(compgen -W "${names[*]}" -- "$cur") ) -} - - -_podman_attach() { - local options_with_args=" - --detach-keys - " - local boolean_options=" - --help -h - --latest -l - --no-stdin - --sig-proxy - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; - esac -} - -_podman_container_attach() { - _podman_attach -} - -_podman_container_checkpoint() { - local options_with_args=" - -e - --export - " - local boolean_options=" - --all -a - --help -h - --ignore-rootfs - --keep -k - --latest -l - --leave-running -R - --tcp-established - " - case "$prev" in - -e|--export) - _filedir - return - ;; - esac - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; - esac -} - -_podman_container_commit() { - _podman_commit -} - -_podman_container_cp() { - _podman_cp -} - -_podman_container_create() { - _podman_create -} - -_podman_container_diff() { - _podman_diff -} - -_podman_container_exec() { - _podman_exec -} - -_podman_container_export() { - _podman_export -} - -_podman_container_init() { - _podman_init -} - -_podman_container_inspect() { - _podman_inspect -} - -_podman_container_kill() { - _podman_kill -} - -_podman_container_list() { - _podman_ls -} - -_podman_container_ls() { - _podman_ls -} - -_podman_container_logs() { - _podman_logs -} - -_podman_container_mount() { - _podman_mount -} - -_podman_container_pause() { - _podman_pause -} - -_podman_container_port() { - _podman_port -} - -_podman_container_ps() { - _podman_ls -} - -_podman_container_refresh() { - local options_with_args=" - " - local boolean_options=" - --help - -h - " - _complete_ "$options_with_args" "$boolean_options" -} - -_podman_container_restart() { - _podman_restart -} - -_podman_container_restore() { - local options_with_args=" - -i - --import - -n - --name - " - local boolean_options=" - --all -a - --help -h - --ignore-rootfs - --ignore-static-ip - --ignore-static-mac - --keep -k - --latest -l - --tcp-established - " - case "$prev" in - -i|--import) - _filedir - return - ;; - esac - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_created - ;; - esac -} - -_podman_container_rm() { - _podman_rm -} - -_podman_container_start() { - _podman_start -} - -_podman_container_stats() { - _podman_stats -} - -_podman_container_stop() { - _podman_stop -} - -_podman_container_top() { - _podman_top -} - -_podman_container_umount() { - _podman_umount -} - -_podman_container_unmount() { - _podman_unmount -} - -_podman_container_unpause() { - _podman_unpause -} - -_podman_container_wait() { - _podman_wait -} - -_podman_healthcheck() { - local boolean_options=" - --help - -h - " - subcommands=" - run - " - __podman_subcommands "$subcommands $aliases" && return - - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) - ;; - *) - COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) - ;; - esac -} - -_podman_network() { - local boolean_options=" - --help - -h - " - subcommands=" - create - inspect - ls - rm - " - __podman_subcommands "$subcommands $aliases" && return - - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) - ;; - *) - COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) - ;; - esac -} - -_podman_network_create() { - local options_with_args=" - -d - --driver - --gateway - --ip-range - --macvlan - --subnet - " - local boolean_options=" - --disable-dns - --help -h - --internal - " - _complete_ "$options_with_args" "$boolean_options" - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - esac -} - -_podman_network_inspect() { - local options_with_args=" - --format - -f - " - local boolean_options=" - --help - -h - " - _complete_ "$options_with_args" "$boolean_options" - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - esac -} - -_podman_network_ls() { - local options_with_args=" - --filter - --format -f - " - local boolean_options=" - --help - -h - --quiet - -q - " - _complete_ "$options_with_args" "$boolean_options" - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - esac -} - -_podman_network_rm() { - local options_with_args=" - " - local boolean_options=" - --force -f - --help -h - " - _complete_ "$options_with_args" "$boolean_options" - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - esac -} - -_podman_generate() { - local boolean_options=" - --help - -h - " - subcommands=" - kube - systemd - " - __podman_subcommands "$subcommands $aliases" && return - - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) - ;; - *) - COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) - ;; - esac -} - -_podman_play() { - local boolean_options=" - --help - -h - " - subcommands=" - kube - " - __podman_subcommands "$subcommands $aliases" && return - - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) - ;; - *) - COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) - ;; - esac -} -_podman_container() { - local boolean_options=" - --help - -h - " - subcommands=" - attach - checkpoint - commit - cp - create - diff - exec - exists - export - inspect - kill - list - logs - mount - pause - port - prune - refresh - restart - restore - rm - run - runlabel - start - stats - stop - top - umount - unmount - unpause - wait - " - local aliases=" - list - ps - " - __podman_subcommands "$subcommands $aliases" && return - - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) - ;; - *) - COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) - ;; - esac -} - -_podman_system_reset() { - local options_with_args=" - " - local boolean_options=" - -h - --help - --force - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - esac -} - -_podman_system_df() { - local options_with_args=" - --format - --verbose - " - local boolean_options=" - -h - --help - --verbose - -v - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - esac -} - -_podman_system_info() { - _podman_info -} - -_podman_system_prune() { - local options_with_args=" - " - - local boolean_options=" - --all -a - --force -f - --help -h - --volumes - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - esac -} - -_podman_system_service() { - local options_with_args=" - -t - --timeout - " - local boolean_options=" - --help - -h - --varlink - " - _complete_ "$options_with_args" "$boolean_options" -} - -_podman_system() { - local boolean_options=" - --help - -h - " - subcommands=" - df - info - migrate - prune - renumber - reset - service - " - __podman_subcommands "$subcommands" && return - - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) - ;; - *) - COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) - ;; - esac -} - -_podman_commit() { - local options_with_args=" - --author - -a - --change - -c - --message - -m - --iidfile - " - local boolean_options=" - --help -h - --pause -p - --quiet -q - " - _complete_ "$options_with_args" "$boolean_options" - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; - esac -} - -_podman_build() { - local boolean_options=" - --force-rm - --help -h - --layers - --no-cache - --pull - --pull-always - --pull-never - --quiet -q - --rm - --squash - --squash-all - --tls-verify - " - - local options_with_args=" - --add-host - --annotation - --authfile - --build-arg - --cap-add - --cap-drop - --cgroup-parent - --cni-config-dir - --cni-plugin-path - --cpu-period - --cpu-quota - --cpu-shares - --cpuset-cpus - --cpuset-mems - --creds - --file -f - --format - --iidfile - --ipc - --label - --memory -m - --memory-swap - --mount - --net - --network - --pid - --runtime-flag - --security-opt - --shm-size - --tag -t - --ulimit - --userns - --userns-gid-map - --userns-gid-map-group - --userns-uid-map - --userns-uid-map-user - --uts - --volume -v - " - - case "$prev" in - --file|-f) - COMPREPLY=($(compgen -W "`ls`" -- "$cur")) - ;; - esac - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - esac -} - -_podman_diff() { - local options_with_args=" - --format - " - local boolean_options=" - --help - -h - " - _complete_ "$options_with_args" "$boolean_options" - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; - esac -} - -_podman_exec() { - local options_with_args=" - --detach-keys - -e - --env - --env-file - --user - -u - --workdir - -w - " - local boolean_options=" - --help -h - --latest -l - --privileged - --tty -t - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; - esac - -} -_podman_export() { - local options_with_args=" - --output - -o - " - local boolean_options=" - --help - -h - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; - esac -} - -_podman_history() { - local options_with_args=" - --format - " - local boolean_options=" - --help -h - --human -H - --no-trunc - --quiet -q - " - _complete_ "$options_with_args" "$boolean_options" - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; - esac -} - - -_podman_import() { - local options_with_args=" - --change - -c - --message - -m - " - local boolean_options=" - --help - -h - --quiet - -q - " - case "$prev" in - --change|-c|--message|-m) - return - ;; - esac - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - local counter=$(__podman_pos_first_nonflag '--change|-c|--message|-m') - if [ "$cword" -eq "$counter" ]; then - _filedir - return - elif [ "$cword" -eq "$((counter + 1))" ]; then - __podman_complete_images --repo --tag - return - fi - ;; - esac -} - -_podman_info() { - local boolean_options=" - --help - -h - --debug - " - local options_with_args=" - -f - --format - " - - local all_options="$options_with_args $boolean_options" - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_list_images - ;; - esac -} - -_podman_image_umount() { - _podman_image_unmount -} - -_podman_image_unmount() { - local boolean_options=" - --all -a - --help -h - --force -f - " - local options_with_args=" - " - - local all_options="$options_with_args $boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --force-tag --id - ;; - esac -} - -_podman_image_mount() { - local boolean_options=" - --all -a - --help -h - " - - local options_with_args=" - --format - " - - local all_options="$options_with_args $boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --force-tag --id - ;; - esac -} - -_podman_image_build() { - _podman_build -} - -_podman_image_history() { - _podman_history -} - -_podman_image_import() { - _podman_import -} - -_podman_image_inspect() { - _podman_inspect -} - -_podman_image_load() { - _podman_load -} - -_podman_image_list() { - _podman_images -} - -_podman_image_ls() { - _podman_images -} - -_podman_image_pull() { - _podman_pull -} - -_podman_image_push() { - _podman_push -} - -_podman_image_rm() { - _podman_rmi -} - -_podman_image_save() { - _podman_save -} - -_podman_image_tag() { - _podman_tag -} - - -_podman_image_untag() { - _podman_untag -} - -_podman_image() { - local boolean_options=" - --help - -h - " - subcommands=" - build - exists - history - import - inspect - load - ls - mount - prune - pull - push - rm - save - sign - tag - trust - umount - unmount - untag - " - local aliases=" - list - " - __podman_subcommands "$subcommands $aliases" && return - - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) - ;; - *) - COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) - ;; - esac -} - -_podman_images() { - local boolean_options=" - --all -a - --digests - --filter -f - --help -h - --history - --no-trunc - --noheading - --notruncate -n - --quiet -q - " - local options_with_args=" - --format - --sort - " - - local all_options="$options_with_args $boolean_options" - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; - esac -} - -_podman_inspect() { - local boolean_options=" - --help -h - --latest -l - " - local options_with_args=" - --format - -f - --type - -t - --size - -s - " - - local all_options="$options_with_args $boolean_options" - - local preselected_type - local type - - if [ "$1" = "--type" ] ; then - preselected_type=yes - type="$2" - else - type=$(__podman_value_of_option --type) - fi - - case "$prev" in - --format|-f) - return - ;; - --type) - if [ -z "$preselected_type" ] ; then - COMPREPLY=( $( compgen -W "container image" -- "$cur" ) ) - return - fi - ;; - esac - - case "$cur" in - -*) - local options="--format -f --help --size -s" - if [ -z "$preselected_type" ] ; then - options+=" --type" - fi - COMPREPLY=( $( compgen -W "$options" -- "$cur" ) ) - ;; - *) - case "$type" in - '') - COMPREPLY=( $( compgen -W " - $(__podman_containers --all) - $(__podman_images --force-tag --id) - " -- "$cur" ) ) - __ltrim_colon_completions "$cur" - ;; - container) - __podman_complete_containers_all - ;; - image) - __podman_complete_images --force-tag --id - ;; - esac - esac -} - -_podman_kill() { - local options_with_args=" - --signal -s - " - local boolean_options=" - --all -a - --help -h - --latest -l - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; - esac -} - -_podman_logs() { - local options_with_args=" - --since - --tail - " - local boolean_options=" - --follow -f - --help -h - --latest -l - --timestamps -t - " - _complete_ "$options_with_args" "$boolean_options" - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_list_containers - ;; - esac -} - -_podman_manifest() { - local boolean_options=" - --help - -h - " - subcommands=" - add - create - inspect - push - remove - " - __podman_subcommands "$subcommands" && return - - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) - ;; - *) - COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) - ;; - esac -} - -_podman_manifest_add() { - local options_with_args=" - --annotation - --arch - --authfile - --cert-dir - --creds - --features - --os - --os-version - --variant - " - - local boolean_options=" - --all - --help - -h - --tls-verify - " - - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; - esac -} - -_podman_manifest_annotate() { - local options_with_args=" - --annotation - --arch - --features - --os - --os-features - --os-version - --variant - " - - local boolean_options=" - --help - -h - " - - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; - esac -} - -_podman_manifest_create() { - local boolean_options=" - --all - --help - -h - " - - _complete_ "$boolean_options" -} - -_podman_manifest_inspect() { - local options_with_args=" - " - - local boolean_options=" - " - - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - - ;; - esac -} - -_podman_manifest_push() { - local options_with_args=" - --authfile - --cert-dir - --creds - --digestfile - --format -f - --sign-by - --signature-policy, - " - - local boolean_options=" - --all - --help -h - --purge - --quiet - --remove-signatures - --tls-verify - " - - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; - esac -} - -_podman_manifest_remove() { - local options_with_args=" - " - - local boolean_options=" - " - - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; - esac -} - -_podman_pull() { - local options_with_args=" - --authfile - --cert-dir - --creds - --override-arch - --override-os - --override-variant - " - local boolean_options=" - --all-tags -a - --disable-content-trust - --help -h - --quiet -q - --tls-verify - " - _complete_ "$options_with_args" "$boolean_options" -} - -_podman_search() { - local options_with_args=" - --authfile - --filter -f - --format - --limit - " - local boolean_options=" - --help - -h - --no-trunc - --list-tags - " - _complete_ "$options_with_args" "$boolean_options" -} - -_podman_unmount() { - _podman_umount $@ -} - -_podman_umount() { - local boolean_options=" - --all -a - --help -h - --force -f - --latest -l - " - local options_with_args=" - " - - local all_options="$options_with_args $boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; - esac -} - -_podman_mount() { - local boolean_options=" - --all -a - --help -h - --latest -l - --notruncate - " - - local options_with_args=" - --format - " - - local all_options="$options_with_args $boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; - esac -} - -_podman_push() { - local boolean_options=" - --compress - --digestflag - --help -h - --quiet -q - --tls-verify - " - - local options_with_args=" - --authfile - --cert-dir - --creds - --format - --sign-by - " - - local all_options="$options_with_args $boolean_options" - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; - esac -} - -_podman_container_run() { - local options_with_args=" - --add-host - --annotation - --attach -a - --blkio-weight - --blkio-weight-device - --builtin-volume - --cap-add - --cap-drop - --cgroup-conf - --cgroup-parent - --cidfile - --conmon-pidfile - --cpu-period - --cpu-quota - --cpu-rt-period - --cpu-rt-runtime - --cpu-shares -c - --cpus - --cpuset-cpus - --cpuset-mems - --device - --device-cgroup-rule - --device-read-bps - --device-read-iops - --device-write-bps - --device-write-iops - --dns - --dns-option - --dns-search - --entrypoint - --env -e - --env-file - --env-host - --expose - --gidmap - --group-add - --health-cmd - --health-interval - --health-retries - --health-start-period - --health-timeout - --hostname -h - --http-proxy - --image-volume - --init-path - --ip - --ipc - --kernel-memory - --label -l - --label-file - --log-driver - --log-opt - --mac-address - --memory -m - --memory-reservation - --memory-swap - --memory-swappiness - --name - --network - --no-healthcheck - --no-hosts - --oom-score-adj - --override-arch - --override-os - --override-variant - --pid - --pids-limit - --pod - --pod-id-file - --preserve-fds - --publish -p - --pull - --restart - --rootfs - --runtime - --security-opt - --shm-size - --stop-signal - --stop-timeout - --subgidname - --subuidname - --sysctl - --systemd - --tmpfs - --tz - --uidmap - --ulimit - --umask - --user -u - --userns - --uts - --volume -v - --volumes-from - --workdir -w - " - - local boolean_options=" - --disable-content-trust=false - --help -h - --init - --interactive -i - --oom-kill-disable - --privileged - --publish-all -P - --quiet - --read-only - --read-only-tmpfs - --tty -t - " - - if [ "$command" = "run" -o "$subcommand" = "run" ] ; then - options_with_args="$options_with_args - --detach-keys - --health-cmd - --health-interval - --health-retries - --health-start-period - --health-timeout - " - boolean_options="$boolean_options - --detach -d - --rm - --rmi - --sig-proxy=false - " - __podman_complete_detach_keys && return - __podman_complete_restart && return - fi - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - return - ;; - *) - __podman_complete_images --id - ;; - esac - - - __podman_complete_log_driver_options && return - - local key=$(__podman_map_key_of_current_option '--security-opt') - case "$key" in - label) - [[ $cur == *: ]] && return - COMPREPLY=( $( compgen -W "user: role: type: level: disable" -- "${cur##*=}") ) - if [ "${COMPREPLY[*]}" != "disable" ] ; then - __podman_nospace - fi - return - ;; - seccomp) - local cur=${cur##*=} - _filedir - COMPREPLY+=( $( compgen -W "unconfined" -- "$cur" ) ) - return - ;; - esac - - case "$prev" in - --add-host) - case "$cur" in - *:) - __podman_complete_resolved_hostname - return - ;; - esac - ;; - --attach|-a) - COMPREPLY=( $( compgen -W 'stdin stdout stderr' -- "$cur" ) ) - return - ;; - --cap-add|--cap-drop) - __podman_complete_capabilities - return - ;; - --cidfile|--env-file|--init-path|--label-file|--pod-id-file) - _filedir - return - ;; - --device|--tmpfs|--volume|-v) - case "$cur" in - *:*) - # TODO somehow do _filedir for stuff inside the image, if it's already specified (which is also somewhat difficult to determine) - ;; - '') - COMPREPLY=( $( compgen -W '/' -- "$cur" ) ) - __podman_nospace - ;; - /*) - _filedir - __podman_nospace - ;; - esac - return - ;; - --env|-e) - # we do not append a "=" here because "-e VARNAME" is legal syntax, too - COMPREPLY=( $( compgen -e -- "$cur" ) ) - __podman_nospace - return - ;; - --ipc) - case "$cur" in - *:*) - cur="${cur#*:}" - __podman_complete_containers_running - ;; - *) - COMPREPLY=( $( compgen -W 'host private container:' -- "$cur" ) ) - if [ "$COMPREPLY" = "container:" ]; then - __podman_nospace - fi - ;; - esac - return - ;; - --log-driver) - __podman_complete_log_drivers - return - ;; - --log-opt) - __podman_complete_log_options - return - ;; - --network) - case "$cur" in - container:*) - __podman_complete_containers_all --cur "${cur#*:}" - ;; - *) - COMPREPLY=( $(compgen -W "bridge none host ns: private slirp4netns $(__podman_networks) container:" -- "$cur")) - if [ "${COMPREPLY[*]}" = "container:" ] ; then - __podman_nospace - fi - ;; - esac - return - ;; - --pod) - __podman_complete_pod_names - return - ;; - --pid) - case "$cur" in - *:*) - __podman_complete_containers_running --cur "${cur#*:}" - ;; - *) - COMPREPLY=( $( compgen -W 'host container: private' -- "$cur" ) ) - if [ "$COMPREPLY" = "container:" ]; then - __podman_nospace - fi - ;; - esac - return - ;; - --runtime) - __podman_complete_runtimes - return - ;; - --security-opt) - COMPREPLY=( $( compgen -W "apparmor= label= no-new-privileges seccomp=" -- "$cur") ) - if [ "${COMPREPLY[*]}" != "no-new-privileges" ] ; then - __podman_nospace - fi - return - ;; - --storage-opt) - COMPREPLY=( $( compgen -W "size" -S = -- "$cur") ) - __podman_nospace - return - ;; - --user|-u) - __podman_complete_user_group - return - ;; - --userns) - COMPREPLY=( $( compgen -W "auto container: host keep-id ns: private" -- "$cur" ) ) - return - ;; - --volumes-from) - __podman_complete_containers_all - return - ;; - $(__podman_to_extglob "$options_with_args") ) - return - ;; - esac - - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "$all_options" -- "$cur" ) ) - ;; - *) - local counter=$( __podman_pos_first_nonflag $( __podman_to_alternatives "$options_with_args" ) ) - if [ $cword -eq $counter ]; then - __podman_complete_images - fi - ;; - esac -} - - -_podman_create() { - _podman_container_run -} - - -_podman_run() { - _podman_container_run -} - -_podman_restart() { - local options_with_args=" - --time -t - " - local boolean_options=" - --all -a - --help -h - --latest -l - --running - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; - esac -} - -_podman_rm() { - local boolean_options=" - --all -a - --cidfile - --force -f - --help -h - --ignore -i - --latest -l - --volumes -v - " - - local options_with_args=" - " - - local all_options="$options_with_args $boolean_options" - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; - esac -} - -_podman_rmi() { - local boolean_options=" - --all -a - --force -f - --help -h - " - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; - esac -} - -_podman_stats() { - local boolean_options=" - --all -a - --format - --help -h - --no-reset - --no-stream - " - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; - esac -} - -_podman_tag() { - local options_with_args=" - " - local boolean_options=" - --help - -h - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images - ;; - esac -} - -_podman_untag() { - local options_with_args=" - " - local boolean_options=" - --help - -h - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images - ;; - esac -} - -__podman_top_descriptors() { - podman top --list-descriptors -} - -__podman_complete_top_descriptors() { - COMPREPLY=($(compgen -W "$(__podman_top_descriptors)" -- "$cur")) -} - -_podman_top() { - local options_with_args=" - " - local boolean_options=" - --help - -h - --latest - -l - " - - # podman-top works on only *one* container, which means that when we have - # three or more arguments, we can complete with top descriptors. - if [[ "${COMP_CWORD}" -ge 3 ]]; then - __podman_complete_top_descriptors - return +__podman_debug() +{ + if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then + echo "$*" >> "${BASH_COMP_DEBUG_FILE}" fi - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; - esac -} - -_podman_version() { - local boolean_options=" - --help - -h - " - local options_with_args=" - --format - -f - " - local all_options="$options_with_args $boolean_options" - - _complete_ "$options_with_args" "$boolean_options" -} - -_podman_save() { - local options_with_args=" - --output -o - --format - " - local boolean_options=" - --compress - --help -h - --quiet -q - " - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; - esac -} - -_podman_pause() { - local boolean_options=" - --all - -a - --help - -h - " - local options_with_args=" - " - local boolean_options="" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; - esac -} - -_podman_port() { - local options_with_args=" - " - local boolean_options=" - --all -a - --help -h - --latest -l - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; - esac -} - -_podman_ls() { - _podman_ps -} - -_podman_ps() { - local options_with_args=" - --filter -f - --format - --last -n - --sort - --watch -w - " - local boolean_options=" - --all -a - --external - --help -h - --latest -l - --namespace --ns - --no-trunc - --pod -p - --quiet -q - --size -s - --sync - " - _complete_ "$options_with_args" "$boolean_options" -} - -_podman_init() { - local boolean_options=" - --all - -a - --help - -h - --latest - -l - " - local options_with_args=" - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_unpauseable - ;; - esac -} - -_podman_start() { - local options_with_args=" - --detach-keys - " - - local boolean_options=" - --attach -a - --help -h - --interactive -i - --latest -l - --sig-proxy - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_stopped - ;; - esac -} -_podman_stop() { - local options_with_args=" - --time -t - " - local boolean_options=" - --all -a - --cidfile - --help -h - --ignore -i - --latest -l - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_running - ;; - esac -} - -_podman_unpause() { - local boolean_options=" - --all - -a - --help - -h - " - local options_with_args=" - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_containers_unpauseable - ;; - esac -} - -_podman_varlink() { - local options_with_args=" - --timeout -t - " - local boolean_options=" - --help - -h - " - _complete_ "$options_with_args" "$boolean_options" -} - -_podman_wait() { - local options_with_args="" - local boolean_options=" - --help -h - --interval -i - --latest -l - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_container_names - ;; - esac -} - -_complete_() { - local options_with_args=$1 - local boolean_options="$2 -h --help" - - case "$prev" in - $options_with_args) - return - ;; - esac - - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) - ;; - esac -} - -_podman_load() { - local options_with_args=" - --input -i - " - local boolean_options=" - --help -h - --quiet -q - " - _complete_ "$options_with_args" "$boolean_options" -} - -_podman_cp() { - local boolean_options=" - --extract - --help -h - --pause - " - _complete_ "$boolean_options" -} - -_podman_login() { - local options_with_args=" - --authfile - --get-login - --password -p - --username -u - " - local boolean_options=" - --help - -h - --password-stdin - " - _complete_ "$options_with_args" "$boolean_options" -} - -_podman_logout() { - local options_with_args=" - --authfile - " - local boolean_options=" - --all - -a - --help - -h - " - _complete_ "$options_with_args" "$boolean_options" -} - -_podman_healthcheck_run() { - local options_with_args="" - - local boolean_options=" - -h - --help - " - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - COMPREPLY=( $( compgen -W " - $(__podman_containers --all) - " -- "$cur" ) ) - __ltrim_colon_completions "$cur" - ;; - esac -} - -_podman_generate_kube() { - local options_with_args=" - --filename -f - " - - local boolean_options=" - -h - --help - -s - --service - " - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - COMPREPLY=( $( compgen -W " - $(__podman_containers --all) - $(__podman_pods) - " -- "$cur" ) ) - __ltrim_colon_completions "$cur" - ;; - esac -} - -_podman_generate_systemd() { - local options_with_args=" - --restart-policy - -t - --time - --container-prefix - --pod-prefix - --separator" - - local boolean_options=" - -h - --help - -n - --name - " - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - COMPREPLY=( $( compgen -W " - $(__podman_containers --all) - " -- "$cur" ) ) - __ltrim_colon_completions "$cur" - ;; - esac -} - -_podman_play_kube() { - local options_with_args=" - --authfile - --cert-dir - --creds - --network - " - - local boolean_options=" - --help -h - --quiet -q - --seccomp-profile-root - --tls-verify - " - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - _filedir - ;; - esac -} - -_podman_events() { - local options_with_args=" - --filter - --format - --help -h - --since - --until - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$options_with_args" -- "$cur")) - ;; - esac -} - -_podman_container_runlabel() { - local options_with_args=" - --authfile - --cert-dir - --creds - --name - " - - local boolean_options=" - --display - --help -h - --quiet -q - --replace - --tls-verify - " - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images --id - ;; - esac -} - -_podman_image_sign() { - local options_with_args=" - --cert-dir - --directory -d - --sign-by - " - local boolean_options=" - --help - -h - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images - ;; - esac -} - -_podman_image_trust_set() { - echo hello - local options_with_args=" - --pubkeysfile -f - --type -t - " - local boolean_options=" - --help - -h - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - COMPREPLY=($(compgen -W "default $( __podman_list_registries )" -- "$cur")) - ;; - esac -} - -_podman_image_trust_show() { - local options_with_args=" - " - local boolean_options=" - --help -h - --json -j - --raw - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images - ;; - esac -} - -_podman_image_trust() { - local boolean_options=" - --help - -h - " - subcommands=" - set - show - " - local aliases=" - list - " - command=image_trust - __podman_subcommands "$subcommands $aliases" && return - - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) - ;; - *) - COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) - ;; - esac -} - -_podman_images_prune() { - local options_with_args=" - " - - local boolean_options=" - --all -a - --help -h - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - esac -} - -_podman_container_prune() { - local options_with_args=" - --filter - " - - local boolean_options=" - --force -f - --help -h - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - esac -} - -_podman_container_exists() { - local options_with_args=" - " - - local boolean_options=" - --external - --help -h - " - - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_images - ;; - esac - -} - -_podman_pod_exists() { - local options_with_args=" - " - - local boolean_options=" - " -} - -_podman_image_exists() { - local options_with_args=" - " - - local boolean_options=" - " -} - -_podman_pod_create() { - local options_with_args=" - --add-host - --cgroup-parent - --dns - --dns-opt - --dns-search - --infra-command - --infra-conmon-pidfile - --infra-image - --ip - --label-file - --label - -l - --mac-address - --name - --network - --no-hosts - --podidfile - --publish - -p - --share - " - - local boolean_options=" - --help -h - --infra - --replace - " - _complete_ "$options_with_args" "$boolean_options" } -_podman_pod_kill() { - local options_with_args=" - " - - local boolean_options=" - --all -a - --help -h - --latest -l - --signal -s - " - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_pod_names - ;; - esac -} - -__podman_pod_ps() { - local options_with_args=" - --filter -f - --format - --sort - " - - local boolean_options=" - --cgroup - --ctr-ids - --ctr-names - --ctr-status - --help -h - --labels - --latest -l - --no-trunc - --quiet -q - " - _complete_ "$options_with_args" "$boolean_options" -} - -_podman_pod_ls() { - __podman_pod_ps -} - -_podman_pod_list() { - __podman_pod_ps -} - -_podman_pod_ps() { - __podman_pod_ps -} - -_podman_pod_prune() { - local options_with_args=" - " - - local boolean_options=" - -f - -h - --help - " - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - esac -} - -_podman_pod_restart() { - local options_with_args=" - " - - local boolean_options=" - --all -a - --help -h - --latest -l - " - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_pod_names - ;; - esac -} - -_podman_pod_rm() { - local options_with_args=" - --pod-id-file - " - - local boolean_options=" - --all -a - --force -f - --help -h - --ignore -i - --latest -l - " - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_pod_names - ;; - esac -} - -_podman_pod_start() { - local options_with_args=" - --pod-id-file - " - - local boolean_options=" - --all -a - --help -h - --latest -l - " - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_pod_names - ;; - esac -} - -_podman_pod_stop() { - local options_with_args=" - --pod-id-file - --time -t - " - - local boolean_options=" - --all -a - --cleanup - --help -h - --ignore -i - --latest -l - " - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_pod_names - ;; - esac -} - -_podman_pod_pause() { - local options_with_args=" - " - - local boolean_options=" - --all -a - --help -h - --latest -l - " - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_pod_names - ;; - esac -} - -_podman_pod_unpause() { - local options_with_args=" - " - - local boolean_options=" - --all -a - --help -h - --latest -l - " - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_pod_names - ;; - esac -} - -_podman_pod_inspect() { - local options_with_args=" - --format -f - --latest -l - " - - _complete_ "$options_with_args" -} - - -_podman_pod() { - local boolean_options=" - --help - -h - " - subcommands=" - create - inspect - kill - pause - ps - restart - rm - start - stats - stop - top - unpause - " - local aliases=" - list - ls - " - __podman_subcommands "$subcommands $aliases" && return - - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) - ;; - *) - COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) - ;; - esac -} - -_podman_volume_create() { - local options_with_args=" - --driver - --label -l - --opt -o - " - - local boolean_options=" - --help - -h - " - - _complete_ "$options_with_args" "$boolean_options" -} - -_podman_volume_ls() { - local options_with_args=" - --filter - --format -f - " - - local boolean_options=" - --help -h - --quiet -q - " - - _complete_ "$options_with_args" "$boolean_options" -} - -_podman_volume_inspect() { - local options_with_args=" - --format - -f - " - - local boolean_options=" - --all -a - --help -h - " +__podman_perform_completion() +{ + __podman_debug + __podman_debug "========= starting completion logic ==========" + __podman_debug "cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}, cword is $cword" + + # The user could have moved the cursor backwards on the command-line. + # We need to trigger completion from the $cword location, so we need + # to truncate the command-line ($words) up to the $cword location. + words=("${words[@]:0:$cword+1}") + __podman_debug "Truncated words[*]: ${words[*]}," + + local shellCompDirectiveError=1 + local shellCompDirectiveNoSpace=2 + local shellCompDirectiveNoFileComp=4 + local shellCompDirectiveFilterFileExt=8 + local shellCompDirectiveFilterDirs=16 + local shellCompDirectiveLegacyCustomComp=32 + local shellCompDirectiveLegacyCustomArgsComp=64 + + local out requestComp lastParam lastChar comp directive args flagPrefix + + # Prepare the command to request completions for the program. + # Calling ${words[0]} instead of directly podman allows to handle aliases + args=("${words[@]:1}") + requestComp="${words[0]} __completeNoDesc ${args[*]}" + + lastParam=${words[$((${#words[@]}-1))]} + lastChar=${lastParam:$((${#lastParam}-1)):1} + __podman_debug "lastParam ${lastParam}, lastChar ${lastChar}" + + if [ -z "${cur}" ] && [ "${lastChar}" != "=" ]; then + # If the last parameter is complete (there is a space following it) + # We add an extra empty parameter so we can indicate this to the go method. + __podman_debug "Adding extra empty parameter" + requestComp="${requestComp} \"\"" + fi - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_volume_names - ;; - esac -} + # When completing a flag with an = (e.g., podman -n=) + # bash focuses on the part after the =, so we need to remove + # the flag part from $cur + if [[ "${cur}" == -*=* ]]; then + flagPrefix="${cur%%=*}=" + cur="${cur#*=}" + fi -_podman_volume_rm() { - local options_with_args="" + __podman_debug "Calling ${requestComp}" + # Use eval to handle any environment variables and such + out=$(eval "${requestComp}" 2>/dev/null) + + # Extract the directive integer at the very end of the output following a colon (:) + directive=${out##*:} + # Remove the directive + out=${out%:*} + if [ "${directive}" = "${out}" ]; then + # There is not directive specified + directive=0 + fi + __podman_debug "The completion directive is: ${directive}" + __podman_debug "The completions are: ${out[*]}" + + if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then + # Error code. No completion. + __podman_debug "Received error from custom completion go code" + return + else + if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then + if [[ $(type -t compopt) = "builtin" ]]; then + __podman_debug "Activating no space" + compopt -o nospace + fi + fi + if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then + if [[ $(type -t compopt) = "builtin" ]]; then + __podman_debug "Activating no file completion" + compopt +o default + fi + fi + fi - local boolean_options=" - --all -a - --force -f - --help -h - " + if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then + # File extension filtering + local fullFilter filter filteringCmd + + # Do not use quotes around the $out variable or else newline + # characters will be kept. + for filter in ${out[*]}; do + fullFilter+="$filter|" + done + + filteringCmd="_filedir $fullFilter" + __podman_debug "File filtering command: $filteringCmd" + $filteringCmd + elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then + # File completion for directories only + + # Use printf to strip any trailing newline + local subdir + subdir=$(printf "%s" "${out[0]}") + if [ -n "$subdir" ]; then + __podman_debug "Listing directories in $subdir" + pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return + else + __podman_debug "Listing directories in ." + _filedir -d + fi + elif [ $((directive & shellCompDirectiveLegacyCustomComp)) -ne 0 ]; then + local cmd + __podman_debug "Legacy custom completion. Directive: $directive, cmds: ${out[*]}" + + # The following variables should get their value through the commands + # we have received as completions and are parsing below. + local last_command + local nouns + + # Execute every command received + while IFS='' read -r cmd; do + __podman_debug "About to execute: $cmd" + eval "$cmd" + done < <(printf "%s\n" "${out[@]}") + + __podman_debug "last_command: $last_command" + __podman_debug "nouns[0]: ${nouns[0]}, nouns[1]: ${nouns[1]}" + + if [ $((directive & shellCompDirectiveLegacyCustomArgsComp)) -ne 0 ]; then + # We should call the global legacy custom completion function, if it is defined + if declare -F __podman_custom_func >/dev/null; then + # Use command name qualified legacy custom func + __podman_debug "About to call: __podman_custom_func" + __podman_custom_func + elif declare -F __custom_func >/dev/null; then + # Otherwise fall back to unqualified legacy custom func for compatibility + __podman_debug "About to call: __custom_func" + __custom_func + fi + fi + else + local tab + tab=$(printf '\t') + local longest=0 + # Look for the longest completion so that we can format things nicely + while IFS='' read -r comp; do + comp=${comp%%$tab*} + if ((${#comp}>longest)); then + longest=${#comp} + fi + done < <(printf "%s\n" "${out[@]}") + + local completions=() + while IFS='' read -r comp; do + if [ -z "$comp" ]; then + continue + fi + + __podman_debug "Original comp: $comp" + comp="$(__podman_format_comp_descriptions "$comp" "$longest")" + __podman_debug "Final comp: $comp" + completions+=("$comp") + done < <(printf "%s\n" "${out[@]}") + + while IFS='' read -r comp; do + # Although this script should only be used for bash + # there may be programs that still convert the bash + # script into a zsh one. To continue supporting those + # programs, we do this single adaptation for zsh + if [ -n "${ZSH_VERSION}" ]; then + # zsh completion needs --flag= prefix + COMPREPLY+=("$flagPrefix$comp") + else + COMPREPLY+=("$comp") + fi + done < <(compgen -W "${completions[*]}" -- "$cur") + + # If there is a single completion left, remove the description text + if [ ${#COMPREPLY[*]} -eq 1 ]; then + __podman_debug "COMPREPLY[0]: ${COMPREPLY[0]}" + comp="${COMPREPLY[0]%% *}" + __podman_debug "Removed description from single completion, which is now: ${comp}" + COMPREPLY=() + COMPREPLY+=("$comp") + fi + fi - _complete_ "$options_with_args" "$boolean_options" - case "$cur" in - -*) - COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) - ;; - *) - __podman_complete_volume_names - ;; - esac + __podman_handle_special_char "$cur" : + __podman_handle_special_char "$cur" = } -_podman_volume_prune() { - local options_with_args="" - - local boolean_options=" - --force -f - --help -h - " - - _complete_ "$options_with_args" "$boolean_options" +__podman_handle_special_char() +{ + local comp="$1" + local char=$2 + if [[ "$comp" == *${char}* && "$COMP_WORDBREAKS" == *${char}* ]]; then + local word=${comp%"${comp##*${char}}"} + local idx=${#COMPREPLY[*]} + while [[ $((--idx)) -ge 0 ]]; do + COMPREPLY[$idx]=${COMPREPLY[$idx]#"$word"} + done + fi } -_podman_volume() { - local boolean_options=" - --help -h - " - subcommands=" - create - inspect - ls - prune - rm - " - local aliases=" - list - remove - " - __podman_subcommands "$subcommands $aliases" && return +__podman_format_comp_descriptions() +{ + local tab + tab=$(printf '\t') + local comp="$1" + local longest=$2 + + # Properly format the description string which follows a tab character if there is one + if [[ "$comp" == *$tab* ]]; then + desc=${comp#*$tab} + comp=${comp%%$tab*} + + # $COLUMNS stores the current shell width. + # Remove an extra 4 because we add 2 spaces and 2 parentheses. + maxdesclength=$(( COLUMNS - longest - 4 )) + + # Make sure we can fit a description of at least 8 characters + # if we are to align the descriptions. + if [[ $maxdesclength -gt 8 ]]; then + # Add the proper number of spaces to align the descriptions + for ((i = ${#comp} ; i < longest ; i++)); do + comp+=" " + done + else + # Don't pad the descriptions so we can fit more text after the completion + maxdesclength=$(( COLUMNS - ${#comp} - 4 )) + fi + + # If there is enough space for any description text, + # truncate the descriptions that are too long for the shell width + if [ $maxdesclength -gt 0 ]; then + if [ ${#desc} -gt $maxdesclength ]; then + desc=${desc:0:$(( maxdesclength - 1 ))} + desc+="…" + fi + comp+=" ($desc)" + fi + fi - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) - ;; - *) - COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) - ;; - esac + # Must use printf to escape all special characters + printf "%q" "${comp}" } -_podman_podman() { - local options_with_args=" - --cni-config-dir - --conmon - --connection -c - --events-backend - --hooks-dir - --identity - --log-level - --namespace - --network-cmd-path - --root - --runroot - --runtime - --storage-driver - --storage-opt - --tmpdir - --url - " - local boolean_options=" - --help -h - --remote -r - --syslog - --version -v - " - commands=" - attach - auto-update - build - commit - container - cp - create - diff - events - exec - export - generate - healthcheck - history - image - images - import - info - inspect - kill - load - login - logout - logs - manifest - mount - network - pause - play - pod - port - ps - pull - push - restart - rm - rmi - run - save - search - start - stats - stop - system - tag - top - umount - unmount - unpause - untag - varlink - version - volume - wait - " +__start_podman() +{ + local cur prev words cword - case "$prev" in - $main_options_with_args_glob ) - return - ;; - esac + COMPREPLY=() + _get_comp_words_by_ref -n "=:" cur prev words cword - case "$cur" in - -*) - COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) - ;; - *) - COMPREPLY=( $( compgen -W "${commands[*]} help" -- "$cur" ) ) - ;; - esac + __podman_perform_completion } -_cli_bash_autocomplete() { - local cur opts base - - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - COMPREPLY=() - local cur prev words cword +if [[ $(type -t compopt) = "builtin" ]]; then + complete -o default -F __start_podman podman +else + complete -o default -o nospace -F __start_podman podman +fi - _get_comp_words_by_ref -n : cur prev words cword - - local command=${PROG} cpos=0 - local counter=1 - counter=1 - while [ $counter -lt $cword ]; do - case "!${words[$counter]}" in - *) - command=$(echo "${words[$counter]}" | sed 's/-/_/g') - cpos=$counter - (( cpos++ )) - break - ;; - esac - (( counter++ )) - done - - local completions_func=_podman_${command} - declare -F $completions_func >/dev/null && $completions_func - - eval "$previous_extglob_setting" - return 0 -} +# ex: ts=4 sw=4 et filetype=sh -complete -F _cli_bash_autocomplete podman +# This file is generated with "podman completion"; see: podman-completion(1) diff --git a/completions/bash/podman-remote b/completions/bash/podman-remote new file mode 100644 index 000000000000..43a5ce959b8e --- /dev/null +++ b/completions/bash/podman-remote @@ -0,0 +1,271 @@ +# bash completion for podman-remote -*- shell-script -*- + +__podman-remote_debug() +{ + if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then + echo "$*" >> "${BASH_COMP_DEBUG_FILE}" + fi +} + +__podman-remote_perform_completion() +{ + __podman-remote_debug + __podman-remote_debug "========= starting completion logic ==========" + __podman-remote_debug "cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}, cword is $cword" + + # The user could have moved the cursor backwards on the command-line. + # We need to trigger completion from the $cword location, so we need + # to truncate the command-line ($words) up to the $cword location. + words=("${words[@]:0:$cword+1}") + __podman-remote_debug "Truncated words[*]: ${words[*]}," + + local shellCompDirectiveError=1 + local shellCompDirectiveNoSpace=2 + local shellCompDirectiveNoFileComp=4 + local shellCompDirectiveFilterFileExt=8 + local shellCompDirectiveFilterDirs=16 + local shellCompDirectiveLegacyCustomComp=32 + local shellCompDirectiveLegacyCustomArgsComp=64 + + local out requestComp lastParam lastChar comp directive args flagPrefix + + # Prepare the command to request completions for the program. + # Calling ${words[0]} instead of directly podman-remote allows to handle aliases + args=("${words[@]:1}") + requestComp="${words[0]} __completeNoDesc ${args[*]}" + + lastParam=${words[$((${#words[@]}-1))]} + lastChar=${lastParam:$((${#lastParam}-1)):1} + __podman-remote_debug "lastParam ${lastParam}, lastChar ${lastChar}" + + if [ -z "${cur}" ] && [ "${lastChar}" != "=" ]; then + # If the last parameter is complete (there is a space following it) + # We add an extra empty parameter so we can indicate this to the go method. + __podman-remote_debug "Adding extra empty parameter" + requestComp="${requestComp} \"\"" + fi + + # When completing a flag with an = (e.g., podman-remote -n=) + # bash focuses on the part after the =, so we need to remove + # the flag part from $cur + if [[ "${cur}" == -*=* ]]; then + flagPrefix="${cur%%=*}=" + cur="${cur#*=}" + fi + + __podman-remote_debug "Calling ${requestComp}" + # Use eval to handle any environment variables and such + out=$(eval "${requestComp}" 2>/dev/null) + + # Extract the directive integer at the very end of the output following a colon (:) + directive=${out##*:} + # Remove the directive + out=${out%:*} + if [ "${directive}" = "${out}" ]; then + # There is not directive specified + directive=0 + fi + __podman-remote_debug "The completion directive is: ${directive}" + __podman-remote_debug "The completions are: ${out[*]}" + + if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then + # Error code. No completion. + __podman-remote_debug "Received error from custom completion go code" + return + else + if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then + if [[ $(type -t compopt) = "builtin" ]]; then + __podman-remote_debug "Activating no space" + compopt -o nospace + fi + fi + if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then + if [[ $(type -t compopt) = "builtin" ]]; then + __podman-remote_debug "Activating no file completion" + compopt +o default + fi + fi + fi + + if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then + # File extension filtering + local fullFilter filter filteringCmd + + # Do not use quotes around the $out variable or else newline + # characters will be kept. + for filter in ${out[*]}; do + fullFilter+="$filter|" + done + + filteringCmd="_filedir $fullFilter" + __podman-remote_debug "File filtering command: $filteringCmd" + $filteringCmd + elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then + # File completion for directories only + + # Use printf to strip any trailing newline + local subdir + subdir=$(printf "%s" "${out[0]}") + if [ -n "$subdir" ]; then + __podman-remote_debug "Listing directories in $subdir" + pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return + else + __podman-remote_debug "Listing directories in ." + _filedir -d + fi + elif [ $((directive & shellCompDirectiveLegacyCustomComp)) -ne 0 ]; then + local cmd + __podman-remote_debug "Legacy custom completion. Directive: $directive, cmds: ${out[*]}" + + # The following variables should get their value through the commands + # we have received as completions and are parsing below. + local last_command + local nouns + + # Execute every command received + while IFS='' read -r cmd; do + __podman-remote_debug "About to execute: $cmd" + eval "$cmd" + done < <(printf "%s\n" "${out[@]}") + + __podman-remote_debug "last_command: $last_command" + __podman-remote_debug "nouns[0]: ${nouns[0]}, nouns[1]: ${nouns[1]}" + + if [ $((directive & shellCompDirectiveLegacyCustomArgsComp)) -ne 0 ]; then + # We should call the global legacy custom completion function, if it is defined + if declare -F __podman-remote_custom_func >/dev/null; then + # Use command name qualified legacy custom func + __podman-remote_debug "About to call: __podman-remote_custom_func" + __podman-remote_custom_func + elif declare -F __custom_func >/dev/null; then + # Otherwise fall back to unqualified legacy custom func for compatibility + __podman-remote_debug "About to call: __custom_func" + __custom_func + fi + fi + else + local tab + tab=$(printf '\t') + local longest=0 + # Look for the longest completion so that we can format things nicely + while IFS='' read -r comp; do + comp=${comp%%$tab*} + if ((${#comp}>longest)); then + longest=${#comp} + fi + done < <(printf "%s\n" "${out[@]}") + + local completions=() + while IFS='' read -r comp; do + if [ -z "$comp" ]; then + continue + fi + + __podman-remote_debug "Original comp: $comp" + comp="$(__podman-remote_format_comp_descriptions "$comp" "$longest")" + __podman-remote_debug "Final comp: $comp" + completions+=("$comp") + done < <(printf "%s\n" "${out[@]}") + + while IFS='' read -r comp; do + # Although this script should only be used for bash + # there may be programs that still convert the bash + # script into a zsh one. To continue supporting those + # programs, we do this single adaptation for zsh + if [ -n "${ZSH_VERSION}" ]; then + # zsh completion needs --flag= prefix + COMPREPLY+=("$flagPrefix$comp") + else + COMPREPLY+=("$comp") + fi + done < <(compgen -W "${completions[*]}" -- "$cur") + + # If there is a single completion left, remove the description text + if [ ${#COMPREPLY[*]} -eq 1 ]; then + __podman-remote_debug "COMPREPLY[0]: ${COMPREPLY[0]}" + comp="${COMPREPLY[0]%% *}" + __podman-remote_debug "Removed description from single completion, which is now: ${comp}" + COMPREPLY=() + COMPREPLY+=("$comp") + fi + fi + + __podman-remote_handle_special_char "$cur" : + __podman-remote_handle_special_char "$cur" = +} + +__podman-remote_handle_special_char() +{ + local comp="$1" + local char=$2 + if [[ "$comp" == *${char}* && "$COMP_WORDBREAKS" == *${char}* ]]; then + local word=${comp%"${comp##*${char}}"} + local idx=${#COMPREPLY[*]} + while [[ $((--idx)) -ge 0 ]]; do + COMPREPLY[$idx]=${COMPREPLY[$idx]#"$word"} + done + fi +} + +__podman-remote_format_comp_descriptions() +{ + local tab + tab=$(printf '\t') + local comp="$1" + local longest=$2 + + # Properly format the description string which follows a tab character if there is one + if [[ "$comp" == *$tab* ]]; then + desc=${comp#*$tab} + comp=${comp%%$tab*} + + # $COLUMNS stores the current shell width. + # Remove an extra 4 because we add 2 spaces and 2 parentheses. + maxdesclength=$(( COLUMNS - longest - 4 )) + + # Make sure we can fit a description of at least 8 characters + # if we are to align the descriptions. + if [[ $maxdesclength -gt 8 ]]; then + # Add the proper number of spaces to align the descriptions + for ((i = ${#comp} ; i < longest ; i++)); do + comp+=" " + done + else + # Don't pad the descriptions so we can fit more text after the completion + maxdesclength=$(( COLUMNS - ${#comp} - 4 )) + fi + + # If there is enough space for any description text, + # truncate the descriptions that are too long for the shell width + if [ $maxdesclength -gt 0 ]; then + if [ ${#desc} -gt $maxdesclength ]; then + desc=${desc:0:$(( maxdesclength - 1 ))} + desc+="…" + fi + comp+=" ($desc)" + fi + fi + + # Must use printf to escape all special characters + printf "%q" "${comp}" +} + +__start_podman-remote() +{ + local cur prev words cword + + COMPREPLY=() + _get_comp_words_by_ref -n "=:" cur prev words cword + + __podman-remote_perform_completion +} + +if [[ $(type -t compopt) = "builtin" ]]; then + complete -o default -F __start_podman-remote podman-remote +else + complete -o default -o nospace -F __start_podman-remote podman-remote +fi + +# ex: ts=4 sw=4 et filetype=sh + +# This file is generated with "podman-remote completion"; see: podman-completion(1) diff --git a/completions/fish/podman-remote.fish b/completions/fish/podman-remote.fish new file mode 100644 index 000000000000..e0216844d0af --- /dev/null +++ b/completions/fish/podman-remote.fish @@ -0,0 +1,182 @@ +# fish completion for podman-remote -*- shell-script -*- + +function __podman_remote_debug + set file "$BASH_COMP_DEBUG_FILE" + if test -n "$file" + echo "$argv" >> $file + end +end + +function __podman_remote_perform_completion + __podman_remote_debug "Starting __podman_remote_perform_completion" + + set args (string split -- " " (commandline -c)) + set lastArg "$args[-1]" + + __podman_remote_debug "args: $args" + __podman_remote_debug "last arg: $lastArg" + + set emptyArg "" + if test -z "$lastArg" + __podman_remote_debug "Setting emptyArg" + set emptyArg \"\" + end + __podman_remote_debug "emptyArg: $emptyArg" + + if not type -q "$args[1]" + # This can happen when "complete --do-complete podman-remote" is called when running this script. + __podman_remote_debug "Cannot find $args[1]. No completions." + return + end + + set requestComp "$args[1] __complete $args[2..-1] $emptyArg" + __podman_remote_debug "Calling $requestComp" + + set results (eval $requestComp 2> /dev/null) + set comps $results[1..-2] + set directiveLine $results[-1] + + # For Fish, when completing a flag with an = (e.g., -n=) + # completions must be prefixed with the flag + set flagPrefix (string match -r -- '-.*=' "$lastArg") + + __podman_remote_debug "Comps: $comps" + __podman_remote_debug "DirectiveLine: $directiveLine" + __podman_remote_debug "flagPrefix: $flagPrefix" + + for comp in $comps + printf "%s%s\n" "$flagPrefix" "$comp" + end + + printf "%s\n" "$directiveLine" +end + +# This function does two things: +# - Obtain the completions and store them in the global __podman_remote_comp_results +# - Return false if file completion should be performed +function __podman_remote_prepare_completions + __podman_remote_debug "" + __podman_remote_debug "========= starting completion logic ==========" + + # Start fresh + set --erase __podman_remote_comp_results + + set results (__podman_remote_perform_completion) + __podman_remote_debug "Completion results: $results" + + if test -z "$results" + __podman_remote_debug "No completion, probably due to a failure" + # Might as well do file completion, in case it helps + return 1 + end + + set directive (string sub --start 2 $results[-1]) + set --global __podman_remote_comp_results $results[1..-2] + + __podman_remote_debug "Completions are: $__podman_remote_comp_results" + __podman_remote_debug "Directive is: $directive" + + set shellCompDirectiveError 1 + set shellCompDirectiveNoSpace 2 + set shellCompDirectiveNoFileComp 4 + set shellCompDirectiveFilterFileExt 8 + set shellCompDirectiveFilterDirs 16 + set shellCompDirectiveLegacyCustomComp 32 + set shellCompDirectiveLegacyCustomArgsComp 64 + + if test -z "$directive" + set directive 0 + end + + set compErr (math (math --scale 0 $directive / $shellCompDirectiveError) % 2) + if test $compErr -eq 1 + __podman_remote_debug "Received error directive: aborting." + # Might as well do file completion, in case it helps + return 1 + end + + set legacyCustom (math (math --scale 0 $directive / $shellCompDirectiveLegacyCustomComp) % 2) + set legacyCustomArgs (math (math --scale 0 $directive / $shellCompDirectiveLegacyCustomArgsComp) % 2) + if test $legacyCustom -eq 1; or test $legacyCustomArgs -eq 1 + __podman_remote_debug "Legacy bash custom completion not applicable to fish" + # Do full file completion instead + set --global __podman_remote_comp_do_file_comp 1 + return 1 + end + + set filefilter (math (math --scale 0 $directive / $shellCompDirectiveFilterFileExt) % 2) + set dirfilter (math (math --scale 0 $directive / $shellCompDirectiveFilterDirs) % 2) + if test $filefilter -eq 1; or test $dirfilter -eq 1 + __podman_remote_debug "File extension filtering or directory filtering not supported" + # Do full file completion instead + return 1 + end + + set nospace (math (math --scale 0 $directive / $shellCompDirectiveNoSpace) % 2) + set nofiles (math (math --scale 0 $directive / $shellCompDirectiveNoFileComp) % 2) + + __podman_remote_debug "nospace: $nospace, nofiles: $nofiles" + + # If we want to prevent a space, or if file completion is NOT disabled, + # we need to count the number of valid completions. + # To do so, we will filter on prefix as the completions we have received + # may not already be filtered so as to allow fish to match on different + # criteria than prefix. + if test $nospace -ne 0; or test $nofiles -eq 0 + set prefix (commandline -t) + __podman_remote_debug "prefix: $prefix" + + set completions + for comp in $__podman_remote_comp_results + if test (string match -e -r "^$prefix" "$comp") + set -a completions $comp + end + end + set --global __podman_remote_comp_results $completions + __podman_remote_debug "Filtered completions are: $__podman_remote_comp_results" + + # Important not to quote the variable for count to work + set numComps (count $__podman_remote_comp_results) + __podman_remote_debug "numComps: $numComps" + + if test $numComps -eq 1; and test $nospace -ne 0 + # To support the "nospace" directive we trick the shell + # by outputting an extra, longer completion. + # We must first split on \t to get rid of the descriptions because + # the extra character we add to the fake second completion must be + # before the description. We don't need descriptions anyway since + # there is only a single real completion which the shell will expand + # immediately. + __podman_remote_debug "Adding second completion to perform nospace directive" + set split (string split --max 1 \t $__podman_remote_comp_results[1]) + set --global __podman_remote_comp_results $split[1] $split[1]. + __podman_remote_debug "Completions are now: $__podman_remote_comp_results" + end + + if test $numComps -eq 0; and test $nofiles -eq 0 + # To be consistent with bash and zsh, we only trigger file + # completion when there are no other completions + __podman_remote_debug "Requesting file completion" + return 1 + end + end + + return 0 +end + +# Since Fish completions are only loaded once the user triggers them, we trigger them ourselves +# so we can properly delete any completions provided by another script. +# The space after the the program name is essential to trigger completion for the program +# and not completion of the program name itself. +complete --do-complete "podman-remote " > /dev/null 2>&1 +# Using '> /dev/null 2>&1' since '&>' is not supported in older versions of fish. + +# Remove any pre-existing completions for the program since we will be handling all of them. +complete -c podman-remote -e + +# The call to __podman_remote_prepare_completions will setup __podman_remote_comp_results +# which provides the program's completion choices. +complete -c podman-remote -n '__podman_remote_prepare_completions' -f -a '$__podman_remote_comp_results' + + +# This file is generated with "podman-remote completion"; see: podman-completion(1) diff --git a/completions/fish/podman.fish b/completions/fish/podman.fish new file mode 100644 index 000000000000..2a89e7118cee --- /dev/null +++ b/completions/fish/podman.fish @@ -0,0 +1,182 @@ +# fish completion for podman -*- shell-script -*- + +function __podman_debug + set file "$BASH_COMP_DEBUG_FILE" + if test -n "$file" + echo "$argv" >> $file + end +end + +function __podman_perform_completion + __podman_debug "Starting __podman_perform_completion" + + set args (string split -- " " (commandline -c)) + set lastArg "$args[-1]" + + __podman_debug "args: $args" + __podman_debug "last arg: $lastArg" + + set emptyArg "" + if test -z "$lastArg" + __podman_debug "Setting emptyArg" + set emptyArg \"\" + end + __podman_debug "emptyArg: $emptyArg" + + if not type -q "$args[1]" + # This can happen when "complete --do-complete podman" is called when running this script. + __podman_debug "Cannot find $args[1]. No completions." + return + end + + set requestComp "$args[1] __complete $args[2..-1] $emptyArg" + __podman_debug "Calling $requestComp" + + set results (eval $requestComp 2> /dev/null) + set comps $results[1..-2] + set directiveLine $results[-1] + + # For Fish, when completing a flag with an = (e.g., -n=) + # completions must be prefixed with the flag + set flagPrefix (string match -r -- '-.*=' "$lastArg") + + __podman_debug "Comps: $comps" + __podman_debug "DirectiveLine: $directiveLine" + __podman_debug "flagPrefix: $flagPrefix" + + for comp in $comps + printf "%s%s\n" "$flagPrefix" "$comp" + end + + printf "%s\n" "$directiveLine" +end + +# This function does two things: +# - Obtain the completions and store them in the global __podman_comp_results +# - Return false if file completion should be performed +function __podman_prepare_completions + __podman_debug "" + __podman_debug "========= starting completion logic ==========" + + # Start fresh + set --erase __podman_comp_results + + set results (__podman_perform_completion) + __podman_debug "Completion results: $results" + + if test -z "$results" + __podman_debug "No completion, probably due to a failure" + # Might as well do file completion, in case it helps + return 1 + end + + set directive (string sub --start 2 $results[-1]) + set --global __podman_comp_results $results[1..-2] + + __podman_debug "Completions are: $__podman_comp_results" + __podman_debug "Directive is: $directive" + + set shellCompDirectiveError 1 + set shellCompDirectiveNoSpace 2 + set shellCompDirectiveNoFileComp 4 + set shellCompDirectiveFilterFileExt 8 + set shellCompDirectiveFilterDirs 16 + set shellCompDirectiveLegacyCustomComp 32 + set shellCompDirectiveLegacyCustomArgsComp 64 + + if test -z "$directive" + set directive 0 + end + + set compErr (math (math --scale 0 $directive / $shellCompDirectiveError) % 2) + if test $compErr -eq 1 + __podman_debug "Received error directive: aborting." + # Might as well do file completion, in case it helps + return 1 + end + + set legacyCustom (math (math --scale 0 $directive / $shellCompDirectiveLegacyCustomComp) % 2) + set legacyCustomArgs (math (math --scale 0 $directive / $shellCompDirectiveLegacyCustomArgsComp) % 2) + if test $legacyCustom -eq 1; or test $legacyCustomArgs -eq 1 + __podman_debug "Legacy bash custom completion not applicable to fish" + # Do full file completion instead + set --global __podman_comp_do_file_comp 1 + return 1 + end + + set filefilter (math (math --scale 0 $directive / $shellCompDirectiveFilterFileExt) % 2) + set dirfilter (math (math --scale 0 $directive / $shellCompDirectiveFilterDirs) % 2) + if test $filefilter -eq 1; or test $dirfilter -eq 1 + __podman_debug "File extension filtering or directory filtering not supported" + # Do full file completion instead + return 1 + end + + set nospace (math (math --scale 0 $directive / $shellCompDirectiveNoSpace) % 2) + set nofiles (math (math --scale 0 $directive / $shellCompDirectiveNoFileComp) % 2) + + __podman_debug "nospace: $nospace, nofiles: $nofiles" + + # If we want to prevent a space, or if file completion is NOT disabled, + # we need to count the number of valid completions. + # To do so, we will filter on prefix as the completions we have received + # may not already be filtered so as to allow fish to match on different + # criteria than prefix. + if test $nospace -ne 0; or test $nofiles -eq 0 + set prefix (commandline -t) + __podman_debug "prefix: $prefix" + + set completions + for comp in $__podman_comp_results + if test (string match -e -r "^$prefix" "$comp") + set -a completions $comp + end + end + set --global __podman_comp_results $completions + __podman_debug "Filtered completions are: $__podman_comp_results" + + # Important not to quote the variable for count to work + set numComps (count $__podman_comp_results) + __podman_debug "numComps: $numComps" + + if test $numComps -eq 1; and test $nospace -ne 0 + # To support the "nospace" directive we trick the shell + # by outputting an extra, longer completion. + # We must first split on \t to get rid of the descriptions because + # the extra character we add to the fake second completion must be + # before the description. We don't need descriptions anyway since + # there is only a single real completion which the shell will expand + # immediately. + __podman_debug "Adding second completion to perform nospace directive" + set split (string split --max 1 \t $__podman_comp_results[1]) + set --global __podman_comp_results $split[1] $split[1]. + __podman_debug "Completions are now: $__podman_comp_results" + end + + if test $numComps -eq 0; and test $nofiles -eq 0 + # To be consistent with bash and zsh, we only trigger file + # completion when there are no other completions + __podman_debug "Requesting file completion" + return 1 + end + end + + return 0 +end + +# Since Fish completions are only loaded once the user triggers them, we trigger them ourselves +# so we can properly delete any completions provided by another script. +# The space after the the program name is essential to trigger completion for the program +# and not completion of the program name itself. +complete --do-complete "podman " > /dev/null 2>&1 +# Using '> /dev/null 2>&1' since '&>' is not supported in older versions of fish. + +# Remove any pre-existing completions for the program since we will be handling all of them. +complete -c podman -e + +# The call to __podman_prepare_completions will setup __podman_comp_results +# which provides the program's completion choices. +complete -c podman -n '__podman_prepare_completions' -f -a '$__podman_comp_results' + + +# This file is generated with "podman completion"; see: podman-completion(1) diff --git a/completions/zsh/_podman b/completions/zsh/_podman index b65c3dbb848d..b25e9cb08eca 100644 --- a/completions/zsh/_podman +++ b/completions/zsh/_podman @@ -1,379 +1,181 @@ -#compdef podman +#compdef _podman podman -# To get zsh to reread this file: unset -f _podman;rm -f ~/.zcompdump;compinit +# zsh completion for podman -*- shell-script -*- -# On rereads, reset cache. (Not that the caching works, but some day it might) -unset -m '_podman_*' - -############################################################################### -# BEGIN 'podman help' parsers -- for options, subcommands, and usage - -# Run 'podman XX --help', set _podman_commands to a formatted list of cmds -_read_podman_commands() { - local line - - # Cache: the intention here is to run each 'podman help' only once. - # Unfortunately it doesn't seem to actually be working: even though - # I can see the var_ref in my shell, it's not visible here. - local _var_ref=_podman_commands_"${*// /_}" - typeset -ga _podman_commands - _podman_commands=(${(P)_var_ref}) - (( $#_podman_commands )) && return - - _call_program podman podman "$@" --help |\ - sed -n -e '0,/^Available Commands/d' -e '/^[A-Z]/q;p' |\ - sed -e 's/^ \+\([^ ]\+\) \+/\1:/' |\ - egrep . | while read line; do - _podman_commands+=($line) - done - - eval "typeset -ga $_var_ref" - eval "$_var_ref=(\$_podman_commands)" -} - -# Run 'podman XX --help', set _podman_option_list to a formatted list -# of option options for XX -_read_podman_options() { - local line - - local _var_ref=_podman_options_"${*// /_}" - eval "typeset -ga ${_var_ref}" - typeset -ga _podman_option_list - _podman_option_list=(${(P)_var_ref}) - (( $#_podman_option_list )) && return - - # Extract the Options; strip leading whitespace; pack '-f, --foo' - # as '-f,--foo' (no space); then add '=' to '--foo string'. - # The result will be, e.g. '-f,--foo=string Description of Option' - _call_program podman podman "$@" --help |\ - sed -n -e '0,/^Options:/d' -e '/^$/q;p' |\ - grep '^ \+-' |\ - sed -e 's/^ *//' -e 's/^\(-.,\) --/\1--/' |\ - sed -e 's/^\(-[^ ]\+\) \([^ ]\+\) /\1=\2 /' |\ - while read options desc;do - # options like --foo=string: split into --foo & string - local -a tmpa - local optval= - tmpa=(${(s.=.)options}) - if [ -n "$tmpa[2]" ]; then - options=$tmpa[1] - optval=$tmpa[2] - fi - - # 'podman attach --detach-keys' includes ']' in help msg - desc=${desc//\]/\\]} - - for option in ${(s:,:)options}; do - if [ -n "$optval" ]; then - _podman_option_list+=("${option}[$desc]:$(_podman_find_helper ${options} ${optval} ${desc})") - else - _podman_option_list+=("${option}[$desc]") - fi - done - done - - eval "typeset -ga $_var_ref=(\$_podman_option_list)" -} - -# Run 'podman XXX --help', set _podman_usage to the line after "Usage:" -_read_podman_usage() { - local _var_ref=_podman_usage_"${*// /_}" - typeset -ga _podman_usage - _podman_usage=${(P)_var_ref} - (( $#_podman_usage )) && return - - _podman_usage=$(_call_program podman podman "$@" --help |\ - grep -A1 'Usage:'|\ - tail -1 |\ - sed -e 's/^ *//') - - eval "typeset -ga $_var_ref" - eval "$_var_ref=\$_podman_usage" -} - -# END 'podman help' parsers -############################################################################### -# BEGIN custom helpers for individual option arguments - -# Find a zsh helper for a given option or command-line option -_podman_find_helper() { - local options=$1 - local optval=$2 - local desc=$3 - local helper= - - # Yes, this is a lot of hardcoding. IMHO it's still better than - # hardcoding every possible podman option. - # FIXME: there are many more options that could use helpers. - if expr "$desc" : ".*[Dd]irectory" >/dev/null; then - optval="directory" - helper="_files -/" - elif expr "$desc" : ".*[Pp]ath" >/dev/null; then - optval="path" - helper=_files - # For messages like 'restart policy ("always"|"no"|"on-failure") - elif optlist=$(expr "$desc" : '.*(\(\"[^\\)]\+|[^\\)]\+\"\))' 2>/dev/null); then - optval=${${options##--}//-/ } # "--log-level" => "log level" - optlist=${optlist//\"/} # "a"|"b"|"c" => a|b|c - optlist=${optlist//\|/ } # a|b|c => a b c - # FIXME: how to present values _in order_, not sorted alphabetically? - helper="($optlist)" +__podman_debug() +{ + local file="$BASH_COMP_DEBUG_FILE" + if [[ -n ${file} ]]; then + echo "$*" >> "${file}" fi - echo "$optval:$helper" -} - -# END custom helpers for individual option arguments -############################################################################### -# BEGIN helpers for command-line args (containers, images) - -__podman_helper_generic() { - local expl line - local -a results - - local foo1=$1; shift - local name=$2; shift - - _call_program $foo1 podman "$@" |\ - while read line; do - results+=(${=line}) - done - - _wanted $foo1 expl $name compadd ${(u)results} -} - -_podman_helper_image() { - __podman_helper_generic podman-images 'images' \ - images --format '{{.ID}}\ {{.Repository}}:{{.Tag}}' -} - -# FIXME: at some point, distinguish between running & stopped containers -_podman_helper_container() { - __podman_helper_generic podman-containers 'containers' \ - ps -a --format '{{.Names}}\ {{.ID}}' -} - -_podman_helper_pod() { - __podman_helper_generic podman-pods 'pods' pod list --format '{{.Name}}' } -_podman_helper_volume() { - __podman_helper_generic podman-volumes 'volumes' volume ls --format '{{.Name}}' -} - -# Combinations. This one seen in diff & inspect -_podman_helper_container-or-image() { - _podman_helper_image - _podman_helper_container -} - -# Seen in generate-kube -_podman_helper_container-or-pod() { - _podman_helper_container - _podman_helper_pod -} - -# For top and pod-top -_podman_helper_format-descriptors() { - __podman_helper_generic top-format-descriptors 'format descriptors' \ - top --list-descriptors -} - -# for push, login/logout, and trust -# FIXME: some day, use this to define a helper for IMAGE-PATH (in 'pull') -_podman_helper_registry() { - local expl - local -a registries +_podman() +{ + local shellCompDirectiveError=1 + local shellCompDirectiveNoSpace=2 + local shellCompDirectiveNoFileComp=4 + local shellCompDirectiveFilterFileExt=8 + local shellCompDirectiveFilterDirs=16 + local shellCompDirectiveLegacyCustomComp=32 + local shellCompDirectiveLegacyCustomArgsComp=64 + + local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace + local -a completions + + __podman_debug "\n========= starting completion logic ==========" + __podman_debug "CURRENT: ${CURRENT}, words[*]: ${words[*]}" + + # The user could have moved the cursor backwards on the command-line. + # We need to trigger completion from the $CURRENT location, so we need + # to truncate the command-line ($words) up to the $CURRENT location. + # (We cannot use $CURSOR as its value does not work when a command is an alias.) + words=("${=words[1,CURRENT]}") + __podman_debug "Truncated words[*]: ${words[*]}," + + lastParam=${words[-1]} + lastChar=${lastParam[-1]} + __podman_debug "lastParam: ${lastParam}, lastChar: ${lastChar}" + + # For zsh, when completing a flag with an = (e.g., podman -n=) + # completions must be prefixed with the flag + setopt local_options BASH_REMATCH + if [[ "${lastParam}" =~ '-.*=' ]]; then + # We are dealing with a flag with an = + flagPrefix="-P ${BASH_REMATCH}" + fi - # Suggestions for improvement more than welcome. - python3 -c 'from configparser import ConfigParser;cp=ConfigParser();cp.read("/etc/containers/registries.conf");registries=eval(cp.get("registries.search","registries"));[print(r) for r in registries]' 2>/dev/null | while read line; do - registries+=($line) - done + # Prepare the command to obtain completions + requestComp="${words[1]} __complete ${words[2,-1]}" + if [ "${lastChar}" = "" ]; then + # If the last parameter is complete (there is a space following it) + # We add an extra empty parameter so we can indicate this to the go completion code. + __podman_debug "Adding extra empty parameter" + requestComp="${requestComp} \"\"" + fi - if (( $#registries )); then - _wanted podman-registry expl "registry" compadd ${(u)registries} + __podman_debug "About to call: eval ${requestComp}" + + # Use eval to handle any environment variables and such + out=$(eval ${requestComp} 2>/dev/null) + __podman_debug "completion output: ${out}" + + # Extract the directive integer following a : from the last line + local lastLine + while IFS='\n' read -r line; do + lastLine=${line} + done < <(printf "%s\n" "${out[@]}") + __podman_debug "last line: ${lastLine}" + + if [ "${lastLine[1]}" = : ]; then + directive=${lastLine[2,-1]} + # Remove the directive including the : and the newline + local suffix + (( suffix=${#lastLine}+2)) + out=${out[1,-$suffix]} else - _hosts + # There is no directive specified. Leave $out as is. + __podman_debug "No directive found. Setting do default" + directive=0 fi -} - -# END helpers for command-line args -############################################################################### -# BEGIN figure out completion helpers for a given (sub)command -# Read Usage string for this subcommand, set up helpers for its subargs -_set_up_podman_args() { - _read_podman_usage "$@" + __podman_debug "directive: ${directive}" + __podman_debug "completions: ${out}" + __podman_debug "flagPrefix: ${flagPrefix}" - typeset -ga _podman_args=() - # E.g. 'podman exec [options] CONTAINER [...' -> 'CONTAINER [....' - local usage_rhs=$(expr "$_podman_usage" : ".*\[options\] \+\(.*\)") - - # e.g. podman pod ps which takes no further args - if [ -z "$usage_rhs" ]; then + if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then + __podman_debug "Completion received error. Ignoring completions." return fi - # podman diff & inspect accept 'CONTAINER | IMAGE'; make into one keyword. - usage_rhs=${usage_rhs// | /-OR-} + while IFS='\n' read -r comp; do + if [ -n "$comp" ]; then + # If requested, completions are returned with a description. + # The description is preceded by a TAB character. + # For zsh's _describe, we need to use a : instead of a TAB. + # We first need to escape any : as part of the completion itself. + comp=${comp//:/\\:} - # Arg parsing. There are three possibilities in Usage messages: - # - # [IMAGE] - optional image arg (zero or one) - # IMAGE - exactly one image arg - # IMAGE [IMAGE...] - one or more image args - # and, theoretically: - # [IMAGE...] - zero or more? Haven't seen it in practice. Defer. - # - # For completion purposes, we only need to provide two options: - # one, or more than one? That is: continue offering completion - # suggestions after the first one? For that, we make two passes; - # in the first, mark an option as either '' (only one) or + local tab=$(printf '\t') + comp=${comp//$tab/:} - # Parse each command-line arg seen in usage message - local word - local -A _seen=() - for word in ${=usage_rhs}; do - local unbracketed=$(expr "$word" : "\[\(.*\)\]") + __podman_debug "Adding completion: ${comp}" + completions+=${comp} + lastComp=$comp + fi + done < <(printf "%s\n" "${out[@]}") - if [ -n "$unbracketed" ]; then - # Remove all dots; assume(!?) that they'll all be at the end - unbracketed=${unbracketed//./} + if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then + __podman_debug "Activating nospace." + noSpace="-S ''" + fi - if (( $_seen[$unbracketed] )); then - # Is this the same word as the previous arg? - if expr "$_podman_args[-1]" : ":$unbracketed:" >/dev/null; then - # Yes. Make it '*:...' instead of ':...', indicating >1 - _podman_args[-1]="*$_podman_args[-1]" - fi - continue + if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then + # File extension filtering + local filteringCmd + filteringCmd='_files' + for filter in ${completions[@]}; do + if [ ${filter[1]} != '*' ]; then + # zsh requires a glob pattern to do file filtering + filter="\*.$filter" fi - - word=$unbracketed + filteringCmd+=" -g $filter" + done + filteringCmd+=" ${flagPrefix}" + + __podman_debug "File filtering command: $filteringCmd" + _arguments '*:filename:'"$filteringCmd" + elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then + # File completion for directories only + local subDir + subdir="${completions[1]}" + if [ -n "$subdir" ]; then + __podman_debug "Listing directories in $subdir" + pushd "${subdir}" >/dev/null 2>&1 + else + __podman_debug "Listing directories in ." fi - # As of 2019-03 all such instances are '[COMMAND [ARG...]]' and are, - # of course, at the end of the line. We can't offer completion for - # these, because the container will have different commands than - # the host system... but try anyway. - if [ "$word" = '[COMMAND' ]; then - # e.g. podman create, exec, run - _podman_args+=( - ":command: _command_names -e" - "*::arguments: _normal" - ) - return + local result + _arguments '*:dirname:_files -/'" ${flagPrefix}" + result=$? + if [ -n "$subdir" ]; then + popd >/dev/null 2>&1 fi + return $result + else + __podman_debug "Calling _describe" + if eval _describe "completions" completions $flagPrefix $noSpace; then + __podman_debug "_describe found some completions" - # Look for an existing helper, e.g. IMAGE -> _podman_helper_image - local helper="_podman_helper_${(L)word}" - if (( $+functions[$helper] )); then - : + # Return the success of having called _describe + return 0 else - # No defined helper. Reset, but check for known expressions. - helper= - case "$word" in - KUBEFILE) helper='_files -g "*.y(|a)ml(-.)"' ;; - PATH) helper='_files' ;; - esac - fi - - # Another special case: 'top' actually takes multiple options - local multi= - if [ "$word" = "FORMAT-DESCRIPTORS" ]; then - multi='*' + __podman_debug "_describe did not find completions." + __podman_debug "Checking if we should do file completion." + if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then + __podman_debug "deactivating file completion" + + # We must return an error code here to let zsh know that there were no + # completions found by _describe; this is what will trigger other + # matching algorithms to attempt to find completions. + # For example zsh can match letters in the middle of words. + return 1 + else + # Perform file completion + __podman_debug "Activating file completion" + + # We must return the result of this command, so it must be the + # last command, or else we must store its result to return it. + _arguments '*:filename:_files'" ${flagPrefix}" + fi fi - _podman_args+=("$multi:${(L)word}:$helper") - _seen[$word]=1 - done -} - -# For an endpoint command, i.e. not a subcommand. -_podman_terminus() { - typeset -A opt_args - typeset -ga _podman_option_list - typeset -ga _podman_args - integer ret=1 - - # Find out what args it takes (e.g. image(s), container(s)) and see - # if we have helpers for them. - _set_up_podman_args "$@" - _arguments -C $_podman_option_list $_podman_args && ret=0 - - return ret -} - -# END figure out completion helpers for a given (sub)command -################################################################################ -# BEGIN actual entry point - -# This is the main entry point; it's also where we (recursively) come in -# to handle nested subcommands such as 'podman container' or even 3-level -# ones like 'podman generate kube'. Nesting is complicated, so here's -# my best understanding as of 2019-03-12: -# -# Easy first: when you do "podman " zsh calls us, we run 'podman --help', -# figure out the global options and subcommands, and run the magic _arguments -# command. That will offer those options/subcommands, and complete, etc. -# -# Where it gets harder is when you do "podman container mount ". -# zsh first calls us with words=(podman container mount) but we don't -# want all that full context yet! We want to go a piece at a time, -# handling 'container' first, then 'mount'; ending up with our -# final 'podman container mount --help' giving us suitable options -# and no subcommands; from which we determine that it's a terminus -# and jump to a function that handles non-subcommand arguments. -# -# This is the closest I've yet come to understanding zsh completion; -# it is still incomplete and may in fact be incorrect. But it works -# better than anything I've played with so far. -_podman_subcommand() { - local curcontext="$curcontext" state line - typeset -A opt_args - integer ret=1 - - # Run 'podman --help' / 'podman system --help' for our context (initially - # empty, then possibly under subcommands); from those, get a list of - # options appropriate for this context and, if applicable, subcommands. - _read_podman_options "$@" - _read_podman_commands "$@" - - # Now, is this a sub-subcommand, or does it have args? - if (( $#_podman_commands )); then - # Subcommands required (podman, podman system, etc) - local cmd=${words// /_} - _arguments -C $_podman_option_list \ - "(-): :->command" \ - "(-)*:: :->option-or-argument" \ - && ret=0 - - case $state in - (command) - _describe -t command "podman $* command" _podman_commands && ret=0 - ;; - (option-or-argument) - # I think this is when we have a _completed_ subcommand. - # Recurse back into here, offering options for that subcommand. - curcontext=${curcontext%:*:*}:podman-${words[1]}: - _podman_subcommand "$@" ${words[1]} && ret=0 - ;; - esac - else - # At a terminus, i.e. podman info, podman history; find out - # what args it takes. - _podman_terminus "$@" && ret=0 fi - - return ret } -_podman() { - _podman_subcommand -} +# don't run the completion function when being source-ed or eval-ed +if [ "$funcstack[1]" = "_podman" ]; then + _podman +fi -# Local Variables: -# mode: shell-script -# sh-indentation: 4 -# indent-tabs-mode: nil -# sh-basic-offset: 4 -# End: -# vim: ft=zsh sw=4 ts=4 et +# This file is generated with "podman completion"; see: podman-completion(1) diff --git a/completions/zsh/_podman-remote b/completions/zsh/_podman-remote new file mode 100644 index 000000000000..fc2984cfd439 --- /dev/null +++ b/completions/zsh/_podman-remote @@ -0,0 +1,181 @@ +#compdef _podman-remote podman-remote + +# zsh completion for podman-remote -*- shell-script -*- + +__podman-remote_debug() +{ + local file="$BASH_COMP_DEBUG_FILE" + if [[ -n ${file} ]]; then + echo "$*" >> "${file}" + fi +} + +_podman-remote() +{ + local shellCompDirectiveError=1 + local shellCompDirectiveNoSpace=2 + local shellCompDirectiveNoFileComp=4 + local shellCompDirectiveFilterFileExt=8 + local shellCompDirectiveFilterDirs=16 + local shellCompDirectiveLegacyCustomComp=32 + local shellCompDirectiveLegacyCustomArgsComp=64 + + local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace + local -a completions + + __podman-remote_debug "\n========= starting completion logic ==========" + __podman-remote_debug "CURRENT: ${CURRENT}, words[*]: ${words[*]}" + + # The user could have moved the cursor backwards on the command-line. + # We need to trigger completion from the $CURRENT location, so we need + # to truncate the command-line ($words) up to the $CURRENT location. + # (We cannot use $CURSOR as its value does not work when a command is an alias.) + words=("${=words[1,CURRENT]}") + __podman-remote_debug "Truncated words[*]: ${words[*]}," + + lastParam=${words[-1]} + lastChar=${lastParam[-1]} + __podman-remote_debug "lastParam: ${lastParam}, lastChar: ${lastChar}" + + # For zsh, when completing a flag with an = (e.g., podman-remote -n=) + # completions must be prefixed with the flag + setopt local_options BASH_REMATCH + if [[ "${lastParam}" =~ '-.*=' ]]; then + # We are dealing with a flag with an = + flagPrefix="-P ${BASH_REMATCH}" + fi + + # Prepare the command to obtain completions + requestComp="${words[1]} __complete ${words[2,-1]}" + if [ "${lastChar}" = "" ]; then + # If the last parameter is complete (there is a space following it) + # We add an extra empty parameter so we can indicate this to the go completion code. + __podman-remote_debug "Adding extra empty parameter" + requestComp="${requestComp} \"\"" + fi + + __podman-remote_debug "About to call: eval ${requestComp}" + + # Use eval to handle any environment variables and such + out=$(eval ${requestComp} 2>/dev/null) + __podman-remote_debug "completion output: ${out}" + + # Extract the directive integer following a : from the last line + local lastLine + while IFS='\n' read -r line; do + lastLine=${line} + done < <(printf "%s\n" "${out[@]}") + __podman-remote_debug "last line: ${lastLine}" + + if [ "${lastLine[1]}" = : ]; then + directive=${lastLine[2,-1]} + # Remove the directive including the : and the newline + local suffix + (( suffix=${#lastLine}+2)) + out=${out[1,-$suffix]} + else + # There is no directive specified. Leave $out as is. + __podman-remote_debug "No directive found. Setting do default" + directive=0 + fi + + __podman-remote_debug "directive: ${directive}" + __podman-remote_debug "completions: ${out}" + __podman-remote_debug "flagPrefix: ${flagPrefix}" + + if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then + __podman-remote_debug "Completion received error. Ignoring completions." + return + fi + + while IFS='\n' read -r comp; do + if [ -n "$comp" ]; then + # If requested, completions are returned with a description. + # The description is preceded by a TAB character. + # For zsh's _describe, we need to use a : instead of a TAB. + # We first need to escape any : as part of the completion itself. + comp=${comp//:/\\:} + + local tab=$(printf '\t') + comp=${comp//$tab/:} + + __podman-remote_debug "Adding completion: ${comp}" + completions+=${comp} + lastComp=$comp + fi + done < <(printf "%s\n" "${out[@]}") + + if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then + __podman-remote_debug "Activating nospace." + noSpace="-S ''" + fi + + if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then + # File extension filtering + local filteringCmd + filteringCmd='_files' + for filter in ${completions[@]}; do + if [ ${filter[1]} != '*' ]; then + # zsh requires a glob pattern to do file filtering + filter="\*.$filter" + fi + filteringCmd+=" -g $filter" + done + filteringCmd+=" ${flagPrefix}" + + __podman-remote_debug "File filtering command: $filteringCmd" + _arguments '*:filename:'"$filteringCmd" + elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then + # File completion for directories only + local subDir + subdir="${completions[1]}" + if [ -n "$subdir" ]; then + __podman-remote_debug "Listing directories in $subdir" + pushd "${subdir}" >/dev/null 2>&1 + else + __podman-remote_debug "Listing directories in ." + fi + + local result + _arguments '*:dirname:_files -/'" ${flagPrefix}" + result=$? + if [ -n "$subdir" ]; then + popd >/dev/null 2>&1 + fi + return $result + else + __podman-remote_debug "Calling _describe" + if eval _describe "completions" completions $flagPrefix $noSpace; then + __podman-remote_debug "_describe found some completions" + + # Return the success of having called _describe + return 0 + else + __podman-remote_debug "_describe did not find completions." + __podman-remote_debug "Checking if we should do file completion." + if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then + __podman-remote_debug "deactivating file completion" + + # We must return an error code here to let zsh know that there were no + # completions found by _describe; this is what will trigger other + # matching algorithms to attempt to find completions. + # For example zsh can match letters in the middle of words. + return 1 + else + # Perform file completion + __podman-remote_debug "Activating file completion" + + # We must return the result of this command, so it must be the + # last command, or else we must store its result to return it. + _arguments '*:filename:_files'" ${flagPrefix}" + fi + fi + fi +} + +# don't run the completion function when being source-ed or eval-ed +if [ "$funcstack[1]" = "_podman-remote" ]; then + _podman-remote +fi + +# This file is generated with "podman-remote completion"; see: podman-completion(1) diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in index 2a3041ccc971..ee8ce4d45da3 100644 --- a/contrib/spec/podman.spec.in +++ b/contrib/spec/podman.spec.in @@ -499,6 +499,7 @@ export GOPATH=%{buildroot}/%{gopath}:$(pwd)/vendor:%{gopath} %{_bindir}/%{name} %{_datadir}/bash-completion/completions/* %{_datadir}/zsh/site-functions/* +%{_datadir}/fish/vendor_completions.d/* %{_libexecdir}/%{name}/conmon %config(noreplace) %{_sysconfdir}/cni/net.d/87-%{name}-bridge.conflist %{_unitdir}/podman-auto-update.service diff --git a/docs/source/markdown/podman-completion.1.md b/docs/source/markdown/podman-completion.1.md index 43409e2825b1..50b0b6145365 100644 --- a/docs/source/markdown/podman-completion.1.md +++ b/docs/source/markdown/podman-completion.1.md @@ -11,14 +11,14 @@ The completion command allows you to generate shell completion scripts. Supporte These script are used by the shell to provide suggestions and complete commands when you are typing the command and press [TAB]. -Usually these scripts are automatically installed via rpm/deb packages. +Usually these scripts are automatically installed via the package manager. ## OPTIONS -**--file**, **-f** +#### **--file**, **-f** Write the generated output to file. -**--no-desc** +#### **--no-desc** Do not provide description in the completions.