# Advent 2019 part 18, Exploring Bootleg Dive into yet another GraalVM based Clojure CLI tool *This post is part of [Advent of Parens 2019](https://lambdaisland.com/blog/2019-11-25-advent-of-parens), my attempt to publish one blog post a day during the 24 days of the advent.* With the advent of Graal it's now relatively straightforward to compile Clojure code to a compact and fast native binary, which has led to an explosion of new tools. In previous episodes I talked about Babashka, jet, and rep. Today I'll explore what looks like another interesting tool: [Bootleg](https://github.com/retrogradeorbit/bootleg). This post uses Nextjournal, a computational notebook environment with a focus on reproducibility. Go ahead and remix this notebook to run the code cells yourself. First things first, let's install Bootleg, I'll simply follow the instructions in the README. ```bash id=ce2bbffa-088a-4fec-81ee-dad4b33a0310 curl -sLO https://github.com/retrogradeorbit/bootleg/releases/download/v0.1.6-1/bootleg-0.1.6-1-linux-amd64.tgz tar xvf bootleg-0.1.6-1-linux-amd64.tgz && rm bootleg-0.1.6-1-linux-amd64.tgz mv bootleg /usr/bin bootleg --help ``` Bootleg's main job is being a template processing tool for building static websites. Let's try that out by adding a Hiccup template. ```clojure no-exec id=0cebceaf-74c4-4513-872c-84cb803be7b0 [:html [:body [:h1 "A simple webpage"] [:p "Made with bootleg for maximum powers!"]]] ``` And running it through `bootleg`: ```bash id=3715e033-8bd2-40bd-a281-695f925fed99 bootleg a_simple_template.clj ``` So it expands Hiccup, basically acting as a Hiccup -> HTML converter. It can also take hiccup forms directly at the command line. ```bash id=5df6ab2b-dbea-418e-b22b-bd7da849ee6f bootleg -e '[:p "pretty sweet!"]' ``` And these forms are evaluated, you have the full power of Clojure at your disposal thanks to [Sci](https://github.com/borkdude/sci), the Small Clojure Interpreter that also powers Babashka. ```bash id=e4e5a2c0-7241-4779-9504-27b0d53e78f7 bootleg -e '[:li (for [t ["Green" "Black" "Wulong"]] [:ul t])]' ``` So in a way Bootleg is just a Clojure interpreter, similar to `bb`, but with two main differences: it renders the result of the expression to HTML, and it includes a whole slew of utility functions for dealing with various templating and markdown formats (markdown, mustache, ...), as well as doing file system manipulation like creating directories or symlinks, and for reading data from yaml, json, or edn. ```bash id=77d71548-c186-46f0-9b52-c28a0d67ee87 bootleg -e '(str (+ 13 29))' ``` ```bash id=b737a1d1-f47c-446c-bbf0-7de85a953816 bootleg -e '(markdown "https://raw.githubusercontent.com/retrogradeorbit/bootleg/master/README.md")' ``` So say you have this simple "layout" template, and you want to render some markdown into that ```clojure no-exec id=06f2590e-811a-45bf-aeff-af3eface2c29 [:html [:head [:title]] [:body]] ``` ```clojure no-exec id=c3a8f810-1b07-4e39-857a-f61a6507898a # My first page **cool stuff** ``` ```bash id=b0e01571-e8ee-47d5-833f-47c5fc484004 bootleg -e '(-> (hiccup "layout.clj") (enlive/at [:title] (enlive/content "My first page")) (enlive/at [:body] (enlive/content (markdown "my_first_page.md"))))' ``` What I like about the approach bootleg has taken is that it gives you all the raw tools to set up your static site building, without dictating any of the specifics. It gives you all the building blocks, what you do with them is up to you! *Hi, my name is Arne (aka @plexus) and I consult companies and teams about application architecture, development process, tooling and testing. I collaborate with other talented people under the banner [Gaiwan](http://gaiwan.co). If you like to have a chat about how we could help you with your project then please [get in touch!](https://lambdaisland.com/p/contact)*
This notebook was exported from https://nextjournal.com/a/LzKrYGsEq87XQUsBuaxqK?change-id=Cc4xezk2YwK9SWs34PhMFg ```edn nextjournal-metadata {:article {:nodes {"06f2590e-811a-45bf-aeff-af3eface2c29" {:id "06f2590e-811a-45bf-aeff-af3eface2c29", :kind "code-listing", :name "layout.clj"}, "0cebceaf-74c4-4513-872c-84cb803be7b0" {:id "0cebceaf-74c4-4513-872c-84cb803be7b0", :kind "code-listing", :name "a_simple_template.clj"}, "3715e033-8bd2-40bd-a281-695f925fed99" {:compute-ref #uuid "03e695ba-217e-4a86-b17a-3507c921f48f", :exec-duration 637, :id "3715e033-8bd2-40bd-a281-695f925fed99", :kind "code", :name "A simple page", :output-log-lines {:stdout 0}, :refs (), :runtime [:runtime "64cab0a7-7ca5-43eb-baa7-224d0d3ef4b4"]}, "5df6ab2b-dbea-418e-b22b-bd7da849ee6f" {:compute-ref #uuid "48ff87a7-ff47-4aa8-8b7e-d6a4f516ad75", :exec-duration 618, :id "5df6ab2b-dbea-418e-b22b-bd7da849ee6f", :kind "code", :output-log-lines {:stdout 0}, :refs (), :runtime [:runtime "64cab0a7-7ca5-43eb-baa7-224d0d3ef4b4"]}, "64cab0a7-7ca5-43eb-baa7-224d0d3ef4b4" {:environment [:environment "64cab0a7-7ca5-43eb-baa7-224d0d3ef4b4"], :environment? false, :id "64cab0a7-7ca5-43eb-baa7-224d0d3ef4b4", :kind "runtime", :language "bash", :type :nextjournal, :docker/environment-image "docker.nextjournal.com/environment@sha256:246f8bda6edc332e20ec112066116e9c3a0f02f7aa7687556eb40c49ac74881c", :runtime/mounts [{:src [:node "0cebceaf-74c4-4513-872c-84cb803be7b0"], :dest "/a_simple_template.clj"} {:src [:node "06f2590e-811a-45bf-aeff-af3eface2c29"], :dest "/layout.clj"} {:src [:node "c3a8f810-1b07-4e39-857a-f61a6507898a"], :dest "/my_first_page.md"}]}, "77d71548-c186-46f0-9b52-c28a0d67ee87" {:compute-ref #uuid "fa1d5c07-539e-4065-ad19-0bf1070837ec", :exec-duration 675, :id "77d71548-c186-46f0-9b52-c28a0d67ee87", :kind "code", :output-log-lines {:stdout 0}, :refs (), :runtime [:runtime "64cab0a7-7ca5-43eb-baa7-224d0d3ef4b4"]}, "b0e01571-e8ee-47d5-833f-47c5fc484004" {:compute-ref #uuid "c478314b-c8e3-4902-b53a-5825f22445bd", :exec-duration 886, :id "b0e01571-e8ee-47d5-833f-47c5fc484004", :kind "code", :output-log-lines {:stdout 0}, :refs (), :runtime [:runtime "64cab0a7-7ca5-43eb-baa7-224d0d3ef4b4"]}, "b737a1d1-f47c-446c-bbf0-7de85a953816" {:compute-ref #uuid "8095af6d-a920-4073-b526-d2ad58995714", :exec-duration 1052, :id "b737a1d1-f47c-446c-bbf0-7de85a953816", :kind "code", :output-log-lines {:stdout 142}, :refs (), :runtime [:runtime "64cab0a7-7ca5-43eb-baa7-224d0d3ef4b4"]}, "c3a8f810-1b07-4e39-857a-f61a6507898a" {:id "c3a8f810-1b07-4e39-857a-f61a6507898a", :kind "code-listing", :name "my_first_page.md"}, "ce2bbffa-088a-4fec-81ee-dad4b33a0310" {:compute-ref #uuid "57868200-c2f0-4336-ac93-6a8116c2f056", :exec-duration 2811, :id "ce2bbffa-088a-4fec-81ee-dad4b33a0310", :kind "code", :locked? true, :name "Install bootleg", :output-log-lines {:stdout 14}, :refs (), :runtime [:runtime "64cab0a7-7ca5-43eb-baa7-224d0d3ef4b4"]}, "e4e5a2c0-7241-4779-9504-27b0d53e78f7" {:compute-ref #uuid "0550c3ff-296d-4a02-9079-315df51f8d57", :exec-duration 522, :id "e4e5a2c0-7241-4779-9504-27b0d53e78f7", :kind "code", :output-log-lines {:stdout 0}, :refs (), :runtime [:runtime "64cab0a7-7ca5-43eb-baa7-224d0d3ef4b4"]}}, :nextjournal/id #uuid "02ca759f-3078-4a4f-be49-7860271ba356", :article/change {:nextjournal/id #uuid "5df9ff54-6cb3-41c4-8964-aaf8416cd123"}}} ```