flyedge.service runs /opt/fly/current/fly-edge After= and Requires= flysim.service, with its metrics on loopback :9102 and a ConditionPathExists so a release without the binary leaves it inactive. It is in no target and 07-enable.sh does not enable it; the header has the switch and the way back. build-flysim.sh also builds fly-edge beside the flysim binary and package-release.sh ships it when present. 05-deploy.sh writes FLY_FEED_VIA (default direct) into fly.env, flysim.service names FLY_BUS_DIR=/run/fly/bus and tmpfiles creates it. Watchdog check 2 reads the feed counters from whoever serves the feed: flyedge when fly.env says bus. lint.sh holds all of that, and drives check 2's choice against a fixture.
139 lines
6.6 KiB
Bash
Executable file
139 lines
6.6 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# infra/build/package-release.sh VERSION FLYSIM_BIN STAGE_DIR BRIDGE_DIR OUT_DIR
|
|
#
|
|
# Assembles a release tarball from the three built artifacts (flysim
|
|
# binary, apps/stage's built static page, services/bridge's node app +
|
|
# node_modules) plus a MANIFEST of every file's sha256. Run on the
|
|
# operator box or the fly-build CT, wherever the three artifacts already
|
|
# exist — this script does not build anything itself: see build-flysim.sh
|
|
# for the Rust build, build-bridge.sh for BRIDGE_DIR, and `npm run build -w
|
|
# @flybrain/stage` for STAGE_DIR.
|
|
#
|
|
# Output: OUT_DIR/flybrain-<version>.tar.gz, laid out as
|
|
# flysim (the binary, mode 0755)
|
|
# fly-edge (the feed-bus edge, mode 0755, when build-flysim.sh
|
|
# left one beside FLYSIM_BIN; flyedge.service stays
|
|
# inactive on a release without it)
|
|
# stage/... (apps/stage's build output)
|
|
# bridge/... (services/bridge + node_modules)
|
|
# data/fafb-v783/... (the connectome, from the repo; FLY_DATASET points here)
|
|
# MANIFEST (a few '#'-prefixed provenance comments, git_tag=
|
|
# and git_commit= among them, then sha256
|
|
# relative/path checksum lines, one per file,
|
|
# sorted)
|
|
#
|
|
# The '#' comment lines are deliberate: GNU coreutils' `sha256sum -c` skips
|
|
# blank and '#'-prefixed lines rather than treating them as malformed, so
|
|
# 05-deploy.sh's post-extraction `sha256sum -c MANIFEST --quiet` verifies
|
|
# cleanly with the provenance header still in the file (checked by hand: a
|
|
# MANIFEST with such a header produces no warning and exits 0).
|
|
#
|
|
# git_tag is the exact annotated tag (`git describe --exact-match --tags`)
|
|
# when this script is run from a tree checked out at one — the normal case
|
|
# for a ROLE=release build per infra/build/tag-release.sh and
|
|
# docs/stream-mvp-plan.md's "release container runs TAGGED commits only" —
|
|
# and otherwise the best `git describe --tags --always` can do (a dev
|
|
# build's short sha, typically), so a release deploy's tag-match check in
|
|
# 05-deploy.sh always has something to compare VERSION against.
|
|
#
|
|
# 05-deploy.sh pushes this tarball into the container, extracts it under
|
|
# /opt/fly/releases/<version>/, and re-verifies MANIFEST after extraction
|
|
# before flipping the `current` symlink.
|
|
set -euo pipefail
|
|
|
|
usage() { echo "usage: $0 VERSION FLYSIM_BIN STAGE_DIR BRIDGE_DIR OUT_DIR" >&2; exit 2; }
|
|
[ $# -eq 5 ] || usage
|
|
|
|
VERSION="$1"
|
|
FLYSIM_BIN="$2"
|
|
STAGE_DIR="$3"
|
|
BRIDGE_DIR="$4"
|
|
OUT_DIR="$5"
|
|
|
|
log() { echo "package-release: $*" >&2; }
|
|
die() { echo "package-release: FATAL: $*" >&2; exit 1; }
|
|
|
|
[ -x "$FLYSIM_BIN" ] || die "flysim binary not found or not executable: $FLYSIM_BIN"
|
|
[ -d "$STAGE_DIR" ] || die "stage build dir not found: $STAGE_DIR"
|
|
[ -d "$BRIDGE_DIR" ] || die "bridge dir not found: $BRIDGE_DIR"
|
|
# infra/units/flybridge.service's ExecStart and its ConditionPathExists are both
|
|
# on bridge/index.js. A BRIDGE_DIR without one packages a release whose chat
|
|
# bridge can never start — and the condition makes that failure SILENT: the unit
|
|
# stays cleanly inactive, verify.sh SKIPs it as "expected before P3", and the
|
|
# only symptom is a live channel with no bot in it. That is exactly what v0.1.0
|
|
# shipped on 2026-09-16. Build the directory with infra/build/build-bridge.sh,
|
|
# which produces this shape by construction.
|
|
[ -f "${BRIDGE_DIR}/index.js" ] || die "no index.js in ${BRIDGE_DIR} — flybridge.service execs bridge/index.js and will refuse to start without it (ConditionPathExists), silently. Build it with infra/build/build-bridge.sh"
|
|
[[ "$VERSION" =~ ^[A-Za-z0-9._-]+$ ]] || die "VERSION must match [A-Za-z0-9._-]+, got: $VERSION"
|
|
|
|
mkdir -p "$OUT_DIR"
|
|
work="$(mktemp -d "${TMPDIR:-/tmp}/package-release.XXXXXX")"
|
|
trap 'rm -rf "$work"' EXIT
|
|
|
|
release_dir="${work}/release"
|
|
mkdir -p "$release_dir"
|
|
|
|
cp "$FLYSIM_BIN" "${release_dir}/flysim"
|
|
chmod 0755 "${release_dir}/flysim"
|
|
EDGE_BIN="$(dirname "$FLYSIM_BIN")/fly-edge"
|
|
if [ -x "$EDGE_BIN" ]; then
|
|
cp "$EDGE_BIN" "${release_dir}/fly-edge"
|
|
chmod 0755 "${release_dir}/fly-edge"
|
|
else
|
|
log "no fly-edge beside $FLYSIM_BIN; packaging without it (FLY_FEED_VIA=bus unavailable in this release)"
|
|
fi
|
|
cp -a "$STAGE_DIR" "${release_dir}/stage"
|
|
cp -a "$BRIDGE_DIR" "${release_dir}/bridge"
|
|
|
|
# The connectome travels with the release. flysim cannot start without it and
|
|
# nothing else in infra/ ever put it on the container, so before the P0 spike
|
|
# every provisioned container had a flysim that exited looking for
|
|
# /srv/fly/data/fafb-v783. Shipping it here (rather than as a separate
|
|
# provisioning step) also means a rollback to an older release gets that
|
|
# release's dataset, and the MANIFEST below covers its every file.
|
|
DATASET_SRC="${DATASET_SRC:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/data/fafb-v783}"
|
|
[ -d "$DATASET_SRC" ] || die "dataset dir not found: $DATASET_SRC (override with DATASET_SRC=)"
|
|
[ -f "${DATASET_SRC}/meta.json" ] || die "no meta.json in $DATASET_SRC — not a dataset directory"
|
|
mkdir -p "${release_dir}/data"
|
|
cp -a "$DATASET_SRC" "${release_dir}/data/"
|
|
log "staged dataset $(basename "$DATASET_SRC") ($(du -sh "$DATASET_SRC" | cut -f1))"
|
|
|
|
# Provenance: which commit/tag this release was built from. REPO_DIR is
|
|
# the flybrain checkout this script itself lives in (infra/build/../..),
|
|
# not necessarily the same tree 05-deploy.sh runs from — recorded here so
|
|
# a MANIFEST always says where its bits came from even when it does not.
|
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
GIT_TAG=unknown
|
|
GIT_COMMIT=unknown
|
|
if git -C "$REPO_DIR" rev-parse --git-dir >/dev/null 2>&1; then
|
|
GIT_COMMIT="$(git -C "$REPO_DIR" rev-parse HEAD)"
|
|
GIT_TAG="$(git -C "$REPO_DIR" describe --exact-match --tags 2>/dev/null || true)"
|
|
if [ -z "$GIT_TAG" ]; then
|
|
GIT_TAG="$(git -C "$REPO_DIR" describe --tags --always 2>/dev/null || echo unknown)"
|
|
fi
|
|
else
|
|
log "WARNING: $REPO_DIR is not a git checkout — MANIFEST will record git_tag=unknown git_commit=unknown"
|
|
fi
|
|
log "provenance: git_tag=${GIT_TAG} git_commit=${GIT_COMMIT}"
|
|
|
|
log "computing MANIFEST"
|
|
{
|
|
echo "# flybrain release MANIFEST"
|
|
echo "# version=${VERSION}"
|
|
echo "# git_tag=${GIT_TAG}"
|
|
echo "# git_commit=${GIT_COMMIT}"
|
|
(
|
|
cd "$release_dir"
|
|
find . -type f ! -name MANIFEST -print0 \
|
|
| sort -z \
|
|
| xargs -0 sha256sum \
|
|
| sed 's#\./##'
|
|
)
|
|
} > "${release_dir}/MANIFEST"
|
|
|
|
tarball="${OUT_DIR}/flybrain-${VERSION}.tar.gz"
|
|
log "writing ${tarball}"
|
|
tar -C "$release_dir" -czf "$tarball" .
|
|
|
|
log "sha256 of the tarball itself: $(sha256sum "$tarball" | awk '{print $1}')"
|
|
log "done: ${tarball}"
|