base: add pi-devbox-version command + startup banner
Wraps /etc/pi-devbox/build-manifest.json (already written at docker-build time in Dockerfile.variant) into a human-readable summary instead of requiring users to know the manifest path and pipe it through jq themselves. - rootfs/usr/local/bin/pi-devbox-version: human (default) / --json / --quiet output modes. Also flags live drift — compares the baked pi_version against the actually-running `pi --version` and warns on mismatch rather than trusting the manifest blindly (same ground-truth philosophy as the manifest generation itself). Exits 1 with a short stderr notice on images built before the manifest existed, instead of failing silently. - entrypoint-user.sh: calls it as the very first line. CMD is `bash -l` with tty:true in compose, so this banner lands directly above the first prompt on container start — no separate motd/bashrc hook needed (deliberately not wired into .bash_aliases, which would reprint on every docker exec -it). - Dockerfile.base: COPY + chmod, same pattern as dot-watch/studio-expose. - scripts/smoke-test.sh: 4 new checks (binary present+executable, human output has release tag, --json round-trips the manifest, --quiet is a single line). - README.md / AGENTS.md / CHANGELOG.md updated.
This commit is contained in:
Executable
+83
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env bash
|
||||
# pi-devbox-version — show which pi-devbox image build is running.
|
||||
#
|
||||
# WHY THIS EXISTS
|
||||
# The image bakes ground-truth build info into /etc/pi-devbox/build-manifest.json
|
||||
# at `docker build` time (see Dockerfile.variant): the release tag, build date,
|
||||
# source commit, live `pi --version` at build time, and the actual checked-out
|
||||
# commit of every /opt component clone. That answers "what image am I running?"
|
||||
# — but only if you know to go look for the file. This wraps it into one
|
||||
# command, prints it human-first at container start (see entrypoint-user.sh),
|
||||
# and stays available on demand for the rest of the session.
|
||||
#
|
||||
# USAGE
|
||||
# pi-devbox-version human-readable summary (default)
|
||||
# pi-devbox-version --json raw manifest JSON (for scripting)
|
||||
# pi-devbox-version --quiet one-line "release_tag (source_revision)" form
|
||||
#
|
||||
# EXIT STATUS
|
||||
# 0 on success. 1 if the manifest is missing (e.g. an image built before
|
||||
# this file existed, or a non-pi-devbox base) — prints a short notice
|
||||
# to stderr rather than failing silently.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
MANIFEST=/etc/pi-devbox/build-manifest.json
|
||||
MODE="human"
|
||||
|
||||
case "${1:-}" in
|
||||
--json) MODE="json" ;;
|
||||
--quiet|-q) MODE="quiet" ;;
|
||||
--help|-h)
|
||||
sed -n '2,20p' "$0" | sed 's/^# \?//'
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ ! -f "$MANIFEST" ]; then
|
||||
echo "pi-devbox-version: no build manifest at $MANIFEST" >&2
|
||||
echo " (image predates the manifest, or this isn't a pi-devbox image)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
echo "pi-devbox-version: jq not found; dumping raw manifest instead" >&2
|
||||
cat "$MANIFEST"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$MODE" = "json" ]; then
|
||||
cat "$MANIFEST"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
release_tag=$(jq -r '.release_tag' "$MANIFEST")
|
||||
build_date=$(jq -r '.build_date' "$MANIFEST")
|
||||
source_rev=$(jq -r '.source_revision' "$MANIFEST")
|
||||
pi_version_baked=$(jq -r '.pi_version' "$MANIFEST")
|
||||
|
||||
if [ "$MODE" = "quiet" ]; then
|
||||
printf '%s (%s)\n' "$release_tag" "${source_rev:0:7}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Live drift check: has `pi` been upgraded since this container was built?
|
||||
# (image is immutable, but a volume-persisted ~/.pi could in theory shadow
|
||||
# the baked binary — this stays honest rather than trusting the manifest
|
||||
# blindly, same "ground truth over intent" spirit as how the manifest
|
||||
# itself is generated in Dockerfile.variant.)
|
||||
pi_version_live=""
|
||||
if command -v pi >/dev/null 2>&1; then
|
||||
pi_version_live=$(pi --version 2>/dev/null | head -n1 | tr -d '\r\n')
|
||||
fi
|
||||
|
||||
printf 'pi-devbox %s\n' "$release_tag"
|
||||
printf ' built: %s (source %s)\n' "$build_date" "${source_rev:0:12}"
|
||||
if [ -n "$pi_version_live" ] && [ "$pi_version_live" != "$pi_version_baked" ]; then
|
||||
printf ' pi: %s \033[33m(baked as %s — drift detected)\033[0m\n' "$pi_version_live" "$pi_version_baked"
|
||||
else
|
||||
printf ' pi: %s\n' "${pi_version_live:-$pi_version_baked}"
|
||||
fi
|
||||
|
||||
printf ' components:\n'
|
||||
jq -r '.components | to_entries[] | select(.value != null) | " \(.key): \(.value[0:12])"' "$MANIFEST"
|
||||
Reference in New Issue
Block a user