diff options
| author | Ahmed <git@gumx.cc> | 2026-06-02 00:21:16 +0300 |
|---|---|---|
| committer | Ahmed <git@gumx.cc> | 2026-06-02 00:21:16 +0300 |
| commit | 6e1e8effd3e595ad342d11644b072725a218c1eb (patch) | |
| tree | 11d4c650734d814c6180db6618b89dbf3ae8c8d3 /build.sh | |
init: moved to gumx.cc
Diffstat (limited to 'build.sh')
| -rw-r--r-- | build.sh | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..2973c2f --- /dev/null +++ b/build.sh @@ -0,0 +1,215 @@ +#!/bin/bash +# build.sh - ubergeek static site generator +# Converts the wiki markdown structure into HTML using lowdown + mo. + +[[ "$(basename "${0}")" == "build.sh" ]] || { echo "Do not source build.sh"; exit 1; } + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +if [[ ! -f "${SCRIPT_DIR}/build/mo" ]]; then + echo "[error] build/mo not found. Run: curl -sL https://raw.githubusercontent.com/tests-always-included/mo/master/mo -o build/mo && chmod +x build/mo" >&2 + exit 1 +fi +. "${SCRIPT_DIR}/build/mo" + +FORCE=false +while [[ $# -gt 0 ]]; do + case "$1" in + -f|--force) FORCE=true ;; + *) echo "[error] Unknown option: $1" >&2; exit 1 ;; + esac + shift +done + +TMPDIR_BUILD="$(mktemp -d)" +cleanup() { rm -rf "${TMPDIR_BUILD}"; } +trap cleanup EXIT INT TERM + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +get_frontmatter() { + local key="$1" file="$2" + lowdown -X "${key}" "${file}" 2>/dev/null || true +} + +check_has_code() { + local html="$1" + if echo "${html}" | grep -qE '<pre><code|<code class='; then + HAS_CODE="true" + else + HAS_CODE="" + fi +} + +render_page() { + local template="$1" outfile="$2" + mkdir -p "$(dirname "${outfile}")" + local tname="${template##build/templates/}" + cp "${template}" "build/templates/partials/${tname}" + (cd build/templates/partials && mo "${tname}") > "${outfile}" + rm -f "build/templates/partials/${tname}" +} + +build_breadcrumbs() { + local path="$1" + BREADCRUMBS="" + local components="${path}" + while [[ "${components}" != "." ]]; do + BREADCRUMBS=" / <a href=\"/${components}\">$(basename "${components}")</a>${BREADCRUMBS}" + components="$(dirname "${components}")" + done +} + +# --------------------------------------------------------------------------- +# process_dir dir +# Recursively renders topic and module pages, returns a markdown list +# of direct children into ${TMPDIR_BUILD}/${dir//\//_}.list.md +# --------------------------------------------------------------------------- +process_dir() { + local dir="$1" + local list_file="${TMPDIR_BUILD}/${dir//\//_}.list.md" + : > "${list_file}" + + local find_list="${TMPDIR_BUILD}/${dir//\//_}.find.list" + find "${dir}" -mindepth 1 -maxdepth 1 -not -name '.*' -print0 | sort -z > "${find_list}" + + while IFS= read -r -d '' node; do + if [[ -d "${node}" ]]; then + local subdir_title + subdir_title="$(get_frontmatter title "${node}/index.md" 2>/dev/null || true)" + [[ -z "${subdir_title}" ]] && subdir_title="$(basename "${node}")" + printf -- '- [%s](/%s)\n' "${subdir_title}" "${node}" >> "${list_file}" + process_dir "${node}" + + elif [[ "${node}" == *.md && "$(basename "${node}")" != "index.md" ]]; then + local slug="${node%.md}" + local title date lang + title="$(get_frontmatter title "${node}")" + [[ -z "${title}" ]] && title="$(basename "${slug}")" + date="$(get_frontmatter date "${node}")" + lang="$(get_frontmatter lang "${node}")" + + local out_html="output/${slug}/index.html" + local content + content="$(lowdown "${node}")" + check_has_code "${content}" + build_breadcrumbs "${slug}" + + export PAGE_TITLE="${title}" + export CONTENT="${content}" + export BREADCRUMBS + export HEADER_EXTRA="${date}" + export META_DATE="${date}" + export META_DESCRIPTION="" + export HAS_CODE + export LANG="${lang:-en}" + export DIR="" + + render_page "build/templates/page.html" "${out_html}" + printf -- '- [%s](/%s)\n' "${title}" "${slug}" >> "${list_file}" + echo "[built] ${out_html}" + fi + done < "${find_list}" + + # Build this directory's index page + local index_src="${dir}/index.md" + local index_md="${TMPDIR_BUILD}/${dir//\//_}.index.md" + local dir_title + + if [[ -f "${index_src}" ]]; then + dir_title="$(get_frontmatter title "${index_src}")" + cp "${index_src}" "${index_md}" + else + dir_title="$(basename "${dir}")" + printf '# %s\n\n' "${dir_title}" > "${index_md}" + fi + printf '\n\n' >> "${index_md}" + cat "${list_file}" >> "${index_md}" + + local out_html="output/${dir}/index.html" + local content + content="$(lowdown "${index_md}")" + check_has_code "${content}" + build_breadcrumbs "${dir}" + + export PAGE_TITLE="${dir_title}" + export CONTENT="${content}" + export BREADCRUMBS + export HEADER_EXTRA="" + export META_DATE="" + export META_DESCRIPTION="" + export HAS_CODE + export LANG="en" + export DIR="" + + render_page "build/templates/page.html" "${out_html}" + echo "[built] output/${dir}/index.html" +} + +# --------------------------------------------------------------------------- +# Main build +# --------------------------------------------------------------------------- + +mkdir -p output + +# Discover top-level topic directories (exclude hidden, build, output) +topics_list="${TMPDIR_BUILD}/topics.list.md" +: > "${topics_list}" + +find_list="${TMPDIR_BUILD}/toplevel.find.list" +find . -mindepth 1 -maxdepth 1 -type d \ + -not -name '.*' -not -name 'build' -not -name 'output' \ + -print0 | sort -z > "${find_list}" + +while IFS= read -r -d '' topic; do + topic="${topic#./}" + topic_title="$(get_frontmatter title "${topic}/index.md" 2>/dev/null || true)" + [[ -z "${topic_title}" ]] && topic_title="${topic}" + printf -- '- [%s](/%s)\n' "${topic_title}" "${topic}" >> "${topics_list}" + process_dir "${topic}" +done < "${find_list}" + +# Home page — README.md + topic listing +home_md="${TMPDIR_BUILD}/home.md" +cp README.md "${home_md}" +printf '\n\n## topics:\n\n' >> "${home_md}" +cat "${topics_list}" >> "${home_md}" + +content="$(lowdown "${home_md}")" +check_has_code "${content}" + +export PAGE_TITLE="" +export CONTENT="${content}" +export BREADCRUMBS="" +export HEADER_EXTRA="" +export META_DATE="" +export META_DESCRIPTION="" +export HAS_CODE +export LANG="en" +export DIR="" + +render_page "build/templates/home.html" "output/index.html" +echo "[built] output/index.html" + +# License page +if [[ -f "LICENSE.md" ]]; then + content="$(lowdown LICENSE.md)" + check_has_code "${content}" + export PAGE_TITLE="license" + export CONTENT="${content}" + export BREADCRUMBS=" / <a href=\"/license\">license</a>" + export HEADER_EXTRA="" + export META_DATE="" + export META_DESCRIPTION="" + export HAS_CODE + export LANG="en" + export DIR="" + render_page "build/templates/page.html" "output/license/index.html" + echo "[built] output/license/index.html" +fi + +echo "" +echo "[done] Build complete. Output in output/" |
