Files
soleprint/rig/ctrl/ports.sh
2026-09-22 05:15:49 -03:00

111 lines
3.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Give each environment its own block of host ports, derived from the directory name.
# base = 20000 + (hash(slug) % 200) * 10; +0 HTTP +1 HTTPS +2 TILT +3 REGISTRY
# Usage: ports.sh show | active | derive | persist
# Notes: docs/notes/ports.md
set -euo pipefail
cd "$(dirname "$0")"
source ./lib/config.sh
# derive_port_base lives in lib/config.sh so every script resolves the same block
# without going through this one.
derive_base() { derive_port_base "$1"; }
derive() {
load_config
local base; base=$(derive_base "$CLUSTER")
DERIVED_HTTP=$base
DERIVED_HTTPS=$((base + 1))
DERIVED_TILT=$((base + 2))
DERIVED_REGISTRY=$((base + 3))
}
# Resolved facts for consumers outside bash, space-separated, positional:
# CLUSTER KUBECONTEXT HTTP HTTPS TILT REGISTRY MANIFESTS_DIR OVERLAY_DIR
# The two paths are absolute, or - when there is none. Read this, not `derive`.
active() {
load_config
local m="-" o="-"
if [ -n "$MANIFESTS_DIR" ]; then m=$(_abs_from_ctrl "$MANIFESTS_DIR"); fi
if [ -n "$OVERLAY_DIR" ]; then o=$(_abs_from_ctrl "$OVERLAY_DIR"); fi
case "$m$o" in
*[[:space:]]*)
echo "a path here holds whitespace, and these facts are split on spaces: $m $o" >&2
exit 1 ;;
esac
echo "$CLUSTER $KUBECONTEXT $HTTP_PORT $HTTPS_PORT $TILT_PORT $REGISTRY_PORT $m $o"
}
show() {
derive
echo "environment $CLUSTER"
echo "derived base $(derive_base "$CLUSTER")"
echo
printf " %-14s %-8s %-8s %s\n" KEY DERIVED ACTIVE SOURCE
_row HTTP_PORT "$DERIVED_HTTP"
_row HTTPS_PORT "$DERIVED_HTTPS"
_row TILT_PORT "$DERIVED_TILT"
_row REGISTRY_PORT "$DERIVED_REGISTRY"
}
_row() {
local key="$1" derived="$2" active="${!1:-}" src="derived"
if [ -n "$active" ] && [ "$active" != "$derived" ]; then
src="override"
elif [ -z "$active" ]; then
active="$derived"
fi
printf " %-14s %-8s %-8s %s\n" "$key" "$derived" "$active" "$src"
}
# Write the derived block into ctrl/.env, once. Existing keys are never
# rewritten — an override stays an override.
persist() {
derive
# ctrl/.env belongs to this rig, not to an overlay: a pin written now would
# follow every overlay this rig later runs, and two of them would collide.
if [ -n "${OVERLAY:-}" ]; then
echo "not pinning: OVERLAY is set, and ctrl/.env would carry this block to every overlay" >&2
echo " its ports stay derived from its folder name ($CLUSTER): $DERIVED_HTTP-$DERIVED_REGISTRY" >&2
exit 1
fi
[ -f ./.env ] || cp ./.env.example ./.env
local wrote=0 key val
for key in HTTP_PORT:$DERIVED_HTTP \
HTTPS_PORT:$DERIVED_HTTPS \
TILT_PORT:$DERIVED_TILT \
REGISTRY_PORT:$DERIVED_REGISTRY; do
val="${key#*:}"; key="${key%%:*}"
if grep -qE "^${key}=[0-9]" ./.env 2>/dev/null; then
continue
fi
if [ "$wrote" -eq 0 ]; then
{
echo ""
echo "# Port block for this environment, derived from the directory name"
echo "# so copies never collide. Pinned here on first use — edit freely."
} >> ./.env
wrote=1
fi
# Replace a commented/empty placeholder if present, else append.
if grep -qE "^#?\s*${key}=" ./.env 2>/dev/null; then
sed -i "s|^#\?\s*${key}=.*|${key}=${val}|" ./.env
else
echo "${key}=${val}" >> ./.env
fi
done
[ "$wrote" -eq 1 ] && echo "pinned port block into ctrl/.env" || echo "ports already set in ctrl/.env"
return 0
}
case "${1:-show}" in
show) show ;;
derive) derive; echo "$DERIVED_HTTP $DERIVED_HTTPS $DERIVED_TILT $DERIVED_REGISTRY" ;;
active) active ;;
persist) persist ;;
*) echo "usage: $0 [show|active|derive|persist]" >&2; exit 1 ;;
esac