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.

274 lines
9.9 KiB

  1. ;;; docker-image.el --- Emacs interface to docker-image -*- 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 'json)
  23. (require 'tablist)
  24. (require 'magit-popup)
  25. (require 'docker-group)
  26. (require 'docker-process)
  27. (require 'docker-utils)
  28. (defgroup docker-image nil
  29. "Docker images customization group."
  30. :group 'docker)
  31. (defcustom docker-image-default-sort-key '("Repository" . nil)
  32. "Sort key for docker images.
  33. This should be a cons cell (NAME . FLIP) where
  34. NAME is a string matching one of the column names
  35. and FLIP is a boolean to specify the sort order."
  36. :group 'docker-image
  37. :type '(cons (choice (const "Repository")
  38. (const "Tag")
  39. (const "Id")
  40. (const "Created")
  41. (const "Size"))
  42. (choice (const :tag "Ascending" nil)
  43. (const :tag "Descending" t))))
  44. (defcustom docker-image-run-arguments '("-i" "-t" "--rm")
  45. "Default arguments for `docker-image-run-popup'."
  46. :group 'docker-image
  47. :type '(repeat (string :tag "Argument")))
  48. (defun docker-image-parse (line)
  49. "Convert a LINE from \"docker image ls\" to a `tabulated-list-entries' entry."
  50. (condition-case nil
  51. (let* ((data (json-read-from-string line))
  52. (name (format "%s:%s" (aref data 0) (aref data 1))))
  53. (setf (aref data 3) (format-time-string "%F %T" (date-to-time (aref data 3))))
  54. (list (if (s-contains? "<none>" name) (aref data 2) name) data))
  55. (json-readtable-error
  56. (error "Could not read following string as json:\n%s" line))))
  57. (defun docker-image-entries ()
  58. "Return the docker images data for `tabulated-list-entries'."
  59. (let* ((fmt (if (docker-utils-podman-p) "json" "[{{json .Repository}},{{json .Tag}},{{json .ID}},{{json .CreatedAt}},{{json .Size}}]"))
  60. (data (docker-run "image ls" docker-image-ls-arguments (format "--format=\"%s\"" fmt)))
  61. (lines (s-split "\n" data t)))
  62. (-map #'docker-image-parse lines)))
  63. (defun docker-image-refresh ()
  64. "Refresh the images list."
  65. (setq tabulated-list-entries (docker-image-entries)))
  66. (defun docker-image-read-name ()
  67. "Read an image name."
  68. (completing-read "Image: " (-map #'car (docker-image-entries))))
  69. (defun docker-image-human-size-predicate (a b)
  70. "Sort A and B by image size."
  71. (let* ((a-size (elt (cadr a) 4))
  72. (b-size (elt (cadr b) 4)))
  73. (< (docker-utils-human-size-to-bytes a-size) (docker-utils-human-size-to-bytes b-size))))
  74. ;;;###autoload
  75. (defun docker-pull (name &optional all)
  76. "Pull the image named NAME. If ALL is set, use \"-a\"."
  77. (interactive (list (docker-image-read-name) current-prefix-arg))
  78. (docker-run "pull" (when all "-a ") name))
  79. ;;;###autoload
  80. (defun docker-push (name)
  81. "Push the image named NAME."
  82. (interactive (list (docker-image-read-name)))
  83. (docker-run "push" name))
  84. ;;;###autoload
  85. (defun docker-rmi (name &optional force no-prune)
  86. "Destroy or untag the image named NAME.
  87. Force removal of the image when FORCE is set.
  88. Do not delete untagged parents when NO-PRUNE is set."
  89. (interactive (list (docker-image-read-name) current-prefix-arg))
  90. (docker-run "rmi" (when force "-f") (when no-prune "--no-prune") name))
  91. ;;;###autoload
  92. (defun docker-tag (image name)
  93. "Tag IMAGE using NAME."
  94. (interactive (list (docker-image-read-name) (read-string "Name: ")))
  95. (docker-run "tag" image name))
  96. (defun docker-image-inspect-selection ()
  97. "Run \"docker inspect\" on the images selection."
  98. (interactive)
  99. (--each (docker-utils-get-marked-items-ids)
  100. (docker-utils-with-buffer (format "inspect %s" it)
  101. (insert (docker-run "inspect" (docker-image-inspect-arguments) it))
  102. (json-mode))))
  103. (defun docker-image-pull-selection ()
  104. "Run \"docker pull\" on the images selection."
  105. (interactive)
  106. (--each (docker-utils-get-marked-items-ids)
  107. (docker-run "pull" (docker-image-pull-arguments) it))
  108. (tablist-revert))
  109. (defun docker-image-push-selection ()
  110. "Run \"docker push\" on the images selection."
  111. (interactive)
  112. (--each (docker-utils-get-marked-items-ids)
  113. (docker-run "push" (docker-image-push-arguments) it)))
  114. (defun docker-image-rm-selection ()
  115. "Run \"docker rmi\" on the images selection."
  116. (interactive)
  117. (--each (docker-utils-get-marked-items-ids)
  118. (docker-run "rmi" (docker-image-rm-arguments) it))
  119. (tablist-revert))
  120. (defun docker-image-run-selection (command)
  121. "Run \"docker run\" with COMMAND on the images selection."
  122. (interactive "sCommand: ")
  123. (let ((default-directory (if (and docker-run-as-root
  124. (not (file-remote-p default-directory)))
  125. "/sudo::"
  126. default-directory)))
  127. (--each (docker-utils-get-marked-items-ids)
  128. (async-shell-command
  129. (format "%s run %s %s %s" docker-command (s-join " " (docker-image-run-arguments)) it command)
  130. (generate-new-buffer (format "*run %s*" it))))))
  131. (defun docker-image-tag-selection ()
  132. "Tag images."
  133. (interactive)
  134. (docker-utils-select-if-empty)
  135. (--each (docker-utils-get-marked-items-ids)
  136. (docker-tag it (read-string (format "Tag for %s: " it))))
  137. (tablist-revert))
  138. (magit-define-popup docker-image-inspect-popup
  139. "Popup for inspecting images."
  140. 'docker-image
  141. :man-page "docker-inspect"
  142. :actions '((?I "Inspect" docker-image-inspect-selection))
  143. :setup-function #'docker-utils-setup-popup)
  144. (magit-define-popup docker-image-ls-popup
  145. "Popup for listing images."
  146. 'docker-image
  147. :man-page "docker-image-ls"
  148. :switches '((?a "All" "--all")
  149. (?d "Dangling" "-f dangling=true")
  150. (?n "Don't truncate" "--no-trunc"))
  151. :options '((?f "Filter" "--filter "))
  152. :actions `((?l "List" ,(docker-utils-set-then-call 'docker-image-ls-arguments 'tablist-revert))))
  153. (magit-define-popup docker-image-pull-popup
  154. "Popup for pulling images."
  155. 'docker-image
  156. :man-page "docker-pull"
  157. :switches '((?a "All" "-a"))
  158. :actions '((?F "Pull" docker-image-pull-selection))
  159. :setup-function #'docker-utils-setup-popup)
  160. (magit-define-popup docker-image-push-popup
  161. "Popup for pushing images."
  162. 'docker-image
  163. :man-page "docker-push"
  164. :actions '((?P "Push" docker-image-push-selection))
  165. :setup-function #'docker-utils-setup-popup)
  166. (magit-define-popup docker-image-rm-popup
  167. "Popup for removing images."
  168. 'docker-image
  169. :man-page "docker-rmi"
  170. :switches '((?f "Force" "-f")
  171. (?n "Don't prune" "--no-prune"))
  172. :actions '((?D "Remove" docker-image-rm-selection))
  173. :setup-function #'docker-utils-setup-popup)
  174. (magit-define-popup docker-image-run-popup
  175. "Popup for running images."
  176. 'docker-image
  177. :man-page "docker-run"
  178. :switches '((?D "With display" "-v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY")
  179. (?T "Synchronize time" "-v /etc/localtime:/etc/localtime:ro")
  180. (?W "Web ports" "-p 80:80 -p 443:443 -p 8080:8080")
  181. (?d "Daemonize" "-d")
  182. (?i "Interactive" "-i")
  183. (?o "Read only" "--read-only")
  184. (?p "Privileged" "--privileged")
  185. (?r "Remove container when it exits" "--rm")
  186. (?t "TTY" "-t"))
  187. :options '((?e "environment" "-e ")
  188. (?m "name" "--name ")
  189. (?n "entrypoint" "--entrypoint ")
  190. (?p "port" "-p ")
  191. (?u "user" "-u ")
  192. (?v "volume" "-v ")
  193. (?w "workdir" "-w "))
  194. :actions '((?R "Run images" docker-image-run-selection))
  195. :setup-function #'docker-utils-setup-popup)
  196. (magit-define-popup docker-image-help-popup
  197. "Help popup for docker images."
  198. 'docker-image
  199. :actions '("Docker images help"
  200. (?D "Remove" docker-image-rm-popup)
  201. (?F "Pull" docker-image-pull-popup)
  202. (?I "Inspect" docker-image-inspect-popup)
  203. (?P "Push" docker-image-push-popup)
  204. (?R "Run" docker-image-run-popup)
  205. (?T "Tag" docker-image-tag-selection)
  206. (?l "List" docker-image-ls-popup)))
  207. (defvar docker-image-mode-map
  208. (let ((map (make-sparse-keymap)))
  209. (define-key map "?" 'docker-image-help-popup)
  210. (define-key map "D" 'docker-image-rm-popup)
  211. (define-key map "F" 'docker-image-pull-popup)
  212. (define-key map "I" 'docker-image-inspect-popup)
  213. (define-key map "P" 'docker-image-push-popup)
  214. (define-key map "R" 'docker-image-run-popup)
  215. (define-key map "T" 'docker-image-tag-selection)
  216. (define-key map "l" 'docker-image-ls-popup)
  217. map)
  218. "Keymap for `docker-image-mode'.")
  219. ;;;###autoload
  220. (defun docker-images ()
  221. "List docker images."
  222. (interactive)
  223. (docker-utils-pop-to-buffer "*docker-images*")
  224. (docker-image-mode)
  225. (tablist-revert))
  226. (define-derived-mode docker-image-mode tabulated-list-mode "Images Menu"
  227. "Major mode for handling a list of docker images."
  228. (setq tabulated-list-format [("Repository" 30 t)("Tag" 20 t)("Id" 16 t)("Created" 23 t)("Size" 10 docker-image-human-size-predicate)])
  229. (setq tabulated-list-padding 2)
  230. (setq tabulated-list-sort-key docker-image-default-sort-key)
  231. (add-hook 'tabulated-list-revert-hook 'docker-image-refresh nil t)
  232. (tabulated-list-init-header)
  233. (tablist-minor-mode))
  234. (provide 'docker-image)
  235. ;;; docker-image.el ends here