Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/retrogradeorbit/bootleg

Simple template processing command line tool to help build static websites
https://github.com/retrogradeorbit/bootleg

Last synced: 17 days ago
JSON representation

Simple template processing command line tool to help build static websites

Awesome Lists containing this project

README

        

# bootleg

[![Github Action](https://github.com/retrogradeorbit/bootleg/workflows/Github%20Actions%20Tests/badge.svg)](https://github.com/retrogradeorbit/bootleg/actions?query=workflow%3A%22Github+Actions+Tests%22)
[![CircleCI](https://circleci.com/gh/retrogradeorbit/bootleg/tree/master.svg?style=shield)](https://circleci.com/gh/retrogradeorbit/bootleg/tree/master)

Static website generation made simple. A powerful, fast, clojure html templating solution.

Bootleg is a command line tool that rapidly renders clojure based templates. With inbuilt support for html, hiccup, hickory, selmer, mustache, markdown, enlive, json, yaml and edn, it enables you to pull together disparate elements and glue them together to generate the static website of your dreams.

## Quickstart

Install for Linux:

```shell
$ curl -LO https://github.com/retrogradeorbit/bootleg/releases/download/v0.1.9/bootleg-0.1.9-linux-amd64.tgz
$ tar xvf bootleg-0.1.9-linux-amd64.tgz
$ mv bootleg ~/bin
```

Install for MacOS:

```shell
$ curl -LO https://github.com/retrogradeorbit/bootleg/releases/download/v0.1.9/bootleg-0.1.9-macos-amd64.zip
$ unzip bootleg-0.1.9-macos-amd64.zip
$ mv bootleg /usr/local/bin
```

Clone this repository and change into the `examples/quickstart` directory:

```shell
$ git clone https://github.com/retrogradeorbit/bootleg.git
$ cd bootleg/examples/quickstart
```

A simple page:

```clojure
$ cat example-simple.clj
[:html
[:body
[:h1 "A simple webpage"]
[:p "Made with bootleg for maximum powers!"]]]
```

```html
$ bootleg example-simple.clj

A simple webpage

Made with bootleg for maximum powers!


```

A dynamic example:

```clojure
$ cat example-dynamic.clj
[:div.countdown
(for [n (range 10 0 -1)]
[:p n])
[:p "blast off!"]]
```

```html
$ bootleg example-dynamic.clj


10


9


8


7


6


5


4


3


2


1


blast off!



```

Mustache:

```clojure
$ cat example-mustache.clj
(mustache "quickstart.html" (yaml "fields.yml"))
```

```html
$ cat quickstart.html

{{ title }}


by {{ author }}


{{& body }}

```

```yaml
$ cat fields.yml
title: Bootleg
author: Crispin
body: I'm going to rewrite all my sites with this!
```

```html
$ bootleg example-mustache.clj

Bootleg


by Crispin


I'm going to rewrite all my sites with this!

```

Markdown support. Evaluate from command line. Easy downloading of resources by url (for any command):

```html
$ bootleg -e '(markdown "https://raw.githubusercontent.com/retrogradeorbit/bootleg/master/README.md")'

bootleg

Static website generation made simple. A powerful, fast, clojure templating solution that rocks!...
```

CSS selector based processing. The magic of enlive:

```clojure
$ cat example-enlive.clj
(-> (markdown "simple.md")
(enlive/at [:p] (enlive/set-attr :style "color:green;")))
```

```markdown
$ cat simple.md
# Markdown support

This is some simple markdown
```

```html
$ bootleg example-enlive.clj

Markdown support

This is some simple markdown


```

Combine hiccup, mustache, markdown and enlive processing:

```clojure
$ cat example-combine.clj
(mustache "quickstart.html"
(assoc (yaml "fields.yml")
:body (markdown "simple.md" :html)))
```

```html
$ bootleg example-combine.clj

Bootleg


by Crispin



Markdown support


This is some simple markdown



```

Data output with -d flag:

```clojure
$ cat example-data.clj
(-> (mustache "quickstart.html"
(assoc (yaml "fields.yml")
:body (markdown "simple.md" :html)))
(convert-to :hickory-seq))
```

```clojure
$ bootleg -d example-data.clj
({:type :element, :attrs nil, :tag :h1, :content ["Bootleg"]}
"\n"
{:type :element, :attrs nil, :tag :h2, :content ["by Crispin"]}
"\n"
{:type :element,
:attrs nil,
:tag :div,
:content [{:type :element,
:attrs nil,
:tag :h1,
:content ["Markdown support"]}
{:type :element,
:attrs nil,
:tag :p,
:content ["This is some simple markdown"]}]}
"\n")
```

```shell
$ bootleg example-data.clj # <- no -d flag means output will be html

Bootleg


by Crispin



Markdown support


This is some simple markdown


```

## Installation

Bootleg is distributed for linux as a single executable file. Download the latest tarball from https://github.com/retrogradeorbit/bootleg/releases and then extract it. Once extracted, move the binary to your path. For system wide installation try `/usr/local/bin` or for personal use `~/bin`

```shell
$ curl -LO https://github.com/retrogradeorbit/bootleg/releases/download/v0.1.9/bootleg-0.1.9-linux-amd64.tgz
$ tar xvf bootleg-0.1.9-linux-amd64.tgz
$ mv bootleg /usr/local/bin
```

### Other Platforms

Windows support is experimental. Download (https://github.com/retrogradeorbit/bootleg/releases/download/v0.1.9/bootleg-0.1.9-windows-amd64.zip) and unzip the archive. Copy the bootleg.exe binary to somewhere on your path.

The jar release file is also an option if you have java installed. You can run it as follows:

```shell
$ java -jar bootleg-0.1.9.jar
```

## Usage

Run at the command line for options:

```shell
$ bootleg -h
Static website generation made simple. A powerful, fast, clojure html templating solution.

Usage: bootleg [options] [clj-file]

Options:
-h, --help Print the command line help
-v, --version Print the version string and exit
-e, --evaluate CODE Pass in the hiccup to evaluate on the command line
-d, --data Output the rendered template as a clojure form instead of html
-o, --output FILE Write the output to the specified file instead of stdout
-t, --traceback Print the full exception traceback
-c, --colour Print outputs in colour where appropriate
--color Alias for --colour
```

### Babashka Pod Usage

Note: There is a known issue with this pod and bb v0.2.1. Use bb v0.2.2 or higher.

Install the binary, then launch the pod in babashka by invoking the binary:

```clojure
(ns mybbscript
(:require [babashka.pods :as pods]))

(pods/load-pod "bootleg")
(require '[pod.retrogradeorbit.bootleg.utils :as utils])

(-> [:div
[:h1 "Using Bootleg From Babashka"]
[:p "This is a demo"]]
(utils/convert-to :html))
;;=> "


Using Bootleg From Babashka


This is a demo


"
```

When invoked as a pod, bootleg reveals the following namespaces to your babashka script:

#### Useful namespaces.

- pod.retrogradeorbit.bootleg.glob
- pod.retrogradeorbit.bootleg.utils
- pod.retrogradeorbit.bootleg.markdown
- pod.retrogradeorbit.bootleg.mustache
- pod.retrogradeorbit.bootleg.selmer
- pod.retrogradeorbit.bootleg.html
- pod.retrogradeorbit.bootleg.yaml
- pod.retrogradeorbit.bootleg.json
- pod.retrogradeorbit.bootleg.edn
- pod.retrogradeorbit.bootleg.file
- pod.retrogradeorbit.bootleg.enlive
- pod.retrogradeorbit.net.cgrand.enlive-html
- pod.retrogradeorbit.hickory.select
- pod.retrogradeorbit.hickory.zip

#### Compatibility

Bootleg 0.1.9 requires babashka 0.0.98 or higher.
Bootleg 0.1.9 requires babashka 0.0.99 or higher.

As a large library with lots of namespaces and functionality there may
be parts that dont work correctly. Please open tickets for any such
issues mentioning the problem is for the pod.

An example of testing verified working parts can be found here:
https://github.com/retrogradeorbit/bootleg/blob/master/test/pod/bbpodtest.clj

## Overview

`bootleg` loads and evaluates the clj file specified on the command line, or evaluates the `CODE` form specified in the -e flag. The code can return any of the supported data structures listed below. `bootleg` will then automatically convert that format into html and write it out to standard out, or to `FILE` if specified. This conversion to html step can be prevented by calling with the `-d` flag. In this case the output will be a pretty formatted edn form of the output data structure.

`bootleg` supports five main markup data structures. Three are more flexible. And two are limited. We will begin describing the two limited data structures and why they are limited.

### hiccup

Hiccup is a standard clojure DSL syntax for representing markup as nested sequences of vectors, and is represented in option flags by the keyword `:hiccup`. An example of some hiccup: the html `

This is an example

` is represented in hiccup as `[:div [:p "This is an example"]]`.

Hiccup, as the term is used in bootleg, is refering to this vector form. It represents a single root element and its children. This means there are template fragments that *cannot* be represented like this. For example, the html snippet `

one

two

` cannot be represented as hiccup. It is comprised of two hiccup forms. `[:p "one"]` and `[:p "two"]`. See `hiccup-seq` below for information about this form.

### hickory

Hickory is a format used to internally represent document trees in clojure for programmatic processing. In option flags it is referenced by the keyword `:hickory`. It is very verbose and not suitable to write by hand. It is supported internally for passing between functions that use it. A simple example of some hickory: the html `

one

` is represented in hickory as `{:type :element, :attrs nil, :tag :p, :content ["one"]}`.

Both the hickory and enlive clojure projects use this format internally to represent and manipulate DOM trees.

Hickory, as the term is used in bootleg, is refering to this hashmap form. It represents a single root element and its children. This means there are template fragments that *cannot* be represented in hickory. For example, the html snippet `

one

two

` cannot be represented as hickory. It is comprised of two hickory forms. `{:type :element, :attrs nil, :tag :p, :content ["one"]}` and `{:type :element, :attrs nil, :tag :p, :content ["two"]}`. See `hickory-seq` below for information about this form.

### hiccup-seq

Hiccup-seq is simply a clojure sequence (or vector) of hiccup forms. In option flags it is referenced by the keyword `:hiccup-seq`. By wrapping multiple hiccup forms in a sequence, hiccup-seq can represent any single root element (and it's children) *and* any template fragment composed of sibling elements.

For example: the html snippet `

one

two

` is represented in hiccup-seq as: `([:p "one"] [:p "two"])`

### hickory-seq

Hickory-seq is simply a clojure sequence (or vector) of hickory forms. In option flags it is referenced by the keyword `:hickory-seq`. By wrapping multiple hickory forms in a sequence, hickory-seq can represent any single root element (and it's children) *and* any template fragment composed of sibling elements.

For example: the html snippet `

one

two

` is represented in hickory-seq as: `({:type :element, :attrs nil, :tag :p, :content ["one"]} {:type :element, :attrs nil, :tag :p, :content ["two"]})`

### html

html is represented internally as a string. This is a flexible type and can hold a root element and children, or a number of sibling elements sequentially.

### xml

xml is represented internally as a string. This type always starts with an XML header ``

You can output xml with bootleg by converting to type `:xml` first:

```clojure
$ bootleg -e '(convert-to [:link "foo"] :xml)'
foo
```

## Inbuilt functions

The following functions are inbuilt into the clojure interpreter:

### Markup Processing Functions

#### markdown

`(markdown source & options)`

Load the markdown from the file specified in `source` and render it. `source` can be a local file path (relative to the executing hiccup file location) or a URL to gather the markdown from.

Options can be used to alter the behaviour of the function. Options are a list of keywords and can be specified in any order after the source parameter. Options can be:

* `:data` Interpret the `source` argument as markdown data, not a file to load
* `:hiccup-seq` Return the rendered markdown as a hiccup sequence data structure
* `:hickory-seq` Return the rendered markdown as a hickory sequence data structure
* `:html` Return the rendered markdown as an html string

eg.

```clojure
$ bootleg -e '(markdown "# heading\nparagraph" :data)'

heading

paragraph


```
```clojure
$ bootleg -d -e '(markdown "# heading\nparagraph" :data :hickory-seq)'
({:type :element, :attrs nil, :tag :h1, :content ["heading"]}
{:type :element, :attrs nil, :tag :p, :content ["paragraph"]})
```

```clojure
$ bootleg -d -e '(markdown "# heading\nparagraph" :data :hiccup-seq)'
([:h1 "heading"] [:p "paragraph"])
```

```clojure
$ bootleg -d -e '(markdown "# heading\nparagraph" :data :html)'
"

heading

paragraph

"
```

#### mustache

`(mustache source vars & options)`

Load a mustache template from the file specified in `source` and render it substituting the vars from `vars`. `source` can be a local file path (relative to the executing hiccup file location) or a URL to gather the markdown from.

Options can be used to alter the behaviour of the function. Options are a list of keywords and can be specified in any order after the source parameter. Options can be:

* `:data` Interpret the `source` argument as mustache data, not a file to load
* `:hiccup` Return the rendered mustache as hiccup
* `:hiccup-seq` Return the rendered mustache as a hiccup sequence data structure
* `:hickory` Return the rendered mustache as hickory
* `:hickory-seq` Return the rendered mustache as a hickory sequence data structure
* `:html` Return the rendered mustache as an html string

eg.

```clojure
$ bootleg -e '(mustache "

{{var1}}

{{&var2}}
" {:var1 "value 1" :var2 "

markup

"} :data)'

value 1

markup


```

```clojure
$ bootleg -d -e '(mustache "

{{var1}}

" {:var1 "value 1"} :data :hiccup-seq)'
([:p "value 1"])
```

#### selmer

`(selmer source vars & options)`

Load a selmer template from the file specified in `source` and render it substituting the vars from `vars`. `source` can be a local file path (relative to the executing hiccup file location) or a URL to gather the markdown from.

Options can be used to alter the behaviour of the function. Options are a list of keywords and can be specified in any order after the source parameter. Options can be:

* `:data` Interpret the `source` argument as selmer data, not a file to load
* `:hiccup` Return the rendered selmer as hiccup
* `:hiccup-seq` Return the rendered selmer as a hiccup sequence data structure
* `:hickory` Return the rendered selmer as hickory
* `:hickory-seq` Return the rendered selmer as a hickory sequence data structure
* `:html` Return the rendered selmer as an html string

eg.

```clojure
$ bootleg -e '(selmer "

Hello {{name|capitalize}}!

" {:name "world"} :data)'

Hello World!


```

```clojure
$ bootleg -d -e '(selmer "

Hello {{name|capitalize}}!

" {:name "world"} :data :hiccup-seq)'
([:p "Hello World!"])
```

The `selmer` namespaces are also provided at their usual namespace locations.

* selmer.filter-parser
* selmer.filters
* selmer.middleware
* selmer.node
* selmer.parser
* selmer.tags
* selmer.template-parser
* selmer.util
* selmer.validator

#### slurp

`(slurp source)`

Load the contents of a file, from a local or remote source, into memory and return it. This `slurp` can load from URLs. Does no interpretation of the file contents at all. Returns them as is.

#### html

`(html source & options)`

Loads the contents of a html or xml file and returns them in `:hiccup-seq` (by default).

Options can be:

* `:data` Interpret the `source` argument as markdown data, not a file to load
* `:hiccup` Return the rendered markdown as hiccup
* `:hiccup-seq` Return the rendered markdown as a hiccup sequence data structure
* `:hickory` Return the rendered markdown as hickory
* `:hickory-seq` Return the rendered markdown as a hickory sequence data structure
* `:html` Return the rendered markdown as an html string

eg.

```clojure
$ bootleg -d -e '(html "

heading

body

" :data :hiccup-seq)'
([:h1 "heading"] [:p "body"])
```

```clojure
$ bootleg -d -e '(html "


heading


body


" :data :hiccup)'
[:div [:h1 "heading"] [:p "body"]]
```

#### hiccup

`(hiccup source)`

Loads and evaluates the clojure source from another file.

### Filesystem Functions

#### glob

`(glob pattern)`

Returns a sequence of files that match the globbing pattern `pattern`. Supports `*`, `**`, `?`, `[abc]`, `[a-z]`, `[!a]` and relative file paths `.` and `..`. File paths are returned relative to the directory of the executing file.

```shell
$ bootleg -d -e '(glob "**/*.y?l")'
(".github/workflows/deploy.yml"
".circleci/config.yml"
"examples/quickstart/fields.yml"
"test/files/simple.yml")
```

#### symlink

`(symlink link target)`

Make a symlink from `link` to `target`. Operates idempotently. If the link already exists it does nothing. If the `link` exists but points to another target, changes the link to point to the specified `target`. If the `link` exists but is not a symbolic link, throws an exception. On success returns the path of the link.

#### mkdir

`(mkdir path)`

Make a directory `path`. Does not create any parent directories. Operates idempotently. If the direcotry exists, it does nothing. Otherwise it tries to create the directory. On success it returns the directory path.

#### mkdirs

`(mkdirs path)`

Make a directory `path` including all the parent directories. Operates idempotently. If the direcotry exists, it does nothing. Otherwise it tries to create the directories. On success it returns the final directory path.

#### spit

`(spit filename data)`

Write `data` into the specified `filename`. The filename is interpereted relative to the path of the current script.

### Var Loading Functions

#### yaml

`(yaml source & options)`

Load yaml data from `source` and process it. Returns the parsed data structure.

Options can be:

* `:data` Interpret the `source` argument as yaml data, not a file to load

#### json

`(json source & options)`

Load json data from `source` and process it. Returns the parsed data structure.

Options can be:

* `:data` Interpret the `source` argument as json data, not a file to load

#### edn

`(edn source & options)`

Load edn data from `source` and process it. Returns the parsed data structure.

Options can be:

* `:data` Interpret the `source` argument as edn data, not a file to load

### Data Testing

#### is-hiccup?

`(is-hiccup? data)`

Test the markup in `data`. Return `true` if the data is a hiccup form.

#### is-hiccup-seq?

`(is-hiccup-seq? data)`

Test the markup in `data`. Return `true` if the data is a sequence of hiccup forms.

#### is-hickory?

`(is-hickory? data)`

Test the markup in `data`. Return `true` if the data is a hickory form.

#### is-hickory-seq?

`(is-hickory-seq? data)`

Test the markup in `data`. Return `true` if the data is a sequence of hickory forms.

### Data Conversion

#### convert-to

`(convert-to data type)`

Convert one supported data type to another. Input data may be hiccup, hiccup-seq, hickory, hickory-seq or html.

Type may be `:hiccup`, `:hiccup-seq`, `:hickory`, `:hickory-seq` or `:html`.

Example:

```clojure
$ bootleg -d -e '(convert-to [:p#id.class "one"] :hickory)'
{:type :element,
:attrs {:class "class", :id "id"},
:tag :p,
:content ["one"]}
```

```clojure
$ bootleg -d -e '(convert-to "

one

" :hiccup)'
[:p {:class "class", :id "id"} "one"]
```

```clojure
$ bootleg -d -e '(convert-to "

one

two

" :hiccup-seq)'
([:p "one"] [:p "two"])
```

```clojure
$ bootleg -d -e '(convert-to {:type :element :tag :p :content ["one"]} :html)'
"

one

"
```

```clojure
$ bootleg -d -e '(convert-to [:link "foo"] :xml)'
"foo"
```

**Note:** Some conversions are lossy. Converting from html or any *-seq data type to hickory or hiccup may lose forms. Only the last form will be returned.

```clojure
$ bootleg -d -e '(convert-to "

one

two

" :hiccup)'
Warning: converting markup from :html to :hiccup lost 1 form
[:p "two"]
```

#### as-html

`(as-html data)`

Convert any supported input format passed into `data` to html output. Same as `(convert-to data :html)`

### Enlive Processing

Enlive html functions are to be found in the `enlive` namespace. A new version of `at` is supplied that provides automatic type coercion for the inputs and outputs.

In addition to this the standard enlive namespaces are available in their usual locations:

* net.cgrand.enlive-html
* net.cgrand.jsoup
* net.cgrand.tagsoup
* net.cgrand.xml

#### at

`(at data selector transform & more)`

Take the markup `data` and process every element matching `selector` through the transform `transform`

#### deftemplate

`(deftemplate name source args & forms)`

Defines a template as a function that returns a *hiccup-seq*.

** Note ** the original deftemplate returned a sequence of strings

#### defsnippet

`(defsnippet name source selector args & forms)`

Define a named snippet -- equivalent to (def name (snippet source selector args ...)).

Returns a hickory-seq on nodes.

### Enlive Transforms

#### content

`(content & values)`

Replaces the content of the element. Values can be any supported formats: hickory, hickory-seq, hiccup, hiccup-seq or html.

** note: ** This is different to the standard enlive `content` function. The standard function is present as `content*`. Passing html to `content` will embed that markup in the output. In contrast, passing html to `content*` will insert that html in an escaped form.

#### html-snippet

`(html-snippet & values)`

Concatenate values as a string and then parse it with tagsoup. html-snippet doesn't insert missing or tags.

#### html-content

`(html-content & values)`

Replaces the content of the element. Values are strings containing html code. This is present for backwards compatibility. The new `content` function can take and embed html code and should be used instead.

#### wrap

`(wrap tag attr)`

Wraps selected node into the given tag. eg. `(wrap :div)` or `(wrap :div {:class "foo"})`

#### unwrap

`unwrap`

Opposite to wrap, returns the content of the selected node.

#### set-attr

`(set-attr & key-value-pairs)`

Assocs attributes on the selected element. eg. `(set-attr :attr1 "val1" :attr2 "val2")`

#### remove-attr

`(remove-attr & attr-names)`

Sets given key value pairs as attributes for selected node. eg. `(remove-attr :attr1 :attr2)`

#### add-class

`(add-class & classes)`

Adds class(es) to the selected node. eg. `(add-class "foo" "bar")`

#### remove-class

`(add-class & classes)`

Removes class(es) from the selected node. eg. `(remove-class "foo" "bar")`

#### do->

`(do-> & fns)`

Chains (composes) several transformations. Applies functions from left to right. eg. `(do-> transformation1 transformation2)`

#### append

`(append & values)`

Appends the values to the content of the selected element. eg. `(append "xyz" a-node "abc")`

Values can be any supported formats: hickory, hickory-seq, hiccup, hiccup-seq or html.

#### prepend

`(prepend & values)`

Prepends the values to the content of the selected element. eg. `(prepend "xyz" a-node "abc")`

Values can be any supported formats: hickory, hickory-seq, hiccup, hiccup-seq or html.

#### after

`(after & values)`

Inserts the values after the current selection (node or fragment). eg. `(after "xyz" a-node "abc")`

Values can be any supported formats: hickory, hickory-seq, hiccup, hiccup-seq or html.

#### before

`(before & values)`

Inserts the values before the current selection (node or fragment). eg. `(before "xyz" a-node "abc")`

Values can be any supported formats: hickory, hickory-seq, hiccup, hiccup-seq or html.

#### substitute

`(substitute & values)`

Replaces the current selection (node or fragment). eg. `(substitute "xyz" a-node "abc")`

Values can be any supported formats: hickory, hickory-seq, hiccup, hiccup-seq or html.

#### move

`(move src-selector dest-selector)`
`(src-selector dest-selector combiner)`

Takes all nodes (under the current element) matched by src-selector, removes them and combines them with the elements matched by dest-selector. eg. `(move [:.footnote] [:#footnotes] content)`

#### content*

`(content* & values)`

The original enlive content transformer. Replaces the content of the element. Values can be hickory nodes, collection of hikory nodes, or plain text strings.

#### append*

`(append* & values)`

The original enlive append transformer. Appends the values to the content of the selected element. eg. `(append "xyz" a-node "abc")`

#### prepend*

`(prepend* & values)`

The original enlive prepend transformer. Prepends the values to the content of the selected element. eg. `(prepend "xyz" a-node "abc")`

#### after*

`(after* & values)`

The original enlive after transformer. Inserts the values after the current selection (node or fragment). eg. `(after "xyz" a-node "abc")`

#### before*

`(before* & values)`

The original enlive before transformer. Inserts the values before the current selection (node or fragment). eg. `(before "xyz" a-node "abc")`

#### substitute*

`(substitute* & values)`

The original enlive substitute transformer. Replaces the current selection (node or fragment). eg. `(substitute "xyz" a-node "abc")`

### Hickory

The `hickory` namespaces are provided at their usual namespace locations.

* hickory.convert
* hickory.hiccup-utils
* hickory.render
* hickory.select
* hickory.utils
* hickory.zip

### Other Functions

#### pprint

`(pprint form)`

Pretty print to stdout the passed in form. If `--colour` is passed on command line then print with colour highlighting.

#### parse-string

`(parse-string string)`

Parse the passed in string into a clojure type. Useful for converting strings to numbers, keywords, vectors or hashmaps. A binding of [edamame's](https://github.com/borkdude/edamame) `parse-string` is used for parsing.

### Java Packages

The following java classes are included and can be imported and used:

* java.time.* (https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html)

#### java.time

```shell
$ bootleg -d -e '(import [java.time LocalDate]) (LocalDate/now)'
#object[java.time.LocalDate "0x7d108063" "2020-01-28"]
```

## Passing in Context

### Environment Variables

You can access environment variables through the `System` [namespace](https://docs.oracle.com/javase/8/docs/api/java/lang/System.html). This namespace has the `getenv` function:

```shell
$ FOO=bar bootleg -d -e '(System/getenv "FOO")'
"bar"
```

### Command Line Arguments

Command line arguments are available in the `*command-line-args*` var:

```shell
$ bootleg -d -e '*command-line-args*'
("-d" "-e" "*command-line-args*")
```

Also included is the `clojure.tools.cli` namespace that you can `require` as needed to process command line args, or reference its namespace directly:

```shell
$ bootleg -d -e '(clojure.tools.cli/parse-opts *command-line-args* [["-e" "--evaluate CODE" ""] ["-d" "--data" ""]])'
{:options {:data true,
:evaluate "(clojure.tools.cli/parse-opts *command-line-args* [[\"-e\" \"--evaluate CODE\" \"\"] [\"-d\" \"--data\" \"\"]])"},
:arguments [],
:summary " -e, --evaluate CODE\n -d, --data",
:errors nil}
```

If you want to pass in edn in a env var or command line you can use edamame's reader that is already available under `parse-string`:

```shell
$ FOO='{:a 1 :b 2}' bootleg -d -e '(-> "FOO" System/getenv parse-string :b)'
2
```

### Standard Input

When no `-e` argument is passed on the command line and no filename is supplied then bootleg will read its clojure script from standard in:

```shell
$ bootleg <<< '[:p 1]'

1


```

`*in*` is bound to `clojure.lang.LineNumberingPushbackReader` on standard in as it is in clojure. So you can slurp in to process standard in:

```shell
echo -n "" | bootleg -d -e '(-> *in* slurp (convert-to :hiccup))'
[:html]
```

Remember to be careful of trailing newlines when using bash's `<<<` pipe form.

```
$ bootleg -d -e '(-> *in* slurp (convert-to :hiccup))' <<< ''
Warning: converting markup from :html to :hiccup lost 1 form
"\n"
$ bootleg -d -e '(-> *in* slurp (convert-to :hiccup-seq))' <<< ''
([:html] "\n")
```

### Shebang

Bootleg scripts can contain a shebang line. Then if the executable bit is set, they can be run like programmes. Examine the shebang example in `examples/quickstart/shebang.clj`.

```shell
$ cat shebang.clj
#!/usr/bin/env bootleg

[:div
[:h1 "Command Line Args"]
[:ul
(for [arg *command-line-args*]
[:li arg])]]
```

Make it executable:

```shell
$ chmod a+x shebang.clj
```

Run it on the command line:

```shell
$ ./shebang.clj arg1 arg2 "This is argument 3"


Command Line Args



  • ./shebang.clj

  • arg1

  • arg2

  • This is argument 3



```

## Building the executable

Ensure graalvm community edition 19.3.0 is installed in your home directory and the native image extension is also installed.

```shell
$ make clean
$ make all
```

The compiled file will be at `build/bootleg`

To use a different version of graal or one installed in a different path, add the GRAALVM suffix like:

```shell
$ make all GRAALVM=/path/to/graal-vm
```

## Examples

The following are some example sites built using bootleg for you to use as inspiration, or as a base for your own work.

* [epiccastle.io](https://github.com/epiccastle/epiccastle.io)
* [michielborkent.nl](https://github.com/borkdude/michielborkent.nl)
* [gaiwan.co](https://github.com/lambdaisland/gaiwan_co)

## Blog Posts

* https://epiccastle.io/blog/generating-xml-with-bootleg/
* https://nextjournal.com/plexus/advent-2019-part-18-exploring-bootleg

### Submit Your Own Example

Have you built a website with bootleg? Is the source of this website open source? If so [open an issue](https://github.com/retrogradeorbit/bootleg/issues/new) on the project with a link to your github project with the source tree in it and I will add it to the examples list. This way there will be more reference material for bootleg users to draw apon!

## Thanks

`bootleg` leverages other people's amazing work. The following projects and people enable this to exist at all.

* [Michiel Borkent](https://www.michielborkent.nl/) built [Sci](https://github.com/borkdude/sci)
* [James Reeves](https://www.booleanknot.com/) built [Hiccup](https://github.com/weavejester/hiccup)
* [Christophe Grand](http://clj-me.cgrand.net/) built [Enlive](https://github.com/cgrand/enlive)
* [David Santiago](https://github.com/davidsantiago) built [Hickory](https://github.com/davidsantiago/hickory)
* [Dmitri Sotnikov](https://yogthos.net/) built [Selmer](https://github.com/yogthos/Selmer)

## License

Copyright © 2019 Crispin Wellington

This program and the accompanying materials are made available under the
terms of the Eclipse Public License 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0.

This Source Code may also be made available under the following Secondary
Licenses when the conditions for such availability set forth in the Eclipse
Public License, v. 2.0 are satisfied: GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or (at your
option) any later version, with the GNU Classpath Exception which is available
at https://www.gnu.org/software/classpath/license.html.