#!/usr/bin/env bash set -Eeuo pipefail # Build a self-contained release on the target Linux architecture. Native # addons (SQLite, Argon2 and image processing) must be installed on the same # architecture/libc as the artifact. ROOT=$(cd -- "$(dirname -- "$0")/.." && pwd -P) VERSION=${1:-} OUT_DIR=${2:-$ROOT/release} [[ "$(uname -s)" == "Linux" ]] || { printf 'release builds must run on Linux; detected %s\n' "$(uname -s)" >&2; exit 2; } if [[ -z "$VERSION" ]]; then VERSION=$(node -p 'require("./package.json").version') fi VERSION=${VERSION#v} [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$ ]] || { printf 'invalid version: %s\n' "$VERSION" >&2; exit 2; } case "$(uname -m)" in x86_64|amd64) ARCH=x64 ;; aarch64|arm64) ARCH=arm64 ;; armv7l|armv7|armhf) ARCH=armv7 ;; *) printf 'unsupported architecture: %s\n' "$(uname -m)" >&2; exit 2 ;; esac LIBC=glibc if command -v ldd >/dev/null 2>&1 && ldd --version 2>&1 | grep -qi musl; then LIBC=musl; fi cd "$ROOT" pnpm build stage=$(mktemp -d) trap 'rm -rf "$stage"' EXIT mkdir -p "$stage/dist" "$stage/migrations" "$stage/bin" "$stage/scripts" "$stage/systemd" "$stage/runtime/bin" cp -a dist/. "$stage/dist/" cp -a migrations/. "$stage/migrations/" cp package.json pnpm-lock.yaml "$stage/" cp -a bin/. "$stage/bin/" cp -a scripts/tallynote-update.sh scripts/tallynote-update-runner.sh "$stage/scripts/" cp -a systemd/tallynote.service systemd/tallynote-update.service systemd/tallynote-update.path systemd/tallynote.env.example "$stage/systemd/" node_path=$(command -v node) cp -L "$node_path" "$stage/runtime/bin/node" chmod 755 "$stage/bin/tallynote" "$stage/scripts"/*.sh "$stage/runtime/bin/node" # pnpm's default linker creates symlinks. A release archive is deliberately # symlink-free so the installer can reject traversal links deterministically. (cd "$stage" && pnpm install --prod --node-linker=hoisted --frozen-lockfile) find "$stage" -type l -delete mkdir -p "$OUT_DIR" archive="$OUT_DIR/tallynote-${VERSION}-linux-${ARCH}-${LIBC}.tar.gz" tar -C "$stage" -czf "$archive" --owner=0 --group=0 --numeric-owner . # Keep the sidecar useful when a caller builds more than one architecture into # the same directory. The publishing script recomputes this list immediately # before signing, so stale or hand-edited entries can never reach a Release. (cd "$OUT_DIR" && sha256sum ./*.tar.gz | sed 's#^\./##' | LC_ALL=C sort > SHA256SUMS) printf 'built %s\n' "$archive"