Files
TallyNote/scripts/build-release.sh
T
Qiufeng 4b9c80cc3a
TallyNote release / linux-x64 (push) Successful in 6m16s
feat: add safe one-click uninstall
2026-09-01 06:57:52 +08:00

54 lines
2.5 KiB
Bash
Executable File

#!/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 uninstall.sh "$stage/uninstall.sh"
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" "$stage/uninstall.sh"
# 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"