From debfc132286f42ad8281297765f72a06e05b1ce8 Mon Sep 17 00:00:00 2001 From: "Yann Esposito (Yogsototh)" Date: Sun, 9 May 2021 17:32:15 +0200 Subject: [PATCH] Improve makefile by writing a blog --- Makefile | 5 +- engine/mk-html.sh | 9 +- .../index.org | 216 ++++++++++++++++++ 3 files changed, 222 insertions(+), 8 deletions(-) create mode 100644 src/posts/0018-makefile-as-static-site-builder-follow-up/index.org diff --git a/Makefile b/Makefile index 510bddb..2bc722d 100644 --- a/Makefile +++ b/Makefile @@ -35,13 +35,12 @@ css: $(DST_CSS_FILES) # ORG -> HTML EXT ?= .org SRC_PANDOC_FILES ?= $(shell find $(SRC_DIR) -type f -name "*$(EXT)" $(NO_DRAFT)) -DST_PANDOC_FILES ?= $(subst $(EXT),.html, \ +DST_PANDOC_FILES ?= $(patsubst %$(EXT),%.html, \ $(patsubst $(SRC_DIR)/%,$(DST_DIR)/%, \ $(SRC_PANDOC_FILES))) PANDOC_TEMPLATE ?= templates/post.html -PANDOC_CSS ?= /css/y.css MK_HTML := engine/mk-html.sh -PANDOC := $(MK_HTML) $(PANDOC_CSS) $(PANDOC_TEMPLATE) +PANDOC := $(MK_HTML) $(PANDOC_TEMPLATE) $(DST_DIR)/%.html: $(SRC_DIR)/%.org $(PANDOC_TEMPLATE) $(MK_HTML) @mkdir -p "$(dir $@)" $(PANDOC) "$<" "$@.tmp" diff --git a/engine/mk-html.sh b/engine/mk-html.sh index ae9c556..b76355c 100755 --- a/engine/mk-html.sh +++ b/engine/mk-html.sh @@ -2,10 +2,9 @@ set -eu cd "$(git rev-parse --show-toplevel)" || exit 1 -css="$1" -template="$2" -orgfile="$3" -htmlfile="$4" +template="$1" +orgfile="$2" +htmlfile="$3" tocoption="" if grep -ie '^#+options:' "$orgfile" | grep 'toc:t'>/dev/null; then @@ -13,7 +12,7 @@ if grep -ie '^#+options:' "$orgfile" | grep 'toc:t'>/dev/null; then fi set -x -pandoc -c "$css" $tocoption \ +pandoc $tocoption \ --template="$template" \ --mathml \ --from org \ diff --git a/src/posts/0018-makefile-as-static-site-builder-follow-up/index.org b/src/posts/0018-makefile-as-static-site-builder-follow-up/index.org new file mode 100644 index 0000000..3691c41 --- /dev/null +++ b/src/posts/0018-makefile-as-static-site-builder-follow-up/index.org @@ -0,0 +1,216 @@ +#+TITLE: Makefile as static site builder +#+DESCRIPTION: A few Makefile features tutorial +#+KEYWORDS: blog static +#+AUTHOR: Yann Esposito +#+EMAIL: yann@esposito.host +#+DATE: [2021-05-09 Sun] +#+LANG: en +#+OPTIONS: auto-id:t +#+STARTUP: showeverything + +After many different tools, I recently switched to a simple Makefile to +generate my static website. +In [[https://her.esy.fun/posts/0017-static-blog-builder/index.html][Static Blog Builder]] I give a starter pack. +Along the way I had to learn about Makefiles. +So here are a few pointers and helpers. + +So an important one. +The first rule of your Makefile will be the default rule. +I called mine =all= which will depends on another rule call =site=. +Why? +Because, the rule format is generally something like: + +#+begin_src makefile +file_to_generate: file_to_use another_file_to_use + build --input file_to_use another_file_to_user \ + --output file_to_generate +#+end_src + +if =file_to_generate= does not exists, then =make= will look at its +dependencies. +If any of its dependency need to be updated, it will run all the rules in +the correct order to rebuild them, and finally run the script to build +=file_to_generate=. +A file need to be updated if one of its dependency need to be updated or is +newer. + +The ususal case of =make= is about building a single binary out of many +source files. +But for a static website, we need to generate a lot of files from a lot of +files. +So we construct the rules like this: + +#+begin_src makefile +all: site + +# build a list of files that will need to be build +DST_FILES := .... +ALL += $(DST_FILES) + +# another list of files +DST_FILES_2 := .... +ALL += $(DST_FILES_2) + +site: $(ALL) +#+end_src + +In my =Makefile= I have many similar block with the same pattern. + +1. I retrieve a list of source files +2. I construct the list of destination files (change the directory, the extension) +3. I declare a rule to construct these destination files +4. I add the destination files to the =ALL= variable. + +So I have a block for: +- raw assets I just want copied +- images I would like to compress for the web +- =html= I would like to generate from org mode files +- =gmi= I would like to generate from org mode files +- =xml= files I use as cache to build different index files +- =index.html= file containing a list of my posts +- =rss.xml= file containing a list of my posts +- =gemini-atom.xml= file containing a list of my posts + +So to go further, let's take a look at a simplified raw assets copy block: + +#+begin_src makefile +SRC_ASSETS := $(shell find src -type f) +DST_ASSETS := $(patsubst src/%,_site/%,$(SRC_ASSETS)) +_site/% : src/% + @mkdir -p "$(dir $@)" + cp "$<" "$@" +ALL += $(DST_ASSETS) +#+end_src + +OK, this looks terrible. +But mainly: + +1. ~SRC_ASSETS~ will contains the result of the command ~find~. +2. We replace all =src/= prefix of all those files by the =_site/= prefix. +3. We create a rule, if you are asked to build =_site/= look at + =src/= and + - create the directory to put =_site/= in + - copy the file + +About the line ~@mkdir -p "$(dir $@)"~: +- the =@= at the start of the command simply means that we make this execution silent. +- The =$@= is replaced by the target string. +- And =$(dir $@)= will generate the dirname of =$@=. + +For the line with ~cp~ you just need to know that =$<= will represent the +first dependency. + +Once you have this pattern in mind. +Adding new block become a bit natural. +You will also like to use some variables for repetitive names. + +** Prelude +:PROPERTIES: +:CUSTOM_ID: prelude +:END: + +#+begin_src makefile +all: site +SRC_DIR ?= src +DST_DIR ?= _site +CACHE_DIR ?= .cache + +# we don't want to publish files in drafts +NO_DRAFT := -not -path '$(SRC_DIR)/drafts/*' +# we don't copy source files +NO_SRC_FILE := ! -name '*.org' +#+end_src + +** CSS +:PROPERTIES: +:CUSTOM_ID: css +:END: + +#+begin_src makefile +# CSS +SRC_CSS_FILES := $(shell find $(SRC_DIR) -type f -name '*.css') +DST_CSS_FILES := $(patsubst $(SRC_DIR)/%,$(DST_DIR)/%,$(SRC_RAW_FILES)) +ALL += $(DST_CSS_FILES) +$(DST_DIR)/%.css : $(SRC_DIR)/%.css + @mkdir -p "$(dir $@)" + minify "$<" > "$@" +css: $(DST_CSS_FILES) +#+end_src + +This is very similar to the block for raw assets. +The difference is just that instead of using =cp= we use the =minify= +command. +And also I use global constants (=SRC_DIR= and =DST_DIR=). + +** ORG -> HTML +:PROPERTIES: +:CUSTOM_ID: org----html +:END: + +Now this one is more complex but is still follow the same pattern. + +#+begin_src makefile +# ORG -> HTML +EXT ?= .org +SRC_PANDOC_FILES ?= $(shell find $(SRC_DIR) -type f -name "*$(EXT)" $(NO_DRAFT)) +DST_PANDOC_FILES ?= $(patsubst %$(EXT),%.html, \ + $(patsubst $(SRC_DIR)/%,$(DST_DIR)/%, \ + $(SRC_PANDOC_FILES))) +PANDOC_TEMPLATE ?= templates/post.html +MK_HTML := engine/mk-html.sh +PANDOC := $(MK_HTML) $(PANDOC_CSS) $(PANDOC_TEMPLATE) +$(DST_DIR)/%.html: $(SRC_DIR)/%.org $(PANDOC_TEMPLATE) $(MK_HTML) + @mkdir -p "$(dir $@)" + $(PANDOC) "$<" "$@.tmp" + minify --mime text/html "$@.tmp" > "$@" + @rm "$@.tmp" +ALL += $(DST_PANDOC_FILES) +html: $(DST_PANDOC_FILES) +#+end_src + +So to construct =DST_PANDOC_FILES= this time we also need to change the +extension of the file from =org= to =html=. +We need to provide a template that will be passed to pandoc. + +And of course, as if we change the template file we would like to +regenerate all HTML files we put the template as a dependency. +But importantly *not* at the first place. Because we use =$<= that will be +the first dependency. + +I also have a short script instead of directly using =pandoc=. +Because I would like to handle the =toc= depending on the metadatas in the +file. + +The =mk-html.sh= is quite straightforward: + +#+begin_src bash +#!/usr/bin/env bash +set -eu + +# put me at the top level of my project (like Makefile) +cd "$(git rev-parse --show-toplevel)" || exit 1 +template="$1" +orgfile="$2" +htmlfile="$3" + +# check if there is the #+OPTIONS: toc:t +tocoption="" +if grep -ie '^#+options:' "$orgfile" | grep 'toc:t'>/dev/null; then + tocoption="--toc" +fi + +set -x +pandoc $tocoption \ + --template="$template" \ + --mathml \ + --from org \ + --to html5 \ + --standalone \ + $orgfile \ + --output "$htmlfile" +#+end_src + +Once generated I also minify the html file. +And, that's it. +But the important part is that now, if I change my script or the template +or the file, it will generate the dependencies.