Rolls back the HTML-tool side of the Codeberg-as-canonical refactor (commits2dc9ad2,b28c4ae,bdac8dc) in favor of a simpler model: per-version HTML files committed under website/releases/ as immutable real files; partial-version pins (<tool>_v<X.Y>.html, <tool>_v<X>.html) and channel mirrors (<tool>_<channel>.html) are checked-in symlinks. Docker-tag pattern: :1.2.3 is pinned, :1.2 floats, :1 floats further, :stable floats furthest. URL scheme — every URL resolves to actual HTML via the symlink chain; no JS indirection, no manifest.json, no Caddy regex-rewrite: /releases/<tool>_v<X.Y.Z>.html exact version (real file) /releases/<tool>_v<X.Y>.html latest patch within X.Y.* (symlink) /releases/<tool>_v<X>.html latest within X.*.* (symlink) /releases/<tool>_stable.html current stable (symlink) /releases/<tool>_beta.html current beta (symlink to stable when no active beta; real file when beta is in flight) /releases/<tool>_alpha.html current alpha (similar — symlink to beta or stable when no active alpha) Cascade rule (in shared/build-lib.sh promote_release): --release [version] (stable cut) → write per-version file; refresh 5 symlinks (_v<X.Y>, _v<X>, _stable, _beta, _alpha) → new versioned file; tag <tool>-v<X.Y.Z>. --release beta → overwrite <tool>_beta.html with real bytes; cascade _alpha.html → _beta.html (symlink). No tag — channel URLs are stable URLs by design; counters defeat that. --release alpha → overwrite <tool>_alpha.html with real bytes. No tag, no other side-effects. Plain `sh tool/build.sh` → dist/ only. No website/releases/ side-effect, no commit. Code changes: - .gitignore — drop website/releases/*.html and website/releases/zddc-server-* exclusions; HTML tool files are tracked again. Replace the comment with the new model description. - shared/build-lib.sh — drop next_prerelease (no -alpha.N / -beta.N counter tags). Drop the Codeberg-upload path for HTML tools (no longer sourcing publish-codeberg-release.sh from build-lib). promote_release rewritten with two helpers: _promote_stable (per-version file + 5 symlinks + tag) and _promote_channel (overwrite mirror + cascade alpha→beta on beta cut). - zddc/release.sh — drop alpha/beta channel path entirely; binaries publish only on stable cuts. zddc-server's beta/alpha builds-from-source via the helm charts (next phase) — no binary distribution needed for those channels. - bootstrap/level2.html.tmpl — drop manifest.json fetch; resolve ?v= to a static URL via the symlink chain. New suffixFor() handles channel names, exact versions, and partial-version pins (?v=0.0, ?v=0). Same logic in level1.html.tmpl already works because the local-staging files (e.g. ../<tool>_v0.0.html) exist via the same symlink scheme. - build.sh build_releases_index — revert to filesystem scan of website/releases/ instead of Codeberg API call. Drop manifest.json generation. Per-tool sections list channel chips + per-version pin links; zddc-server section links to Codeberg release pages directly. - tests/build-label.spec.js — fix the channel-label regex to match the pre-release-semver format introduced in commit9459139("v0.0.3-alpha · ..."). Pre-existing test failure that wasn't caught at the time. Storage: - 30 new committed files under website/releases/ — 10 real (per-version) + 20 symlinks (5 tools × 4 partial/channel variants, plus alpha as a real file by default). - Initial state: stable v0.0.2 across all 5 tools; alpha/beta/v0.0/v0 symlinks all point at <tool>_v0.0.2.html. - manifest.json deleted (no longer needed). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
296 lines
13 KiB
Bash
Executable file
296 lines
13 KiB
Bash
Executable file
#!/bin/sh
|
||
set -eu
|
||
|
||
# Top-level build script — builds all ZDDC HTML tools, the zddc-server
|
||
# binaries, and the bootstrap stubs published under website/bootstrap/.
|
||
|
||
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
|
||
|
||
echo "=== Building ZDDC tools ==="
|
||
|
||
sh "$SCRIPT_DIR/transmittal/build.sh" "${1:-}" "${2:-}"
|
||
sh "$SCRIPT_DIR/archive/build.sh" "${1:-}" "${2:-}"
|
||
sh "$SCRIPT_DIR/classifier/build.sh" "${1:-}" "${2:-}"
|
||
sh "$SCRIPT_DIR/mdedit/build.sh" "${1:-}" "${2:-}"
|
||
sh "$SCRIPT_DIR/landing/build.sh" "${1:-}" "${2:-}"
|
||
|
||
echo ""
|
||
echo "=== Assembling zddc/dist/web/ ==="
|
||
# Only landing and archive ship inside the server bundle: they call the
|
||
# server's JSON API (GET / for the project list, directory listings for the
|
||
# archive) and are useless without it. transmittal, classifier, and mdedit
|
||
# are pure client-side tools that work from file:// or any static host;
|
||
# they are released to website/ for download but not bundled with the server.
|
||
mkdir -p "$SCRIPT_DIR/zddc/dist/web"
|
||
cp "$SCRIPT_DIR/landing/dist/index.html" "$SCRIPT_DIR/zddc/dist/web/index.html"
|
||
cp "$SCRIPT_DIR/archive/dist/archive.html" "$SCRIPT_DIR/zddc/dist/web/archive.html"
|
||
echo "Wrote zddc/dist/web/index.html"
|
||
echo "Wrote zddc/dist/web/archive.html"
|
||
|
||
# Cross-compiled zddc-server binaries — only relevant if you're shipping
|
||
# standalone Linux/macOS/Windows binaries to users. Skipped silently when
|
||
# Go isn't on PATH. (zddc/release.sh handles the publish flow that
|
||
# uploads these to Codeberg release assets.)
|
||
echo ""
|
||
echo "=== Building zddc-server binaries ==="
|
||
if command -v go >/dev/null 2>&1; then
|
||
cd "$SCRIPT_DIR/zddc"
|
||
mkdir -p dist
|
||
for target in linux/amd64 darwin/amd64 darwin/arm64 windows/amd64; do
|
||
os="${target%/*}"; arch="${target#*/}"
|
||
out="zddc-server-${os}-${arch}"
|
||
case "$os" in windows) out="${out}.exe" ;; esac
|
||
echo " building $out"
|
||
CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" \
|
||
go build -trimpath -ldflags="-s -w" -o "dist/$out" ./cmd/zddc-server
|
||
done
|
||
cd "$SCRIPT_DIR"
|
||
else
|
||
echo "go not found — skipping cross-compiled binary build."
|
||
echo " (Install Go 1.24+ to build standalone binaries.)"
|
||
fi
|
||
|
||
# ─── Bootstrap stubs ─────────────────────────────────────────────────────────
|
||
# Generated from bootstrap/level{1,2}.html.tmpl on every build and published
|
||
# as standalone files under website/bootstrap/. The website's "Install on
|
||
# your server" section prints copy-pasteable shell snippets that curl these
|
||
# files into the operator's deployment directory.
|
||
#
|
||
# bootstrap/level1/<tool>.html — same-origin stubs for
|
||
# <project>/<tool>.html (4 tools;
|
||
# landing only lives at root)
|
||
# bootstrap/track-<channel>/<tool>.html — level-2 stubs that fetch the
|
||
# named channel from upstream
|
||
# (5 tools × 3 channels = 15)
|
||
|
||
WEBSITE_DIR="$SCRIPT_DIR/website"
|
||
RELEASES_DIR="$WEBSITE_DIR/releases"
|
||
BOOTSTRAP_DIR="$SCRIPT_DIR/bootstrap"
|
||
|
||
mkdir -p "$WEBSITE_DIR"
|
||
|
||
# tool|filename|title
|
||
TOOL_TABLE='archive|archive.html|Archive
|
||
transmittal|transmittal.html|Transmittal
|
||
classifier|classifier.html|Classifier
|
||
mdedit|mdedit.html|Markdown Editor
|
||
landing|index.html|ZDDC'
|
||
|
||
# Substitute {{TOOL}}, {{TOOL_TITLE}}, {{CHANNEL}}, {{FAVICON}} in a template.
|
||
# The favicon is a base64-encoded data URI built once from shared/favicon.svg.
|
||
_favicon_data_uri=""
|
||
if [ -f "$SCRIPT_DIR/shared/favicon.svg" ]; then
|
||
_favicon_data_uri="data:image/svg+xml;base64,$(base64 -w 0 "$SCRIPT_DIR/shared/favicon.svg")"
|
||
fi
|
||
render_stub() {
|
||
sed \
|
||
-e "s|{{TOOL_TITLE}}|$3|g" \
|
||
-e "s|{{TOOL}}|$2|g" \
|
||
-e "s|{{CHANNEL}}|${4:-}|g" \
|
||
-e "s|{{FAVICON}}|$_favicon_data_uri|g" \
|
||
"$1" > "$5"
|
||
}
|
||
|
||
build_bootstrap_stubs() {
|
||
_stubs="$WEBSITE_DIR/bootstrap"
|
||
rm -rf "$_stubs"
|
||
mkdir -p "$_stubs/level1"
|
||
|
||
# Level-1 stubs (same-origin, channel-agnostic). Drop into a project
|
||
# subdirectory so <project>/<tool>.html fetches ../<tool>.html.
|
||
# Landing has no level-1 stub — landing only lives at deployment root.
|
||
while IFS='|' read -r _tool _file _title; do
|
||
render_stub "$BOOTSTRAP_DIR/level1.html.tmpl" "$_tool" "$_title" "" \
|
||
"$_stubs/level1/$_file"
|
||
done <<EOF
|
||
archive|archive.html|Archive
|
||
transmittal|transmittal.html|Transmittal
|
||
classifier|classifier.html|Classifier
|
||
mdedit|mdedit.html|Markdown Editor
|
||
EOF
|
||
echo "Wrote $_stubs/level1/{archive,transmittal,classifier,mdedit}.html"
|
||
|
||
# Level-2 stubs, one set per channel. Each fetches its named channel
|
||
# from upstream on every page load.
|
||
for _channel in alpha beta stable; do
|
||
mkdir -p "$_stubs/track-$_channel"
|
||
while IFS='|' read -r _tool _file _title; do
|
||
render_stub "$BOOTSTRAP_DIR/level2.html.tmpl" "$_tool" "$_title" "$_channel" \
|
||
"$_stubs/track-$_channel/$_file"
|
||
done <<EOF
|
||
$TOOL_TABLE
|
||
EOF
|
||
echo "Wrote $_stubs/track-$_channel/ (5 stubs)"
|
||
done
|
||
}
|
||
|
||
# Regenerate website/releases/index.html from a filesystem scan of
|
||
# website/releases/. Lists per-version files (real .html files, immutable
|
||
# archives) plus channel mirrors and partial-version pins (symlinks).
|
||
#
|
||
# All URLs in the page resolve directly under <upstream>/releases/<file>
|
||
# — no Codeberg API call, no manifest, no proxy magic. Page is static
|
||
# and current as of the last `sh build.sh` run.
|
||
#
|
||
# zddc-server's section links to its Codeberg release pages directly
|
||
# (different distribution model — per-platform binaries).
|
||
build_releases_index() {
|
||
_out="$RELEASES_DIR/index.html"
|
||
mkdir -p "$RELEASES_DIR"
|
||
|
||
{
|
||
cat <<'HEAD'
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Releases — ZDDC</title>
|
||
<meta name="description" content="All released versions and channel builds of every ZDDC tool.">
|
||
<meta name="theme-color" content="#2a5a8a">
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||
<link rel="stylesheet" href="../css/style.css">
|
||
<style>
|
||
.rel-tool { margin-top: var(--spacing-xl); padding: var(--spacing-md); border: 1px solid var(--color-border); border-radius: 8px; }
|
||
.rel-tool h2 { margin-top: 0; }
|
||
.rel-channels { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.75rem 0 1.25rem 0; }
|
||
.rel-channels a { padding: 0.25rem 0.625rem; border-radius: 999px; text-decoration: none; border: 1px solid var(--color-border); color: var(--color-text); font-size: 0.9rem; }
|
||
.rel-channels a.stable { border-color: var(--color-primary); color: var(--color-primary); font-weight: 600; }
|
||
.rel-channels a.beta, .rel-channels a.alpha { color: var(--color-text-muted); }
|
||
.rel-channels a:hover { background: var(--color-bg-subtle); }
|
||
.rel-versions { font-size: 0.875rem; color: var(--color-text-muted); }
|
||
.rel-versions a { margin-right: 0.5rem; color: var(--color-text); text-decoration: none; padding: 0.1rem 0.4rem; border-radius: 4px; }
|
||
.rel-versions a:hover { background: var(--color-bg-subtle); text-decoration: underline; }
|
||
.rel-meta { font-size: 0.85rem; color: var(--color-text-muted); margin-top: 0.5rem; }
|
||
.rel-bin-table { width: 100%; border-collapse: collapse; margin: 0.5rem 0 1rem; font-size: 0.9rem; }
|
||
.rel-bin-table th, .rel-bin-table td { text-align: left; padding: 0.4rem 0.6rem; border-bottom: 1px solid var(--color-border); }
|
||
.rel-bin-table th { font-weight: 600; color: var(--color-text-muted); }
|
||
.rel-bin-table td.ch-stable { color: var(--color-primary); font-weight: 600; }
|
||
.rel-bin-table td.ch-beta, .rel-bin-table td.ch-alpha { color: var(--color-text-muted); }
|
||
.rel-bin-table a { color: var(--color-text); text-decoration: none; padding: 0.1rem 0.35rem; border-radius: 4px; }
|
||
.rel-bin-table a:hover { background: var(--color-bg-subtle); text-decoration: underline; }
|
||
.rel-bin-table td.empty { color: var(--color-text-muted); font-style: italic; }
|
||
.rel-pull { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.85rem; background: var(--color-bg-subtle); padding: 0.25rem 0.5rem; border-radius: 4px; display: inline-block; margin: 0.2rem 0; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<header class="site-header">
|
||
<div class="container header-content">
|
||
<a href="/" class="brand">
|
||
<div class="brand-logo">
|
||
<svg viewBox="0 0 24 24"><path d="M3 5h18v2H3V5zm0 6h12v2H3v-2zm0 6h6v2H3v-2z" /></svg>
|
||
</div>
|
||
<span class="brand-name">ZDDC</span>
|
||
</a>
|
||
<nav class="header-nav">
|
||
<a href="/" class="nav-link">Home</a>
|
||
<a href="../reference.html" class="nav-link">Docs</a>
|
||
<a href="index.html" class="nav-link active">Releases</a>
|
||
</nav>
|
||
</div>
|
||
</header>
|
||
|
||
<section class="hero">
|
||
<div class="container">
|
||
<h1>Releases</h1>
|
||
<p class="hero-subtitle">All published versions and channel builds of every ZDDC tool. Stable releases are immutable; alpha and beta channels are rebuilt without notice.</p>
|
||
</div>
|
||
</section>
|
||
|
||
<main class="container" style="margin-bottom: var(--spacing-2xl);">
|
||
HEAD
|
||
# Render one section per HTML tool, scanning website/releases/ for
|
||
# <tool>_v*.html real files (per-version archives) and resolving the
|
||
# current channel symlinks.
|
||
for _tool_entry in 'archive|Archive' \
|
||
'transmittal|Transmittal' \
|
||
'classifier|Classifier' \
|
||
'mdedit|Markdown Editor' \
|
||
'landing|Landing (project picker)'; do
|
||
_tool="${_tool_entry%%|*}"
|
||
_title="${_tool_entry#*|}"
|
||
|
||
# All per-version real files for this tool, semver-descending.
|
||
# Use find to filter out symlinks; grep + sort -Vr for ordering.
|
||
_versioned=$(find "$RELEASES_DIR" -maxdepth 1 -type f -name "${_tool}_v*.html" 2>/dev/null \
|
||
| sed "s|^${RELEASES_DIR}/||" \
|
||
| sort -Vr)
|
||
|
||
if [ -z "$_versioned" ]; then
|
||
continue
|
||
fi
|
||
|
||
printf ' <section class="rel-tool">\n'
|
||
printf ' <h2>%s</h2>\n' "$_title"
|
||
|
||
# Channel chips — only render if the symlink exists.
|
||
printf ' <div class="rel-channels">\n'
|
||
for _ch in stable beta alpha; do
|
||
_link="${_tool}_${_ch}.html"
|
||
if [ -e "$RELEASES_DIR/$_link" ]; then
|
||
printf ' <a class="%s" href="%s">%s</a>\n' "$_ch" "$_link" "$_ch"
|
||
fi
|
||
done
|
||
printf ' </div>\n'
|
||
|
||
# Pin-to-version row: every per-version real file, descending.
|
||
printf ' <div class="rel-versions"><strong>Pin to version:</strong>\n'
|
||
printf '%s\n' "$_versioned" | while read -r _f; do
|
||
[ -n "$_f" ] || continue
|
||
# Display as v<X.Y.Z> stripped of <tool>_v prefix and .html suffix.
|
||
_v="${_f#${_tool}_v}"
|
||
_v="${_v%.html}"
|
||
printf ' <a href="%s">v%s</a>\n' "$_f" "$_v"
|
||
done
|
||
printf ' </div>\n'
|
||
|
||
printf ' </section>\n'
|
||
done
|
||
|
||
# zddc-server section — links to Codeberg release pages directly,
|
||
# since binaries don't live under website/releases/.
|
||
printf ' <section class="rel-tool">\n'
|
||
printf ' <h2>zddc-server (Go file server)</h2>\n'
|
||
printf ' <p>Binaries are published as Codeberg release assets. Pick a platform from the release page; or build from source via the helm charts under <code>helm/</code>.</p>\n'
|
||
printf ' <p><a href="https://codeberg.org/VARASYS/ZDDC/releases">Browse zddc-server releases on Codeberg →</a></p>\n'
|
||
printf ' </section>\n'
|
||
|
||
cat <<'TAIL'
|
||
|
||
<section style="margin-top: var(--spacing-2xl); color: var(--color-text-muted); font-size: 0.9rem;">
|
||
<p>Append <code>?v=stable</code>, <code>?v=beta</code>, <code>?v=alpha</code>, <code>?v=0.0</code> (latest 0.0.x), or <code>?v=0.0.1</code> (exact) to any deployment URL to switch versions for a single request — see <a href="../">the home page</a>.</p>
|
||
</section>
|
||
</main>
|
||
|
||
<footer class="site-footer">
|
||
<div class="container footer-content">
|
||
<span>ZDDC is open source — <a href="https://codeberg.org/VARASYS/ZDDC">codeberg.org/VARASYS/ZDDC</a></span>
|
||
</div>
|
||
</footer>
|
||
</body>
|
||
</html>
|
||
TAIL
|
||
} > "$_out"
|
||
echo "Wrote $_out"
|
||
}
|
||
|
||
echo ""
|
||
echo "=== Building bootstrap stubs and releases/index.html ==="
|
||
build_bootstrap_stubs
|
||
build_releases_index
|
||
|
||
echo ""
|
||
echo "=== All tools built successfully ==="
|
||
echo ""
|
||
echo "Server deployment package: zddc/dist/"
|
||
echo " Binaries: zddc-server-{linux,darwin,windows}-*"
|
||
echo " Web files: web/ (copy contents to ZDDC_ROOT)"
|
||
echo ""
|
||
echo "Bootstrap stubs: website/bootstrap/"
|
||
echo " level1/<tool>.html — same-origin stubs for project subdirs"
|
||
echo " track-{alpha,beta,stable}/ — level-2 stubs for each channel"
|
||
echo ""
|
||
echo "The home page's 'Install on your server' section prints copy-pasteable"
|
||
echo "shell snippets that curl these files into the operator's deployment dir."
|