95 lines
5.4 KiB
Bash
Executable File
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"
|