Execute shell commands in Boot with boot-exec
In several recent projects, I've needed to execute a shell command from within a Boot task, and sometimes use a predicate function to determine if the command should be executed or skipped, each time it's invoked.
I found one existing task, degree9/boot-exec, but this does not satisfy the requirement for conditional execution or allow me to define the command as a simple string. So I decided to write my own version, simplified and with these specific needs in mind.
You can find it on Clojars and include it your
(set-env! :dependencies '[[adamrenklint/boot-exec "1.0.1"]]) (require '[adamrenklint.boot-exec :refer [exec]])
Let's say we have some images that need to be transformed with a fictional image transformer executable, that does not have an existing Clojure wrapper. From the command line, we'd just write:
> transform-image resources/images/my-image.png
To make this composable with the rest of our build pipeline, we simply add a new task to
build.boot, using the command as a string:
(deftask transform-image  "Transform my-image" (exec :cmd "transform-image resources/images/my-image.png"))
Our fictional executable would perform the transformation and save the result to
But what if executing the command is expensive, and we want to avoid unnecessary operations when including the
transform-image in another task, which is called with
watch and invoked every time a file in our
(deftask dev  (comp (watch) (build) (transform-image) (target)))
We can solve this by providing the exec task with a predicate function.
(require '[clojure.java.io :as io]) (defn is-image-not-transformed?  (not (.exists (io/file "resources/images/my-image-transformed.png")))) (deftask transform-image  "Transform my-image" (exec :cmd "transform-image resources/images/my-image.png" :pred-fn 'is-image-not-transformed?))
With this simple change, we skip executing the expensive command if the artifact it produces already exists.
Please note that we intentionally ignore the idea that the source image could change - the example is simplified and a bit contrived for sake of clarity. The real world use case for this task was much more complex, and explaining it here would probably have been more confusing than enlightening.