/ docker-container.el
docker-container.el
1 ;;; docker-container.el --- Interface to docker-container -*- lexical-binding: t -*- 2 3 ;; Author: Philippe Vaucher <philippe.vaucher@gmail.com> 4 ;; Yuki Inoue <inouetakahiroki@gmail.com> 5 6 ;; This file is NOT part of GNU Emacs. 7 8 ;; This program is free software; you can redistribute it and/or modify 9 ;; it under the terms of the GNU General Public License as published by 10 ;; the Free Software Foundation; either version 3, or (at your option) 11 ;; any later version. 12 ;; 13 ;; This program is distributed in the hope that it will be useful, 14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 ;; GNU General Public License for more details. 17 ;; 18 ;; You should have received a copy of the GNU General Public License 19 ;; along with GNU Emacs; see the file COPYING. If not, write to the 20 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 ;; Boston, MA 02110-1301, USA. 22 23 ;;; Commentary: 24 25 ;;; Code: 26 (eval-when-compile 27 (setq-local byte-compile-warnings '(not docstrings))) 28 29 (require 's) 30 (require 'aio) 31 (require 'dash) 32 (require 'json) 33 (require 'tablist) 34 (require 'transient) 35 36 (require 'docker-core) 37 (require 'docker-faces) 38 (require 'docker-utils) 39 40 (defgroup docker-container nil 41 "Docker container customization group." 42 :group 'docker) 43 44 (defconst docker-container-id-template 45 "{{ json .Names }}" 46 "This Go template extracts the container id which will be passed to transient commands.") 47 48 (defcustom docker-container-shell-file-name "/bin/sh" 49 "Shell to use when entering containers." 50 :group 'docker-container 51 :type 'string) 52 53 (defcustom docker-container-tramp-method "docker" 54 "TRAMP method to use for connecting to Docker containers." 55 :group 'docker-container 56 :type 'string) 57 58 (defcustom docker-container-default-sort-key '("Image" . nil) 59 "Sort key for docker containers. 60 61 This should be a cons cell (NAME . FLIP) where 62 NAME is a string matching one of the column names 63 and FLIP is a boolean to specify the sort order." 64 :group 'docker-container 65 :type '(cons (string :tag "Column Name" 66 :validate (lambda (widget) 67 (unless (--any-p (equal (plist-get it :name) (widget-value widget)) docker-container-columns) 68 (widget-put widget :error "Default Sort Key must match a column name") 69 widget))) 70 (choice (const :tag "Ascending" nil) 71 (const :tag "Descending" t)))) 72 73 (defcustom docker-container-columns 74 '((:name "Id" :width 16 :template "{{ json .ID }}" :sort nil :format nil) 75 (:name "Image" :width 15 :template "{{ json .Image }}" :sort nil :format nil) 76 (:name "Command" :width 30 :template "{{ json .Command }}" :sort nil :format nil) 77 (:name "Created" :width 23 :template "{{ json .CreatedAt }}" :sort nil :format (lambda (x) (format-time-string "%F %T" (date-to-time x)))) 78 (:name "Status" :width 20 :template "{{ json .Status }}" :sort nil :format nil) 79 (:name "Ports" :width 10 :template "{{ json .Ports }}" :sort nil :format nil) 80 (:name "Names" :width 10 :template "{{ json .Names }}" :sort nil :format nil)) 81 "Column specification for docker containers. 82 83 The order of entries defines the displayed column order. 'Template' is 84 the Go template passed to `docker-container-ls' to create the column data. 85 It should return a string delimited with double quotes. 'Sort function' is 86 a binary predicate that should return true when the first argument should be 87 sorted before the second. 'Format function' is a function from string to 88 string that transforms the displayed values in the column." 89 :group 'docker-container 90 :set 'docker-utils-columns-setter 91 :get 'docker-utils-columns-getter 92 :type '(repeat (list :tag "Column" 93 (string :tag "Name") 94 (integer :tag "Width") 95 (string :tag "Template") 96 (sexp :tag "Sort function") 97 (sexp :tag "Format function")))) 98 99 (defalias 'docker-container-inspect 'docker-inspect) 100 101 (defun docker-container--read-shell (&optional read-shell-name) 102 "Return `docker-container-shell-file-name' or read a shell name if READ-SHELL-NAME is truthy." 103 (if read-shell-name (read-shell-command "Shell: ") docker-container-shell-file-name)) 104 105 (defun docker-container-status-face (status) 106 "Return the correct face according to STATUS." 107 (cond 108 ((s-starts-with? "Up" status) 109 'docker-face-status-up) 110 ((s-starts-with? "Exited" status) 111 'docker-face-status-down) 112 (t 113 'docker-face-status-other))) 114 115 (aio-defun docker-container-entries (&rest args) 116 "Return the docker containers data for `tabulated-list-entries'." 117 (let* ((fmt (docker-utils-make-format-string docker-container-id-template docker-container-columns)) 118 (data (aio-await (docker-run-docker-async "container" "ls" args (format "--format=\"%s\"" fmt)))) 119 (lines (s-split "\n" data t))) 120 (-map (-partial #'docker-utils-parse docker-container-columns) lines))) 121 122 (aio-defun docker-container-entries-propertized (&rest args) 123 "Return the propertized docker containers data for `tabulated-list-entries'." 124 (let ((entries (aio-await (docker-container-entries args)))) 125 (-map #'docker-container-propertize-entry entries))) 126 127 (defun docker-container-propertize-entry (entry) 128 "Propertize ENTRY." 129 (let* ((index (--find-index (string-equal "Status" (plist-get it :name)) docker-container-columns)) 130 (data (cadr entry)) 131 (status (aref data index))) 132 (aset data index (propertize status 'font-lock-face (docker-container-status-face status))) 133 entry)) 134 135 (aio-defun docker-container-update-status-async () 136 "Write the status to `docker-status-strings'." 137 (plist-put docker-status-strings :containers "Containers") 138 (when (or (eq docker-show-status t) (and (eq docker-show-status 'local-only) (not (file-remote-p default-directory)))) 139 (let* ((entries (aio-await (docker-container-entries-propertized (docker-container-ls-arguments)))) 140 (index (--find-index (string-equal "Status" (plist-get it :name)) docker-container-columns)) 141 (statuses (--map (aref (cadr it) index) entries)) 142 (faces (--map (get-text-property 0 'font-lock-face it) statuses)) 143 (all (length faces)) 144 (up (-count (-partial #'equal 'docker-face-status-up) faces)) 145 (down (-count (-partial #'equal 'docker-face-status-down) faces)) 146 (other (- all up down))) 147 (plist-put docker-status-strings 148 :containers 149 (format "Containers (%s total, %s up, %s down, %s other)" 150 all 151 (propertize (number-to-string up) 'face 'docker-face-status-up) 152 (propertize (number-to-string down) 'face 'docker-face-status-down) 153 (propertize (number-to-string other) 'face 'docker-face-status-other))) 154 (transient--redisplay)))) 155 156 (add-hook 'docker-open-hook #'docker-container-update-status-async) 157 158 (aio-defun docker-container-refresh () 159 "Refresh the containers list." 160 (docker-utils-refresh-entries 161 (docker-container-entries-propertized (docker-container-ls-arguments)))) 162 163 (defun docker-container-read-name () 164 "Read an container name." 165 (completing-read "Container: " (-map #'car (aio-wait-for (docker-container-entries))))) 166 167 (defvar eshell-buffer-name) 168 169 ;;;###autoload (autoload 'docker-container-eshell "docker-container" nil t) 170 (defun docker-container-eshell (container) 171 "Open `eshell' in CONTAINER." 172 (interactive (list (docker-container-read-name))) 173 (let* ((container-address (format "%s:%s:/" docker-container-tramp-method container)) 174 (file-prefix (let ((prefix (file-remote-p default-directory))) 175 (if prefix 176 (format "%s|" (s-chop-suffix ":" prefix)) 177 "/"))) 178 (default-directory (format "%s%s" file-prefix container-address)) 179 (eshell-buffer-name (docker-utils-generate-new-buffer-name "docker" "eshell:" default-directory))) 180 (eshell))) 181 182 (defun docker-container-assert-tramp-docker () 183 "Assert tramp docker support is available." 184 (unless (or (assoc docker-container-tramp-method tramp-methods) 185 (docker-utils-package-p 'docker-tramp)) 186 (error "Tramp docker support was not detected, try installing docker-tramp"))) 187 188 ;;;###autoload (autoload 'docker-container-find-directory "docker-container" nil t) 189 (defun docker-container-find-directory (container directory) 190 "Inside CONTAINER open DIRECTORY." 191 (interactive 192 (let* ((container-name (docker-container-read-name)) 193 (tramp-filename (read-directory-name "Directory: " (format "/%s:%s:/" docker-container-tramp-method container-name)))) 194 (with-parsed-tramp-file-name tramp-filename nil 195 (list host localname)))) 196 (docker-container-assert-tramp-docker) 197 (dired (format "/%s:%s:%s" docker-container-tramp-method container directory))) 198 199 (defalias 'docker-container-dired 'docker-container-find-directory) 200 201 ;;;###autoload (autoload 'docker-container-find-file "docker-container" nil t) 202 (defun docker-container-find-file (container file) 203 "Open FILE inside CONTAINER." 204 (interactive 205 (let* ((container-name (docker-container-read-name)) 206 (tramp-filename (read-file-name "File: " (format "/%s:%s:/" docker-container-tramp-method container-name)))) 207 (with-parsed-tramp-file-name tramp-filename nil 208 (list host localname)))) 209 (docker-container-assert-tramp-docker) 210 (find-file (format "/%s:%s:%s" docker-container-tramp-method container file))) 211 212 ;;;###autoload (autoload 'docker-container-shell "docker-container" nil t) 213 (defun docker-container-shell (container &optional read-shell) 214 "Open `shell' in CONTAINER. When READ-SHELL is not nil, ask the user for it." 215 (interactive (list 216 (docker-container-read-name) 217 current-prefix-arg)) 218 (let* ((shell-file-name (docker-container--read-shell read-shell)) 219 (container-address (format "%s:%s:/" docker-container-tramp-method container)) 220 (file-prefix (let ((prefix (file-remote-p default-directory))) 221 (if prefix 222 (format "%s|" (s-chop-suffix ":" prefix)) 223 "/"))) 224 (default-directory (format "%s%s" file-prefix container-address))) 225 (shell (docker-utils-generate-new-buffer "docker" "shell:" default-directory)))) 226 227 ;;;###autoload (autoload 'docker-container-shell-env "docker-container" nil t) 228 (aio-defun docker-container-shell-env (container &optional read-shell) 229 "Open `shell' in CONTAINER with the environment variable set 230 and default directory set to workdir. When READ-SHELL is not 231 nil, ask the user for it." 232 (interactive (list 233 (docker-container-read-name) 234 current-prefix-arg)) 235 (docker-container-assert-tramp-docker) 236 (let* ((shell-file-name (docker-container--read-shell read-shell)) 237 (container-address (format "%s:%s:" docker-container-tramp-method container)) 238 (file-prefix (let ((prefix (file-remote-p default-directory))) 239 (if prefix 240 (format "%s|" (s-chop-suffix ":" prefix)) 241 "/"))) 242 (container-config (cdr (assq 'Config (aref (json-read-from-string (aio-await (docker-run-docker-async "inspect" container))) 0)))) 243 (container-workdir (cdr (assq 'WorkingDir container-config))) 244 (container-env (cdr (assq 'Env container-config))) 245 (default-directory (format "%s%s%s" file-prefix container-address container-workdir)) 246 ;; process-environment doesn't work with tramp if you call this function more than one per emacs session 247 (tramp-remote-process-environment (append container-env nil))) 248 (shell (docker-utils-generate-new-buffer "docker" "shell-env:" default-directory)))) 249 250 ;;;###autoload (autoload 'docker-container-vterm "docker-container" nil t) 251 (defun docker-container-vterm (container) 252 "Open `vterm' in CONTAINER." 253 (interactive (list (docker-container-read-name))) 254 (if (fboundp 'vterm-other-window) 255 (let* ((container-address (format "%s:%s:/" docker-container-tramp-method container)) 256 (file-prefix (let ((prefix (file-remote-p default-directory))) 257 (if prefix 258 (format "%s|" (s-chop-suffix ":" prefix)) 259 "/"))) 260 (default-directory (format "%s%s" file-prefix container-address))) 261 (vterm-other-window (docker-utils-generate-new-buffer-name "docker" "vterm:" default-directory))) 262 (error "The vterm package is not installed"))) 263 264 ;;;###autoload (autoload 'docker-container-vterm-env "docker-container" nil t) 265 (aio-defun docker-container-vterm-env (container) 266 "Open `vterm' in CONTAINER with the environment variable set and 267 default directory set to workdir." 268 (interactive (list 269 (docker-container-read-name))) 270 (docker-container-assert-tramp-docker) 271 (let* ((container-address (format "%s:%s:" docker-container-tramp-method container)) 272 (file-prefix (let ((prefix (file-remote-p default-directory))) 273 (if prefix 274 (format "%s|" (s-chop-suffix ":" prefix)) 275 "/"))) 276 (container-config (cdr (assq 'Config (aref (json-read-from-string (aio-await (docker-run-docker-async "inspect" container))) 0)))) 277 (container-workdir (cdr (assq 'WorkingDir container-config))) 278 (container-env (cdr (assq 'Env container-config))) 279 (default-directory (format "%s%s%s" file-prefix container-address container-workdir)) 280 ;; process-environment doesn't work with tramp if you call this function more than one per emacs session 281 (tramp-remote-process-environment (append container-env nil))) 282 (if (fboundp 'vterm-other-window) 283 (vterm-other-window (docker-utils-generate-new-buffer-name "docker" "vterm-env:" default-directory)) 284 (error "The vterm package is not installed")))) 285 286 (defvar eat-buffer-name) 287 288 ;;;###autoload (autoload 'docker-container-eat "docker-container" nil t) 289 (defun docker-container-eat (container) 290 "Open `eat' in CONTAINER." 291 (interactive (list (docker-container-read-name))) 292 (if (fboundp 'eat-other-window) 293 (let* ((container-address (format "%s:%s:/" docker-container-tramp-method container)) 294 (file-prefix (let ((prefix (file-remote-p default-directory))) 295 (if prefix 296 (format "%s|" (s-chop-suffix ":" prefix)) 297 "/"))) 298 (default-directory (format "%s%s" file-prefix container-address)) 299 (eat-buffer-name (format "*eat:%s" default-directory))) 300 (eat-other-window)) 301 (error "The eat package is not installed"))) 302 303 ;;;###autoload (autoload 'docker-container-eat-env "docker-container" nil t) 304 (aio-defun docker-container-eat-env (container) 305 "Open `eat' in CONTAINER with the environment variable set and 306 default directory set to workdir." 307 (interactive (list 308 (docker-container-read-name))) 309 (docker-container-assert-tramp-docker) 310 (let* ((container-address (format "%s:%s:" docker-container-tramp-method container)) 311 (file-prefix (let ((prefix (file-remote-p default-directory))) 312 (if prefix 313 (format "%s|" (s-chop-suffix ":" prefix)) 314 "/"))) 315 (container-config (cdr (assq 'Config (aref (json-read-from-string (aio-await (docker-run-docker-async "inspect" container))) 0)))) 316 (container-workdir (cdr (assq 'WorkingDir container-config))) 317 (container-env (cdr (assq 'Env container-config))) 318 (default-directory (format "%s%s%s" file-prefix container-address container-workdir)) 319 ;; process-environment doesn't work with tramp if you call this function more than one per emacs session 320 (tramp-remote-process-environment (append container-env nil)) 321 (eat-buffer-name (format "*eat-env:%s" default-directory))) 322 (if (fboundp 'eat-other-window) 323 (eat-other-window) 324 (error "The eat package is not installed")))) 325 326 (defun docker-container-cp-from-selection (container-path host-path) 327 "Run \"docker cp\" from CONTAINER-PATH to HOST-PATH for selected container." 328 (interactive "sContainer path: \nFHost path: ") 329 (docker-utils-ensure-items) 330 (--each (docker-utils-get-marked-items-ids) 331 (docker-run-docker-async "cp" (concat it ":" container-path) host-path))) 332 333 (defun docker-container-cp-to-selection (host-path container-path) 334 "Run \"docker cp\" from HOST-PATH to CONTAINER-PATH for selected containers." 335 (interactive "fHost path: \nsContainer path: ") 336 (docker-utils-ensure-items) 337 (--each (docker-utils-get-marked-items-ids) 338 (docker-run-docker-async "cp" host-path (concat it ":" container-path)))) 339 340 (defun docker-container-eshell-selection () 341 "Run `docker-container-eshell' on the containers selection." 342 (interactive) 343 (docker-utils-ensure-items) 344 (--each (docker-utils-get-marked-items-ids) 345 (docker-container-eshell it))) 346 347 (defun docker-container-find-directory-selection (path) 348 "Run `docker-container-find-directory' for PATH on the containers selection." 349 (interactive "sPath: ") 350 (docker-utils-ensure-items) 351 (--each (docker-utils-get-marked-items-ids) 352 (docker-container-find-directory it path))) 353 354 (defun docker-container-find-file-selection (path) 355 "Run `docker-container-find-file' for PATH on the containers selection." 356 (interactive "sPath: ") 357 (docker-utils-ensure-items) 358 (--each (docker-utils-get-marked-items-ids) 359 (docker-container-find-file it path))) 360 361 (aio-defun docker-container-rename-selection () 362 "Rename containers." 363 (interactive) 364 (docker-utils-ensure-items) 365 (--each (docker-utils-get-marked-items-ids) 366 (aio-await (docker-run-docker-async "rename" it (read-string (format "Rename \"%s\" to: " it))))) 367 (tablist-revert)) 368 369 (defun docker-container-shell-selection (prefix) 370 "Run `docker-container-shell' on the containers selection forwarding PREFIX." 371 (interactive "P") 372 (docker-utils-ensure-items) 373 (--each (docker-utils-get-marked-items-ids) 374 (docker-container-shell it prefix))) 375 376 (defun docker-container-shell-env-selection (prefix) 377 "Run `docker-container-shell-env' on the containers selection forwarding PREFIX." 378 (interactive "P") 379 (docker-utils-ensure-items) 380 (--each (docker-utils-get-marked-items-ids) 381 (docker-container-shell-env it prefix))) 382 383 (defun docker-container-vterm-selection () 384 "Run `docker-container-vterm' on the containers selection." 385 (interactive) 386 (docker-utils-ensure-items) 387 (--each (docker-utils-get-marked-items-ids) 388 (docker-container-vterm it))) 389 390 (defun docker-container-vterm-env-selection () 391 "Run `docker-container-vterm-env' on the containers selection." 392 (interactive) 393 (docker-utils-ensure-items) 394 (--each (docker-utils-get-marked-items-ids) 395 (docker-container-vterm-env it))) 396 397 (defun docker-container-shell-command (container) 398 "Run exec of a CONTAINER." 399 (interactive (list (docker-container-read-name))) 400 (let* ((default-command (string-join (append (list docker-command) 401 (docker-arguments) 402 (list "exec" container)) 403 " ")) 404 (command (read-shell-command "Run: " default-command))) 405 (shell-command command))) 406 407 (defun docker-container-shell-command-selection () 408 "Run `docker exec' on the containers selection." 409 (interactive) 410 (docker-utils-ensure-items) 411 (--each (docker-utils-get-marked-items-ids) 412 (docker-container-shell-command it))) 413 414 (defun docker-container-eat-selection () 415 "Run `docker-container-eat' on the containers selection." 416 (interactive) 417 (docker-utils-ensure-items) 418 (--each (docker-utils-get-marked-items-ids) 419 (docker-container-eat it))) 420 421 (defun docker-container-eat-env-selection () 422 "Run `docker-container-eat-env' on the containers selection." 423 (interactive) 424 (docker-utils-ensure-items) 425 (--each (docker-utils-get-marked-items-ids) 426 (docker-container-eat-env it))) 427 428 (docker-utils-transient-define-prefix docker-container-attach () 429 "Transient for attaching to containers." 430 :man-page "docker-container-attach" 431 ["Arguments" 432 ("n" "No STDIN" "--no-stdin") 433 ("d" "Key sequence for detaching" "--detach-keys " read-string)] 434 [:description docker-generic-action-description 435 ("a" "Attach" docker-generic-action-with-buffer-interactive)]) 436 437 (docker-utils-transient-define-prefix docker-container-cp () 438 "Transient for copying files from/to containers." 439 :man-page "docker-container-cp" 440 [:description docker-generic-action-description 441 ("f" "Copy From" docker-container-cp-from-selection) 442 ("t" "Copy To" docker-container-cp-to-selection)]) 443 444 (docker-utils-transient-define-prefix docker-container-diff () 445 "Transient for showing containers diffs." 446 :man-page "docker-container-diff" 447 [:description docker-generic-action-description 448 ("d" "Diff" docker-generic-action-with-buffer)]) 449 450 (docker-utils-transient-define-prefix docker-container-open () 451 "Transient for opening containers files." 452 [:description docker-generic-action-description 453 ("d" "Open directory" docker-container-find-directory-selection) 454 ("f" "Open file" docker-container-find-file-selection)]) 455 456 (docker-utils-transient-define-prefix docker-container-kill () 457 "Transient for kill signaling containers" 458 :man-page "docker-container-kill" 459 ["Arguments" 460 ("s" "Signal" "-s " read-string)] 461 [:description docker-generic-action-description 462 ("K" "Kill" docker-generic-action-multiple-ids)]) 463 464 (defun docker-container-logs-action (action args) 465 "Show container logs, streaming if -f flag is present, otherwise collect then display. 466 ACTION is the docker action, ARGS are the transient arguments." 467 (interactive (list (docker-get-transient-action) 468 (transient-args transient-current-command))) 469 (if (member "-f" args) 470 (docker-generic-action-with-buffer-noninteractive action args) 471 (aio-wait-for (docker-generic-action-with-buffer action args)))) 472 473 (docker-utils-transient-define-prefix docker-container-logs () 474 "Transient for showing containers logs." 475 :man-page "docker-container-logs" 476 ["Arguments" 477 ("f" "Follow" "-f") 478 ("s" "Since" "--since " read-string) 479 ("t" "Tail" "--tail " read-string) 480 ("u" "Until" "--until " read-string)] 481 [:description docker-generic-action-description 482 ("L" "Logs" docker-container-logs-action)]) 483 484 (docker-utils-define-transient-arguments docker-container-ls) 485 486 (transient-define-prefix docker-container-ls () 487 "Transient for listing containers." 488 :man-page "docker-container-ls" 489 :value '("--all") 490 ["Arguments" 491 ("N" "Last" "--last " transient-read-number-N0) 492 ("a" "All" "--all") 493 ("e" "Exited containers" "--filter status=exited") 494 ("f" "Filter" "--filter " read-string) 495 ("n" "Don't truncate" "--no-trunc")] 496 ["Actions" 497 ("l" "List" tablist-revert)]) 498 499 (docker-utils-transient-define-prefix docker-container-pause () 500 "Transient for pausing containers." 501 :man-page "docker-container-pause" 502 [:description docker-generic-action-description 503 ("P" "Pause" docker-generic-action-multiple-ids)]) 504 505 (docker-utils-transient-define-prefix docker-container-unpause () 506 "Transient for pausing containers." 507 :man-page "docker-container-unpause" 508 [:description docker-generic-action-description 509 ("N" "Unpause" docker-generic-action-multiple-ids)]) 510 511 (docker-utils-transient-define-prefix docker-container-restart () 512 "Transient for restarting containers." 513 :man-page "docker-container-restart" 514 ["Arguments" 515 ("t" "Timeout" "-t " transient-read-number-N0)] 516 [:description docker-generic-action-description 517 ("R" "Restart" docker-generic-action-multiple-ids)]) 518 519 (docker-utils-transient-define-prefix docker-container-rm () 520 "Transient for removing containers." 521 :man-page "docker-container-rm" 522 ["Arguments" 523 ("f" "Force" "-f") 524 ("v" "Volumes" "-v")] 525 [:description docker-generic-action-description 526 ("D" "Remove" docker-generic-action-multiple-ids)]) 527 528 (docker-utils-transient-define-prefix docker-container-shells () 529 "Transient for using shells on containers." 530 [:description docker-generic-action-description 531 ("!" "Shell command" docker-container-shell-command-selection) 532 ("b" "Shell" docker-container-shell-selection) 533 ("B" "Shell with env" docker-container-shell-env-selection) 534 ("e" "Eshell" docker-container-eshell-selection) 535 ("v" "Vterm" docker-container-vterm-selection) 536 ("V" "Vterm with env" docker-container-vterm-env-selection) 537 ("a" "Eat" docker-container-eat-selection) 538 ("A" "Eat with env" docker-container-eat-env-selection)]) 539 540 (docker-utils-transient-define-prefix docker-container-start () 541 "Transient for starting containers." 542 :man-page "docker-container-start" 543 [:description docker-generic-action-description 544 ("S" "Start" docker-generic-action-multiple-ids)]) 545 546 (docker-utils-transient-define-prefix docker-container-stop () 547 "Transient for stoping containers." 548 :man-page "docker-container-stop" 549 ["Arguments" 550 ("t" "Timeout" "-t " transient-read-number-N0)] 551 [:description docker-generic-action-description 552 ("O" "Stop" docker-generic-action-multiple-ids)]) 553 554 (transient-define-prefix docker-container-help () 555 "Help transient for docker containers." 556 ["Docker Containers" 557 ["Lifecycle" 558 ("K" "Kill" docker-container-kill) 559 ("O" "Stop" docker-container-stop) 560 ("N" "Unpause" docker-container-unpause) 561 ("P" "Pause" docker-container-pause) 562 ("R" "Restart" docker-container-restart) 563 ("S" "Start" docker-container-start)] 564 ["Admin" 565 ("C" "Copy" docker-container-cp) 566 ("D" "Remove" docker-container-rm) 567 ("I" "Inspect" docker-container-inspect) 568 ("L" "Logs" docker-container-logs) 569 ("a" "Attach" docker-container-attach) 570 ("b" "Shell" docker-container-shells) 571 ("d" "Diff" docker-container-diff) 572 ("f" "Find file" docker-container-open) 573 ("l" "List" docker-container-ls) 574 ("r" "Rename" docker-container-rename-selection)]]) 575 576 (defvar docker-container-mode-map 577 (let ((map (make-sparse-keymap))) 578 (define-key map "?" 'docker-container-help) 579 (define-key map "C" 'docker-container-cp) 580 (define-key map "D" 'docker-container-rm) 581 (define-key map "I" 'docker-container-inspect) 582 (define-key map "K" 'docker-container-kill) 583 (define-key map "L" 'docker-container-logs) 584 (define-key map "O" 'docker-container-stop) 585 (define-key map "N" 'docker-container-unpause) 586 (define-key map "P" 'docker-container-pause) 587 (define-key map "R" 'docker-container-restart) 588 (define-key map "S" 'docker-container-start) 589 (define-key map "a" 'docker-container-attach) 590 (define-key map "b" 'docker-container-shells) 591 (define-key map "d" 'docker-container-diff) 592 (define-key map "f" 'docker-container-open) 593 (define-key map "l" 'docker-container-ls) 594 (define-key map "r" 'docker-container-rename-selection) 595 map) 596 "Keymap for `docker-container-mode'.") 597 598 ;;;###autoload (autoload 'docker-containers "docker-container" nil t) 599 (defun docker-containers () 600 "List docker containers." 601 (interactive) 602 (docker-utils-pop-to-buffer "*docker-containers*") 603 (docker-container-mode) 604 (tablist-revert)) 605 606 (define-derived-mode docker-container-mode tabulated-list-mode "Containers Menu" 607 "Major mode for handling a list of docker containers." 608 (setq tabulated-list-format (docker-utils-columns-list-format docker-container-columns)) 609 (setq tabulated-list-padding 2) 610 (setq tabulated-list-sort-key docker-container-default-sort-key) 611 (add-hook 'tabulated-list-revert-hook 'docker-container-refresh nil t) 612 (tabulated-list-init-header) 613 (tablist-minor-mode)) 614 615 (provide 'docker-container) 616 617 ;;; docker-container.el ends here