]> git.eshelyaron.com Git - emacs.git/commitdiff
kubed.el: Add optional per-column value-formatting function
authorEshel Yaron <me@eshelyaron.com>
Fri, 26 Jul 2024 21:18:55 +0000 (23:18 +0200)
committerEshel Yaron <me@eshelyaron.com>
Fri, 26 Jul 2024 21:18:55 +0000 (23:18 +0200)
lisp/net/kubed.el

index 838e9e84b58581574cd32efc6f871e2a712c24be..538169da4c84446fb10679248942c7b8a841c956 100644 (file)
@@ -122,20 +122,21 @@ interacting with Kubernetes RESOURCEs:
 This macro also defines a prefix keymap, `kubed-RESOURCE-prefix-map',
 with bindings for the above commands.
 
-PROPERTIES is a list of elements (PROPERTY JSON-PATH WIDTH SORT . ATTRS)
-that specify properties of RESOURCEs.  PROPERTY is the name of the
-property, as a symbol; JSON-PATH is a JSONPath expression that evaluates
-to the value of PROPERTY when applied to the full JSON representation of
-a RESOURCE.  WIDTH, SORT and ATTRS are optional and can be omitted.
-WIDTH is used as the default width of the column corresponding to
-PROPERTY in RESOURCEs list buffers; SORT is sort predicate, a function
-that takes two values of PROPERTY as strings and return non-nil if the
-first should sort before the second; ATTRS is a plist of additional
-attributes of the PROPERTY column, see `tabulated-list-format' for
-available attributes.  For example, (phase \".status.phase\" 10) says
-that RESOURCE has a `phase' property at JSONPath \".status.phase\" whose
-values are typically 10 columns wide.  The first property in PROPERTIES,
-is used to annotate completion candidates when prompting for a RESOURCE.
+PROPERTIES is a list of lists (PROP JSON-PATH WIDTH SORT FORMAT . ATTRS)
+that specify properties of RESOURCEs.  PROP is the name of the property,
+as a symbol; JSON-PATH is a JSONPath expression that evaluates to the
+value of PROP when applied to the JSON representation of a RESOURCE.
+WIDTH, SORT, FORMAT and ATTRS are optional and can be omitted.  WIDTH is
+used as the default width of the column corresponding to PROP in
+RESOURCEs list buffers; SORT is sort predicate, a function that takes
+two values of PROP as strings and return non-nil if the first should
+sort before the second; FORMAT is a function that takes a value of PROP
+and formats it; and ATTRS is a plist of additional attributes of the
+PROP column, see `tabulated-list-format' for available attributes.  For
+example, (phase \".status.phase\" 10) says that RESOURCE has a `phase'
+property at JSONPath \".status.phase\" whose values are typically 10
+columns wide.  The first property in PROPERTIES, is used to annotate
+completion candidates when prompting for a RESOURCE.
 
 COMMANDS is a list of elements (COMMAND KEYS DOC-PREFIX . BODY) that
 define commands for RESOURCE list buffers.  COMMAND is a symbol
@@ -316,42 +317,60 @@ Other keyword arguments that go between PROPERTIES and COMMANDS are:
                                                                  (cadr p)))
                                                        properties)))
                                    ",")))
-                :sentinel (lambda (_proc status)
-                            (cond
-                             ((string= status "finished\n")
-                              (let (new offsets eol)
-                                (with-current-buffer ,out-name
-                                  (goto-char (point-min))
-                                  (setq eol (pos-eol))
-                                  (while (re-search-forward "[^ ]+" eol t)
-                                    (push (1- (match-beginning 0)) offsets))
-                                  (setq offsets (nreverse offsets))
-                                  (forward-char 1)
-                                  (while (not (eobp))
-                                    (let ((cols nil)
-                                          (beg (car offsets))
-                                          (ends (cdr offsets)))
-                                      (dolist (end ends)
-                                        (push (string-trim (buffer-substring
-                                                            (+ (point) beg)
-                                                            (+ (point) end)))
-                                              cols)
-                                        (setq beg end))
-                                      (push (string-trim (buffer-substring
-                                                          (+ (point) beg)
-                                                          (pos-eol)))
-                                            cols)
-                                      (push (nreverse cols) new))
-                                    (forward-line 1)))
-                                (setq ,list-var new
-                                      ,proc-var nil)
-                                (run-hooks ',hook-var)
-                                (message ,(format "Updated Kubernetes %Ss." resource))))
-                             ((string= status "exited abnormally with code 1\n")
-                              (with-current-buffer ,err-name
-                                (goto-char (point-max))
-                                (insert "\n" status))
-                              (display-buffer ,err-name))))))
+                :sentinel
+                (lambda (_proc status)
+                  (cond
+                   ((string= status "finished\n")
+                    (let (new offsets eol)
+                      (with-current-buffer ,out-name
+                        (goto-char (point-min))
+                        (setq eol (pos-eol))
+                        (while (re-search-forward "[^ ]+" eol t)
+                          (push (1- (match-beginning 0)) offsets))
+                        (setq offsets (nreverse offsets))
+                        (forward-char 1)
+                        (while (not (eobp))
+                          (let ((cols nil)
+                                (beg (car offsets))
+                                (ends (append (cdr offsets) (list (- (pos-eol) (point))))))
+                            ,@(let ((read-col
+                                     (lambda (p)
+                                       ;; Fresh list to avoid circles.
+                                       (list `(push ,(if-let ((f (nth 4 p)))
+                                                         `(funcall ,f (string-trim (buffer-substring
+                                                                                    (+ (point) beg)
+                                                                                    (+ (point) (car ends)))))
+                                                       `(string-trim (buffer-substring
+                                                                      (+ (point) beg)
+                                                                      (+ (point) (car ends)))))
+                                                    cols)
+                                             '(setq beg (pop ends))))))
+                                (if namespaced
+                                    ;; Resource is namespaced, generate
+                                    ;; code that is sensitive to
+                                    ;; `kubed-all-namespaces-mode'.
+                                    `((if kubed-all-namespaces-mode
+                                          (progn
+                                            ,@(mapcan
+                                               read-col
+                                               ;; Two nils, one for the
+                                               ;; name column, another
+                                               ;; for the namespace.
+                                               `(nil nil . ,properties)))
+                                        ,@(mapcan read-col `(nil . ,properties))))
+                                  ;; Non-namespaced.
+                                  (mapcan read-col `(nil . ,properties))))
+                            (push (nreverse cols) new))
+                          (forward-line 1)))
+                      (setq ,list-var new
+                            ,proc-var nil)
+                      (run-hooks ',hook-var)
+                      (message ,(format "Updated Kubernetes %Ss." resource))))
+                   ((string= status "exited abnormally with code 1\n")
+                    (with-current-buffer ,err-name
+                      (goto-char (point-max))
+                      (insert "\n" status))
+                    (display-buffer ,err-name))))))
          (minibuffer-message ,(format "Updating Kubernetes %Ss..." resource)))
 
        (defun ,affx-fun (,plrl-var)
@@ -748,7 +767,7 @@ Optional argument DEFAULT is the minibuffer default argument." resource)
                                       (funcall ,sorter (aref (cadr l) c) (aref (cadr r) c)))
                                  `(funcall ,sorter (aref (cadr l) ,i) (aref (cadr r) ,i))))
                          t))
-                 (nthcdr 4 p))
+                 (nthcdr 5 p))
                 res))
              (reverse res)))
 
@@ -843,7 +862,30 @@ Optional argument DEFAULT is the minibuffer default argument." resource)
 ;;;###autoload (autoload 'kubed-create-pod "kubed" nil t)
 ;;;###autoload (autoload 'kubed-pod-prefix-map "kubed" nil t 'keymap)
 (kubed-define-resource pod
-    ((phase ".status.phase" 10) (starttime ".status.startTime" 20))
+    ((phase ".status.phase" 10
+            nil                         ; sorting function
+            (lambda (ph)
+              (if-let ((face (pcase ph
+                               ;; TODO: Define/derive bespoke faces.
+                               ("Pending"   'warning)
+                               ("Running"   'success)
+                               ("Succeeded" 'shadow)
+                               ("Failed"    'error))))
+                  (propertize ph 'face face)
+                ph)))
+     (ready ".status.containerStatuses[?(.ready==true)].name" 6
+            (lambda (l r) (< (string-to-number l) (string-to-number r)))
+            (lambda (cs)
+              (if (string= cs "<none>") "0"
+                (number-to-string (1+ (seq-count (lambda (c) (= c ?,)) cs)))))
+            :right-align t)
+     (total ".status.containerStatuses[*].name" 6
+            (lambda (l r) (< (string-to-number l) (string-to-number r)))
+            (lambda (cs)
+              (if (string= cs "<none>") "0"
+                (number-to-string (1+ (seq-count (lambda (c) (= c ?,)) cs)))))
+            :right-align t)
+     (starttime ".status.startTime" 20))
   :prefix ("L" #'kubed-logs
            "A" #'kubed-attach
            "X" #'kubed-exec
@@ -880,7 +922,15 @@ Optional argument DEFAULT is the minibuffer default argument." resource)
 ;;;###autoload (autoload 'kubed-create-namespace "kubed" nil t)
 ;;;###autoload (autoload 'kubed-namespace-prefix-map "kubed" nil t 'keymap)
 (kubed-define-resource namespace
-    ((phase ".status.phase" 10)
+    ((phase ".status.phase" 10
+            nil                         ; sorting function
+            (lambda (ph)
+              (if-let ((face (pcase ph
+                               ;; TODO: Define/derive bespoke faces.
+                               ("Active"      'success)
+                               ("Terminating" 'shadow))))
+                  (propertize ph 'face face)
+                ph)))
      (creationtimestamp ".metadata.creationTimestamp" 20))
   :namespaced nil
   :prefix ("S" #'kubed-set-namespace)
@@ -948,6 +998,7 @@ Optional argument DEFAULT is the minibuffer default argument." resource)
 (kubed-define-resource deployment
     ((reps ".status.replicas" 4
            (lambda (l r) (< (string-to-number l) (string-to-number r)))
+           nil                          ; formatting function
            :right-align t)
      (creationtimestamp ".metadata.creationTimestamp" 20))
   :create
@@ -1003,6 +1054,7 @@ optional command to run in the images."
 (kubed-define-resource replicaset
     ((reps ".status.replicas" 4
            (lambda (l r) (< (string-to-number l) (string-to-number r)))
+           nil                           ; formatting function
            :right-align t)
      (ownerkind ".metadata.ownerReferences[0].kind" 12)
      (ownername ".metadata.ownerReferences[0].name" 16)
@@ -1017,6 +1069,7 @@ optional command to run in the images."
 (kubed-define-resource statefulset
     ((reps ".status.replicas" 4
            (lambda (l r) (< (string-to-number l) (string-to-number r)))
+           nil                          ; formatting function
            :right-align t)
      (ownerkind ".metadata.ownerReferences[0].kind" 12)
      (ownername ".metadata.ownerReferences[0].name" 16)