Files
Memoh/scripts/release.sh
T

241 lines
6.7 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
TARGET_OS="${TARGET_OS:-$(go env GOOS)}"
TARGET_ARCH="${TARGET_ARCH:-$(go env GOARCH)}"
VERSION="${VERSION:-dev}"
COMMIT_HASH="${COMMIT_HASH:-unknown}"
BUILD_TIME="${BUILD_TIME:-$(date -u +"%Y-%m-%dT%H:%M:%SZ")}"
OUTPUT_DIR="${OUTPUT_DIR:-$ROOT_DIR/dist}"
PREPARE_ASSETS_ONLY="false"
UPX_COMPRESS_AGENT_BIN="${UPX_COMPRESS_AGENT_BIN:-false}"
UPX_ARGS="${UPX_ARGS:--3}"
UPX_ALLOW_DARWIN="${UPX_ALLOW_DARWIN:-false}"
AUTO_INSTALL_UPX="${AUTO_INSTALL_UPX:-}"
if [[ -z "$AUTO_INSTALL_UPX" ]]; then
AUTO_INSTALL_UPX=$([[ "${GITHUB_ACTIONS:-}" == "true" ]] && echo "true" || echo "false")
fi
WEB_DIR="$ROOT_DIR/internal/embedded/web"
AGENT_DIR="$ROOT_DIR/internal/embedded/agent"
BUN_DIR="$ROOT_DIR/internal/embedded/bun"
log() {
echo "[release] $*"
}
usage() {
cat <<'EOF'
Usage: scripts/release.sh [options]
Options:
--os <os> Target OS (default: current GOOS)
--arch <arch> Target ARCH (default: current GOARCH)
--version <version> Version string injected into memoh binary
--commit-hash <sha> Commit hash injected into memoh binary
--output-dir <dir> Output directory for release artifacts
--prepare-assets Only prepare embedded assets, do not build archive
Compatibility options:
--bun-version <v> Deprecated; ignored (kept for backward compatibility)
EOF
}
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--os)
TARGET_OS="$2"
shift 2
;;
--arch)
TARGET_ARCH="$2"
shift 2
;;
--bun-version)
# Bun runtime archives are no longer embedded; keep arg for compatibility.
shift 2
;;
--version)
VERSION="$2"
shift 2
;;
--commit-hash)
COMMIT_HASH="$2"
shift 2
;;
--output-dir)
OUTPUT_DIR="$2"
shift 2
;;
--prepare-assets)
PREPARE_ASSETS_ONLY="true"
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown arg: $1" >&2
usage >&2
exit 1
;;
esac
done
}
write_keep_gitignore() {
local dir="$1"
printf "*\n!.gitignore\n" > "$dir/.gitignore"
}
resolve_agent_compile_target() {
case "${TARGET_OS}-${TARGET_ARCH}" in
linux-amd64) echo "bun-linux-x64|agent-bin" ;;
linux-arm64) echo "bun-linux-arm64|agent-bin" ;;
darwin-amd64) echo "bun-darwin-x64|agent-bin" ;;
darwin-arm64) echo "bun-darwin-arm64|agent-bin" ;;
windows-amd64) echo "bun-windows-x64|agent-bin.exe" ;;
*) echo "|" ;;
esac
}
prepare_embed_dirs() {
rm -rf "$WEB_DIR" "$AGENT_DIR" "$BUN_DIR"
mkdir -p "$WEB_DIR" "$AGENT_DIR" "$BUN_DIR"
write_keep_gitignore "$WEB_DIR"
write_keep_gitignore "$AGENT_DIR"
write_keep_gitignore "$BUN_DIR"
}
prepare_assets() {
prepare_embed_dirs
log "building web assets"
pnpm --dir "$ROOT_DIR" web:build
cp -R "$ROOT_DIR/packages/web/dist/." "$WEB_DIR/"
gzip_embedded_web_assets "$WEB_DIR"
local target_key="${TARGET_OS}-${TARGET_ARCH}"
local resolved bun_compile_target agent_bin_name
resolved="$(resolve_agent_compile_target)"
bun_compile_target="${resolved%%|*}"
agent_bin_name="${resolved##*|}"
if [[ -z "$bun_compile_target" || -z "$agent_bin_name" ]]; then
echo "agent-bin not available for ${target_key}" > "$AGENT_DIR/UNAVAILABLE"
log "skipped agent-bin compile for unsupported target ${target_key}"
return 0
fi
log "building agent executable (${bun_compile_target})"
(
cd "$ROOT_DIR/agent"
bun build src/index.ts --compile --target "$bun_compile_target" --outfile "$AGENT_DIR/$agent_bin_name"
)
chmod +x "$AGENT_DIR/$agent_bin_name" || true
compress_agent_bin_if_enabled "$AGENT_DIR/$agent_bin_name" "$TARGET_OS"
log "embedded assets prepared (${target_key})"
}
compress_agent_bin_if_enabled() {
local bin_path="$1"
local target_os="$2"
if [[ "$UPX_COMPRESS_AGENT_BIN" != "true" ]]; then
return 0
fi
ensure_upx_available
if [[ "$target_os" == "darwin" && "$UPX_ALLOW_DARWIN" != "true" ]]; then
log "skip upx on darwin (set UPX_ALLOW_DARWIN=true to force)"
return 0
fi
local before_bytes after_bytes
before_bytes="$(wc -c < "$bin_path" | tr -d ' ')"
read -r -a upx_flags <<< "$UPX_ARGS"
upx "${upx_flags[@]}" "$bin_path"
after_bytes="$(wc -c < "$bin_path" | tr -d ' ')"
log "upx compressed agent-bin: ${before_bytes} -> ${after_bytes} bytes"
}
ensure_upx_available() {
if command -v upx >/dev/null 2>&1; then
return 0
fi
if [[ "$AUTO_INSTALL_UPX" != "true" ]]; then
echo "[release] UPX_COMPRESS_AGENT_BIN=true but upx not found in PATH" >&2
echo "[release] install upx or set AUTO_INSTALL_UPX=true" >&2
exit 1
fi
log "upx not found; attempting auto-install"
if [[ "$OSTYPE" == linux* ]] && command -v apt-get >/dev/null 2>&1; then
if command -v sudo >/dev/null 2>&1; then
sudo apt-get update -y && sudo apt-get install -y upx-ucl
else
apt-get update -y && apt-get install -y upx-ucl
fi
elif [[ "$OSTYPE" == darwin* ]] && command -v brew >/dev/null 2>&1; then
brew install upx
fi
if ! command -v upx >/dev/null 2>&1; then
echo "[release] failed to auto-install upx" >&2
exit 1
fi
}
gzip_embedded_web_assets() {
local web_dir="$1"
log "precompressing web assets (.gz)"
while IFS= read -r -d '' file_path; do
if [[ "$(basename "$file_path")" == ".gitignore" ]]; then
continue
fi
gzip -9 -c "$file_path" > "${file_path}.gz"
rm -f "$file_path"
done < <(find "$web_dir" -type f -print0)
}
build_archive() {
mkdir -p "$OUTPUT_DIR"
local ext=""
if [[ "$TARGET_OS" == "windows" ]]; then
ext=".exe"
fi
local binary_name="memoh${ext}"
local target_dir="$OUTPUT_DIR/memoh_${VERSION}_${TARGET_OS}_${TARGET_ARCH}"
mkdir -p "$target_dir"
log "building binary ${TARGET_OS}/${TARGET_ARCH}"
CGO_ENABLED=0 GOOS="$TARGET_OS" GOARCH="$TARGET_ARCH" \
go build \
-trimpath \
-ldflags "-s -w -X github.com/memohai/memoh/internal/version.Version=${VERSION} -X github.com/memohai/memoh/internal/version.CommitHash=${COMMIT_HASH} -X github.com/memohai/memoh/internal/version.BuildTime=${BUILD_TIME}" \
-o "$target_dir/$binary_name" \
"$ROOT_DIR/cmd/memoh"
if [[ "$TARGET_OS" == "windows" ]]; then
(cd "$OUTPUT_DIR" && zip -q -r "memoh_${VERSION}_${TARGET_OS}_${TARGET_ARCH}.zip" "memoh_${VERSION}_${TARGET_OS}_${TARGET_ARCH}")
else
tar -C "$OUTPUT_DIR" -czf "$OUTPUT_DIR/memoh_${VERSION}_${TARGET_OS}_${TARGET_ARCH}.tar.gz" "memoh_${VERSION}_${TARGET_OS}_${TARGET_ARCH}"
fi
log "archive created (${TARGET_OS}-${TARGET_ARCH})"
}
parse_args "$@"
prepare_assets
if [[ "$PREPARE_ASSETS_ONLY" == "true" ]]; then
log "prepare-assets only mode completed"
exit 0
fi
build_archive