what are build commands?

flower allows you to write custom build commands that are integrated into the flower build process. for example, this gets you live-reload for the commands, automatic rebuild detection if part of your site depends on the command, and progress messages that are integrated with a normal build.

NOTE: build tasks are not general purpose task runners. ninja silences all output from tasks unless they fail, and builds all tasks by default.

background

Flower is a build system masquerading as a static site generator. The build process is encoded in the build.ninja file generated by flower configure, and flower watch is a fancy wrapper around running ninja in a loop. "Flower core" (the flower binary itself) is extremely simple: basically just a clojure interpreter, file watcher, and http server.

Almost all of flower is defined in expressions/default-build.clj. You can think of build.clj as introducing new concepts. Custom commands are a way to introduce new concepts to your site.

adding a custom command

jyn.dev is built using flower, and developed in tandem. It has a custom command to rebuild flower on changes that looks like so (simplified):

(require '[expressions.default-build :as builder])
(def plan
  {:phony [{:name "flower" :depends "target/flower"}]
   :rules
    [{:name "flower-meta"
      :command "cd .. && clojure -T:build native"
      :description "rebuild flower itself"}]
   :builds
    [{:rule "flower-meta"
      :outputs "target/flower"
      :inputs (fs/glob "../flower" "**")}]})

(def default-plan (builder/default-build-plan))

(ninja/generate! (merge-deep default-plan plan))

The basic idea is that you get a "default build plan" shipped with flower, which is what is used if you don't add a custom build.clj. It is a normal clojure map, which you can modify as you like. ninja/generate! serializes it to a build.ninja file.

For the most part, this is a 1-1 mapping between ninja and a clojure map. Further docs are a WIP. See expressions/default-build.clj for examples and expressions/ninja.clj for the implementation.

constraints

note that we had to explicitly name all the inputs and outputs of the custom command. this is an intentional restriction:

  • knowing all inputs allows flower to know when your files need to be rebuilt.
  • knowing all outputs allows flower to pass a list of your files to your index pages.

TODO: document how to set up an existing site

you may not care about including your existing site in your index pages; for example if your index pages are generated by your existing site. in that case, you can opt-out by simply running your-build-command && flower build, i.e. move the work outside of flower. live-reload will still work (even for files not created by flower!), and flower will never delete any path it did not create itself. however, flower cannot know when a previous build command conflicts with its own output files, so you'll have to verify that yourself.