183 lines
6.8 KiB
EmacsLisp
183 lines
6.8 KiB
EmacsLisp
;; kubernetes-utils.el --- Common utilities. -*- lexical-binding: t; -*-
|
|
;;; Commentary:
|
|
;;; Code:
|
|
|
|
(require 'dash)
|
|
(require 'subr-x)
|
|
(require 'term)
|
|
|
|
(require 'kubernetes-ast)
|
|
(require 'kubernetes-kubectl)
|
|
(require 'kubernetes-props)
|
|
(require 'kubernetes-state)
|
|
(require 'kubernetes-timers)
|
|
(require 'kubernetes-vars)
|
|
|
|
(autoload 'org-read-date "org")
|
|
|
|
(defalias 'kubernetes-utils-read-pod-name 'kubernetes-pods--read-name
|
|
"Exporting `kubernetes-pods--read-name'")
|
|
|
|
(defun kubernetes-utils-read-iso-datetime (&rest _)
|
|
(let* ((date (org-read-date nil t))
|
|
(tz (format-time-string "%z" date)))
|
|
(concat
|
|
(format-time-string "%Y-%m-%dT%H:%M:%S" date)
|
|
(replace-regexp-in-string (rx (group (? (any "+-")) digit digit)
|
|
(group digit digit))
|
|
"\\1:\\2"
|
|
tz))))
|
|
|
|
(defun kubernetes-get-pod-container-names (pod)
|
|
"Return the names of all containers available in the specified pod."
|
|
(-let [(&alist 'spec (&alist 'containers containers)) pod]
|
|
(-map (-lambda ((&alist 'name name)) name) containers)))
|
|
|
|
(defun kubernetes-utils-read-container-name (&rest _)
|
|
"Read a container name from the pod at POINT or a user-supplied pod."
|
|
(letrec ((state (kubernetes-state))
|
|
(pod-name (or (kubernetes-utils-maybe-pod-name-at-point)
|
|
(kubernetes-utils-read-pod-name state)))
|
|
(pod (kubernetes-state-lookup-pod pod-name state))
|
|
(pod-containers (kubernetes-get-pod-container-names pod)))
|
|
(completing-read "Container name: " pod-containers nil t)))
|
|
|
|
(defun kubernetes-utils-read-time-value (&rest _)
|
|
"Read a relative time value in the style accepted by kubectl. E.g. 20s, 3h, 5m."
|
|
(let (result)
|
|
(while (null result)
|
|
(let ((input (read-string "Time value (e.g. 20s): ")))
|
|
(if (string-match-p (rx bol (* space) (+ digit) (* space) (any "smh") (* space) eol)
|
|
input)
|
|
(setq result input)
|
|
(message "Invalid time value")
|
|
(sit-for 1))))
|
|
result))
|
|
|
|
(defun kubernetes-utils-maybe-pod-name-at-point ()
|
|
(let ((nav-buffer (get-buffer kubernetes-overview-buffer-name)))
|
|
(with-current-buffer nav-buffer
|
|
(pcase (get-text-property (point) 'kubernetes-nav nav-buffer)
|
|
(`(:pod-name ,value)
|
|
value)))))
|
|
|
|
(defun kubernetes-utils-ellipsize (s threshold)
|
|
(if (> (length s) threshold)
|
|
(concat (substring s 0 (1- threshold)) "…")
|
|
s))
|
|
|
|
(defun kubernetes-utils-parse-utc-timestamp (timestamp)
|
|
"Parse TIMESTAMP string from the API into the representation used by Emacs."
|
|
(let ((parsed (parse-time-string (replace-regexp-in-string "Z" "" (replace-regexp-in-string "T" " " timestamp)))))
|
|
(setf (nth 8 parsed) 0)
|
|
parsed))
|
|
|
|
(defun kubernetes-utils-time-diff-string (start now)
|
|
"Find the interval between START and NOW, and return a string of the coarsest unit."
|
|
(let ((diff (time-to-seconds (time-subtract now start))))
|
|
(car (split-string (format-seconds "%yy,%dd,%hh,%mm,%ss%z" diff) ","))))
|
|
|
|
(defun kubernetes-utils-kill-buffer (proc-buf &rest _)
|
|
(if-let (win (get-buffer-window proc-buf))
|
|
(quit-window t win)
|
|
(kill-buffer proc-buf)))
|
|
|
|
(defun kubernetes-utils-make-cleanup-fn (buf)
|
|
"Make a function to add to `kill-buffer-hook' for a Kubernetes buffer.
|
|
|
|
BUF is the buffer used to display a Kubernetes feature. A
|
|
reference to it is needed to determine which buffers remain.
|
|
|
|
The function will terminate polling when the last Kubernetes
|
|
buffer is killed."
|
|
(lambda ()
|
|
(let* ((bufs (-keep #'get-buffer (list kubernetes-label-query-buffer-name
|
|
kubernetes-overview-buffer-name)))
|
|
(more-buffers (remove buf bufs)))
|
|
(unless more-buffers
|
|
(dolist (b bufs)
|
|
(with-current-buffer b
|
|
(kubernetes-state-clear)))
|
|
(kubernetes-process-kill-polling-processes)
|
|
(kubernetes-timers-kill-timers)))))
|
|
|
|
(defun kubernetes-utils-term-buffer-start (bufname command args)
|
|
;; Kill existing process.
|
|
(when-let ((existing (get-buffer bufname))
|
|
(proc (get-buffer-process existing)))
|
|
(kubernetes-process-kill-quietly proc))
|
|
|
|
(let ((buf (get-buffer-create bufname)))
|
|
(with-current-buffer buf
|
|
(erase-buffer)
|
|
(buffer-disable-undo)
|
|
(term-mode)
|
|
(goto-char (point-min))
|
|
(let ((time-str (format "Session started at %s" (substring (current-time-string) 0 19)))
|
|
(command-str (format "%s %s" command (string-join args " "))))
|
|
(kubernetes-ast-eval
|
|
`((line ,(propertize time-str 'face 'magit-dimmed))
|
|
(padding)
|
|
(line ,(propertize command-str 'face 'magit-dimmed))
|
|
(padding))))
|
|
|
|
(term-exec (current-buffer) "kuberenetes-term" command nil args)
|
|
(let ((proc (get-buffer-process (current-buffer))))
|
|
(set-process-query-on-exit-flag proc nil)
|
|
(term-char-mode)
|
|
(add-hook 'kill-buffer-hook (lambda ()
|
|
(when-let (win (get-buffer-window buf))
|
|
(quit-window nil win)))
|
|
nil t)))
|
|
|
|
buf))
|
|
|
|
(defun kubernetes-utils-process-buffer-start (bufname setup-fn command args &optional process-filter)
|
|
(let ((buf (get-buffer-create bufname)))
|
|
(buffer-disable-undo buf)
|
|
|
|
(with-current-buffer buf
|
|
(let ((inhibit-read-only t))
|
|
(erase-buffer)
|
|
(funcall setup-fn)
|
|
(let ((time-str (format "Process started at %s" (substring (current-time-string) 0 19)))
|
|
(command-str (format "%s %s" command (string-join args " "))))
|
|
(kubernetes-ast-eval
|
|
`((line ,(propertize time-str 'face 'magit-dimmed))
|
|
(padding)
|
|
(line ,(propertize command-str 'face 'magit-dimmed))
|
|
(padding))))))
|
|
|
|
(let ((proc (apply #'start-process "kubernetes-exec" buf command args)))
|
|
(when process-filter
|
|
(set-process-filter proc process-filter))
|
|
(set-process-query-on-exit-flag proc nil))
|
|
buf))
|
|
|
|
(defun kubernetes-utils-overview-buffer-selected-p ()
|
|
(equal (current-buffer) (get-buffer kubernetes-overview-buffer-name)))
|
|
|
|
(defmacro kubernetes-utils--save-window-state (&rest body)
|
|
"Restore window state after executing BODY.
|
|
|
|
This is useful if the buffer is erased and repopulated in BODY,
|
|
in which case `save-excursion' is insufficient to restore the
|
|
window state."
|
|
`(let ((pos (point))
|
|
(col (current-column))
|
|
(window-start-line (window-start))
|
|
(inhibit-redisplay t))
|
|
(save-excursion
|
|
,@body)
|
|
(goto-char pos)
|
|
(move-to-column col)
|
|
(set-window-start (selected-window) window-start-line)))
|
|
|
|
(defun kubernetes-utils-up-to-existing-dir (dir)
|
|
(while (not (file-directory-p dir))
|
|
(setq dir (file-name-directory (directory-file-name dir))))
|
|
dir)
|
|
|
|
(provide 'kubernetes-utils)
|
|
|
|
;;; kubernetes-utils.el ends here
|