koopa-admin-log/scripts/taler-landing/stamp-landing-stack.sh

196 lines
6.5 KiB
Bash

#!/usr/bin/env bash
# Fill landing stack-bar package versions from live CTR dpkg (not hand-edited HTML).
#
# Reads: configs/shared/landing-stack.json (package lists + vanilla href)
# Writes: configs/{bank,exchange,merchant}-landing/index.html (<!-- stack-bar --> block)
# configs/shared/landing-stack-versions.json (last dpkg snapshot)
#
# Usage (from koopa-admin-log root, laptop or koopa):
# ./scripts/taler-landing/stamp-landing-stack.sh
# ./scripts/taler-landing/stamp-landing-stack.sh --ctr goa-regio-ng --ssh hernani@192.168.100.95
# ./scripts/taler-landing/stamp-landing-stack.sh bank exchange
# ./scripts/taler-landing/stamp-landing-stack.sh --deploy
# stamp then publish via deploy-landings.sh --ssh (same host/ctr)
#
# After this, bump footer dates with:
# ./scripts/taler-landing/stamp-landing-version.sh --bump --all
# One-shot stamp+live (preferred — avoids stamped-but-not-deployed lag):
# ./scripts/taler-landing/stamp-landing-stack.sh --deploy
# ./scripts/taler-landing/stamp-landing-version.sh --bump --all --deploy
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
STACK_FILE="$ROOT/configs/shared/landing-stack.json"
VERS_OUT="$ROOT/configs/shared/landing-stack-versions.json"
CTR="${LANDING_CTR:-goa-regio-ng}"
SSH_HOST="${LANDING_SSH:-hernani@192.168.100.95}"
USE_SSH=1
DO_DEPLOY=0
sites=()
while [ $# -gt 0 ]; do
case "$1" in
--ctr) CTR="${2:-}"; shift 2 ;;
--ssh) SSH_HOST="${2:-}"; USE_SSH=1; shift 2 ;;
--local) USE_SSH=0; shift ;;
--deploy) DO_DEPLOY=1; shift ;;
bank|exchange|merchant) sites+=("$1"); shift ;;
-h|--help)
sed -n '2,24p' "$0"
exit 0
;;
*) echo "unknown arg: $1" >&2; exit 2 ;;
esac
done
if [ "${#sites[@]}" -eq 0 ]; then
sites=(bank exchange merchant)
fi
[ -f "$STACK_FILE" ] || { echo "missing $STACK_FILE" >&2; exit 1; }
# Collect unique package names from JSON for the selected sites
mapfile -t PKGS < <(python3 - "$STACK_FILE" "${sites[@]}" <<'PY'
import json, sys
data = json.load(open(sys.argv[1], encoding="utf-8"))
sites = sys.argv[2:]
seen = []
for s in sites:
for p in data["sites"][s]["packages"]:
if p not in seen:
seen.append(p)
print("\n".join(seen))
PY
)
if [ "${#PKGS[@]}" -eq 0 ]; then
echo "no packages configured" >&2
exit 1
fi
pkg_args=$(printf '%q ' "${PKGS[@]}")
query_cmd="podman exec $(printf '%q' "$CTR") dpkg-query -W -f='\${Package}=\${Version}\n' ${pkg_args}"
if [ "$USE_SSH" = 1 ]; then
echo "dpkg ← ${SSH_HOST} ctr=${CTR}"
# shellcheck disable=SC2086
raw=$(ssh -o BatchMode=yes -o ConnectTimeout=12 "$SSH_HOST" "podman exec $(printf '%q' "$CTR") dpkg-query -W -f='\${Package}=\${Version}\n' ${pkg_args}")
else
echo "dpkg ← local ctr=${CTR}"
# shellcheck disable=SC2086
raw=$(podman exec "$CTR" dpkg-query -W -f='${Package}=${Version}\n' "${PKGS[@]}")
fi
python3 - "$STACK_FILE" "$VERS_OUT" "$ROOT" "$CTR" "$SSH_HOST" "$raw" "${sites[@]}" <<'PY'
import json, re, sys
from pathlib import Path
from datetime import datetime
from zoneinfo import ZoneInfo
stack_path, vers_out, root, ctr, ssh_host, raw = sys.argv[1:7]
sites = sys.argv[7:]
stack = json.load(open(stack_path, encoding="utf-8"))
tz = ZoneInfo("Europe/Zurich")
now = datetime.now(tz)
iso = now.isoformat(timespec="seconds")
human = now.strftime("%Y-%m-%d %H:%M %Z")
versions = {}
for line in raw.splitlines():
line = line.strip()
if not line or "=" not in line:
continue
pkg, ver = line.split("=", 1)
# display upstream-ish: drop Debian revision (1.6.10-0+trixie → 1.6.10)
short = re.sub(r"-[0-9].*$", "", ver)
versions[pkg] = {"dpkg": ver, "display": short}
missing = []
for site in sites:
for pkg in stack["sites"][site]["packages"]:
if pkg not in versions:
missing.append(pkg)
if missing:
raise SystemExit(f"dpkg missing packages: {', '.join(sorted(set(missing)))}")
vanilla_href = stack["vanilla_href"]
vanilla_title = stack.get("vanilla_title", "vanilla")
sep = '<span class="sep">·</span>'
def render_block(site: str) -> str:
meta = stack["sites"][site]
parts = [
f' <!-- stack-bar -->',
f' <p class="stack-bar" role="note" title="{meta["title"]}">',
f' <strong>stack</strong>{sep}',
f' <a href="{vanilla_href}" target="_blank" rel="noopener noreferrer" title="{vanilla_title}">vanilla</a>',
]
for pkg in meta["packages"]:
disp = versions[pkg]["display"]
parts.append(f" {sep}")
parts.append(f" {pkg}&nbsp;{disp}")
parts.append(" </p>")
parts.append(" <!-- /stack-bar -->")
return "\n".join(parts) + "\n"
site_html = {
"bank": Path(root) / "configs/bank-landing/index.html",
"exchange": Path(root) / "configs/exchange-landing/index.html",
"merchant": Path(root) / "configs/merchant-landing/index.html",
}
marker_re = re.compile(r"[ \t]*<!-- stack-bar -->.*?<!-- /stack-bar -->\n?", re.S)
bare_re = re.compile(
r"[ \t]*<p class=\"stack-bar\"[^>]*>.*?</p>\n?",
re.S,
)
for site in sites:
path = site_html[site]
text = path.read_text(encoding="utf-8")
block = render_block(site)
if marker_re.search(text):
text = marker_re.sub(block, text, count=1)
elif bare_re.search(text):
text = bare_re.sub(block, text, count=1)
else:
raise SystemExit(f"no stack-bar in {path}")
path.write_text(text, encoding="utf-8")
print(f"stack → {path.relative_to(root)} ({site})")
out = {
"updated_iso": iso,
"updated_human": human,
"ctr": ctr,
"ssh": ssh_host if ssh_host else None,
"packages": versions,
"sites": {
site: {
"packages": {
pkg: versions[pkg]["display"]
for pkg in stack["sites"][site]["packages"]
}
}
for site in ("bank", "exchange", "merchant")
if site in stack["sites"]
},
}
Path(vers_out).write_text(json.dumps(out, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
print(f"versions → {Path(vers_out).relative_to(root)}")
print(f"OK stack stamped: {' '.join(sites)} @ {human}")
PY
echo "OK stamp-landing-stack: ${sites[*]}${CTR}"
if [ "$DO_DEPLOY" = 1 ]; then
deploy="$ROOT/scripts/taler-landing/deploy-landings.sh"
[ -x "$deploy" ] || { echo "missing $deploy" >&2; exit 1; }
if [ "$USE_SSH" = 1 ]; then
echo "=== --deploy → deploy-landings.sh --ssh ${SSH_HOST} --ctr ${CTR} ==="
LANDING_CTR="$CTR" "$deploy" --ssh "$SSH_HOST" --ctr "$CTR"
else
echo "=== --deploy → deploy-landings.sh --local --ctr ${CTR} ==="
LANDING_CTR="$CTR" "$deploy" --local --ctr "$CTR"
fi
fi