Files
org_web/lisp/build-runner.el
2026-07-08 22:09:29 +01:00

121 lines
4.6 KiB
EmacsLisp

;;; build-runner.el --- Build orchestration -*- lexical-binding: t; -*-
;;; Code:
(require 'ox-publish)
(defun z/wipe-build-dirs ()
"Delete output/ and .org-timestamps/ together."
(dolist (dir (list z/output-root
(site-path ".org-timestamps/")))
(if (file-directory-p dir)
(progn
(z/with-timing (format "delete %s"
(file-name-nondirectory
(directory-file-name dir)))
(delete-directory dir t))
(z/log 'done "Deleted %s" dir))
(z/log 'info "Already absent: %s" dir))))
(defun z/output-integrity-ok-p ()
"Return t if critical output paths all exist."
(let ((missing '()))
(unless (file-directory-p (output-path "assets/"))
(push "output/assets/" missing))
(unless (or (file-exists-p (output-path "index.html"))
(file-exists-p (output-path "sitemap.html")))
(push "output/index.html (or sitemap.html)" missing))
(dolist (m missing)
(z/log 'warn "Integrity check: missing %s" m))
(null missing)))
(defun z/prepare-output-cache ()
"Keep org-publish output and timestamp cache in sync."
(z/log-separator "Pre-build")
(z/log 'info "Site source root : %s" z/site-root)
(z/log 'info "Site output root : %s" z/output-root)
(cond
((getenv "SITE_CLEAN")
(z/log 'warn "SITE_CLEAN=1 - wiping output/ and .org-timestamps/")
(z/wipe-build-dirs)
(setenv "SITE_FORCE" "1"))
((not (z/output-integrity-ok-p))
(z/log 'warn "Output integrity check failed - timestamp cache is stale")
(z/log 'warn "Clearing .org-timestamps/ and forcing full republish")
(let ((ts-dir (site-path ".org-timestamps/")))
(when (file-directory-p ts-dir)
(z/with-timing "delete .org-timestamps"
(delete-directory ts-dir t))
(z/log 'done "Deleted .org-timestamps/")))
(setenv "SITE_FORCE" "1"))
(t
(z/log 'info "Incremental build - output/ looks complete"))))
(defun z/generate-build-inputs ()
"Generate source-side data files required before publishing."
(z/log-separator "Generated inputs")
(z/with-timing "tag page generation"
(condition-case err
(let ((n (z/write-tag-pages)))
(z/log 'done "Tag pages written%s"
(if (numberp n) (format " (%d tags)" n) "")))
(error
(z/log 'error "Tag generation failed: %s" (error-message-string err))
(error "Aborting build: tag generation error"))))
(z/with-timing "comment page manifest"
(condition-case err
(z/generate-comment-pages-json)
(error
(z/log 'error "Comment page manifest failed: %s" (error-message-string err))
(error "Aborting build: comment page manifest error")))))
(defun z/publish-site ()
"Publish the configured site."
(z/log-separator "Publishing")
(if (getenv "SITE_DRY")
(z/log 'warn "SITE_DRY=1 - skipping org-publish-all (dry run)")
(let ((force (not (not (getenv "SITE_FORCE")))))
(when force
(z/log 'info "SITE_FORCE=1 - forcing republish of all files"))
(condition-case err
(progn
(z/with-timing "org-publish-all"
(org-publish-all force))
(z/with-timing "asset sync"
(z/sync-assets-to-output)))
(error
(z/log 'error "org-publish-all failed: %s" (error-message-string err))
(error "Build failed"))))))
(defun z/log-build-summary ()
"Log a summary of output artifacts."
(z/log-separator "Build summary")
(let* ((elapsed (- (float-time) z/build-start-time))
(out-dir z/output-root)
(html-files (when (file-directory-p out-dir)
(length (directory-files-recursively out-dir "\\.html\\'"))))
(css-files (when (file-directory-p out-dir)
(length (directory-files-recursively out-dir "\\.css\\'"))))
(js-files (when (file-directory-p out-dir)
(length (directory-files-recursively out-dir "\\.js\\'"))))
(tag-files (let ((td (output-path "tags/")))
(when (file-directory-p td)
(length (directory-files td nil "\\.html\\'"))))))
(z/log 'metric "Total elapsed : %.2fs" elapsed)
(z/log 'metric "HTML files output: %d" (or html-files 0))
(z/log 'metric "CSS files output: %d" (or css-files 0))
(z/log 'metric "JS files output: %d" (or js-files 0))
(z/log 'metric "Tag pages output: %d" (or tag-files 0))
(z/log 'done "Build complete")))
(defun z/run-build ()
"Run the full site build."
(z/prepare-output-cache)
(z/generate-build-inputs)
(z/publish-site)
(z/log-build-summary))
(provide 'build-runner)
;;; build-runner.el ends here