Files
garden-astro/deploy/auto-build.sh
T
wesandClaude Opus 5 9da9a6cba2 Publish opted-in marimo notebooks at /notebooks
Notebooks from the marimo server can now appear in the garden. A notebook
opts in with an HTML comment in one of its markdown cells — invisible when
rendered, greppable in the .py source:

    <!-- garden:publish
    title: Dream of Spotification
    order: 30
    -->

Default-deny on purpose: garden.c0smere.net is public and the export bakes
each notebook's executed output into the page, not just its code.
export-notebooks.py also carries a NEVER_PUBLISH list (genome_*, coursework)
so a marker pasted into one of those refuses loudly instead of publishing.

Pipeline: export-notebooks.py runs each marked notebook in a one-shot
marimo container (same image/env/GPU as the live server, so it hits the real
databases) into notebooks-export/ + index.json; copy-notebooks.mjs stages
those to public/nb/; Astro reads index.json to build the pages and the
sidebar section.

Isolation choices worth keeping:

- Own timer and own lock, separate from the 5-min garden build — executing a
  notebook takes minutes and must never hold up a build tick.
- Cached on notebook content; both index.json and .cache.json go through
  write_if_changed, since auto-build.sh hashes mtimes under notebooks-export/
  and an unconditional rewrite would force a full rebuild every 30 minutes.
- Per-notebook timeout; a failure keeps the previous export and continues.
- Runs against a throwaway copy of the notebook dir, so notebooks that write
  scratch files don't dirty the notebooks repo.
- Notebooks are NOT injected into the garden collection — they aren't vault
  notes, and doing so would move noteCount and the sitemap.

build.format:'file' makes the listing a file (notebooks.html) beside a
directory of detail pages. Verified against the running nginx: /notebooks and
/notebooks/<slug> resolve through the generic try_files but /notebooks/ does
not, so nginx.conf gets an explicit location for the trailing-slash form.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 22:07:14 -04:00

42 lines
1.4 KiB
Bash
Executable File

#!/bin/sh
# Timer target: rebuild the garden only when the vault or repo changed.
# Successor to the Quartz update_quartz_docker.sh change-detection loop.
# Usage: auto-build.sh [--force] (--force skips change detection — used
# by the manual rebuild hook)
set -eu
REPO=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
VAULT="${VAULT:-/home/nox/docker/obsidian/vaults/weeslahw_coppermind}"
STATE="$REPO/.build_state"
FORCE=0
[ "${1:-}" = "--force" ] && FORCE=1
cd "$REPO"
# serialize builds: the 5-min timer and the manual hook must never run
# docker/npm into the same checkout concurrently
exec 9>"$REPO/.build.lock"
flock 9
# a dirty tree can make pull fail; still rebuild whatever is checked out
git pull -q || echo "git pull failed (dirty tree?) — building local state"
# signature covers committed HEAD, any uncommitted repo edits, vault mtimes,
# and the notebook exports (gitignored, so git status/diff can't see them —
# they land here on their own timer via deploy/export-notebooks.py)
sig=$({
git rev-parse HEAD
git status --porcelain=v1
git diff
find "$VAULT" -name .obsidian -prune -o -type f -printf '%T@ %p\n' | sort
find "$REPO/notebooks-export" -type f -printf '%T@ %p\n' 2>/dev/null | sort
} | sha256sum | cut -d' ' -f1)
if [ "$FORCE" -eq 0 ] && [ -f "$STATE" ] && [ "$(cat "$STATE")" = "$sig" ]; then
exit 0
fi
sh "$REPO/deploy/build.sh"
printf %s "$sig" >"$STATE"
echo "garden rebuilt $(date -Is)"