Files

95 lines
5.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# Build first without secrets; sign and verify the exact containers distributed.
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
TARGET="${1:-universal-apple-darwin}"
BUILD_NUMBER="${2:-1}"
MODE="${3:-all}"
VERSION="$(python3 "$ROOT_DIR/scripts/release/metadata.py")"
TARGET_ROOT="${CARGO_TARGET_DIR:-$ROOT_DIR/target}"
APP_DIR="$TARGET_ROOT/$TARGET/release/bundle/macos"
APP_PATH="$APP_DIR/TTREE.app"
RELEASE_DIR="$ROOT_DIR/dist/macos"
UPDATER_KEY="${TAURI_SIGNING_PRIVATE_KEY:-}"
UPDATER_PATH="${TAURI_SIGNING_PRIVATE_KEY_PATH:-}"
UPDATER_PASSWORD="${TAURI_SIGNING_PRIVATE_KEY_PASSWORD:-}"
unset TAURI_SIGNING_PRIVATE_KEY TAURI_SIGNING_PRIVATE_KEY_PATH TAURI_SIGNING_PRIVATE_KEY_PASSWORD
unset TAURI_PRIVATE_KEY TAURI_PRIVATE_KEY_PATH TAURI_PRIVATE_KEY_PASSWORD
if [[ -z "$UPDATER_KEY" && -n "$UPDATER_PATH" ]]; then UPDATER_KEY="$(cat "$UPDATER_PATH")"; fi
if printf '%s' "$UPDATER_KEY" | grep -Eqi '(minisign|rsign) encrypted secret key'; then
UPDATER_KEY="$(printf '%s' "$UPDATER_KEY" | openssl base64 -A)"
fi
case "$BUILD_NUMBER" in ''|*[!0-9]*) echo 'Invalid build number' >&2; exit 2;; esac
case "$MODE" in all|--build-only|--package-only) ;; *) exit 2;; esac
case "$TARGET" in universal-apple-darwin|aarch64-apple-darwin|x86_64-apple-darwin) ;; *) exit 2;; esac
if [[ "$MODE" != "--build-only" && "$TARGET" != universal-apple-darwin ]]; then
echo 'Distributed macOS assets must be universal' >&2; exit 2
fi
cd "$ROOT_DIR"
if [[ "$MODE" != "--package-only" ]]; then
if [[ "$TARGET" == universal-apple-darwin ]]; then
env -u MACOS_COMMUNITY_CERTIFICATE -u MACOS_COMMUNITY_CERTIFICATE_PASSWORD cargo build --locked --release -p ttree-macos --target aarch64-apple-darwin
env -u MACOS_COMMUNITY_CERTIFICATE -u MACOS_COMMUNITY_CERTIFICATE_PASSWORD cargo build --locked --release -p ttree-macos --target x86_64-apple-darwin
mkdir -p "$TARGET_ROOT/$TARGET/release"
lipo -create "$TARGET_ROOT/aarch64-apple-darwin/release/ttree" "$TARGET_ROOT/x86_64-apple-darwin/release/ttree" -output "$TARGET_ROOT/$TARGET/release/ttree"
else
env -u MACOS_COMMUNITY_CERTIFICATE -u MACOS_COMMUNITY_CERTIFICATE_PASSWORD cargo build --locked --release -p ttree-macos --target "$TARGET"
fi
rm -rf "$APP_PATH"
mkdir -p "$APP_PATH/Contents/MacOS" "$APP_PATH/Contents/Resources"
cp "$TARGET_ROOT/$TARGET/release/ttree" "$APP_PATH/Contents/MacOS/ttree"
cp assets/icons/icon.icns "$APP_PATH/Contents/Resources/icon.icns"
/usr/libexec/PlistBuddy -c 'Clear dict' "$APP_PATH/Contents/Info.plist" >/dev/null
PLIST="$APP_PATH/Contents/Info.plist"
for pair in 'CFBundleName TTREE' 'CFBundleDisplayName TTREE' 'CFBundleExecutable ttree' 'CFBundleIdentifier com.samwstu.ttree' 'CFBundlePackageType APPL' 'CFBundleIconFile icon.icns' 'NSPrincipalClass NSApplication' 'LSMinimumSystemVersion 11.0'; do
/usr/libexec/PlistBuddy -c "Add :${pair%% *} string ${pair#* }" "$PLIST"
done
/usr/libexec/PlistBuddy -c "Add :CFBundleShortVersionString string $VERSION" "$PLIST"
/usr/libexec/PlistBuddy -c "Add :CFBundleVersion string $BUILD_NUMBER" "$PLIST"
/usr/libexec/PlistBuddy -c 'Add :LSUIElement bool true' "$PLIST"
/usr/libexec/PlistBuddy -c 'Add :NSHighResolutionCapable bool true' "$PLIST"
/usr/libexec/PlistBuddy -c 'Add :NSScreenCaptureUsageDescription string TTREE 需要屏幕录制权限以完成自由框选截图 OCR 翻译。' "$PLIST"
fi
test -x "$APP_PATH/Contents/MacOS/ttree"
if [[ "$MODE" == "--build-only" ]]; then
echo "Unsigned verification bundle: $APP_PATH"
exit 0
fi
WORK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/ttree-package.XXXXXX")"
OWN_KEYCHAIN=""
MOUNTED=0
cleanup() {
if [[ "$MOUNTED" == 1 ]]; then hdiutil detach "$WORK_DIR/mount" >/dev/null 2>&1 || true; fi
if [[ -n "$OWN_KEYCHAIN" ]]; then
security delete-keychain "$OWN_KEYCHAIN" >/dev/null 2>&1 || true
rm -rf "$(dirname "$OWN_KEYCHAIN")"
fi
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
SIGNING_KEYCHAIN="${MACOS_COMMUNITY_SIGNING_KEYCHAIN:-}"
if [[ -z "$SIGNING_KEYCHAIN" ]]; then
OWN_KEYCHAIN="$("$ROOT_DIR/scripts/macos/import-certificate.sh")"
SIGNING_KEYCHAIN="$OWN_KEYCHAIN"
fi
"$ROOT_DIR/scripts/macos/sign-app.sh" "$APP_PATH" "$SIGNING_KEYCHAIN"
security lock-keychain "$SIGNING_KEYCHAIN"
mkdir -p "$RELEASE_DIR"
COPYFILE_DISABLE=1 tar -czf "$WORK_DIR/TTREE_universal.app.tar.gz" -C "$APP_DIR" TTREE.app
TAURI_SIGNING_PRIVATE_KEY="$UPDATER_KEY" TAURI_SIGNING_PRIVATE_KEY_PATH="$UPDATER_PATH" \
TAURI_SIGNING_PRIVATE_KEY_PASSWORD="$UPDATER_PASSWORD" "$ROOT_DIR/scripts/release/validate-secrets.sh" updater
# Only the pinned standalone signer receives updater credentials (no frontend build).
TAURI_PRIVATE_KEY="$UPDATER_KEY" \
TAURI_PRIVATE_KEY_PASSWORD="$UPDATER_PASSWORD" \
npx --yes --package @tauri-apps/cli@2.8.4 tauri signer sign "$WORK_DIR/TTREE_universal.app.tar.gz" >/dev/null
mkdir -p "$WORK_DIR/stage"
ditto "$APP_PATH" "$WORK_DIR/stage/TTREE.app"
ln -s /Applications "$WORK_DIR/stage/Applications"
hdiutil create -volname TTREE -srcfolder "$WORK_DIR/stage" -format UDZO -ov "$WORK_DIR/TTREE_${VERSION}_universal.dmg" >/dev/null
cp "$WORK_DIR/TTREE_${VERSION}_universal.dmg" "$WORK_DIR/TTREE_universal.app.tar.gz" "$WORK_DIR/TTREE_universal.app.tar.gz.sig" "$RELEASE_DIR/"
if [[ "$TARGET" == universal-apple-darwin ]]; then
ARCHS="$(lipo -archs "$APP_PATH/Contents/MacOS/ttree")"
[[ " $ARCHS " == *" arm64 "* && " $ARCHS " == *" x86_64 "* ]] || { echo 'Universal binary is missing an architecture' >&2; exit 1; }
fi
echo "Signed macOS assets: $RELEASE_DIR"