author | Alan Dipert
<alan@dipert.org> 2025-10-08 20:21:01 UTC |
committer | Alan Dipert
<alan@dipert.org> 2025-10-08 20:21:01 UTC |
parent | 6adf424946e00d146d80fb11f3c0db4e9e50bfa7 |
Makefile | +11 | -16 |
tools/build_page.sh | +91 | -0 |
tools/gen_index.sh | +7 | -2 |
diff --git a/Makefile b/Makefile index b3382c1..9e7c942 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,9 @@ CSS := tpl/style.css MD2HTML ?= /usr/bin/cmark-gfm CMARK_FLAGS := --to html --extension table --validate-utf8 --unsafe BUILDINFO := tools/buildinfo.sh +BUILDINFO_STAMP := $(OUT)/.buildinfo +GIT_HEAD_REF := $(strip $(shell git symbolic-ref -q HEAD 2>/dev/null)) +GIT_HEAD_FILE := $(if $(GIT_HEAD_REF),.git/$(GIT_HEAD_REF),.git/HEAD) INDEX_HTML := $(OUT)/Index.html DEPLOY_HOST ?= arsien23i2@dreamhost:tailrecursion.com/~alan @@ -16,6 +19,9 @@ HTML := $(patsubst $(SRC)/%.md,$(OUT)/%.html,$(MD_FILES)) all: assets $(OUT)/style.css $(HTML) $(INDEX_HTML) +$(BUILDINFO_STAMP): $(BUILDINFO) .git/HEAD $(GIT_HEAD_FILE) | $(OUT) + $(BUILDINFO) > $@ + $(OUT)/style.css: $(CSS) mkdir -p $(OUT) cp $(CSS) $@ @@ -23,27 +29,16 @@ $(OUT)/style.css: $(CSS) $(OUT): mkdir -p $(OUT) -$(OUT)/%.html: $(SRC)/%.md $(HEAD) $(FOOT) tools/mdlink2html.awk $(BUILDINFO) | $(OUT) - mkdir -p $(@D) - awk -f tools/mdlink2html.awk $< > $@.rewritten.md - $(MD2HTML) $(CMARK_FLAGS) $@.rewritten.md > $@.body.html - root_prefix="$$(dirname "$@" | sed -e 's#^$(OUT)##' -e 's#^/##' -e 's#[^/][^/]*#../#g')"; \ - page_title=$$(basename "$<" .md); \ - build_info=$$($(BUILDINFO)); \ - build_info_esc=$$(printf '%s\n' "$$build_info" | sed 's/[\\/\&]/\\&/g'); \ - page_title_esc=$$(printf '%s\n' "$$page_title" | sed 's/[\\/\&]/\\&/g'); \ - sed -e "s|@ROOT@|$${root_prefix}|g" -e "s|@BUILDINFO@|$${build_info_esc}|g" -e "s|@TITLE@|$${page_title_esc}|g" $(HEAD) > $@.head.html; \ - sed -e "s|@ROOT@|$${root_prefix}|g" -e "s|@BUILDINFO@|$${build_info_esc}|g" -e "s|@TITLE@|$${page_title_esc}|g" $(FOOT) > $@.foot.html; \ - cat $@.head.html $@.body.html $@.foot.html > $@; \ - rm -f $@.head.html $@.foot.html - rm -f $@.rewritten.md $@.body.html +$(OUT)/%.html: $(SRC)/%.md $(HEAD) $(FOOT) tools/mdlink2html.awk tools/build_page.sh $(BUILDINFO_STAMP) | $(OUT) + OUT_DIR="$(OUT)" MD2HTML="$(MD2HTML)" CMARK_FLAGS="$(CMARK_FLAGS)" \ + tools/build_page.sh "$@" "$<" "$(HEAD)" "$(FOOT)" "$(BUILDINFO_STAMP)" tools/mdlink2html.awk assets: mkdir -p $(OUT) rsync -a --include='*/' --exclude='*.md' --exclude='*.MD' --prune-empty-dirs $(SRC)/ $(OUT)/ -$(INDEX_HTML): $(HTML) tools/gen_index.sh tools/index_list.awk $(HEAD) $(FOOT) $(BUILDINFO) | $(OUT) - tools/gen_index.sh $@ $(SRC) +$(INDEX_HTML): $(HTML) tools/gen_index.sh tools/index_list.awk $(HEAD) $(FOOT) $(BUILDINFO_STAMP) | $(OUT) + tools/gen_index.sh $@ $(SRC) $(BUILDINFO_STAMP) deploy: check-git-clean assets all @if [ -z "$(DEPLOY_HOST)" ]; then \ diff --git a/tools/build_page.sh b/tools/build_page.sh new file mode 100755 index 0000000..ff662a4 --- /dev/null +++ b/tools/build_page.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <<'USAGE' +Usage: build_page.sh OUTPUT INPUT HEAD FOOT BUILDINFO MDLINK_AWK + +Render a Markdown INPUT file into OUTPUT HTML using provided HEAD and FOOT templates. + +Environment: + MD2HTML Path to the cmark-gfm executable (default: /usr/bin/cmark-gfm) + CMARK_FLAGS Flags passed to cmark-gfm (default matches Makefile) + OUT_DIR Root output directory used to compute relative links (default: out) +USAGE +} + +if [[ $# -ne 6 ]]; then + usage >&2 + exit 1 +fi + +output=$1 +input_md=$2 +head_tpl=$3 +foot_tpl=$4 +buildinfo_stamp=$5 +mdlink_awk=$6 + +MD2HTML=${MD2HTML:-/usr/bin/cmark-gfm} +CMARK_FLAGS=${CMARK_FLAGS:---to html --extension table --validate-utf8 --unsafe} +OUT_DIR=${OUT_DIR:-out} + +tmpdir=$(mktemp -d) +cleanup() { + rm -rf "$tmpdir" +} +trap cleanup EXIT INT TERM + +mkdir -p "$(dirname "$output")" + +rewritten_md="$tmpdir/rewritten.md" +body_html="$tmpdir/body.html" +head_html="$tmpdir/head.html" +foot_html="$tmpdir/foot.html" + +awk -f "$mdlink_awk" "$input_md" > "$rewritten_md" + +# shellcheck disable=SC2206 # we intentionally split CMARK_FLAGS into array words +read -r -a cmark_args <<< "$CMARK_FLAGS" +"$MD2HTML" "${cmark_args[@]}" "$rewritten_md" > "$body_html" + +page_title=$(basename "$input_md" .md) +build_info=$(cat "$buildinfo_stamp") + +escape_sed() { + printf '%s\n' "$1" | sed 's/[\\/&]/\\&/g' +} + +build_info_esc=$(escape_sed "$build_info") +page_title_esc=$(escape_sed "$page_title") + +relative_path="${output#$OUT_DIR}" +relative_path="${relative_path#/}" +if [[ "$relative_path" == "$output" ]]; then + relative_path="" +fi +relative_dir="$relative_path" +if [[ -n "$relative_dir" ]]; then + relative_dir=${relative_dir%/*} + if [[ "$relative_dir" == "$relative_path" ]]; then + relative_dir="" + fi +fi + +root_prefix="" +if [[ -n "$relative_dir" && "$relative_dir" != "." ]]; then + IFS='/' read -r -a segments <<< "$relative_dir" + for _ in "${segments[@]}"; do + root_prefix+="../" + done +fi + +sed -e "s|@ROOT@|$root_prefix|g" \ + -e "s|@BUILDINFO@|$build_info_esc|g" \ + -e "s|@TITLE@|$page_title_esc|g" "$head_tpl" > "$head_html" + +sed -e "s|@ROOT@|$root_prefix|g" \ + -e "s|@BUILDINFO@|$build_info_esc|g" \ + -e "s|@TITLE@|$page_title_esc|g" "$foot_tpl" > "$foot_html" + +cat "$head_html" "$body_html" "$foot_html" > "$output" diff --git a/tools/gen_index.sh b/tools/gen_index.sh index fa0440c..453524e 100755 --- a/tools/gen_index.sh +++ b/tools/gen_index.sh @@ -1,13 +1,18 @@ #!/usr/bin/env bash set -euo pipefail -output=${1:?"usage: gen_index.sh out/Index.html [src-dir]"} +output=${1:?"usage: gen_index.sh out/Index.html [src-dir] [buildinfo-file]"} src_dir=${2:-md} +buildinfo_file=${3:-} script_dir=$(cd "$(dirname "$0")" && pwd) root_dir=$(cd "$script_dir/.." && pwd) cd "$root_dir" -build_info=$(tools/buildinfo.sh) +if [[ -n "$buildinfo_file" && -f "$buildinfo_file" ]]; then + build_info=$(<"$buildinfo_file") +else + build_info=$(tools/buildinfo.sh) +fi build_info_esc=$(printf '%s\n' "$build_info" | sed 's/[\/&]/\\&/g') css_prefix="" page_title="Index"