A few months ago I posted a
link
on the help list to the CFEngine
layer
for spacemacs. Since then I have learned there
are a few other org-mode users so I wanted to share how I got
cfengine3
src blocks execution working. I added the following to my
dotspacemacs/user-init
.
(defcustom org-babel-cfengine3-command "/var/cfengine/bin/cf-agent"
"Name of command to use for executing CFEngine policy.")
(defvar org-babel-cfengine3-command-options "--no-lock"
"Option string that should be passed to the agent. Note that
--file will be appended to the options.")
(defvar org-babel-cfengine3-file-control-stdlib "body file control{ inputs => { '$(sys.libdir)/stdlib.cf' };}\n"
"File control body to include the standard library from
$(sys.libdir). It is useful to inject into an example source
block before execution so that bundles and bodies from the
standard library are automatically available.")
(defun org-babel-execute:cfengine3 (body params)
"Actuate a block of CFEngine 3 policy.
This function is called by `org-babel-execute-src-block'.
A temporary file is constructed containing
`org-babel-cfengine3-file-control-stdlib and the body of the src
block. `org-babel-cfengine3-command' is used to execute the
temporary file."
(let* ((temporary-file-directory ".")
(tempfile (make-temp-file "cfengine3-")))
(with-temp-file tempfile
;; TODO Consider making automatic stdlib inclusion optional
(insert org-babel-cfengine3-file-control-stdlib)
(insert body))
(unwind-protect
(shell-command-to-string
(concat
org-babel-cfengine3-command
" "
;; TODO Consider adding a header option to specify bundlesequence
org-babel-cfengine3-command-options
" "
(format " --file %s" tempfile)))
(delete-file tempfile))))
Now any time I have a cfengine3
SRC block in org-mode I can simply run
org-babel-execute-src-block
( CTRL-c CTRL-c
in emacs/spacemacs
documentation this is written as C-c C-c
) to have the block written
to a temporary file, executed and the temporary file deleted. For
example with my insertion placed inside the following SRC block.
#+Name: example policy
#+BEGIN_SRC cfengine3 :results raw :wrap EXAMPLE :exports both
bundle agent main
{
reports:
"$(sys.date)";
"CFEngine $(sys.cf_version)";
"Automatic inclusion of '$(sys.libdir)/stdlib.cf' when executed via org-babel-execute-src-block"
classes => results("bundle", "example");
vars:
"c" slist => classesmatching("example_.*");
reports:
"class: '$(c)'";
}
#+END_SRC
I type C-c C-c
and my RESULTS are inserted.
#+RESULTS: example policy
#+BEGIN_EXAMPLE
R: Mon Sep 12 08:26:49 2016
R: CFEngine 3.9.0
R: Automatic inclusion of '/home/nickanderson/.cfagent/inputs/lib/stdlib.cf' when executed via org-babel-execute-src-block
R: class: 'example_kept'
R: class: 'example_reached'
#+END_EXAMPLE
Note that the standard library is automatically included by injecting a
file control body into the temporary file before execution. For a block
to be executed correctly it must contain either a body common control
with the bundlesequence
specified or include a bundle named main
.
Here you can see the exported results, now when I export my document I
get a nicely formatted cfengine3
policy block along with the
accompanying execution output.
bundle agent main
{
reports:
"$(sys.date)";
"CFEngine $(sys.cf_version)";
"Automatic inclusion of '$(sys.libdir)/stdlib.cf' when executed via org-babel-execute-src-block"
classes => results("bundle", "example");
vars:
"c" slist => classesmatching("example_.*");
reports:
"class: '$(c)'";
}
R: Mon Sep 12 08:28:48 2016
R: CFEngine 3.9.0
R: Automatic inclusion of '/home/nickanderson/.cfagent/inputs/lib/stdlib.cf' when executed via org-babel-execute-src-block
R: class: 'example_kept'
R: class: 'example_reached'