docker-compose 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. #!bash
  2. #
  3. # bash completion for docker-compose
  4. #
  5. # This work is based on the completion for the docker command.
  6. #
  7. # This script provides completion of:
  8. # - commands and their options
  9. # - service names
  10. # - filepaths
  11. #
  12. # To enable the completions either:
  13. # - place this file in /etc/bash_completion.d
  14. # or
  15. # - copy this file to e.g. ~/.docker-compose-completion.sh and add the line
  16. # below to your .bashrc after bash completion features are loaded
  17. # . ~/.docker-compose-completion.sh
  18. __docker_compose_q() {
  19. docker-compose 2>/dev/null $daemon_options "$@"
  20. }
  21. # Transforms a multiline list of strings into a single line string
  22. # with the words separated by "|".
  23. __docker_compose_to_alternatives() {
  24. local parts=( $1 )
  25. local IFS='|'
  26. echo "${parts[*]}"
  27. }
  28. # Transforms a multiline list of options into an extglob pattern
  29. # suitable for use in case statements.
  30. __docker_compose_to_extglob() {
  31. local extglob=$( __docker_compose_to_alternatives "$1" )
  32. echo "@($extglob)"
  33. }
  34. # suppress trailing whitespace
  35. __docker_compose_nospace() {
  36. # compopt is not available in ancient bash versions
  37. type compopt &>/dev/null && compopt -o nospace
  38. }
  39. # Extracts all service names from the compose file.
  40. ___docker_compose_all_services_in_compose_file() {
  41. __docker_compose_q config --services
  42. }
  43. # All services, even those without an existing container
  44. __docker_compose_services_all() {
  45. COMPREPLY=( $(compgen -W "$(___docker_compose_all_services_in_compose_file)" -- "$cur") )
  46. }
  47. # All services that have an entry with the given key in their compose_file section
  48. ___docker_compose_services_with_key() {
  49. # flatten sections under "services" to one line, then filter lines containing the key and return section name
  50. __docker_compose_q config \
  51. | sed -n -e '/^services:/,/^[^ ]/p' \
  52. | sed -n 's/^ //p' \
  53. | awk '/^[a-zA-Z0-9]/{printf "\n"};{printf $0;next;}' \
  54. | awk -F: -v key=": +$1:" '$0 ~ key {print $1}'
  55. }
  56. # All services that are defined by a Dockerfile reference
  57. __docker_compose_services_from_build() {
  58. COMPREPLY=( $(compgen -W "$(___docker_compose_services_with_key build)" -- "$cur") )
  59. }
  60. # All services that are defined by an image
  61. __docker_compose_services_from_image() {
  62. COMPREPLY=( $(compgen -W "$(___docker_compose_services_with_key image)" -- "$cur") )
  63. }
  64. # The services for which containers have been created, optionally filtered
  65. # by a boolean expression passed in as argument.
  66. __docker_compose_services_with() {
  67. local containers names
  68. containers="$(__docker_compose_q ps -q)"
  69. names=$(docker 2>/dev/null inspect -f "{{if ${1:-true}}}{{range \$k, \$v := .Config.Labels}}{{if eq \$k \"com.docker.compose.service\"}}{{\$v}}{{end}}{{end}}{{end}}" $containers)
  70. COMPREPLY=( $(compgen -W "$names" -- "$cur") )
  71. }
  72. # The services for which at least one paused container exists
  73. __docker_compose_services_paused() {
  74. __docker_compose_services_with '.State.Paused'
  75. }
  76. # The services for which at least one running container exists
  77. __docker_compose_services_running() {
  78. __docker_compose_services_with '.State.Running'
  79. }
  80. # The services for which at least one stopped container exists
  81. __docker_compose_services_stopped() {
  82. __docker_compose_services_with 'not .State.Running'
  83. }
  84. _docker_compose_build() {
  85. case "$cur" in
  86. -*)
  87. COMPREPLY=( $( compgen -W "--force-rm --help --no-cache --pull" -- "$cur" ) )
  88. ;;
  89. *)
  90. __docker_compose_services_from_build
  91. ;;
  92. esac
  93. }
  94. _docker_compose_config() {
  95. COMPREPLY=( $( compgen -W "--help --quiet -q --services" -- "$cur" ) )
  96. }
  97. _docker_compose_create() {
  98. case "$cur" in
  99. -*)
  100. COMPREPLY=( $( compgen -W "--force-recreate --help --no-build --no-recreate" -- "$cur" ) )
  101. ;;
  102. *)
  103. __docker_compose_services_all
  104. ;;
  105. esac
  106. }
  107. _docker_compose_docker_compose() {
  108. case "$prev" in
  109. --tlscacert|--tlscert|--tlskey)
  110. _filedir
  111. return
  112. ;;
  113. --file|-f)
  114. _filedir "y?(a)ml"
  115. return
  116. ;;
  117. $(__docker_compose_to_extglob "$daemon_options_with_args") )
  118. return
  119. ;;
  120. esac
  121. case "$cur" in
  122. -*)
  123. COMPREPLY=( $( compgen -W "$daemon_boolean_options $daemon_options_with_args --help -h --verbose --version -v" -- "$cur" ) )
  124. ;;
  125. *)
  126. COMPREPLY=( $( compgen -W "${commands[*]}" -- "$cur" ) )
  127. ;;
  128. esac
  129. }
  130. _docker_compose_down() {
  131. case "$prev" in
  132. --rmi)
  133. COMPREPLY=( $( compgen -W "all local" -- "$cur" ) )
  134. return
  135. ;;
  136. esac
  137. case "$cur" in
  138. -*)
  139. COMPREPLY=( $( compgen -W "--help --rmi --volumes -v --remove-orphans" -- "$cur" ) )
  140. ;;
  141. esac
  142. }
  143. _docker_compose_events() {
  144. case "$prev" in
  145. --json)
  146. return
  147. ;;
  148. esac
  149. case "$cur" in
  150. -*)
  151. COMPREPLY=( $( compgen -W "--help --json" -- "$cur" ) )
  152. ;;
  153. *)
  154. __docker_compose_services_all
  155. ;;
  156. esac
  157. }
  158. _docker_compose_help() {
  159. COMPREPLY=( $( compgen -W "${commands[*]}" -- "$cur" ) )
  160. }
  161. _docker_compose_kill() {
  162. case "$prev" in
  163. -s)
  164. COMPREPLY=( $( compgen -W "SIGHUP SIGINT SIGKILL SIGUSR1 SIGUSR2" -- "$(echo $cur | tr '[:lower:]' '[:upper:]')" ) )
  165. return
  166. ;;
  167. esac
  168. case "$cur" in
  169. -*)
  170. COMPREPLY=( $( compgen -W "--help -s" -- "$cur" ) )
  171. ;;
  172. *)
  173. __docker_compose_services_running
  174. ;;
  175. esac
  176. }
  177. _docker_compose_logs() {
  178. case "$prev" in
  179. --tail)
  180. return
  181. ;;
  182. esac
  183. case "$cur" in
  184. -*)
  185. COMPREPLY=( $( compgen -W "--follow -f --help --no-color --tail --timestamps -t" -- "$cur" ) )
  186. ;;
  187. *)
  188. __docker_compose_services_all
  189. ;;
  190. esac
  191. }
  192. _docker_compose_pause() {
  193. case "$cur" in
  194. -*)
  195. COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
  196. ;;
  197. *)
  198. __docker_compose_services_running
  199. ;;
  200. esac
  201. }
  202. _docker_compose_port() {
  203. case "$prev" in
  204. --protocol)
  205. COMPREPLY=( $( compgen -W "tcp udp" -- "$cur" ) )
  206. return;
  207. ;;
  208. --index)
  209. return;
  210. ;;
  211. esac
  212. case "$cur" in
  213. -*)
  214. COMPREPLY=( $( compgen -W "--help --index --protocol" -- "$cur" ) )
  215. ;;
  216. *)
  217. __docker_compose_services_all
  218. ;;
  219. esac
  220. }
  221. _docker_compose_ps() {
  222. case "$cur" in
  223. -*)
  224. COMPREPLY=( $( compgen -W "--help -q" -- "$cur" ) )
  225. ;;
  226. *)
  227. __docker_compose_services_all
  228. ;;
  229. esac
  230. }
  231. _docker_compose_pull() {
  232. case "$cur" in
  233. -*)
  234. COMPREPLY=( $( compgen -W "--help --ignore-pull-failures" -- "$cur" ) )
  235. ;;
  236. *)
  237. __docker_compose_services_from_image
  238. ;;
  239. esac
  240. }
  241. _docker_compose_restart() {
  242. case "$prev" in
  243. --timeout|-t)
  244. return
  245. ;;
  246. esac
  247. case "$cur" in
  248. -*)
  249. COMPREPLY=( $( compgen -W "--help --timeout -t" -- "$cur" ) )
  250. ;;
  251. *)
  252. __docker_compose_services_running
  253. ;;
  254. esac
  255. }
  256. _docker_compose_rm() {
  257. case "$cur" in
  258. -*)
  259. COMPREPLY=( $( compgen -W "--force -f --help -v" -- "$cur" ) )
  260. ;;
  261. *)
  262. __docker_compose_services_stopped
  263. ;;
  264. esac
  265. }
  266. _docker_compose_run() {
  267. case "$prev" in
  268. -e)
  269. COMPREPLY=( $( compgen -e -- "$cur" ) )
  270. __docker_compose_nospace
  271. return
  272. ;;
  273. --entrypoint|--name|--user|-u|--workdir|-w)
  274. return
  275. ;;
  276. esac
  277. case "$cur" in
  278. -*)
  279. COMPREPLY=( $( compgen -W "-d --entrypoint -e --help --name --no-deps --publish -p --rm --service-ports -T --user -u --workdir -w" -- "$cur" ) )
  280. ;;
  281. *)
  282. __docker_compose_services_all
  283. ;;
  284. esac
  285. }
  286. _docker_compose_scale() {
  287. case "$prev" in
  288. =)
  289. COMPREPLY=("$cur")
  290. return
  291. ;;
  292. --timeout|-t)
  293. return
  294. ;;
  295. esac
  296. case "$cur" in
  297. -*)
  298. COMPREPLY=( $( compgen -W "--help --timeout -t" -- "$cur" ) )
  299. ;;
  300. *)
  301. COMPREPLY=( $(compgen -S "=" -W "$(___docker_compose_all_services_in_compose_file)" -- "$cur") )
  302. __docker_compose_nospace
  303. ;;
  304. esac
  305. }
  306. _docker_compose_start() {
  307. case "$cur" in
  308. -*)
  309. COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
  310. ;;
  311. *)
  312. __docker_compose_services_stopped
  313. ;;
  314. esac
  315. }
  316. _docker_compose_stop() {
  317. case "$prev" in
  318. --timeout|-t)
  319. return
  320. ;;
  321. esac
  322. case "$cur" in
  323. -*)
  324. COMPREPLY=( $( compgen -W "--help --timeout -t" -- "$cur" ) )
  325. ;;
  326. *)
  327. __docker_compose_services_running
  328. ;;
  329. esac
  330. }
  331. _docker_compose_unpause() {
  332. case "$cur" in
  333. -*)
  334. COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
  335. ;;
  336. *)
  337. __docker_compose_services_paused
  338. ;;
  339. esac
  340. }
  341. _docker_compose_up() {
  342. case "$prev" in
  343. --timeout|-t)
  344. return
  345. ;;
  346. esac
  347. case "$cur" in
  348. -*)
  349. COMPREPLY=( $( compgen -W "--abort-on-container-exit --build -d --force-recreate --help --no-build --no-color --no-deps --no-recreate --timeout -t --remove-orphans" -- "$cur" ) )
  350. ;;
  351. *)
  352. __docker_compose_services_all
  353. ;;
  354. esac
  355. }
  356. _docker_compose_version() {
  357. case "$cur" in
  358. -*)
  359. COMPREPLY=( $( compgen -W "--short" -- "$cur" ) )
  360. ;;
  361. esac
  362. }
  363. _docker_compose() {
  364. local previous_extglob_setting=$(shopt -p extglob)
  365. shopt -s extglob
  366. local commands=(
  367. build
  368. config
  369. create
  370. down
  371. events
  372. help
  373. kill
  374. logs
  375. pause
  376. port
  377. ps
  378. pull
  379. restart
  380. rm
  381. run
  382. scale
  383. start
  384. stop
  385. unpause
  386. up
  387. version
  388. )
  389. # options for the docker daemon that have to be passed to secondary calls to
  390. # docker-compose executed by this script
  391. local daemon_boolean_options="
  392. --skip-hostname-check
  393. --tls
  394. --tlsverify
  395. "
  396. local daemon_options_with_args="
  397. --file -f
  398. --host -H
  399. --project-name -p
  400. --tlscacert
  401. --tlscert
  402. --tlskey
  403. "
  404. COMPREPLY=()
  405. local cur prev words cword
  406. _get_comp_words_by_ref -n : cur prev words cword
  407. # search subcommand and invoke its handler.
  408. # special treatment of some top-level options
  409. local command='docker_compose'
  410. local daemon_options=()
  411. local counter=1
  412. while [ $counter -lt $cword ]; do
  413. case "${words[$counter]}" in
  414. $(__docker_compose_to_extglob "$daemon_boolean_options") )
  415. local opt=${words[counter]}
  416. daemon_options+=($opt)
  417. ;;
  418. $(__docker_compose_to_extglob "$daemon_options_with_args") )
  419. local opt=${words[counter]}
  420. local arg=${words[++counter]}
  421. daemon_options+=($opt $arg)
  422. ;;
  423. -*)
  424. ;;
  425. *)
  426. command="${words[$counter]}"
  427. break
  428. ;;
  429. esac
  430. (( counter++ ))
  431. done
  432. local completions_func=_docker_compose_${command//-/_}
  433. declare -F $completions_func >/dev/null && $completions_func
  434. eval "$previous_extglob_setting"
  435. return 0
  436. }
  437. complete -F _docker_compose docker-compose