Adds command-line flags to zddc-server alongside the existing env vars.
Each setting can be set via --<flag-name> or ZDDC_<NAME>; the flag wins
on conflict, the env var wins over the hard-coded default.
--root / ZDDC_ROOT (now defaults to CWD if both unset)
--addr / ZDDC_ADDR (:8443)
--tls-cert / ZDDC_TLS_CERT ("none" / empty / path)
--tls-key / ZDDC_TLS_KEY
--log-level / ZDDC_LOG_LEVEL (info)
--index-path / ZDDC_INDEX_PATH (.archive)
--email-header / ZDDC_EMAIL_HEADER (X-Auth-Request-Email)
--cors-origin / ZDDC_CORS_ORIGIN (https://zddc.varasys.io; "" disables)
--insecure-direct / ZDDC_INSECURE_DIRECT (false)
--help (prints flag list to stderr, exits 0)
--version (prints binary + embedded tool versions, exits 0)
So an operator can `cd /srv/zddc && zddc-server` with zero config — the
served root defaults to the current directory, and TLS defaults to a
self-signed cert. config.Load now takes []string (test-friendly: nil
skips flag parsing entirely; tests pass an empty slice for env-only
loads).
Adds a `version` package-level var in main.go injected at link time via
`-ldflags="-X main.version=..."`. The build.sh runs git describe against
zddc-server-v* tags; for in-flight commits between releases it produces
e.g. zddc-server-v0.0.7-19-gadb6904-dirty.
Adds an embedded versions manifest:
- Each tool's compute_build_label (in shared/build-lib.sh) writes a
sidecar <tool>.label to $BUILD_LABELS_DIR if that env var is set.
- Top-level build.sh sets BUILD_LABELS_DIR before running each tool's
build, then assembles zddc/internal/apps/embedded/versions.txt as
one `<app>=<build label>` line per app.
- apps.EmbeddedVersions() loads the manifest at runtime.
- main.go logs a compact summary on every startup; --version dumps
the full per-app label.
Removes the old cfg.BuildVersion field — the X-ZDDC-Source: embedded
header now uses the package-level main.version directly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
311 lines
14 KiB
Bash
Executable file
311 lines
14 KiB
Bash
Executable file
#!/bin/sh
|
||
set -eu
|
||
|
||
# Top-level build script — builds all ZDDC HTML tools, the zddc-server
|
||
# binaries, and the website/releases/index.html versions index.
|
||
|
||
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
|
||
|
||
echo "=== Building ZDDC tools ==="
|
||
|
||
# Each tool's compute_build_label writes a sidecar `<tool>.label` here so
|
||
# we can assemble zddc/internal/apps/embedded/versions.txt below.
|
||
BUILD_LABELS_DIR="$SCRIPT_DIR/zddc/internal/apps/embedded/.labels"
|
||
rm -rf "$BUILD_LABELS_DIR"
|
||
mkdir -p "$BUILD_LABELS_DIR"
|
||
export BUILD_LABELS_DIR
|
||
|
||
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/ ==="
|
||
# All five tool HTMLs ship inside the server bundle. landing and archive call
|
||
# server APIs (GET / for the project list, directory listings for archive) and
|
||
# are useless without zddc-server. transmittal, classifier, and mdedit are
|
||
# pure client-side tools but are still bundled — the server uses these copies
|
||
# as the embedded fallback (//go:embed in internal/apps/embedded/) when both
|
||
# the cache is empty AND the upstream is unreachable.
|
||
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"
|
||
cp "$SCRIPT_DIR/transmittal/dist/transmittal.html" "$SCRIPT_DIR/zddc/dist/web/transmittal.html"
|
||
cp "$SCRIPT_DIR/classifier/dist/classifier.html" "$SCRIPT_DIR/zddc/dist/web/classifier.html"
|
||
cp "$SCRIPT_DIR/mdedit/dist/mdedit.html" "$SCRIPT_DIR/zddc/dist/web/mdedit.html"
|
||
echo "Wrote zddc/dist/web/{index,archive,transmittal,classifier,mdedit}.html"
|
||
|
||
# Mirror the same five HTMLs into the Go embed source dir so the next
|
||
# `go build` of zddc-server picks them up via //go:embed. Files are checked
|
||
# into git as empty placeholders; the build always overwrites them with the
|
||
# fresh dist/ output.
|
||
EMBED_DIR="$SCRIPT_DIR/zddc/internal/apps/embedded"
|
||
mkdir -p "$EMBED_DIR"
|
||
cp "$SCRIPT_DIR/landing/dist/index.html" "$EMBED_DIR/index.html"
|
||
cp "$SCRIPT_DIR/archive/dist/archive.html" "$EMBED_DIR/archive.html"
|
||
cp "$SCRIPT_DIR/transmittal/dist/transmittal.html" "$EMBED_DIR/transmittal.html"
|
||
cp "$SCRIPT_DIR/classifier/dist/classifier.html" "$EMBED_DIR/classifier.html"
|
||
cp "$SCRIPT_DIR/mdedit/dist/mdedit.html" "$EMBED_DIR/mdedit.html"
|
||
echo "Populated $EMBED_DIR/ for //go:embed"
|
||
|
||
# Assemble the embedded versions manifest from the per-tool .label sidecars
|
||
# written by shared/build-lib.sh's compute_build_label. The Go side reads
|
||
# this via //go:embed in internal/apps/versions.go and surfaces it in
|
||
# `zddc-server --version` output and the startup log line.
|
||
VERSIONS_FILE="$EMBED_DIR/versions.txt"
|
||
{
|
||
echo "# Generated by build.sh — do not edit. One <app>=<build label> per line."
|
||
for _tool in archive transmittal classifier mdedit landing; do
|
||
_label_file="$BUILD_LABELS_DIR/${_tool}.label"
|
||
if [ -f "$_label_file" ]; then
|
||
_label=$(cat "$_label_file")
|
||
else
|
||
_label=""
|
||
fi
|
||
printf '%s=%s\n' "$_tool" "$_label"
|
||
done
|
||
} > "$VERSIONS_FILE"
|
||
echo "Wrote $VERSIONS_FILE"
|
||
rm -rf "$BUILD_LABELS_DIR"
|
||
|
||
# Cross-compiled zddc-server binaries for Linux/macOS/Windows. Always built
|
||
# inside docker.io/golang:1.24-alpine via podman (or docker), matching the
|
||
# helm/zddc-server-prod chart's `buildImage` so dev binaries are byte-for-byte
|
||
# what production gets. The build container is downloaded on first run.
|
||
echo ""
|
||
echo "=== Building zddc-server binaries (containerized) ==="
|
||
mkdir -p "$SCRIPT_DIR/zddc/dist"
|
||
|
||
# Pick a container runtime. Both work; podman is preferred (rootless default).
|
||
GO_RUNNER=""
|
||
if command -v podman >/dev/null 2>&1; then
|
||
GO_RUNNER=podman
|
||
elif command -v docker >/dev/null 2>&1; then
|
||
GO_RUNNER=docker
|
||
else
|
||
echo "error: neither podman nor docker is available — cannot build zddc-server binaries." >&2
|
||
echo " Install podman (preferred) or docker. zddc-server build is containerized as policy." >&2
|
||
exit 1
|
||
fi
|
||
|
||
GO_BUILD_IMAGE="${ZDDC_GO_BUILD_IMAGE:-docker.io/golang:1.24-alpine}"
|
||
|
||
# Cache the Go module + build cache across runs via named volumes that
|
||
# persist between container invocations. Second build is fast.
|
||
GO_MOD_VOL="${ZDDC_GO_MOD_VOL:-zddc-go-mod}"
|
||
GO_BUILD_VOL="${ZDDC_GO_BUILD_VOL:-zddc-go-cache}"
|
||
|
||
# Compute the binary's own version: `git describe` if available (clean tag,
|
||
# or tag-N-gSHA[-dirty] for in-flight commits), else falls back to "dev".
|
||
# Surfaces via `zddc-server --version` and in the startup log line.
|
||
ZDDC_BINARY_VERSION=$(git -C "$SCRIPT_DIR" describe --tags --dirty --match 'zddc-server-v*' 2>/dev/null || true)
|
||
if [ -z "$ZDDC_BINARY_VERSION" ]; then
|
||
_sha=$(git -C "$SCRIPT_DIR" rev-parse --short=7 HEAD 2>/dev/null || echo unknown)
|
||
if ! git -C "$SCRIPT_DIR" diff --quiet HEAD 2>/dev/null; then
|
||
_sha="${_sha}-dirty"
|
||
fi
|
||
ZDDC_BINARY_VERSION="dev-${_sha}"
|
||
fi
|
||
echo " binary version: $ZDDC_BINARY_VERSION"
|
||
|
||
# Single container invocation, multiple cross-compile targets inside a
|
||
# `for` loop — avoids paying image-startup overhead 4×.
|
||
"$GO_RUNNER" run --rm \
|
||
-v "$SCRIPT_DIR:/src:Z" \
|
||
-v "${GO_MOD_VOL}:/go/pkg/mod" \
|
||
-v "${GO_BUILD_VOL}:/root/.cache/go-build" \
|
||
-w /src/zddc \
|
||
-e GOFLAGS=-mod=mod \
|
||
-e CGO_ENABLED=0 \
|
||
-e ZDDC_BINARY_VERSION="$ZDDC_BINARY_VERSION" \
|
||
"$GO_BUILD_IMAGE" \
|
||
sh -c '
|
||
set -e
|
||
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"
|
||
GOOS="$os" GOARCH="$arch" \
|
||
go build -trimpath \
|
||
-ldflags="-s -w -X main.version=${ZDDC_BINARY_VERSION}" \
|
||
-o "dist/$out" ./cmd/zddc-server
|
||
done
|
||
'
|
||
|
||
WEBSITE_DIR="$SCRIPT_DIR/website"
|
||
RELEASES_DIR="$WEBSITE_DIR/releases"
|
||
|
||
mkdir -p "$WEBSITE_DIR"
|
||
|
||
# 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">
|
||
<svg class="brand-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" aria-hidden="true">
|
||
<rect width="64" height="64" rx="12" fill="#1e3a5f"/>
|
||
<g fill="#fff">
|
||
<rect x="14" y="18" width="36" height="7"/>
|
||
<polygon points="43,25 50,25 21,43 14,43"/>
|
||
<rect x="14" y="43" width="36" height="7"/>
|
||
</g>
|
||
</svg>
|
||
<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>Each link above is a real static file (or a checked-in symlink resolving to one). Channel chips track the current build of that channel and may change at any time; per-version files are immutable. To install or pin in your own deployment, 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 releases/index.html ==="
|
||
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 "Operator install: see website/index.html 'Install on your server'."
|