diff --git a/.claude/docs/specs/2026-08-25-server-role.md b/.claude/docs/specs/2026-08-25-server-role.md index d0bbcca..bdc1e38 100644 --- a/.claude/docs/specs/2026-08-25-server-role.md +++ b/.claude/docs/specs/2026-08-25-server-role.md @@ -183,8 +183,8 @@ currently parked (dir present, unit not active) — imported anyway, noted as parked in the catalog. **Excluded:** Watchtower (retired — replaced by the update timer after it took -gitea down; its dir stays on junior until cleanup), Completeuphoria, -sierraandtyler, Bang (source checkouts deployed by CI from their own repos — +gitea down; its dir stays on junior until cleanup), the app source +checkouts such as sierraandtyler and Bang (deployed by CI from their own repos — Panama owning a second copy of their compose would drift), `ci/`, `logs/`, and junior's loose scripts other than `update-containers.sh` (§4). diff --git a/server/scripts/update-containers b/server/scripts/update-containers index c460a95..52c0aa9 100755 --- a/server/scripts/update-containers +++ b/server/scripts/update-containers @@ -46,10 +46,6 @@ set -uo pipefail # podman pull && systemctl --user restart podman-.service SKIP=(postgresql authentik watchtower) -# Services built locally rather than pulled. There is no registry image to check, -# so pulling is pointless — they are skipped automatically when no `image:` line -# resolves, but listing them here keeps the log quiet and the intent obvious. -LOCAL_BUILD=(bang completeuphoria sierraandtyler) # ⚠️ NOTE ON GITEA: it is deliberately NOT in SKIP. The three-day outage was caused # by watchtower's recreate mechanism, not by the act of updating — restarting the @@ -90,8 +86,10 @@ list_units() { | sort } -# Images declared in a service's compose.yml. Ignores commented lines and the -# `build:` stanza, which has no pullable image. +# Images declared in a service's compose.yml. Ignores commented lines, and the +# image of any compose service that has a `build:` stanza: that tag names a +# locally built image, so there is nothing in a registry to pull. Those +# services therefore resolve no images and are skipped without a log line. # # Image tags frequently reference variables from the service's .env, e.g. # ghcr.io/get-convex/convex-backend:${BACKEND_TAG:-latest} @@ -102,8 +100,22 @@ list_units() { images_for() { local dir="$1" [ -f "$dir/compose.yml" ] || return 0 - grep -oE '^[[:space:]]*image:[[:space:]]*[^[:space:]#]+' "$dir/compose.yml" 2>/dev/null \ - | sed -E 's/^[[:space:]]*image:[[:space:]]*//' \ + awk ' + function flush() { if (img != "" && !build) print img; img = ""; build = 0 } + /^[[:space:]]*#/ { next } + /^services:[[:space:]]*$/ { in_services = 1; indent = -1; next } + in_services && /^[^[:space:]]/ { flush(); in_services = 0 } + in_services && NF { + match($0, /^ */); here = RLENGTH + if (indent < 0) indent = here + if (here == indent && $0 ~ /^ *[A-Za-z0-9_.-]+:[[:space:]]*$/) { flush(); next } + if ($0 ~ /^[[:space:]]+build:/) build = 1 + if (match($0, /^[[:space:]]+image:[[:space:]]*[^[:space:]#]+/)) { + img = substr($0, RSTART, RLENGTH); sub(/^[[:space:]]+image:[[:space:]]*/, "", img) + } + } + END { flush() } + ' "$dir/compose.yml" 2>/dev/null \ | while IFS= read -r img; do case "$img" in *'${'*) ( set -a; [ -f "$dir/.env" ] && . "$dir/.env" >/dev/null 2>&1; set +a @@ -124,8 +136,8 @@ if [ "${LIST:-0}" = "1" ]; then for svc in $(list_units); do printf '%-22s' "$svc" if in_list "$svc" "${SKIP[@]}"; then echo "SKIP (frozen)"; continue; fi - if in_list "$svc" "${LOCAL_BUILD[@]}"; then echo "SKIP (built locally)"; continue; fi - echo "$(images_for "$(workdir_for "$svc")" | tr '\n' ' ')" + imgs="$(images_for "$(workdir_for "$svc")" | tr '\n' ' ')" + echo "${imgs:-(built locally, nothing to pull)}" done exit 0 fi @@ -142,7 +154,6 @@ for svc in $(list_units); do [ -n "$ONLY" ] && [ "$svc" != "$ONLY" ] && continue if [ -z "$ONLY" ]; then in_list "$svc" "${SKIP[@]}" && { log " $svc: frozen (SKIP list)"; continue; } - in_list "$svc" "${LOCAL_BUILD[@]}" && continue fi # ⚠️ NEVER resurrect a service that is deliberately stopped. `systemctl restart`