Keep infrastructure details out of the repository

The README, the publish script and the workflow named the tarball host, its
address and filesystem paths on the web host and the runner. Hosts and paths
now come only from repository variables, and the workflow shares the work
tree and the build cache through the named Docker volumes jasp-build and
jasp-cache instead of host paths. (The runner does not expand ${{ vars }} in
container.volumes, so a variable could not have replaced the host path there.)

Also drop the unused scripts/gen-tarball-index.py, and give each module build
its own process under a time limit: a module once spun for eight hours in
jaspModuleTools' bundling step and stalled the whole build.

Claude-Session: https://claude.ai/code/session_01GGe7kUhooMFuzY6GaDb2w9
This commit is contained in:
agw
2026-10-01 17:05:00 +02:00
parent e8c3d775aa
commit aa08dc108e
6 changed files with 45 additions and 227 deletions
-192
View File
@@ -1,192 +0,0 @@
#!/usr/bin/env python3
"""Render the index page for https://asger.weirsoe.dk/tarballz/.
Reads the sidecar .json files that publish-tarball.sh writes next to each
tarball (on stdin, one JSON object per line) and emits a standalone HTML page.
The theme tokens are inlined rather than linked to the main site's stylesheet:
that file is content-hashed (_astro/_slug_.<hash>.css) and its name changes on
every site rebuild, so a link would silently rot. Inlining costs a few hundred
bytes and cannot break.
"""
import html
import json
import os
import sys
from datetime import datetime, timezone
GITEA_URL = "https://gitea.weircon.dk/agw/jasp-desktop-bin"
AUR_URL = "https://aur.archlinux.org/packages/jasp-desktop-bin"
PAGE = """<!doctype html>
<html lang="da" data-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tarballs · Asger Weirsøe</title>
<meta name="description" content="Prækompilerede JASP-binærer til Arch Linux, bygget automatisk og udgivet på AUR som jasp-desktop-bin.">
<meta name="robots" content="noindex">
<link rel="icon" type="image/svg+xml" href="https://asger.weirsoe.dk/favicon.svg">
<script>
// Same localStorage key the main site uses, so the chosen theme carries over.
// Inline and before paint, otherwise the page flashes the wrong theme.
try {
var t = localStorage.getItem('theme');
if (!t) t = matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
document.documentElement.dataset.theme = t;
} catch (e) {}
</script>
<style>
:root, :root[data-theme=dark] {
color-scheme: dark;
--bg:#0b0f17; --surface:#121a27; --surface-2:#182232;
--border:#243044; --text:#e6e9ef; --muted:#97a3b6; --accent:#38bdf8;
}
:root[data-theme=light] {
color-scheme: light;
--bg:#f6f8fb; --surface:#fff; --surface-2:#eef2f8;
--border:#dde4ee; --text:#0f1729; --muted:#54617a; --accent:#0284c7;
}
:root[data-theme=terminal] {
color-scheme: dark;
--bg:#050a06; --surface:#0a140c; --surface-2:#102012;
--border:#1d3a22; --text:#4bff7e; --muted:#2fae57; --accent:#7dffa8;
}
* { box-sizing: border-box; }
body {
margin:0; background:var(--bg); color:var(--text);
font-family:"Inter Variable", ui-sans-serif, system-ui, -apple-system, sans-serif;
-webkit-font-smoothing:antialiased; line-height:1.6;
}
code, .mono { font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
a { color:var(--accent); text-decoration:none; }
a:hover { text-decoration:underline; }
header { border-bottom:1px solid color-mix(in srgb, var(--border) 70%, transparent); }
.wrap { max-width:48rem; margin:0 auto; padding:0 1.25rem; }
header .wrap { display:flex; align-items:center; justify-content:space-between; padding-top:.875rem; padding-bottom:.875rem; }
.brand { font-weight:700; font-size:1.125rem; letter-spacing:-.025em; color:var(--text); }
.brand span { color:var(--accent); }
main { padding:3rem 0 1rem; }
h1 { font-size:2.25rem; font-weight:700; letter-spacing:-.025em; margin:0; }
.lede { color:var(--muted); margin-top:.75rem; }
.card { border:1px solid var(--border); border-radius:1rem; background:color-mix(in srgb, var(--surface) 60%, transparent); padding:1.25rem; }
.install { margin-top:1.75rem; }
.install code { display:block; background:var(--surface-2); border-radius:.55rem; padding:.6rem .8rem; font-size:.875rem; overflow-x:auto; }
h2 { font-size:1.25rem; font-weight:600; letter-spacing:-.025em; margin:2.5rem 0 1rem; }
ul.releases { list-style:none; margin:0; padding:0; display:grid; gap:.75rem; }
ul.releases li { border:1px solid var(--border); border-radius:1rem; background:color-mix(in srgb, var(--surface) 60%, transparent); padding:1rem 1.25rem; }
.row { display:flex; flex-wrap:wrap; align-items:baseline; gap:.6rem; justify-content:space-between; }
.ver { font-weight:600; font-size:1.05rem; }
.meta { color:var(--muted); font-size:.8rem; }
.sha { color:var(--muted); font-size:.75rem; word-break:break-all; margin-top:.5rem; }
.empty { color:var(--muted); }
footer { border-top:1px solid color-mix(in srgb, var(--border) 70%, transparent); margin-top:4rem; }
footer .wrap { padding-top:1.5rem; padding-bottom:2rem; color:color-mix(in srgb, var(--muted) 80%, transparent); font-size:.8rem; }
footer .note { font-size:.75rem; }
@media (max-width:480px) { h1 { font-size:1.75rem; } }
</style>
</head>
<body>
<header><div class="wrap">
<a class="brand" href="https://asger.weirsoe.dk/">Asger Weirsøe<span>.</span></a>
<nav class="meta"><a href="https://asger.weirsoe.dk/projekter">Projekter</a></nav>
</div></header>
<main class="wrap">
<h1>Tarballs</h1>
<p class="lede">
Prækompilerede <a href="https://jasp-stats.org/">JASP</a>-binærer til Arch Linux.
JASP udgiver kun installere til Windows og macOS, så disse er bygget fra
kildekoden af <a href="{gitea}">en automatisk pipeline</a> og udgivet på AUR som
<a href="{aur}">jasp-desktop-bin</a>.
</p>
<div class="install">
<p class="meta">Du behøver normalt ikke hente herfra manuelt — brug AUR:</p>
<code>yay -S jasp-desktop-bin</code>
</div>
<h2>Tilgængelige builds</h2>
{releases}
<p class="meta" style="margin-top:1.5rem">
Hver build indeholder sin egen R og de biblioteker den linker mod, så den ikke
bindes til bestemte versioner af noget på dit system.
Kun de nyeste {keep} builds gemmes.
</p>
</main>
<footer><div class="wrap">
<p class="note mono">bygget automatisk · self-hosted på proxmox · <a href="{gitea}">byggeopskrift</a></p>
<p>© {year} Asger Weirsøe</p>
</div></footer>
</body>
</html>
"""
def human_size(n: int) -> str:
for unit in ("B", "KB", "MB", "GB"):
if n < 1024 or unit == "GB":
return f"{n:.1f} {unit}".replace(".0 ", " ")
n /= 1024
return f"{n} B"
def main() -> int:
entries = []
for line in sys.stdin:
line = line.strip()
if not line:
continue
try:
entries.append(json.loads(line))
except json.JSONDecodeError:
print(f"warning: skipping unparsable sidecar line", file=sys.stderr)
# Newest first.
entries.sort(key=lambda e: e.get("built", ""), reverse=True)
if entries:
items = []
for e in entries:
name = html.escape(e["tarball"])
ver = html.escape(e.get("jasp_version", "?"))
built = e.get("built", "")
try:
built_h = datetime.fromisoformat(built).strftime("%d-%m-%Y")
except ValueError:
built_h = html.escape(built)
size = human_size(int(e.get("size_bytes", 0)))
sha = html.escape(e.get("sha256", ""))
r = html.escape(e.get("bundled_r_version", ""))
qt = html.escape(e.get("qt6_minor", ""))
items.append(
f' <li>\n'
f' <div class="row">\n'
f' <span class="ver">JASP {ver}</span>\n'
f' <a href="{name}" download>Hent · {size}</a>\n'
f' </div>\n'
f' <div class="meta">{built_h} · x86_64 · bundlet R {r} · bygget mod Qt {qt}</div>\n'
f' <div class="sha mono">sha256 {sha}</div>\n'
f' </li>'
)
releases = '<ul class="releases">\n' + "\n".join(items) + "\n </ul>"
else:
releases = '<p class="empty">Ingen builds tilgængelige lige nu.</p>'
sys.stdout.write(
PAGE.format(
releases=releases,
gitea=GITEA_URL,
aur=AUR_URL,
keep=len(entries) if entries else 3,
year=datetime.now(timezone.utc).year,
)
)
return 0
if __name__ == "__main__":
sys.exit(main())
+7 -7
View File
@@ -2,16 +2,16 @@
# Publish the built tarball to asger.weirsoe.dk, which is what the AUR PKGBUILD
# downloads from.
#
# TARBALL_SSH_KEY private key authorised on the web host (required)
# TARBALL_HOST web host, e.g. 192.168.10.148 (required)
# TARBALL_PATH directory on that host (required)
# TARBALL_SSH_KEY private key authorised on the web host (required)
# TARBALL_HOST web host to upload to over SSH (required)
# TARBALL_PATH directory on that host (required)
# KEEP_RELEASES how many tarballs to retain (default 3)
# $1 path to the tarball to upload
#
# The files live in /srv/tarballz, deliberately NOT under /var/www/asger: the
# asger-web deploy replaces that directory atomically (build into .new, swap,
# delete .old), so anything stored inside it disappears on the next site deploy.
# nginx exposes /srv/tarballz via a `location /tarballz/` alias.
# TARBALL_PATH is deliberately outside the website's own web root: the site
# deploy replaces its web root atomically, so anything stored inside it would
# disappear on the next deploy. The web server publishes the directory through
# a separate /tarballz/ location.
set -euo pipefail