├── README.md ├── LICENSE └── _docker-compose /README.md: -------------------------------------------------------------------------------- 1 | # docker-compose-zsh-completion 2 | 3 | __UPDATES__ : Zsh completion has been merged in the docker-compose official repository. I will try to keep this repo updated with the official one. 4 | 5 | A zsh completion for [docker-compose](https://github.com/docker/compose) 6 | 7 | ## How to Install 8 | 9 | Put this `_docker-compose` into your `~/.zsh/completion` directory, then reload your shell : 10 | ```sh 11 | mkdir -p ~/.zsh/completion 12 | curl -L https://raw.githubusercontent.com/sdurrheimer/docker-compose-zsh-completion/master/_docker-compose > ~/.zsh/completion/_docker-compose 13 | exec $SHELL -l 14 | ``` 15 | 16 | At this point, if completion doesn't work, add this to your `~/.zshrc` file, then reload one more time your shell : 17 | ```sh 18 | fpath=(~/.zsh/completion $fpath) 19 | autoload -Uz compinit && compinit -i 20 | ``` 21 | ```sh 22 | exec $SHELL -l 23 | ``` 24 | 25 | ## Contributors 26 | 27 | * [sdurrheimer](http://github.com/sdurrheimer) 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Steve Durrheimer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /_docker-compose: -------------------------------------------------------------------------------- 1 | #compdef docker-compose 2 | 3 | # Description 4 | # ----------- 5 | # zsh completion for docker-compose 6 | # https://github.com/sdurrheimer/docker-compose-zsh-completion 7 | # ------------------------------------------------------------------------- 8 | # Version 9 | # ------- 10 | # 1.5.0 11 | # ------------------------------------------------------------------------- 12 | # Authors 13 | # ------- 14 | # * Steve Durrheimer 15 | # ------------------------------------------------------------------------- 16 | # Inspiration 17 | # ----------- 18 | # * @albers docker-compose bash completion script 19 | # * @felixr docker zsh completion script : https://github.com/felixr/docker-zsh-completion 20 | # ------------------------------------------------------------------------- 21 | 22 | # For compatibility reasons, Compose and therefore its completion supports several 23 | # stack compositon files as listed here, in descending priority. 24 | # Support for these filenames might be dropped in some future version. 25 | __docker-compose_compose_file() { 26 | local file 27 | for file in docker-compose.y{,a}ml fig.y{,a}ml ; do 28 | [ -e $file ] && { 29 | echo $file 30 | return 31 | } 32 | done 33 | echo docker-compose.yml 34 | } 35 | 36 | # Extracts all service names from docker-compose.yml. 37 | ___docker-compose_all_services_in_compose_file() { 38 | local already_selected 39 | local -a services 40 | already_selected=$(echo $words | tr " " "|") 41 | awk -F: '/^[a-zA-Z0-9]/{print $1}' "${compose_file:-$(__docker-compose_compose_file)}" 2>/dev/null | grep -Ev "$already_selected" 42 | } 43 | 44 | # All services, even those without an existing container 45 | __docker-compose_services_all() { 46 | [[ $PREFIX = -* ]] && return 1 47 | integer ret=1 48 | services=$(___docker-compose_all_services_in_compose_file) 49 | _alternative "args:services:($services)" && ret=0 50 | 51 | return ret 52 | } 53 | 54 | # All services that have an entry with the given key in their docker-compose.yml section 55 | ___docker-compose_services_with_key() { 56 | local already_selected 57 | local -a buildable 58 | already_selected=$(echo $words | tr " " "|") 59 | # flatten sections to one line, then filter lines containing the key and return section name. 60 | awk '/^[a-zA-Z0-9]/{printf "\n"};{printf $0;next;}' "${compose_file:-$(__docker-compose_compose_file)}" 2>/dev/null | awk -F: -v key=": +$1:" '$0 ~ key {print $1}' 2>/dev/null | grep -Ev "$already_selected" 61 | } 62 | 63 | # All services that are defined by a Dockerfile reference 64 | __docker-compose_services_from_build() { 65 | [[ $PREFIX = -* ]] && return 1 66 | integer ret=1 67 | buildable=$(___docker-compose_services_with_key build) 68 | _alternative "args:buildable services:($buildable)" && ret=0 69 | 70 | return ret 71 | } 72 | 73 | # All services that are defined by an image 74 | __docker-compose_services_from_image() { 75 | [[ $PREFIX = -* ]] && return 1 76 | integer ret=1 77 | pullable=$(___docker-compose_services_with_key image) 78 | _alternative "args:pullable services:($pullable)" && ret=0 79 | 80 | return ret 81 | } 82 | 83 | __docker-compose_get_services() { 84 | [[ $PREFIX = -* ]] && return 1 85 | integer ret=1 86 | local kind 87 | declare -a running paused stopped lines args services 88 | 89 | docker_status=$(docker ps > /dev/null 2>&1) 90 | if [ $? -ne 0 ]; then 91 | _message "Error! Docker is not running." 92 | return 1 93 | fi 94 | 95 | kind=$1 96 | shift 97 | [[ $kind =~ (stopped|all) ]] && args=($args -a) 98 | 99 | lines=(${(f)"$(_call_program commands docker ps $args)"}) 100 | services=(${(f)"$(_call_program commands docker-compose 2>/dev/null $compose_options ps -q)"}) 101 | 102 | # Parse header line to find columns 103 | local i=1 j=1 k header=${lines[1]} 104 | declare -A begin end 105 | while (( j < ${#header} - 1 )); do 106 | i=$(( j + ${${header[$j,-1]}[(i)[^ ]]} - 1 )) 107 | j=$(( i + ${${header[$i,-1]}[(i) ]} - 1 )) 108 | k=$(( j + ${${header[$j,-1]}[(i)[^ ]]} - 2 )) 109 | begin[${header[$i,$((j-1))]}]=$i 110 | end[${header[$i,$((j-1))]}]=$k 111 | done 112 | lines=(${lines[2,-1]}) 113 | 114 | # Container ID 115 | local line s name 116 | local -a names 117 | for line in $lines; do 118 | if [[ ${services[@]} == *"${line[${begin[CONTAINER ID]},${end[CONTAINER ID]}]%% ##}"* ]]; then 119 | names=(${(ps:,:)${${line[${begin[NAMES]},-1]}%% *}}) 120 | for name in $names; do 121 | s="${${name%_*}#*_}:${(l:15:: :::)${${line[${begin[CREATED]},${end[CREATED]}]/ ago/}%% ##}}" 122 | s="$s, ${line[${begin[CONTAINER ID]},${end[CONTAINER ID]}]%% ##}" 123 | s="$s, ${${${line[${begin[IMAGE]},${end[IMAGE]}]}/:/\\:}%% ##}" 124 | if [[ ${line[${begin[STATUS]},${end[STATUS]}]} = Exit* ]]; then 125 | stopped=($stopped $s) 126 | else 127 | if [[ ${line[${begin[STATUS]},${end[STATUS]}]} = *\(Paused\)* ]]; then 128 | paused=($paused $s) 129 | fi 130 | running=($running $s) 131 | fi 132 | done 133 | fi 134 | done 135 | 136 | [[ $kind =~ (running|all) ]] && _describe -t services-running "running services" running "$@" && ret=0 137 | [[ $kind =~ (paused|all) ]] && _describe -t services-paused "paused services" paused "$@" && ret=0 138 | [[ $kind =~ (stopped|all) ]] && _describe -t services-stopped "stopped services" stopped "$@" && ret=0 139 | 140 | return ret 141 | } 142 | 143 | __docker-compose_pausedservices() { 144 | [[ $PREFIX = -* ]] && return 1 145 | __docker-compose_get_services paused "$@" 146 | } 147 | 148 | __docker-compose_stoppedservices() { 149 | [[ $PREFIX = -* ]] && return 1 150 | __docker-compose_get_services stopped "$@" 151 | } 152 | 153 | __docker-compose_runningservices() { 154 | [[ $PREFIX = -* ]] && return 1 155 | __docker-compose_get_services running "$@" 156 | } 157 | 158 | __docker-compose_services() { 159 | [[ $PREFIX = -* ]] && return 1 160 | __docker-compose_get_services all "$@" 161 | } 162 | 163 | __docker-compose_caching_policy() { 164 | oldp=( "$1"(Nmh+1) ) # 1 hour 165 | (( $#oldp )) 166 | } 167 | 168 | __docker-compose_commands() { 169 | local cache_policy 170 | 171 | zstyle -s ":completion:${curcontext}:" cache-policy cache_policy 172 | if [[ -z "$cache_policy" ]]; then 173 | zstyle ":completion:${curcontext}:" cache-policy __docker-compose_caching_policy 174 | fi 175 | 176 | if ( [[ ${+_docker_compose_subcommands} -eq 0 ]] || _cache_invalid docker_compose_subcommands) \ 177 | && ! _retrieve_cache docker_compose_subcommands; 178 | then 179 | local -a lines 180 | lines=(${(f)"$(_call_program commands docker-compose 2>&1)"}) 181 | _docker_compose_subcommands=(${${${lines[$((${lines[(i)Commands:]} + 1)),${lines[(I) *]}]}## #}/ ##/:}) 182 | _store_cache docker_compose_subcommands _docker_compose_subcommands 183 | fi 184 | _describe -t docker-compose-commands "docker-compose command" _docker_compose_subcommands 185 | } 186 | 187 | __docker-compose_subcommand() { 188 | local opts_help='(: -)--help[Print usage]' 189 | integer ret=1 190 | 191 | case "$words[1]" in 192 | (build) 193 | _arguments \ 194 | $opts_help \ 195 | '--no-cache[Do not use cache when building the image.]' \ 196 | '--pull[Always attempt to pull a newer version of the image.]' \ 197 | '*:services:__docker-compose_services_from_build' && ret=0 198 | ;; 199 | (help) 200 | _arguments ':subcommand:__docker-compose_commands' && ret=0 201 | ;; 202 | (kill) 203 | _arguments \ 204 | $opts_help \ 205 | '-s[SIGNAL to send to the container. Default signal is SIGKILL.]:signal:_signals' \ 206 | '*:running services:__docker-compose_runningservices' && ret=0 207 | ;; 208 | (logs) 209 | _arguments \ 210 | $opts_help \ 211 | '--no-color[Produce monochrome output.]' \ 212 | '*:services:__docker-compose_services_all' && ret=0 213 | ;; 214 | (migrate-to-labels) 215 | _arguments -A '-*' \ 216 | $opts_help \ 217 | '(-):Recreate containers to add labels' && ret=0 218 | ;; 219 | (pause) 220 | _arguments \ 221 | $opts_help \ 222 | '*:running services:__docker-compose_runningservices' && ret=0 223 | ;; 224 | (port) 225 | _arguments \ 226 | $opts_help \ 227 | '--protocol=-[tcp or udap (defaults to tcp)]:protocol:(tcp udp)' \ 228 | '--index=-[index of the container if there are mutiple instances of a service (defaults to 1)]:index: ' \ 229 | '1:running services:__docker-compose_runningservices' \ 230 | '2:port:_ports' && ret=0 231 | ;; 232 | (ps) 233 | _arguments \ 234 | $opts_help \ 235 | '-q[Only display IDs]' \ 236 | '*:services:__docker-compose_services_all' && ret=0 237 | ;; 238 | (pull) 239 | _arguments \ 240 | $opts_help \ 241 | '--ignore-pull-failures[Pull what it can and ignores images with pull failures.]' \ 242 | '*:services:__docker-compose_services_from_image' && ret=0 243 | ;; 244 | (rm) 245 | _arguments \ 246 | $opts_help \ 247 | '(-f --force)'{-f,--force}"[Don't ask to confirm removal]" \ 248 | '-v[Remove volumes associated with containers]' \ 249 | '*:stopped services:__docker-compose_stoppedservices' && ret=0 250 | ;; 251 | (run) 252 | _arguments \ 253 | $opts_help \ 254 | '-d[Detached mode: Run container in the background, print new container name.]' \ 255 | '--name[Assign a name to the container]:name: ' \ 256 | '--entrypoint[Overwrite the entrypoint of the image.]:entry point: ' \ 257 | '*-e[KEY=VAL Set an environment variable (can be used multiple times)]:environment variable KEY=VAL: ' \ 258 | '(-u --user)'{-u,--user=-}'[Run as specified username or uid]:username or uid:_users' \ 259 | "--no-deps[Don't start linked services.]" \ 260 | '--rm[Remove container after run. Ignored in detached mode.]' \ 261 | "--service-ports[Run command with the service's ports enabled and mapped to the host.]" \ 262 | '(-p --publish)'{-p,--publish=-}"[Run command with manually mapped container's port(s) to the host.]" \ 263 | '-T[Disable pseudo-tty allocation. By default `docker-compose run` allocates a TTY.]' \ 264 | '(-):services:__docker-compose_services' \ 265 | '(-):command: _command_names -e' \ 266 | '*::arguments: _normal' && ret=0 267 | ;; 268 | (scale) 269 | _arguments \ 270 | $opts_help \ 271 | '(-t --timeout)'{-t,--timeout}"[Specify a shutdown timeout in seconds. (default: 10)]:seconds: " \ 272 | '*:running services:__docker-compose_runningservices' && ret=0 273 | ;; 274 | (start) 275 | _arguments \ 276 | $opts_help \ 277 | '*:stopped services:__docker-compose_stoppedservices' && ret=0 278 | ;; 279 | (stop|restart) 280 | _arguments \ 281 | $opts_help \ 282 | '(-t --timeout)'{-t,--timeout}"[Specify a shutdown timeout in seconds. (default: 10)]:seconds: " \ 283 | '*:running services:__docker-compose_runningservices' && ret=0 284 | ;; 285 | (unpause) 286 | _arguments \ 287 | $opts_help \ 288 | '*:paused services:__docker-compose_pausedservices' && ret=0 289 | ;; 290 | (up) 291 | _arguments \ 292 | $opts_help \ 293 | '-d[Detached mode: Run containers in the background, print new container names.]' \ 294 | '--no-color[Produce monochrome output.]' \ 295 | "--no-deps[Don't start linked services.]" \ 296 | "--force-recreate[Recreate containers even if their configuration and image haven't changed. Incompatible with --no-recreate.]" \ 297 | "--no-recreate[If containers already exist, don't recreate them.]" \ 298 | "--no-build[Don't build an image, even if it's missing]" \ 299 | '(-t --timeout)'{-t,--timeout}"[Specify a shutdown timeout in seconds. (default: 10)]:seconds: " \ 300 | '*:services:__docker-compose_services_all' && ret=0 301 | ;; 302 | (version) 303 | _arguments \ 304 | $opts_help \ 305 | "--short[Shows only Compose's version number.]" && ret=0 306 | ;; 307 | (*) 308 | _message 'Unknown sub command' && ret=1 309 | ;; 310 | esac 311 | 312 | return ret 313 | } 314 | 315 | _docker-compose() { 316 | # Support for subservices, which allows for `compdef _docker docker-shell=_docker_containers`. 317 | # Based on /usr/share/zsh/functions/Completion/Unix/_git without support for `ret`. 318 | if [[ $service != docker-compose ]]; then 319 | _call_function - _$service 320 | return 321 | fi 322 | 323 | local curcontext="$curcontext" state line 324 | integer ret=1 325 | typeset -A opt_args 326 | 327 | _arguments -C \ 328 | '(- :)'{-h,--help}'[Get help]' \ 329 | '--verbose[Show more output]' \ 330 | '(- :)'{-v,--version}'[Print version and exit]' \ 331 | '(-f --file)'{-f,--file}'[Specify an alternate docker-compose file (default: docker-compose.yml)]:file:_files -g "*.yml"' \ 332 | '(-p --project-name)'{-p,--project-name}'[Specify an alternate project name (default: directory name)]:project name:' \ 333 | '--x-networking[(EXPERIMENTAL) Use new Docker networking functionality. Requires Docker 1.9 or later.]' \ 334 | '--x-network-driver[(EXPERIMENTAL) Specify a network driver (default: "bridge"). Requires Docker 1.9 or later.]:Network Driver:(null host bridge overlay)' \ 335 | '(-): :->command' \ 336 | '(-)*:: :->option-or-argument' && ret=0 337 | 338 | local compose_file=${opt_args[-f]}${opt_args[--file]} 339 | local compose_project=${opt_args[-p]}${opt_args[--project-name]} 340 | local compose_options="${compose_file:+--file $compose_file} ${compose_project:+--project-name $compose_project}" 341 | 342 | case $state in 343 | (command) 344 | __docker-compose_commands && ret=0 345 | ;; 346 | (option-or-argument) 347 | curcontext=${curcontext%:*:*}:docker-compose-$words[1]: 348 | __docker-compose_subcommand && ret=0 349 | ;; 350 | esac 351 | 352 | return ret 353 | } 354 | 355 | _docker-compose "$@" 356 | --------------------------------------------------------------------------------