HUGO := hugo PAGEFIND := npx -y pagefind LYCHEE := lychee OUT := public # --- Pinned toolchain (repo-local .tools/; gitignored) --- # `make bootstrap` installs these exact versions into .tools/bin. The PATH # prepend below applies to every recipe, so make targets always use the pinned # tools; your system PATH is never modified. `make tool-versions` shows both. HUGO_VERSION := 0.167.0 NODE_VERSION := 22.11.0 LYCHEE_VERSION := 0.24.2 TOOLS_BIN := $(CURDIR)/.tools/bin export PATH := $(TOOLS_BIN):$(PATH) .PHONY: all build index serve run link-check link-fix external-check external-fix external-fix-apply serve-lan clean bootstrap tool-versions preflight all: index # ONE-TIME per machine: install the pinned hugo/node/lychee into .tools/bin. # Idempotent (present-at-pin tools are skipped); touches nothing outside .tools/. bootstrap: scripts/bootstrap.sh # Diagnostic: pinned (.tools/bin) vs PATH-first (system) tool versions. tool-versions: scripts/tool_versions.sh # Strict tool check; runs automatically before all/serve/serve-lan and # fails with a `make bootstrap` hint instead of a bare "error 127". preflight: scripts/tool_versions.sh --strict # Build Hugo content -> public/ (preflight first so a missing tool fails fast # and in order even under `make -j`). build: preflight $(HUGO) --gc # (Re)build the Pagefind search index from public/ -> public/pagefind/ index: build $(PAGEFIND) --site $(OUT) # Build content + index, then serve the built site WITH search on :1414 (dev preview). # Uses pagefind's own server. Local only (binds 127.0.0.1) -- for LAN use `make serve-lan`. serve: index $(PAGEFIND) --site $(OUT) --serve run: serve # DEAD LINKS -- internal (offline, fast): scan the SOURCE markdown; internal links # resolve to file:// under public/. External links are skipped by --scheme file. # Output: linkcheck/internal.json (exit != 0 when dead links exist; that is fine). link-check: build mkdir -p linkcheck $(LYCHEE) --root-dir $(OUT) --default-extension html --scheme file \ --format json --timeout 10 \ $(wildcard content/*.md) $(wildcard content/*/*.md) > linkcheck/internal.json # Comment out confirmed dead INTERNAL page links, then rebuild content + index so they # leave the live page AND the search index. (External failures -> manual_review.txt.) link-fix: python3 scripts/fix_dead_links.py --report linkcheck/internal.json --apply $(HUGO) --gc $(PAGEFIND) --site $(OUT) # DEAD LINKS -- external (network): scan all http/https links in content. Report-only. # Always exits 0; the report is the point. Also saves the full lychee JSON to # linkcheck/external.json so external-fix can act without re-pinging the web. external-check: python3 scripts/check_external_links.py # Preview which EXTERNAL links are truly dead (domain/DNS no longer exists) and # would be commented out. Reports only; changes nothing. Run external-check first. external-fix: python3 scripts/fix_dead_external_links.py --report linkcheck/external.json # Comment out the truly-dead EXTERNAL links (DNS failed / host unreachable), then # rebuild content + index so they leave the live page AND the search index. # 404s, SSL errors, 5xx, redirects, refused/reset connections are NOT auto-commented # (domain is still alive / ambiguous) -- they go to linkcheck/manual_review_external.txt. external-fix-apply: python3 scripts/fix_dead_external_links.py --report linkcheck/external.json --apply $(HUGO) --gc $(PAGEFIND) --site $(OUT) # Serve the BUILT site on all interfaces so another LAN machine can open it: # http://:8090/ (IP printed at startup; also `hostname -I | head -1`) serve-lan: preflight python3 scripts/serve_lan.py # NOTE: clean does NOT remove .tools/ -- the pinned toolchain is expensive to # reinstall and independent of build output. Remove it manually if ever needed. clean: rm -rf $(OUT) linkcheck