Improve makefile by writing a blog
This commit is contained in:
parent
983b3c8def
commit
debfc13228
3 changed files with 222 additions and 8 deletions
5
Makefile
5
Makefile
|
@ -35,13 +35,12 @@ css: $(DST_CSS_FILES)
|
||||||
# ORG -> HTML
|
# ORG -> HTML
|
||||||
EXT ?= .org
|
EXT ?= .org
|
||||||
SRC_PANDOC_FILES ?= $(shell find $(SRC_DIR) -type f -name "*$(EXT)" $(NO_DRAFT))
|
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)/%, \
|
$(patsubst $(SRC_DIR)/%,$(DST_DIR)/%, \
|
||||||
$(SRC_PANDOC_FILES)))
|
$(SRC_PANDOC_FILES)))
|
||||||
PANDOC_TEMPLATE ?= templates/post.html
|
PANDOC_TEMPLATE ?= templates/post.html
|
||||||
PANDOC_CSS ?= /css/y.css
|
|
||||||
MK_HTML := engine/mk-html.sh
|
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)
|
$(DST_DIR)/%.html: $(SRC_DIR)/%.org $(PANDOC_TEMPLATE) $(MK_HTML)
|
||||||
@mkdir -p "$(dir $@)"
|
@mkdir -p "$(dir $@)"
|
||||||
$(PANDOC) "$<" "$@.tmp"
|
$(PANDOC) "$<" "$@.tmp"
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
cd "$(git rev-parse --show-toplevel)" || exit 1
|
cd "$(git rev-parse --show-toplevel)" || exit 1
|
||||||
css="$1"
|
template="$1"
|
||||||
template="$2"
|
orgfile="$2"
|
||||||
orgfile="$3"
|
htmlfile="$3"
|
||||||
htmlfile="$4"
|
|
||||||
|
|
||||||
tocoption=""
|
tocoption=""
|
||||||
if grep -ie '^#+options:' "$orgfile" | grep 'toc:t'>/dev/null; then
|
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
|
fi
|
||||||
|
|
||||||
set -x
|
set -x
|
||||||
pandoc -c "$css" $tocoption \
|
pandoc $tocoption \
|
||||||
--template="$template" \
|
--template="$template" \
|
||||||
--mathml \
|
--mathml \
|
||||||
--from org \
|
--from 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/<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.
|
Loading…
Reference in a new issue