git_infra

Git infra scripts for git.bracken.jp
git clone https://git.bracken.jp/git_infra.git
Log | Files | Refs | LICENSE

commit 2d9a6bc63a19ca7710b85f65fb2d3f5e9a46c841
parent 2456bf9230380b50a966e65571114fa66ce64829
Author: Chris Bracken <chris@bracken.jp>
Date:   Sun, 16 Aug 2026 18:26:57 +0900

Add gemini, www publish hook

Diffstat:
Apost-receive.d/publish_gemini | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apost-receive.d/publish_www | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 123 insertions(+), 0 deletions(-)

diff --git a/post-receive.d/publish_gemini b/post-receive.d/publish_gemini @@ -0,0 +1,62 @@ +#!/bin/sh -e +# +# post-receive.d hook: publish the Gemini capsule to agate's content root. +# +# Replaces yakumo's hourly cronjob: +# git -C ~/gemini/chris.bracken.jp fetch origin \ +# && git -C ~/gemini/chris.bracken.jp reset --hard origin/master +# +# agate serves one subdirectory per configured hostname, so the target is +# content/<hostname>/ and NOT content/ itself. +# +# Install: +# /home/git/git_infra/post-receive.d/publish_gemini (this file, chmod +x) +# /home/git/<capsule-repo>.git/hooks/post-receive.d/publish_gemini -> symlink +# +# Requires zroot/data/gemini mounted READ-WRITE into the git jail at +# /var/gemini, and the content tree owned by the git user (1001). agate runs +# as gemini (1965) in its own jail and only needs to read, which the world +# bits allow. .certificates stays owned by 1965 - agate may rewrite it. + +BRANCH="master" +TARGET="/var/gemini/content/chris.bracken.jp" + +# agate reads these as a different user in a different jail. +umask 022 + +repo_dir=$(pwd) + +if [ ! -d "$TARGET" ]; then + echo "[gemini] ERROR: $TARGET missing - is the nullfs mount attached?" >&2 + exit 1 +fi +if [ ! -w "$TARGET" ]; then + echo "[gemini] ERROR: $TARGET not writable - check ownership (should be git)" >&2 + exit 1 +fi + +# stdin gives one line per updated ref: <old> <new> <refname> +pushed=0 +while read -r _old new ref; do + [ "$ref" = "refs/heads/${BRANCH}" ] || continue + # Branch deletion - do not wipe the live capsule. + [ "$new" = "0000000000000000000000000000000000000000" ] && continue + pushed=1 +done + +if [ "$pushed" = "0" ]; then + echo "[gemini] ${BRANCH} not updated; nothing to publish" + exit 0 +fi + +echo "[gemini] Publishing ${BRANCH} to ${TARGET}" + +git --git-dir="$repo_dir" --work-tree="$TARGET" checkout -f "$BRANCH" + +# checkout -f does not remove files deleted from the branch. This is what +# `reset --hard` handled before. +# +# NOTE: deletes ANY untracked file under $TARGET. +git --git-dir="$repo_dir" --work-tree="$TARGET" clean -fd + +echo "[gemini] Done" diff --git a/post-receive.d/publish_www b/post-receive.d/publish_www @@ -0,0 +1,61 @@ +#!/bin/sh -e +# +# post-receive.d hook: publish the built site to the web root. +# +# Install: +# /home/git/git_infra/post-receive.d/publish_www (this file, chmod +x) +# /home/git/bracken_jp.git/hooks/post-receive.d/publish_www -> symlink to it +# +# Note this is symlinked ONLY into bracken_jp.git, unlike gout_html which is +# linked into every repo. + +BRANCH="master" +WWW="/var/www/chris.bracken.jp" + +# Files must be readable by the www user in the www jail, which reads this +# same dataset over a read-only nullfs mount. +umask 022 + +# Hooks are called from the repo directory. +repo_dir=$(pwd) + +# Refuse to run if the web root is missing or not writable. Without this a +# missing nullfs mount would publish into the jail's own filesystem, which +# would look like it worked and serve nothing. +if [ ! -d "$WWW" ]; then + echo "[publish] ERROR: $WWW does not exist - is the nullfs mount attached?" >&2 + exit 1 +fi +if [ ! -w "$WWW" ]; then + echo "[publish] ERROR: $WWW is not writable" >&2 + exit 1 +fi + +# stdin gives one line per updated ref: <old> <new> <refname> +pushed=0 +while read -r _old new ref; do + [ "$ref" = "refs/heads/${BRANCH}" ] || continue + # Branch deletion - do not wipe the live site. + [ "$new" = "0000000000000000000000000000000000000000" ] && continue + pushed=1 +done + +if [ "$pushed" = "0" ]; then + echo "[publish] ${BRANCH} not updated; nothing to publish" + exit 0 +fi + +echo "[publish] Publishing ${BRANCH} to ${WWW}" + +# checkout -f writes/overwrites every tracked file into the work tree. +git --git-dir="$repo_dir" --work-tree="$WWW" checkout -f "$BRANCH" + +# checkout -f does not remove files deleted from the branch, so clean up +# anything untracked. This is what made `reset --hard` sufficient before. +# +# NOTE: this deletes ANY untracked file under $WWW. That is correct while the +# whole tree is repo-managed. If you ever need to keep something unmanaged +# there, add it to .gitignore AND drop -x, or this will remove it. +git --git-dir="$repo_dir" --work-tree="$WWW" clean -fd + +echo "[publish] Done"