207 lines
7.6 KiB
Bash
Executable File
207 lines
7.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
cd "$ROOT"
|
|
|
|
case "$(uname -s)" in
|
|
Darwin) ;;
|
|
*) echo "wrong platform: $(uname -s), macOS release requires macOS" >&2; exit 1;;
|
|
esac
|
|
|
|
CARGO_PROFILE="release"
|
|
|
|
PROFILE="${YRXTALS_MACOS_APPSTORE_PROFILE:-/Volumes/External/prvProfiles/Yr_Xtals_MacOS.provisionprofile}"
|
|
if [ ! -f "$PROFILE" ]; then
|
|
echo "ERROR: Mac App Store provisioning profile not found at $PROFILE" >&2
|
|
echo " set YRXTALS_MACOS_APPSTORE_PROFILE to override" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# pins an exact VER=x.y.z when set; otherwise the post-build BUMP step handles the next.
|
|
if [ -n "${VER:-}" ]; then
|
|
if ! [[ "$VER" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
echo "ERROR: VER must be x.y.z (got '$VER')" >&2
|
|
exit 1
|
|
fi
|
|
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VER" "$ROOT/macos/Info.plist"
|
|
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $VER" "$ROOT/macos/Info.plist"
|
|
echo "Pinned macos/Info.plist version to $VER"
|
|
fi
|
|
|
|
BUILD="$ROOT/build"
|
|
APP="$BUILD/macos-release/Yr Xtals.app"
|
|
CONTENTS="$APP/Contents"
|
|
MACOS_DIR="$CONTENTS/MacOS"
|
|
RESOURCES="$CONTENTS/Resources"
|
|
PKG="$BUILD/macos-release/YrXtals.pkg"
|
|
|
|
export MACOSX_DEPLOYMENT_TARGET=14.0
|
|
|
|
echo "Building Rust binary (profile=$CARGO_PROFILE)..."
|
|
cargo build --profile "$CARGO_PROFILE" --bin yr_crystals
|
|
|
|
BIN="/tmp/yr_crystals-target/$CARGO_PROFILE/yr_crystals"
|
|
if [ ! -f "$BIN" ]; then
|
|
echo "ERROR: yr_crystals binary not found at $BIN" >&2
|
|
exit 1
|
|
fi
|
|
|
|
rm -rf "$BUILD/macos-release"
|
|
mkdir -p "$MACOS_DIR" "$RESOURCES"
|
|
|
|
bash "$ROOT/scripts/macos/generate-icons.sh" "$BUILD/macos-release/AppIcon.icns"
|
|
cp "$BUILD/macos-release/AppIcon.icns" "$RESOURCES/AppIcon.icns"
|
|
|
|
cp "$ROOT/macos/Info.plist" "$CONTENTS/Info.plist"
|
|
cp "$BIN" "$MACOS_DIR/yr_crystals"
|
|
chmod +x "$MACOS_DIR/yr_crystals"
|
|
|
|
plutil -replace CFBundleSupportedPlatforms -json '["MacOSX"]' "$CONTENTS/Info.plist"
|
|
|
|
# injects the DT* and BuildMachineOSBuild keys App Store validation demands.
|
|
SDK_VER="$(xcrun --sdk macosx --show-sdk-version)"
|
|
SDK_BUILD="$(xcrun --sdk macosx --show-sdk-build-version)"
|
|
XCODE_VER="$(xcodebuild -version | head -1 | awk '{print $2}')"
|
|
XCODE_BUILD="$(xcodebuild -version | grep 'Build version' | awk '{print $3}')"
|
|
IFS='.' read -r XV_MAJ XV_MIN XV_PAT <<< "$XCODE_VER"
|
|
XV_MAJ="${XV_MAJ:-0}"; XV_MIN="${XV_MIN:-0}"; XV_PAT="${XV_PAT:-0}"
|
|
DT_XCODE="$((XV_MAJ * 100 + XV_MIN * 10 + XV_PAT))"
|
|
OS_BUILD="$(sw_vers -buildVersion)"
|
|
|
|
set_or_add() {
|
|
local key="$1" val="$2"
|
|
/usr/libexec/PlistBuddy -c "Set :$key $val" "$CONTENTS/Info.plist" 2>/dev/null \
|
|
|| /usr/libexec/PlistBuddy -c "Add :$key string $val" "$CONTENTS/Info.plist"
|
|
}
|
|
set_or_add BuildMachineOSBuild "$OS_BUILD"
|
|
set_or_add DTCompiler com.apple.compilers.llvm.clang.1_0
|
|
set_or_add DTPlatformBuild "$SDK_BUILD"
|
|
set_or_add DTPlatformName macosx
|
|
set_or_add DTPlatformVersion "$SDK_VER"
|
|
set_or_add DTSDKBuild "$SDK_BUILD"
|
|
set_or_add DTSDKName "macosx${SDK_VER}"
|
|
set_or_add DTXcode "$DT_XCODE"
|
|
set_or_add DTXcodeBuild "$XCODE_BUILD"
|
|
|
|
cp "$PROFILE" "$CONTENTS/embedded.provisionprofile"
|
|
|
|
ENT="$BUILD/macos-release/entitlements.plist"
|
|
security cms -D -i "$PROFILE" 2>/dev/null \
|
|
| plutil -extract Entitlements xml1 -o "$ENT" - \
|
|
|| { echo "ERROR: could not extract entitlements from profile" >&2; exit 1; }
|
|
|
|
# pins wildcard application-identifier to the concrete TEAM.bundle.id form.
|
|
BUNDLE_ID="$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$CONTENTS/Info.plist")"
|
|
TEAM_ID="$(/usr/libexec/PlistBuddy -c "Print :com.apple.developer.team-identifier" "$ENT" 2>/dev/null \
|
|
|| /usr/libexec/PlistBuddy -c "Print :application-identifier" "$ENT" | cut -d. -f1)"
|
|
case "$(/usr/libexec/PlistBuddy -c "Print :application-identifier" "$ENT")" in
|
|
*\*) /usr/libexec/PlistBuddy -c "Set :application-identifier ${TEAM_ID}.${BUNDLE_ID}" "$ENT" ;;
|
|
esac
|
|
|
|
# Mac App Store mandates the app-sandbox entitlement.
|
|
/usr/libexec/PlistBuddy -c "Set :com.apple.security.app-sandbox true" "$ENT" 2>/dev/null \
|
|
|| /usr/libexec/PlistBuddy -c "Add :com.apple.security.app-sandbox bool true" "$ENT"
|
|
/usr/libexec/PlistBuddy -c "Set :com.apple.security.files.user-selected.read-only true" "$ENT" 2>/dev/null \
|
|
|| /usr/libexec/PlistBuddy -c "Add :com.apple.security.files.user-selected.read-only bool true" "$ENT"
|
|
/usr/libexec/PlistBuddy -c "Set :get-task-allow false" "$ENT" 2>/dev/null \
|
|
|| /usr/libexec/PlistBuddy -c "Add :get-task-allow bool false" "$ENT"
|
|
|
|
# locates an Apple Distribution / Mac App Distribution identity by SHA-matching the profile's certs.
|
|
TMPDIR_PROF="$(mktemp -d)"
|
|
PROFILE_PLIST="$TMPDIR_PROF/profile.plist"
|
|
security cms -D -i "$PROFILE" > "$PROFILE_PLIST" 2>/dev/null
|
|
|
|
PROFILE_SHAS=""
|
|
for i in 0 1 2 3 4 5 6 7 8 9; do
|
|
if ! plutil -extract "DeveloperCertificates.$i" raw -o "$TMPDIR_PROF/c$i.b64" "$PROFILE_PLIST" >/dev/null 2>&1; then
|
|
break
|
|
fi
|
|
base64 -D -i "$TMPDIR_PROF/c$i.b64" -o "$TMPDIR_PROF/c$i.cer"
|
|
sha=$(openssl x509 -inform der -in "$TMPDIR_PROF/c$i.cer" -fingerprint -noout 2>/dev/null \
|
|
| sed 's/.*=//;s/://g')
|
|
PROFILE_SHAS="$PROFILE_SHAS $sha"
|
|
done
|
|
|
|
KEYCHAIN_SHAS=$(security find-identity -v -p codesigning 2>/dev/null \
|
|
| awk '/[0-9A-F]{40}/ {gsub(/[^0-9A-F]/, "", $2); print $2}')
|
|
|
|
APP_IDENTITY=""
|
|
for s in $PROFILE_SHAS; do
|
|
if echo "$KEYCHAIN_SHAS" | grep -qi "^$s$"; then
|
|
APP_IDENTITY="$s"
|
|
break
|
|
fi
|
|
done
|
|
rm -rf "$TMPDIR_PROF"
|
|
|
|
if [ -z "$APP_IDENTITY" ]; then
|
|
echo "ERROR: no Apple/Mac App Distribution identity in keychain matches the profile's certs" >&2
|
|
echo " profile certs:$PROFILE_SHAS" >&2
|
|
exit 1
|
|
fi
|
|
|
|
INSTALLER_IDENTITY="$(security find-identity -v 2>/dev/null \
|
|
| grep -E 'Mac Installer Distribution|3rd Party Mac Developer Installer' \
|
|
| head -1 | awk '{print $2}')"
|
|
if [ -z "$INSTALLER_IDENTITY" ]; then
|
|
echo "ERROR: no 'Mac Installer Distribution' identity in keychain — required to sign the .pkg" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "Signing app with $APP_IDENTITY..."
|
|
codesign --force --deep \
|
|
--sign "$APP_IDENTITY" \
|
|
--entitlements "$ENT" \
|
|
--options runtime \
|
|
--timestamp \
|
|
"$APP"
|
|
|
|
codesign --verify --deep --strict --verbose=2 "$APP"
|
|
|
|
echo "Building .pkg with $INSTALLER_IDENTITY..."
|
|
productbuild --component "$APP" /Applications --sign "$INSTALLER_IDENTITY" "$PKG"
|
|
|
|
SHIPPED_VER="$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$CONTENTS/Info.plist")"
|
|
|
|
# resolves BUMP from --bump flag, BUMP env var, or fallback default.
|
|
EXPLICIT_BUMP=""
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--bump) EXPLICIT_BUMP=patch ;;
|
|
--bump=*) EXPLICIT_BUMP="${arg#--bump=}" ;;
|
|
esac
|
|
done
|
|
if [ -n "$EXPLICIT_BUMP" ]; then
|
|
BUMP="$EXPLICIT_BUMP"
|
|
elif [ -z "${BUMP:-}" ]; then
|
|
if [ -n "${VER:-}" ]; then
|
|
BUMP=none
|
|
else
|
|
BUMP=patch
|
|
fi
|
|
fi
|
|
case "$BUMP" in
|
|
none)
|
|
echo "Skipping version bump (BUMP=none)"
|
|
;;
|
|
major|minor|patch)
|
|
IFS='.' read -r CUR_MAJ CUR_MIN CUR_PATCH <<< "$SHIPPED_VER"
|
|
CUR_MAJ="${CUR_MAJ:-0}"; CUR_MIN="${CUR_MIN:-0}"; CUR_PATCH="${CUR_PATCH:-0}"
|
|
case "$BUMP" in
|
|
major) NEW_VER="$((CUR_MAJ + 1)).0.0" ;;
|
|
minor) NEW_VER="$CUR_MAJ.$((CUR_MIN + 1)).0" ;;
|
|
patch) NEW_VER="$CUR_MAJ.$CUR_MIN.$((CUR_PATCH + 1))" ;;
|
|
esac
|
|
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $NEW_VER" "$ROOT/macos/Info.plist"
|
|
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $NEW_VER" "$ROOT/macos/Info.plist"
|
|
echo "Bumped macos/Info.plist: $SHIPPED_VER -> $NEW_VER ($BUMP) for next release"
|
|
;;
|
|
*)
|
|
echo "ERROR: BUMP must be patch|minor|major|none, got '$BUMP'" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
echo "Built: $PKG ($BUNDLE_ID @ $SHIPPED_VER)"
|