Files
automations/deployments/ergo/build.sh
T
57_WolveandClaude Opus 5 6dba4a5f09 docs(ergo): user guide and admin/moderator cheat sheet
Two quick-reference documents, written to be scanned rather than read:

- USER-GUIDE.md for people new to IRC -- connecting, claiming a nickname,
  the dozen commands that matter, scrollback, and a plain-language privacy
  section (cloaked IP, channels logged for the configured retention, how to
  turn off DM storage).
- ADMIN-CHEATSHEET.md split by where you work: from IRC as an operator
  (UBAN, KILL, DEFCON, ChanServ, NickServ) and on the host via ergoctl, plus
  mode tables and a "when things go wrong" section.

Both use the same placeholder convention as ergo.motd and are rendered by
deploy.sh into $STACK_DIR/docs/ with the network's real name, domain and
retention, so they can be handed straight to users and moderators. Refreshed
on every run, like the other installed files.

Command and mode references were checked against the v2.19.1 sources rather
than written from memory: irc/modes/modes.go for every mode letter, and
irc/chanserv.go and irc/nickserv.go for the service subcommands and which
require an oper capability.

build.sh's embed guard caught the docs being added to FILES without being
added to deploy.sh's EMBEDDED manifest -- the exact failure it was added to
prevent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 21:48:01 -05:00

71 lines
2.2 KiB
Bash

#!/usr/bin/env bash
#
# build.sh -- (re)embed the loose deployment files into deploy.sh as a base64
# tar.gz payload after __ARCHIVE_BELOW__. Idempotent: strips any existing
# payload first.
#
# Run this after editing ANY embedded file below, then re-stage deploy.sh --
# the deployed stack uses the EMBEDDED copies, not the loose files.
set -euo pipefail
DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
SCRIPT="$DIR/deploy.sh"
MARKER="__ARCHIVE_BELOW__"
# README, cloud-init and the build/deploy scripts are NOT embedded. ircd.yaml is
# generated on the host from the pulled image's own default config.
FILES=(
docker-compose.yml
docker-compose.postgres.yml
Caddyfile
conf.d-readme.caddy
ergo.motd
USER-GUIDE.md
ADMIN-CHEATSHEET.md
.env.example
ergolib.sh
update.sh
ergoctl
)
[[ -f "$SCRIPT" ]] || { echo "deploy.sh not found at $SCRIPT" >&2; exit 1; }
for f in "${FILES[@]}"; do
[[ -f "$DIR/$f" ]] || { echo "Missing $DIR/$f" >&2; exit 1; }
done
# Guard: every file deploy.sh reads out of the extracted archive must be in
# FILES, and must be in deploy.sh's own EMBEDDED manifest. Forgetting either is
# a deploy-time abort on every host, so catch it here instead.
missing=0
while IFS= read -r ref; do
case " ${FILES[*]} " in *" $ref "*) ;; *) echo "deploy.sh reads \$SCRIPT_DIR/$ref but build.sh does not embed it" >&2; missing=1 ;; esac
done < <(grep -oE '\$SCRIPT_DIR/[A-Za-z0-9._-]+' "$SCRIPT" | sed 's|^\$SCRIPT_DIR/||' | sort -u)
for f in "${FILES[@]}"; do
grep -q "EMBEDDED=(.*$f" "$SCRIPT" || { echo "$f is embedded but missing from deploy.sh's EMBEDDED manifest" >&2; missing=1; }
done
(( missing == 0 )) || { echo "Refusing to build a deploy.sh that would abort on the target host." >&2; exit 1; }
# Syntax-check the bash payload before embedding it.
for f in ergolib.sh update.sh ergoctl deploy.sh; do
bash -n "$DIR/$f" || { echo "bash -n failed: $f" >&2; exit 1; }
done
PAYLOAD=$(tar -czf - -C "$DIR" "${FILES[@]}" | base64)
TMP=$(mktemp)
trap 'rm -f "$TMP"' EXIT
sed "/^${MARKER}\$/,\$d" "$SCRIPT" > "$TMP"
{
echo "$MARKER"
echo "$PAYLOAD"
} >> "$TMP"
mv "$TMP" "$SCRIPT"
chmod +x "$SCRIPT"
trap - EXIT
size=$(wc -c < "$SCRIPT")
echo "Built $SCRIPT (${size} bytes)"