ZDDC/bootstrap/install.sh
ZDDC d37ff58e11 feat: unified bootstrap/install.sh replaces 4 hand-rolled install snippets
bootstrap/install.sh is a POSIX-sh script that handles all three ZDDC
deployment patterns plus both target shapes in a single command. The
homepage's "Install on your server" section now prints `sh -c
"$(curl -fsSL https://zddc.varasys.io/install.sh)"` invocations instead
of inlining four separate cURL loops.

Modes / channels / target:

  --mode copy   (default)  fetch actual HTML files locally; site is
                           self-contained after install.
  --mode track             install level-2 stubs that fetch the channel
                           from upstream on every page load. Only valid
                           with channel names (stable/beta/alpha); for
                           pinned versions, use --mode copy.

  --channel stable         (default)
  --channel beta | alpha   channel mirrors (auto-update upstream)
  --channel 0.0.2          exact version
  --channel 0.0            latest patch within 0.0.x (symlink-resolved)
  --channel 0              latest within 0.x (symlink-resolved)
  Optional leading 'v' is accepted.

  --target root            5 tool HTMLs (incl. landing as index.html)
                           plus _template/ directory of level-1 stubs
  --target project         4 level-1 stubs that fetch ../<tool>.html
  --target auto (default)  detect from CWD: 'project' if parent has a
                           ZDDC-looking index.html, 'root' otherwise

  --source URL             Override the upstream base URL (default:
                           https://zddc.varasys.io). Use this to point
                           at a private dev server during alpha work;
                           install.sh sed-rewrites the embedded source
                           inside fetched track-channel stubs so they
                           use your URL.

Also:

- website/index.html — replaces the four inlined install-card snippets
  with four use-case-oriented cards that all invoke the same script
  (self-contained / track-channel / pin-to-version / project-subdir).
- website/index.html — fixes the stale "pre-built image at codeberg.org/
  varasys/zddc-server (channel-tagged :stable, :beta, :alpha)" reference;
  zddc-server is now distributed as Codeberg release-asset binaries with
  helm chart examples in the repo.
- website/install.sh — symlink to ../bootstrap/install.sh so the upstream
  serves the script at https://zddc.varasys.io/install.sh.

Verified end-to-end against a file:// source: copy:root, copy:project,
track:root with custom --source (rewrite of base URL inside fetched
stub), and auto-detection of project vs root from CWD's parent
index.html all behave correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 09:44:13 -05:00

250 lines
9.8 KiB
Bash
Executable file

#!/bin/sh
# install.sh — Bootstrap a ZDDC deployment from zddc.varasys.io
# (or any compatible upstream) into the current directory.
#
# This script replaces the four hand-rolled install snippets that used
# to live inline on the home page. It handles all three deployment
# patterns (self-contained / channel-tracking / pinned-version) plus
# both target shapes (ZDDC root or project subdirectory).
#
# Usage:
# sh -c "$(curl -fsSL https://zddc.varasys.io/install.sh)"
# sh -c "$(curl -fsSL https://zddc.varasys.io/install.sh)" -- [options]
#
# Options:
# --channel <stable|beta|alpha|X.Y.Z|X.Y|X>
# Channel or pinned-version selector (default: stable).
# stable / beta / alpha — channel mirrors (auto-update
# on the upstream). X.Y.Z — exact version. X.Y — latest
# patch within X.Y.* (symlink-resolved on upstream).
# X — latest within X.*.* (symlink-resolved upstream).
# Optional leading 'v' is accepted and stripped.
#
# --source <URL> Upstream base URL (default: https://zddc.varasys.io).
# Use this to point at your own dev server during
# active alpha development, or at a mirror.
#
# --mode <copy|track> copy: fetch the actual HTML and save locally —
# site does not depend on the upstream after
# install. Use for pinned-version installs
# and air-gapped deployments. (default)
# track: install tiny level-2 stubs that fetch the
# chosen channel from the upstream on every
# page load. Auto-updates within the channel.
# Only valid with channel names (stable / beta
# / alpha), not with pinned versions.
#
# --target <root|project|auto>
# root: install at the deployment root — five tool
# HTMLs (incl. landing as index.html) plus
# a _template/ directory of level-1 stubs
# to copy into project subdirs.
# project: install in a project subdirectory — four
# level-1 stubs that fetch ../<tool>.html
# (same-origin) at load time. Use this in
# each <project>/ subdir under your root.
# auto: detect from CWD (default). 'project' if
# CWD's parent has a ZDDC-looking index.html;
# 'root' otherwise.
#
# --tools <list> Comma-separated subset of tools to install
# (default: archive,transmittal,classifier,mdedit).
# Landing is always included in --target root copy
# installs as index.html.
#
# --dry-run Print what would happen; don't write any files.
# -h | --help Show this help.
#
# Examples:
#
# Self-contained install of current stable at the deployment root:
# cd /srv/archive
# sh -c "$(curl -fsSL https://zddc.varasys.io/install.sh)"
#
# Track beta from upstream:
# cd /srv/archive
# sh -c "$(curl -fsSL https://zddc.varasys.io/install.sh)" -- \
# --mode track --channel beta
#
# Pin to a specific version (immutable):
# cd /srv/archive
# sh -c "$(curl -fsSL https://zddc.varasys.io/install.sh)" -- \
# --channel 0.0.2
#
# Track alpha from your own dev server (level-2 stubs point at it):
# cd /srv/archive
# sh -c "$(curl -fsSL https://zddc.varasys.io/install.sh)" -- \
# --mode track --channel alpha --source https://my-dev.local
#
# Install level-1 stubs in a project subdirectory (auto-detected):
# cd /srv/archive/Project-A
# sh -c "$(curl -fsSL https://zddc.varasys.io/install.sh)"
set -eu
CHANNEL="stable"
SOURCE="https://zddc.varasys.io"
MODE="copy"
TARGET="auto"
TOOLS="archive,transmittal,classifier,mdedit"
DRY_RUN=0
usage() {
awk '/^# Usage:/,/^$/' "$0" | sed 's/^# \{0,1\}//' >&2
exit "${1:-1}"
}
# --- Parse args ------------------------------------------------------------
while [ $# -gt 0 ]; do
case "$1" in
--channel) CHANNEL="${2:-}"; shift 2 ;;
--source) SOURCE="${2:-}"; shift 2 ;;
--mode) MODE="${2:-}"; shift 2 ;;
--target) TARGET="${2:-}"; shift 2 ;;
--tools) TOOLS="${2:-}"; shift 2 ;;
--dry-run) DRY_RUN=1; shift ;;
-h|--help) usage 0 ;;
*) echo "install.sh: unknown argument '$1'" >&2; usage ;;
esac
done
# Strip a trailing slash from SOURCE so URL composition is consistent.
SOURCE="${SOURCE%/}"
# --- Validate --mode and --target ------------------------------------------
case "$MODE" in
copy|track) ;;
*) echo "install.sh: --mode must be 'copy' or 'track' (got '$MODE')" >&2; exit 1 ;;
esac
case "$TARGET" in
root|project|auto) ;;
*) echo "install.sh: --target must be 'root', 'project', or 'auto' (got '$TARGET')" >&2; exit 1 ;;
esac
# --- Resolve --channel into a filename suffix ------------------------------
# stable / beta / alpha → _stable / _beta / _alpha
# 0.0.4 / v0.0.4 → _v0.0.4
# 0.0 / v0.0 → _v0.0
# 0 / v0 → _v0
_chan_arg="$CHANNEL"
case "$_chan_arg" in
stable|beta|alpha) SUFFIX="_${_chan_arg}" ;;
v*) SUFFIX="_${_chan_arg}" ;;
[0-9]*) SUFFIX="_v${_chan_arg}" ;;
*) echo "install.sh: --channel must be stable, beta, alpha, or a semver (got '$_chan_arg')" >&2; exit 1 ;;
esac
# --mode track is only meaningful for the three named channels — pinned
# version stubs aren't pre-built (they'd need a different stub per version,
# and an immutable pin doesn't really benefit from runtime indirection).
if [ "$MODE" = "track" ]; then
case "$_chan_arg" in
stable|beta|alpha) ;;
*) echo "install.sh: --mode track only supports channel names (stable, beta, alpha); for pinned versions use --mode copy" >&2; exit 1 ;;
esac
fi
# --- Auto-detect --target --------------------------------------------------
if [ "$TARGET" = "auto" ]; then
# Heuristic: parent dir has an index.html with the ZDDC brand string —
# we're inside a project subdirectory of an existing ZDDC deployment.
if [ -f "../index.html" ] && grep -q 'ZDDC' "../index.html" 2>/dev/null; then
TARGET="project"
else
TARGET="root"
fi
echo "install.sh: auto-detected --target=$TARGET (use --target to override)"
fi
# --- Plan summary ----------------------------------------------------------
echo "install.sh: $MODE $_chan_arg into $(pwd) (target=$TARGET, source=$SOURCE)"
[ "$DRY_RUN" = "1" ] && echo " [DRY RUN — no files will be written]"
TOOL_LIST=$(echo "$TOOLS" | tr ',' ' ')
# --- Helpers ---------------------------------------------------------------
fetch_to() {
_url="$1"; _dest="$2"
if [ "$DRY_RUN" = "1" ]; then
echo " [dry-run] $_url -> $_dest"
return 0
fi
echo " $_dest"
curl -fsSL "$_url" -o "$_dest"
}
# Fetch a track-channel stub and rewrite the upstream URL inside it if
# --source is non-default. The stub embeds 'https://zddc.varasys.io/releases/'
# as a constant; sed swaps it for the chosen base when the operator's
# pointed at a different host. POSIX sed handles this fine (no escaping
# concerns since SOURCE doesn't contain ampersand or slash inside the host).
fetch_stub_with_source() {
_url="$1"; _dest="$2"
if [ "$DRY_RUN" = "1" ]; then
echo " [dry-run] $_url -> $_dest (rewrite source if needed)"
return 0
fi
echo " $_dest"
if [ "$SOURCE" = "https://zddc.varasys.io" ]; then
curl -fsSL "$_url" -o "$_dest"
else
# POSIX sed; pipe through stdin to avoid editing in place.
curl -fsSL "$_url" \
| sed "s|https://zddc.varasys.io/releases/|${SOURCE}/releases/|g" \
> "$_dest"
fi
}
# --- Install ---------------------------------------------------------------
case "$MODE:$TARGET" in
copy:root)
# Five tool HTMLs at the root + level-1 _template/ for project subdirs.
for _t in $TOOL_LIST; do
fetch_to "$SOURCE/releases/${_t}${SUFFIX}.html" "${_t}.html"
done
# Landing always becomes index.html in the root install.
fetch_to "$SOURCE/releases/landing${SUFFIX}.html" "index.html"
if [ "$DRY_RUN" = "1" ]; then
echo " [dry-run] mkdir -p _template"
else
mkdir -p _template
fi
for _t in $TOOL_LIST; do
fetch_to "$SOURCE/bootstrap/level1/${_t}.html" "_template/${_t}.html"
done
;;
copy:project)
# Four level-1 stubs only — they fetch ../<tool>.html at load time.
for _t in $TOOL_LIST; do
fetch_to "$SOURCE/bootstrap/level1/${_t}.html" "${_t}.html"
done
;;
track:root)
# Five level-2 stubs (incl. landing as index.html) + _template/.
# Each stub fetches the channel from $SOURCE on every load.
for _t in $TOOL_LIST; do
fetch_stub_with_source "$SOURCE/bootstrap/track-$_chan_arg/${_t}.html" "${_t}.html"
done
fetch_stub_with_source "$SOURCE/bootstrap/track-$_chan_arg/index.html" "index.html"
if [ "$DRY_RUN" = "1" ]; then
echo " [dry-run] mkdir -p _template"
else
mkdir -p _template
fi
for _t in $TOOL_LIST; do
fetch_to "$SOURCE/bootstrap/level1/${_t}.html" "_template/${_t}.html"
done
;;
track:project)
# Same as copy:project — level-1 stubs are channel-agnostic
# (they fetch ../<tool>.html, which is whatever the root has).
for _t in $TOOL_LIST; do
fetch_to "$SOURCE/bootstrap/level1/${_t}.html" "${_t}.html"
done
;;
esac
echo "install.sh: done."