About Org Converge
04 Jun 2014In a past release from Org Ruby, I added the functionality to be able to turn off exporting the results attached to a code block. For example, here only the actual code would make it to the export:
#+begin_src sh :results code
echo 'hello'
#+end_src
#+RESULTS:
#+BEGIN_SRC sh
hello
#+END_SRC
Doing this involved adding support to parse the header arguments from a code block, so I decided to start playing with the idea of implementing tangling code blocks:
#+begin_src sh :tangle /etc/component.yml
port: 4000
#+end_src
This is just a subset of the functionality provided by the powerful
Org Babel mode, and still very basic since it does not
support #+MACROS
for example, which would make feature more
convenient.
After doing this, and since this is all Ruby, I imagined that since there is good interop with other reliable Ruby tools, it would be interesting to reopen foreman for actually running the blocks.
All this functionality is wrapped into a gem named org-converge, named that way in the sense that all reproducible runs should converge into a state.
In the future, I hope to have more Chef/Puppet/Ansible like features, like idempotency:
Idempotency example via :if
and :unless
switches
The way this work is by linking 2 different code blocks, so that one can define whether the second one should be executed.
In order to achieve this, for now the blocks need to be defined sequentially and use the exit status to check whether it should be run or not.
#+name: install-package
#+begin_src sh
echo "brew install something..."
echo "package is installed" > installed
#+end_src
#+name: package-already-installed
#+begin_src sh
if [[ -e installed ]]; then
echo "Already installed"
exit 0
else
echo "Needs install"
exit 1
fi
#+end_src
#+name: install-package-once-again
#+begin_src sh :unless package-already-installed
echo "Installing the package once again..."
echo "not run" >> installed
#+end_src
#+name: do-everything-even-if-package-installed
#+begin_src sh :if package-already-installed
echo "Doing this even if installed already..."
echo "eof" >> installed
#+end_src
Now when we run it the first time, we would get the following output:
gem install org-converge
org-converge idempotent-run.org
[2014-11-28T13:18:13 -0500] package-already-installed -- Needs install
[2014-11-28T13:18:13 -0500] package-already-installed -- started with pid 47963
[2014-11-28T13:18:13 -0500] package-already-installed -- exited with code 1
[2014-11-28T13:18:13 -0500] install-package -- started with pid 47967
[2014-11-28T13:18:13 -0500] install-package -- Installing the package...
[2014-11-28T13:18:13 -0500] install-package -- exited with code 0
…but if we run it again, we would get the following:
org-converge idempotent-run.org
[2014-11-28T13:19:07 -0500] package-already-installed -- started with pid 48474
[2014-11-28T13:19:07 -0500] package-already-installed -- Already installed
[2014-11-28T13:19:07 -0500] package-already-installed -- exited with code 0
[2014-11-28T13:19:07 -0500] install-package -- Skipped since :unless clause matches check from 'package-already-installed'
[2014-11-28T13:19:07 -0500] Run has completed successfully.
Multiprocess run usage
I also have been using lately for doing multi process running, and I have found it pretty comfortable for when practicing literate programming with Org Babel.
An example, the following 3 scripts should be run in parallel with all output being flushed to the screen.
- Count some numbers with bash
#+name: bash_counter
#+begin_src sh :shebang #!/bin/bash
for i in `seq 1 5`; do
echo "Writing! $i"
echo "hello $i from bash"
sleep $(($RANDOM % 5))
done
#+end_src
- Count some numbers with ruby
#+name: ruby_counter
#+begin_src ruby :shebang #!/usr/bin/ruby
$stdout.sync = true
10.times do |n|
puts "And now writing! #{n}"
puts "Hello from Ruby"
sleep 0.5
end
#+end_src
- Print some numbers with python
#+name: python_counter
#+begin_src python :shebang #!/usr/bin/python
for i in range(0, 20):
print "From Python"