The following “functions” are useful for formatting org-mode code
blocks. This is part of my Library of Babel collection. Remember to
hit the C-c C-v i
to add these sections.
The os-table-str
is a :post
function for post-processing the
output from a nova
table output as a string, and re-formats it
into a list data structure so that org-mode can reformat it in its
own table format.
To use it, add the following source code block header:
:post os-table(data=*this*) :results output
Or better yet, use the following header line:
#+HEADER: :post os-table(data=*this*) :results output
To use os-table
make sure that the :results
are set to
output
. Along with data
, you can set header=t
in order to retain the
headers from the nova
command.
(cl-flet* ((non-border-p (line) (not (string-match "^ *[\+-]+-" line)))
(separate-row (line) (split-string line " *| *"))
(trim-cells-front (cells) (if (string-empty-p (car cells))
(cdr cells)
cells))
(trim-cells-back (cells) (if (string-empty-p (car (last cells)))
(butlast cells)
cells))
(trim-row-cells (cells) (trim-cells-back (trim-cells-front cells))))
(let* ((rows (split-string data "[\n\r]+" t))
(table-data (mapcar #'trim-row-cells
(mapcar #'separate-row
(-filter #'non-border-p rows)))))
(cond ((equalp header "no") (cdr table-data))
((equalp header "yes") (append (list (car table-data) 'hline) (cdr table-data)))
( t table-data))))
To verify this code, we first begin with a typical output from a
nova list
command:
+--------------------------------------+----------------------+--------+------------+-------------+----------------------+ | ID | Name | Status | Task State | Power State | Networks | +--------------------------------------+----------------------+--------+------------+-------------+----------------------+ | 521fd286-cbdc-42a6-8c33-0e771d4c37c1 | ha-ci-sdn-chefserver | ACTIVE | - | Running | cedev13=10.96.68.204 | | 542b9f7d-f380-4d67-9eee-f974ba958e3a | ha-ci-sdn-chefserver | ACTIVE | - | Running | cedev13=10.96.68.196 | +--------------------------------------+----------------------+--------+------------+-------------+----------------------+
Our org-mode
source block does nothing more than echo this data as
a string, relying on the :post
call to do the work:
echo "$input"
Real world example that attempts to access an OpenStack system at a
particular IP address. This assumes that the nova credentials are
stored in a file in the home directory, openrc
(as it will attempt
to source those first).
nova list
Uses the os-table
block, but attempts to clean up the nova list
command with better information.
(replace-regexp-in-string "| *cedev[0-9]+=" "| " data)
nova list
If I know the text of a column, this will remove it. This isn’t the most reliable approach, but this needs to be a pre-processor that operates on a string of the results from OpenStack commands.
We take the comma-separated list of column values, colvals
, and then
use a reduce
function to repeatedly call the data
variable and
remove more and more column sections:
(cl-flet ((resetter (data col)
(replace-regexp-in-string (concat "| *" col " *|") "| " data)))
(let ((vals (split-string colvals " *, *")))
(cl-reduce #'resetter vals :initial-value data)))
Let’s test this:
nova list
What if all the data in a column is the same? Why display it? Let’s
remove any columns if every value is the same. This is a more robust
and easier-to-use solution, however, I don’t know how we can use it
as a pre-processor as it expects results as formatted by the
os-table
.
;; (setq data '(("521fd286-cbdc-42a6-8c33-0e771d4c37c1" "ha-ci-other-server" "ACTIVE" "-" "Running" "cedev13=10.96.68.204") ("542b9f7d-f380-4d67-9eee-f974ba958e3a" "ha-ci-sdn-chefserver" "ACTIVE" "-" "Running" "cedev13=10.96.68.196")))
(defun column-same-value-p (table column-number)
"Return `nil' if values in COLUMN-NUMBER are unique. Return
non-nil if the values are all the same."
(if (cdr table)
(let ((column-value (column-unique-p (cdr table) column-number)) )
(when (equalp column-value (nth column-number (car table)))
column-value))
(nth column-number (car table))))
(defun remove-column (table column-value)
"Given a TABLE (a list of lists), removes a column of data
where the first column is 0."
(cl-flet ((remove-from-list (lst pos) (append
(butlast lst (- (length lst) pos))
(nthcdr (1+ pos) lst))))
(mapcar (lambda (row) (remove-from-list row column-value)) table)))
(defun remove-table-same-columns (table &optional column-num)
"Return given TABLE but without any columns were all columns contain the same value."
(let* ((col (if column-num
column-num
(1- (length (car table)))))
(next-col (1- col)))
(if (< col 0) ;; Ran out of columns? Bail out...
table
(let ((modified-table (if (column-same-value-p table col)
(remove-column table col)
table)))
(remove-table-same-columns modified-table next-col)))))
(remove-table-same-columns data)
Now, let’s test that monstrosity out.
nova list