Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

367 lines
15 KiB

  1. ;;; docker-compose.el --- Emacs interface to docker-compose -*- lexical-binding: t -*-
  2. ;; Author: Philippe Vaucher <philippe.vaucher@gmail.com>
  3. ;; This file is NOT part of GNU Emacs.
  4. ;; This program is free software; you can redistribute it and/or modify
  5. ;; it under the terms of the GNU General Public License as published by
  6. ;; the Free Software Foundation; either version 3, or (at your option)
  7. ;; any later version.
  8. ;;
  9. ;; This program is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;;
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs; see the file COPYING. If not, write to the
  16. ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17. ;; Boston, MA 02110-1301, USA.
  18. ;;; Commentary:
  19. ;;; Code:
  20. (require 's)
  21. (require 'dash)
  22. (require 'tablist)
  23. (require 'magit-popup)
  24. (require 'docker-group)
  25. (require 'docker-utils)
  26. (defgroup docker-compose nil
  27. "Docker compose customization group."
  28. :group 'docker)
  29. (defcustom docker-compose-arguments '()
  30. "Arguments to use when calling \"docker-compose\"."
  31. :group 'docker-compose
  32. :type '(repeat (string :tag "Argument")))
  33. (defcustom docker-compose-run-arguments '("--rm")
  34. "Default arguments for `docker-compose-run-popup'."
  35. :group 'docker-compose
  36. :type '(repeat (string :tag "Argument")))
  37. (defcustom docker-compose-run-buffer-name-function 'docker-compose-make-buffer-name
  38. "Names a docker-compose run buffer based on `action' and `args'"
  39. :group 'docker-compose
  40. :type 'function)
  41. (defun docker-compose--run (action &rest args)
  42. "Execute docker ACTION passing arguments ARGS."
  43. (let ((command (format "docker-compose %s %s %s"
  44. (s-join " " docker-compose-arguments)
  45. action
  46. (s-join " " (-flatten (-non-nil args))))))
  47. (message command)
  48. (shell-command-to-string command)))
  49. (defun docker-compose--run-async (action &rest args)
  50. "Execute docker ACTION passing arguments ARGS."
  51. (let ((command (format "docker-compose %s %s %s"
  52. (s-join " " docker-compose-arguments)
  53. action
  54. (s-join " " (-flatten (-non-nil args))))))
  55. (message command)
  56. (async-shell-command command (funcall docker-compose-run-buffer-name-function action (-flatten args)))))
  57. (defun docker-compose-parse (line)
  58. "Convert a LINE from \"docker-compose ps\" to a `tabulated-list-entries' entry."
  59. (let ((data (s-split " \\{3,\\}" line)))
  60. (list (car data) (apply #'vector data))))
  61. (defun docker-compose-entries ()
  62. "Return the docker compose data for `tabulated-list-entries'."
  63. (let* ((data (docker-compose--run "ps"))
  64. (lines (-slice (s-split "\n" data t) 2)))
  65. (-map #'docker-compose-parse lines)))
  66. (defun docker-compose-refresh ()
  67. "Refresh the docker-compose entries."
  68. (setq tabulated-list-entries (docker-compose-entries)))
  69. (defun docker-compose-services ()
  70. "Return the list of services."
  71. (s-split "\n" (docker-compose--run "config" "--services") t))
  72. (defun docker-compose-read-services-names ()
  73. "Read the services names."
  74. (read-string (format "Services (%s or RET): " (s-join "," (docker-compose-services)))))
  75. (defun docker-compose-read-service-name ()
  76. "Read one service name."
  77. (completing-read "Service: " (docker-compose-services)))
  78. (defun docker-compose-read-log-level (&rest _ignore)
  79. "Read the docker-compose log level."
  80. (completing-read "Level: " '(DEBUG INFO WARNING ERROR CRITICAL)))
  81. (defun docker-compose-read-directory (&rest _ignore)
  82. "Wrapper around `read-directory-name'."
  83. (read-directory-name "Directory: "))
  84. (defun docker-compose-read-compose-file (&rest _ignore)
  85. "Wrapper around `read-file-name'."
  86. (read-file-name "Compose file: " nil nil t nil (apply-partially 'string-match ".*\\.yml")))
  87. (defun docker-compose-make-buffer-name (action args)
  88. "Make a buffer name based on ACTION and ARGS."
  89. (format "*docker-compose %s %s*" action (s-join " " (-non-nil args))))
  90. ;;;###autoload
  91. (defun docker-compose-build (services args)
  92. "Run \"docker-compose build ARGS SERVICES\"."
  93. (interactive (list (docker-compose-read-services-names) (docker-compose-build-arguments)))
  94. (docker-compose--run-async "build" args services))
  95. ;;;###autoload
  96. (defun docker-compose-create (services args)
  97. "Run \"docker-compose create ARGS SERVICES\"."
  98. (interactive (list (docker-compose-read-services-names) (docker-compose-create-arguments)))
  99. (docker-compose--run-async "create" args services))
  100. ;;;###autoload
  101. (defun docker-compose-down (services args)
  102. "Run \"docker-compose down ARGS SERVICES\"."
  103. (interactive (list (docker-compose-read-services-names) (docker-compose-down-arguments)))
  104. (docker-compose--run-async "down" args services))
  105. ;;;###autoload
  106. (defun docker-compose-exec (service command args)
  107. "Run \"docker-compose exec ARGS SERVICE COMMAND\"."
  108. (interactive (list (docker-compose-read-service-name) (read-string "Command: ") (docker-compose-exec-arguments)))
  109. (docker-compose--run-async "exec" args service command))
  110. ;;;###autoload
  111. (defun docker-compose-logs (services args)
  112. "Run \"docker-compose logs ARGS SERVICES\"."
  113. (interactive (list (docker-compose-read-services-names) (docker-compose-logs-arguments)))
  114. (docker-compose--run-async "logs" args services))
  115. ;;;###autoload
  116. (defun docker-compose-pull (services args)
  117. "Run \"docker-compose pull ARGS SERVICES\"."
  118. (interactive (list (docker-compose-read-services-names) (docker-compose-pull-arguments)))
  119. (docker-compose--run "pull" args services))
  120. ;;;###autoload
  121. (defun docker-compose-push (services args)
  122. "Run \"docker-compose push ARGS SERVICES\"."
  123. (interactive (list (docker-compose-read-services-names) (docker-compose-push-arguments)))
  124. (docker-compose--run "push" args services))
  125. ;;;###autoload
  126. (defun docker-compose-restart (services args)
  127. "Run \"docker-compose restart ARGS SERVICES\"."
  128. (interactive (list (docker-compose-read-services-names) (docker-compose-restart-arguments)))
  129. (docker-compose--run "restart" args services))
  130. ;;;###autoload
  131. (defun docker-compose-rm (services args)
  132. "Run \"docker-compose rm ARGS SERVICES\"."
  133. (interactive (list (docker-compose-read-services-names) (docker-compose-rm-arguments)))
  134. (docker-compose--run "rm" args services))
  135. ;;;###autoload
  136. (defun docker-compose-run (service command args)
  137. "Run \"docker-compose run ARGS SERVICE COMMAND\"."
  138. (interactive (list (docker-compose-read-service-name) (read-string "Command: ") (docker-compose-run-arguments)))
  139. (docker-compose--run-async "run" args service command))
  140. ;;;###autoload
  141. (defun docker-compose-start (services args)
  142. "Run \"docker-compose start ARGS SERVICES\"."
  143. (interactive (list (docker-compose-read-services-names) (docker-compose-start-arguments)))
  144. (docker-compose--run "start" args services))
  145. ;;;###autoload
  146. (defun docker-compose-stop (services args)
  147. "Run \"docker-compose stop ARGS SERVICES\"."
  148. (interactive (list (docker-compose-read-services-names) (docker-compose-stop-arguments)))
  149. (docker-compose--run "stop" args services))
  150. ;;;###autoload
  151. (defun docker-compose-up (services args)
  152. "Run \"docker-compose up ARGS SERVICES\"."
  153. (interactive (list (docker-compose-read-services-names) (docker-compose-up-arguments)))
  154. (docker-compose--run-async "up" args services))
  155. (defmacro docker-compose--all (command)
  156. "Return a lambda running COMMAND for all services."
  157. `(lambda (args)
  158. (interactive (list (,(intern (format "%s-arguments" command)))))
  159. (,command nil args)))
  160. (magit-define-popup docker-compose-build-popup
  161. "Popup for \"docker-compose build\"."
  162. 'docker-compose
  163. :man-page "docker-compose build"
  164. :switches '((?c "Compress build context" "--compress")
  165. (?f "Always remove intermediate containers" "--force-rm")
  166. (?n "Do not use cache" "--no-cache")
  167. (?p "Attempt to pull a newer version of the image" "--pull")
  168. (?r "Build images in parallel" "--parallel"))
  169. :options '((?b "Build argument" "--build-arg ")
  170. (?m "Memory limit" "--memory "))
  171. :actions `((?B "Build" docker-compose-build)
  172. (?A "All services" ,(docker-compose--all docker-compose-build))))
  173. (magit-define-popup docker-compose-create-popup
  174. "Popup for \"docker-compose create\"."
  175. 'docker-compose
  176. :man-page "docker-compose create"
  177. :switches '((?b "Build" "--build")
  178. (?f "Force recreate" "--force-recreate")
  179. (?n "No recreate" "--no-recreate"))
  180. :actions `((?C "Create" docker-compose-create)
  181. (?A "All services" ,(docker-compose--all docker-compose-create))))
  182. (magit-define-popup docker-compose-down-popup
  183. "Popup for \"docker-compose down\"."
  184. 'docker-compose
  185. :man-page "docker-compose down"
  186. :switches '((?o "Remove orphans" "--remove-orphans")
  187. (?v "Remove volumes" "--volumes"))
  188. :options '((?t "Timeout" "--timeout "))
  189. :actions `((?W "Down" docker-compose-down)
  190. (?A "All services" ,(docker-compose--all docker-compose-down))))
  191. (magit-define-popup docker-compose-exec-popup
  192. "Popup for \"docker-compose exec\"."
  193. 'docker-compose
  194. :man-page "docker-compose exec"
  195. :switches '((?T "Disable pseudo-tty" "-T")
  196. (?d "Detach" "--detach")
  197. (?p "Privileged" "--privileged"))
  198. :options '((?e "Env KEY=VAL" "-e ")
  199. (?u "User " "--user ")
  200. (?w "Workdir" "--workdir "))
  201. :actions '((?E "Exec" docker-compose-exec)))
  202. (magit-define-popup docker-compose-logs-popup
  203. "Popup for \"docker-compose logs\"."
  204. 'docker-compose
  205. :man-page "docker-compose logs"
  206. :switches '((?f "Follow" "--follow")
  207. (?n "No color" "--no-color")
  208. (?t "Timestamps" "--timestamps"))
  209. :options '((?T "Tail" "--tail="))
  210. :actions `((?L "Logs" docker-compose-logs)
  211. (?A "All services" ,(docker-compose--all docker-compose-logs))))
  212. (magit-define-popup docker-compose-pull-popup
  213. "Popup for \"docker-compose pull\"."
  214. 'docker-compose
  215. :man-page "docker-compose pull"
  216. :switches '((?d "Include dependencies" "--include-deps")
  217. (?i "Ignore pull failures" "--ignore-pull-failures")
  218. (?n "No parallel" "--no-parallel"))
  219. :actions `((?F "Pull" docker-compose-pull)
  220. (?A "All services" ,(docker-compose--all docker-compose-pull))))
  221. (magit-define-popup docker-compose-push-popup
  222. "Popup for \"docker-compose push\"."
  223. 'docker-compose
  224. :man-page "docker-compose push"
  225. :switches '((?i "Ignore push failures" "--ignore-push-failures"))
  226. :actions `((?P "Push" docker-compose-push)
  227. (?A "All services" ,(docker-compose--all docker-compose-push))))
  228. (magit-define-popup docker-compose-restart-popup
  229. "Popup for \"docker-compose restart\"."
  230. 'docker-compose
  231. :man-page "docker-compose restart"
  232. :options '((?t "Timeout" "--timeout "))
  233. :actions `((?T "Restart" docker-compose-restart)
  234. (?A "All services" ,(docker-compose--all docker-compose-restart))))
  235. (magit-define-popup docker-compose-rm-popup
  236. "Popup for \"docker-compose rm\"."
  237. 'docker-compose
  238. :man-page "docker-compose rm"
  239. :switches '((?f "Force" "--force")
  240. (?s "Stop" "--stop")
  241. (?v "Remove anonymous volumes" "-v"))
  242. :actions `((?D "Remove" docker-compose-rm)
  243. (?A "All services" ,(docker-compose--all docker-compose-rm))))
  244. (magit-define-popup docker-compose-run-popup
  245. "Popup for \"docker-compose run\"."
  246. 'docker-compose
  247. :man-page "docker-compose run"
  248. :switches '((?T "Disable pseudo-tty" "-T")
  249. (?d "Detach" "--detach")
  250. (?n "No deps" "--no-deps")
  251. (?r "Remove container when it exits" "--rm")
  252. (?s "Enable services ports" "--service-ports"))
  253. :options '((?E "Entrypoint" "--entrypoint ")
  254. (?e "Env KEY=VAL" "-e ")
  255. (?l "Label" "--label ")
  256. (?n "Name" "--name ")
  257. (?u "User " "--user ")
  258. (?w "Workdir" "--workdir "))
  259. :actions '((?R "Run" docker-compose-run)))
  260. (magit-define-popup docker-compose-start-popup
  261. "Popup for \"docker-compose start\"."
  262. 'docker-compose
  263. :man-page "docker-compose start"
  264. :actions `((?S "Start" docker-compose-start)
  265. (?A "All services" ,(docker-compose--all docker-compose-start))))
  266. (magit-define-popup docker-compose-stop-popup
  267. "Popup for \"docker-compose stop\"."
  268. 'docker-compose
  269. :man-page "docker-compose stop"
  270. :options '((?t "Timeout" "--timeout "))
  271. :actions `((?O "Stop" docker-compose-stop)
  272. (?A "All services" ,(docker-compose--all docker-compose-stop))))
  273. (magit-define-popup docker-compose-up-popup
  274. "Popup for \"docker-compose up\"."
  275. 'docker-compose
  276. :man-page "docker-compose up"
  277. :switches '((?b "Build" "--build")
  278. (?d "Detach" "--detach")
  279. (?f "Force recreate" "--force-recreate")
  280. (?n "No deps" "--no-deps")
  281. (?r "Remove orphans" "--remove-orphans"))
  282. :options '((?c "Scale" "--scale ")
  283. (?t "Timeout" "--timeout "))
  284. :actions `((?U "Up" docker-compose-up)
  285. (?A "All services" ,(docker-compose--all docker-compose-up))))
  286. ;;;###autoload (autoload 'docker-compose "docker-compose" nil t)
  287. (magit-define-popup docker-compose
  288. "Popup for docker-compose."
  289. 'docker-compose
  290. :man-page "docker-compose"
  291. :switches '((?a "No ANSI" "--no-ansi")
  292. (?c "Compatibility" "--compatibility")
  293. (?v "Verbose" "--verbose"))
  294. :options `((?d "Project directory" "--project-directory " docker-compose-read-directory)
  295. (?f "Compose file" "--file " docker-compose-read-compose-file)
  296. (?h "Host" "--host ")
  297. (?l "Log level" "--log-level " docker-compose-read-log-level)
  298. (?p "Project name" "--project-name "))
  299. :actions `("Docker-compose"
  300. (?B "Build" ,(docker-utils-set-then-call 'docker-compose-arguments 'docker-compose-build-popup))
  301. (?C "Create" ,(docker-utils-set-then-call 'docker-compose-arguments 'docker-compose-create-popup))
  302. (?D "Remove" ,(docker-utils-set-then-call 'docker-compose-arguments 'docker-compose-rm-popup))
  303. (?E "Exec" ,(docker-utils-set-then-call 'docker-compose-arguments 'docker-compose-exec-popup))
  304. (?F "Pull" ,(docker-utils-set-then-call 'docker-compose-arguments 'docker-compose-pull-popup))
  305. (?L "Logs" ,(docker-utils-set-then-call 'docker-compose-arguments 'docker-compose-logs-popup))
  306. (?O "Stop" ,(docker-utils-set-then-call 'docker-compose-arguments 'docker-compose-stop-popup))
  307. (?P "Push" ,(docker-utils-set-then-call 'docker-compose-arguments 'docker-compose-push-popup))
  308. (?R "Run" ,(docker-utils-set-then-call 'docker-compose-arguments 'docker-compose-run-popup))
  309. (?S "Start" ,(docker-utils-set-then-call 'docker-compose-arguments 'docker-compose-start-popup))
  310. (?T "Restart" ,(docker-utils-set-then-call 'docker-compose-arguments 'docker-compose-restart-popup))
  311. (?U "Up" ,(docker-utils-set-then-call 'docker-compose-arguments 'docker-compose-up-popup))
  312. (?W "Down" ,(docker-utils-set-then-call 'docker-compose-arguments 'docker-compose-down-popup))))
  313. (provide 'docker-compose)
  314. ;;; docker-compose.el ends here