open-standards/wai/quickstart/build.sh
Transaction Science aaf0affc43 wai: the command line through the catalogue, and the agent rules on every command
Every command line resolves through the catalogue (wai_cli/door.rs): its CLI spelling, an
alias, or its mechanical form wai <noun> <verb>; an implementation is found by operation
id, and help is written from the catalogue's entries. dx::VERBS is the developer path's view
of it. Every command keeps the agent rules (wai_cli/agent.rs): exit codes 0 to 7, --json
(a versioned envelope, envelope/1, carrying a command's own JSON or its text in data),
--dry-run on every operation that is not read-only (every write goes through
wai_cli/out.rs), and --yes where a change waits for confirmation (exit 4 off a terminal).
wai ops list, search, schema and export. The tests and the quickstart's packaging check read
the JSON forms from the envelope's data.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-27 04:52:20 -04:00

98 lines
5.3 KiB
Shell
Executable file

#!/usr/bin/env bash
# The quickstart archive: the `wai` command line and what `wai dev` runs, for one target.
#
# bash wai/quickstart/build.sh <out-dir> --web <dir> [--target <triple>] [--version <v>]
#
# Builds, each release and --locked, each from its own workspace:
# wai wai/wai-rs, --no-default-features --features quickstart: the mandatory
# floor, hello, create, dev and verify; no system codec library
# wai-relay the relay (crate joule-moq-relay, joule-code/joule-code-rs)
# wai-room the room service (crate joule-moq-room)
# wai-remote-host a remote desktop room's host agent
# wai-pack the packager
# and writes <out-dir>/wai-<version>-<triple>.tar.gz holding bin/ (those five), share/wai/web/
# (the room client, from --web: bash wai/quickstart/build-web.sh makes it), README.md and
# LICENSE, with <archive>.sha256 beside it in the form `shasum -a 256 -c` reads. The version
# is wai/wai-rs's unless given; the triple is the host's unless given. Extra cargo flags for
# the target (a linker, static linking) come from the environment, as cargo reads them.
set -euo pipefail
usage() { echo "usage: bash wai/quickstart/build.sh <out-dir> --web <dir> [--target <triple>] [--version <v>]" >&2; exit 2; }
[ $# -ge 3 ] || usage
ROOT=$(cd "$(dirname "$0")/../.." && pwd)
OUT=$(mkdir -p "$1" && cd "$1" && pwd); shift
WEBDIR="" TRIPLE="" VERSION=""
while [ $# -gt 0 ]; do
case "$1" in
--web) WEBDIR="$2"; shift 2 ;;
--target) TRIPLE="$2"; shift 2 ;;
--version) VERSION="$2"; shift 2 ;;
*) usage ;;
esac
done
[ -n "$WEBDIR" ] && [ -f "$WEBDIR/room/index.html" ] && [ -f "$WEBDIR/pkg/wai_live_web_bg.wasm" ] && [ -f "$WEBDIR/pkg/joule_moq_web_bg.wasm" ] \
|| { echo "--web: a directory build-web.sh made (room/, moq/, pkg/)" >&2; exit 2; }
HOST=$(rustc -vV | sed -n 's/^host: //p')
TRIPLE=${TRIPLE:-$HOST}
VERSION=${VERSION:-$(sed -n 's/^version = "\(.*\)"$/\1/p' "$ROOT/wai/wai-rs/Cargo.toml" | head -1)}
EXE=""; case "$TRIPLE" in *windows*) EXE=".exe" ;; esac
TGT=(--target "$TRIPLE")
build() { # <dir> <binary> <cargo args...>: the binary's path, or a failure
local dir="$1" bin="$2"; shift 2
(
# Under a target directory shared by every workspace (CARGO_TARGET_DIR), each build gets its
# own: wai also builds as a cdylib, so its rlib's file name carries no hash, and a second
# feature set of it (the room service's) would overwrite the first in one directory.
if [ -n "${CARGO_TARGET_DIR:-}" ]; then export CARGO_TARGET_DIR="$CARGO_TARGET_DIR/quickstart-$bin"; fi
cd "$dir"
cargo build --locked --release "${TGT[@]}" "$@" >&2 || exit 1
t=$(cargo metadata --format-version 1 --no-deps --locked | python3 -c 'import json,sys; print(json.load(sys.stdin)["target_directory"])') || exit 1
echo "$t/$TRIPLE/release/$bin$EXE"
)
}
need() { # <binary> <cargo args...>: copied into the stage, or the script stops
local b
b=$(build "$@") || { echo "build.sh: the build of $2 failed" >&2; exit 1; }
cp "$b" "$STAGE/$NAME/bin/"
}
NAME="wai-$VERSION-$TRIPLE"
STAGE=$(mktemp -d)
trap 'rm -rf "$STAGE"' EXIT
mkdir -p "$STAGE/$NAME/bin" "$STAGE/$NAME/share/wai"
need "$ROOT/wai/wai-rs" wai --no-default-features --features quickstart --bin wai
need "$ROOT/joule-code/joule-code-rs" wai-relay -p joule-moq-relay --bin wai-relay
need "$ROOT/joule-code/joule-code-rs/crates/joule-moq-room" wai-room --bin wai-room
need "$ROOT/joule-code/joule-code-rs/crates/joule-moq-remote" wai-remote-host --bin wai-remote-host
need "$ROOT/wai/wai-pack" wai-pack --bin wai-pack
cp -R "$WEBDIR" "$STAGE/$NAME/share/wai/web"
cp "$ROOT/wai/quickstart/README.md" "$STAGE/$NAME/README.md"
cp "$ROOT/wai/LICENSE" "$STAGE/$NAME/LICENSE"
chmod 755 "$STAGE/$NAME"/bin/*
# Each binary runs before it is packaged, where it can run here.
# The wai packaged must hold this checkout's examples, file for file and byte for byte: a stale
# binary would ship templates from another commit.
if [ "$TRIPLE" = "$HOST" ]; then
"$STAGE/$NAME/bin/wai-pack$EXE" fixture list > /dev/null
python3 - "$STAGE/$NAME/bin/wai$EXE" "$ROOT/wai/examples" <<'PY' || { echo "build.sh: the packaged wai does not hold this checkout's examples" >&2; exit 1; }
import json, os, subprocess, sys, tempfile
wai, ex = sys.argv[1], sys.argv[2]
with tempfile.TemporaryDirectory() as d:
for t in json.loads(subprocess.check_output([wai, "create", "--list", "--json"]))["data"]:
out = os.path.join(d, t["template"])
subprocess.check_output([wai, "create", out, "--template", t["template"]])
for f in t["files"]:
src = os.path.join(ex, t["template"], f)
if os.path.exists(src) and open(src, "rb").read() != open(os.path.join(out, f), "rb").read():
sys.exit(f"{t['template']}/{f} differs")
PY
fi
mkdir -p "$OUT"
# The same bytes for the same inputs: sorted names, fixed owner and times.
if tar --version 2>/dev/null | grep -q GNU; then
tar --sort=name --owner=0 --group=0 --numeric-owner --mtime='2026-01-01 00:00Z' -C "$STAGE" -cf - "$NAME" | gzip -n -9 > "$OUT/$NAME.tar.gz"
else
tar -C "$STAGE" -cf - "$NAME" | gzip -n -9 > "$OUT/$NAME.tar.gz"
fi
( cd "$OUT" && { command -v sha256sum >/dev/null && sha256sum "$NAME.tar.gz" || shasum -a 256 "$NAME.tar.gz"; } > "$NAME.tar.gz.sha256" )
echo "packaged $OUT/$NAME.tar.gz ($(cut -d' ' -f1 "$OUT/$NAME.tar.gz.sha256"), $(du -h "$OUT/$NAME.tar.gz" | cut -f1))"