179 lines
5.8 KiB
Bash
179 lines
5.8 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
|
|
#
|
|
# After this, bump footer dates with:
|
|
# ./scripts/taler-landing/stamp-landing-version.sh --bump --all
|
|
# Then deploy (unified vanilla CTR):
|
|
# LANDING_CTR=goa-regio-ng ./scripts/taler-landing/deploy-landings.sh
|
|
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
|
|
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 ;;
|
|
bank|exchange|merchant) sites+=("$1"); shift ;;
|
|
-h|--help)
|
|
sed -n '2,20p' "$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} {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}"
|