#!/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 `.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 = 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 /releases/ # — 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' Releases — ZDDC

Releases

All published versions and channel builds of every ZDDC tool. Stable releases are immutable; alpha and beta channels are rebuilt without notice.

HEAD # Render one section per HTML tool, scanning website/releases/ for # _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 '
\n' printf '

%s

\n' "$_title" # Channel chips — only render if the symlink exists. printf '
\n' for _ch in stable beta alpha; do _link="${_tool}_${_ch}.html" if [ -e "$RELEASES_DIR/$_link" ]; then printf ' %s\n' "$_ch" "$_link" "$_ch" fi done printf '
\n' # Pin-to-version row: every per-version real file, descending. printf '
Pin to version:\n' printf '%s\n' "$_versioned" | while read -r _f; do [ -n "$_f" ] || continue # Display as v stripped of _v prefix and .html suffix. _v="${_f#${_tool}_v}" _v="${_v%.html}" printf ' v%s\n' "$_f" "$_v" done printf '
\n' printf '
\n' done # zddc-server section — links to Codeberg release pages directly, # since binaries don't live under website/releases/. printf '
\n' printf '

zddc-server (Go file server)

\n' printf '

Binaries are published as Codeberg release assets. Pick a platform from the release page; or build from source via the helm charts under helm/.

\n' printf '

Browse zddc-server releases on Codeberg →

\n' printf '
\n' cat <<'TAIL'

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 the home page.

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'."