Site Generation - Matt Whipple

This site is generated with pandoc. Each html file can be produced by the corresponding source markdown(“Daring Fireball: Markdown” 2021) file which lends itself. The source files themselves can be collected using a wildcard/glob which can then be used to derive the output files. The pattern itself can be used to call pandoc with the desired invocation.

To support execution in CI or on any system without a haskell environment, this will also support execution through a container.

Makefile

Required Commands

This section will define some of the invoked commands using the required command Make recipe. For the time being this will just be copied around.

missing-command = $(error $(or ${${1}_INSTALL}, '${1}; is missing; please install ${1}))
required-command = $(or ${_${1}_which},          \
    $(eval _${1}_which=$(shell which ${1})), \
    ${_${1}_which},                          \
    $(call missing-command,${1}))

DOCKER = $(call required-command,docker)

Basic Project Structure

Next to define some basic project structure with inputs and outputs. A site PHONY target will be defined to enable building of all of the outputs.

BIB_FILE := sources.bib
OUT_DIR  := public/

SOURCES   = $(wildcard *.md)
OUTPUTS   = $(addprefix ${OUT_DIR},${SOURCES:%.md=%.html})

site: ${OUTPUTS}
.PHONY: site

Define Docker Image

Running within a container requires selection of a Docker image. It seems somewhat likely I’ll need to construct a customized image later, but for now I’ll make use of one of the standard pandoc images (“Pandoc/Dockerfiles: Dockerfiles for Various Pandoc Images” 2021).

PANDOC_IMAGE := pandoc/core:2.14.0.1

Run Within Container if Specified

I typically use one of two patterns to run things in containers, either a prefixed target pattern (i.e. docker-<target>) or accepting a flag which swaps out how things are done. Here I’ll use the latter where the passing of a defined IN_DOCKER flag (often provided as an enviornment variable) modifies targets to run within defined containers rather than directly on the host.

If that IN_DOCKER flag is defined then pandoc should be run in a container which works within a bind mount of th local directory, if the flag is not present pandoc should be invoked directly.

TODO: Extract and use current user

ifdef IN_DOCKER
  PANDOC = ${DOCKER} run --rm --volume $(abspath .):/host -w /host ${PANDOC_IMAGE}
else
  PANDOC = $(call required-command,pandoc)
endif

Define Conversion Rule

With all of the building blocks defined, the rule to pass the sourcefiles through pandoc to produce the HTML output can be defined.

${OUT_DIR}%.html: %.md
    ${PANDOC} --citeproc --bibliography ${BIB_FILE} -s -o ${@} ${<}
“Daring Fireball: Markdown.” 2021. https://daringfireball.net/projects/markdown.
“Pandoc/Dockerfiles: Dockerfiles for Various Pandoc Images.” 2021. https://github.com/pandoc/dockerfiles.