Improve makefile by writing a blog

This commit is contained in:
Yann Esposito (Yogsototh) 2021-05-09 17:32:15 +02:00
parent 983b3c8def
commit debfc13228
Signed by untrusted user who does not match committer: yogsototh
GPG Key ID: 7B19A4C650D59646
3 changed files with 222 additions and 8 deletions

View File

@ -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"

View File

@ -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 \

View File

@ -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/<something>= look at
=src/<something>= and
- create the directory to put =_site/<something>= 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.