diff --git a/scripts/release.sh b/scripts/release.sh index 8f8f5d6..2d88187 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -12,8 +12,8 @@ DIST="$ROOT/dist" SIGNING_IDENTITY="${SIGNING_IDENTITY:-B99D353C88996866C49E4389B375645F76870A3F}" TEAM_ID="${TEAM_ID:-39R6U3437D}" NOTARY_PROFILE="${NOTARY_PROFILE:-orion-notary}" -mkdir -p "$ROOT/build-logs" "$DIST" -LOG="$ROOT/build-logs/release-$(date +%Y%m%d-%H%M%S).log" +mkdir -p "$ROOT/.build/build-logs" "$DIST" +LOG="$ROOT/.build/build-logs/release-$(date +%Y%m%d-%H%M%S).log" exec > >(tee "$LOG") 2>&1 command -v xcodebuild >/dev/null command -v hdiutil >/dev/null diff --git a/scripts/release.sh.bak-20261023-075550 b/scripts/release.sh.bak-20261023-075550 deleted file mode 100755 index cd01a5c..0000000 --- a/scripts/release.sh.bak-20261023-075550 +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/zsh -set -euo pipefail -ROOT="$(cd "$(dirname "$0")/.." && pwd)" -cd "$ROOT" -APP_NAME=OrionToolbar -PROJECT="$ROOT/OrionToolbar.xcodeproj" -DERIVED="$ROOT/.build" -WORK="$ROOT/.build/release" -DIST="$ROOT/dist" -SIGNING_IDENTITY="${SIGNING_IDENTITY:-B99D353C88996866C49E4389B375645F76870A3F}" -TEAM_ID="${TEAM_ID:-39R6U3437D}" -NOTARY_PROFILE="${NOTARY_PROFILE:-orion-notary}" -mkdir -p "$ROOT/build-logs" "$DIST" -LOG="$ROOT/build-logs/release-$(date +%Y%m%d-%H%M%S).log" -exec > >(tee "$LOG") 2>&1 -command -v xcodebuild >/dev/null -command -v hdiutil >/dev/null -security find-identity -v -p codesigning | grep -q "$SIGNING_IDENTITY" || { echo 'Developer ID identity missing' >&2; exit 1; } -xcrun notarytool history --keychain-profile "$NOTARY_PROFILE" >/dev/null -rm -rf "$WORK" -mkdir -p "$WORK/export" "$WORK/dmg" -cat > "$WORK/ExportOptions.plist" < - - -methoddeveloper-id -signingStyleautomatic -teamID$TEAM_ID - -PLIST -xcodebuild -project "$PROJECT" -scheme "$APP_NAME" -configuration Release -destination 'generic/platform=macOS' -archivePath "$WORK/$APP_NAME.xcarchive" archive -xcodebuild -exportArchive -archivePath "$WORK/$APP_NAME.xcarchive" -exportPath "$WORK/export" -exportOptionsPlist "$WORK/ExportOptions.plist" -APP="$WORK/export/$APP_NAME.app" -[[ -d "$APP" ]] || { echo 'Exported app missing' >&2; exit 1; } -codesign --verify --deep --strict --verbose=2 "$APP" -ACTUAL_TEAM=$(codesign -dv --verbose=4 "$APP" 2>&1 | sed -n 's/^TeamIdentifier=//p') -[[ "$ACTUAL_TEAM" == "$TEAM_ID" ]] || { echo "Unexpected team: $ACTUAL_TEAM" >&2; exit 1; } -VERSION=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$APP/Contents/Info.plist") -[[ -n "$VERSION" ]] || { echo 'Missing marketing version' >&2; exit 1; } -DMG="$DIST/$APP_NAME-$VERSION.dmg" -ZIP="$WORK/$APP_NAME.zip" -ditto -c -k --keepParent "$APP" "$ZIP" -notarize() { - local file="$1" result status - result=$(xcrun notarytool submit "$file" --keychain-profile "$NOTARY_PROFILE" --wait --output-format json) - echo "$result" - status=$(printf '%s' "$result" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("status", ""))') - [[ "$status" == Accepted ]] || { echo "Notarization not accepted for $file: $status" >&2; exit 1; } -} -notarize "$ZIP" -xcrun stapler staple "$APP" -xcrun stapler validate "$APP" -spctl --assess --type execute --verbose=4 "$APP" -ditto "$APP" "$WORK/dmg/$APP_NAME.app" -ln -s /Applications "$WORK/dmg/Applications" -rm -f "$DMG" -hdiutil create -volname "$APP_NAME" -srcfolder "$WORK/dmg" -ov -format UDZO "$DMG" -codesign --force --timestamp --sign "$SIGNING_IDENTITY" "$DMG" -codesign --verify --verbose=2 "$DMG" -notarize "$DMG" -xcrun stapler staple "$DMG" -xcrun stapler validate "$DMG" -spctl --assess --type open --context context:primary-signature --verbose=4 "$DMG" -shasum -a 256 "$DMG" | tee "$DMG.sha256" -echo "Release complete: $DMG" -echo "Checksum: $DMG.sha256" -echo "Log: $LOG" diff --git a/scripts/release.sh.bak-20261023-080836 b/scripts/release.sh.bak-20261023-080836 deleted file mode 100755 index e9c9335..0000000 --- a/scripts/release.sh.bak-20261023-080836 +++ /dev/null @@ -1,168 +0,0 @@ -#!/bin/zsh -set -euo pipefail -ROOT="$(cd "$(dirname "$0")/.." && pwd)" -cd "$ROOT" -APP_NAME=OrionToolbar -PROJECT="$ROOT/OrionToolbar.xcodeproj" -DERIVED="$ROOT/.build" -WORK="$ROOT/.build/release" -DIST="$ROOT/dist" -SIGNING_IDENTITY="${SIGNING_IDENTITY:-B99D353C88996866C49E4389B375645F76870A3F}" -TEAM_ID="${TEAM_ID:-39R6U3437D}" -NOTARY_PROFILE="${NOTARY_PROFILE:-orion-notary}" -mkdir -p "$ROOT/build-logs" "$DIST" -LOG="$ROOT/build-logs/release-$(date +%Y%m%d-%H%M%S).log" -exec > >(tee "$LOG") 2>&1 -command -v xcodebuild >/dev/null -command -v hdiutil >/dev/null -security find-identity -v -p codesigning | grep -q "$SIGNING_IDENTITY" || { echo 'Developer ID identity missing' >&2; exit 1; } -xcrun notarytool history --keychain-profile "$NOTARY_PROFILE" >/dev/null -rm -rf "$WORK" -mkdir -p "$WORK/export" "$WORK/dmg" -cat > "$WORK/ExportOptions.plist" < - - -methoddeveloper-id -signingStyleautomatic -teamID$TEAM_ID - -PLIST -xcodebuild -project "$PROJECT" -scheme "$APP_NAME" -configuration Release -destination 'generic/platform=macOS' -archivePath "$WORK/$APP_NAME.xcarchive" archive -xcodebuild -exportArchive -archivePath "$WORK/$APP_NAME.xcarchive" -exportPath "$WORK/export" -exportOptionsPlist "$WORK/ExportOptions.plist" -APP="$WORK/export/$APP_NAME.app" -[[ -d "$APP" ]] || { echo 'Exported app missing' >&2; exit 1; } -codesign --verify --deep --strict --verbose=2 "$APP" -ACTUAL_TEAM=$(codesign -dv --verbose=4 "$APP" 2>&1 | sed -n 's/^TeamIdentifier=//p') -[[ "$ACTUAL_TEAM" == "$TEAM_ID" ]] || { echo "Unexpected team: $ACTUAL_TEAM" >&2; exit 1; } -VERSION=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$APP/Contents/Info.plist") -[[ -n "$VERSION" ]] || { echo 'Missing marketing version' >&2; exit 1; } -DMG="$DIST/$APP_NAME-$VERSION.dmg" -ZIP="$WORK/$APP_NAME.zip" -ditto -c -k --keepParent "$APP" "$ZIP" -notarize() { - local file="$1" result status - result=$(xcrun notarytool submit "$file" --keychain-profile "$NOTARY_PROFILE" --wait --output-format json) - echo "$result" - status=$(printf '%s' "$result" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("status", ""))') - [[ "$status" == Accepted ]] || { echo "Notarization not accepted for $file: $status" >&2; exit 1; } -} -notarize "$ZIP" -xcrun stapler staple "$APP" -xcrun stapler validate "$APP" -spctl --assess --type execute --verbose=4 "$APP" -ditto "$APP" "$WORK/dmg/$APP_NAME.app" -ln -s /Applications "$WORK/dmg/Applications" -rm -f "$DMG" -hdiutil create -volname "$APP_NAME" -srcfolder "$WORK/dmg" -ov -format UDZO "$DMG" - - -# ============================================================ -# ORION_CUSTOM_DMG_ICON -# Apply a custom Finder icon before signing/notarization. -# ============================================================ - -echo "=== APPLY CUSTOM DMG ICON ===" - -DMG_ICON_SOURCE="" - -# Prefer dedicated installer artwork. -for candidate in \ - "$ROOT_DIR/OrionToolbar/Assets.xcassets/InstallerIcon.imageset/icon.png" \ - "$ROOT_DIR/OrionToolbar/Assets.xcassets/AppIcon.appiconset/icon_512x512.png" \ - "$ROOT_DIR/OrionToolbar/Assets.xcassets/AppIcon.appiconset/icon_1024x1024.png" -do - if [[ -f "$candidate" ]]; then - DMG_ICON_SOURCE="$candidate" - break - fi -done - -# Fall back to the compiled application icon. -if [[ -z "$DMG_ICON_SOURCE" ]]; then - for candidate in \ - "$APP_PATH/Contents/Resources/AppIcon.icns" \ - "$BUILD_DIR/export/OrionToolbar.app/Contents/Resources/AppIcon.icns" - do - if [[ -f "$candidate" ]]; then - DMG_ICON_SOURCE="$candidate" - break - fi - done -fi - -if [[ -z "$DMG_ICON_SOURCE" ]]; then - echo "ERROR: No installer or application icon found." - exit 1 -fi - -echo "Icon source: $DMG_ICON_SOURCE" - -DMG_ICON_TEMP="$(mktemp -d)" -DMG_ICON_ICNS="$DMG_ICON_TEMP/OrionToolbar.icns" - -if [[ "$DMG_ICON_SOURCE" == *.icns ]]; then - cp "$DMG_ICON_SOURCE" "$DMG_ICON_ICNS" -else - ICONSET="$DMG_ICON_TEMP/OrionToolbar.iconset" - mkdir -p "$ICONSET" - - for size in 16 32 128 256 512; do - sips -s format png -z "$size" "$size" \ - "$DMG_ICON_SOURCE" \ - --out "$ICONSET/icon_${size}x${size}.png" >/dev/null - - double=$((size * 2)) - - sips -s format png -z "$double" "$double" \ - "$DMG_ICON_SOURCE" \ - --out "$ICONSET/icon_${size}x${size}@2x.png" >/dev/null - done - - iconutil -c icns "$ICONSET" -o "$DMG_ICON_ICNS" -fi - -DMG_ICON_RESOURCE="$DMG_ICON_TEMP/OrionToolbar.r" - -python3 - "$DMG_ICON_ICNS" "$DMG_ICON_RESOURCE" <<'ICONPY' -from pathlib import Path -import sys - -icon = Path(sys.argv[1]).read_bytes() - -if not icon.startswith(b"icns"): - raise SystemExit("ERROR: Invalid ICNS file.") - -hexdata = icon.hex().upper() - -with open(sys.argv[2], "w") as output: - output.write("data 'icns' (-16455) {\n") - - for index in range(0, len(hexdata), 64): - output.write( - ' $"' + hexdata[index:index + 64] + '"\n' - ) - - output.write("};\n") -ICONPY - -REZ="$(xcrun --find Rez)" -SETFILE="$(xcrun --find SetFile)" - -"$REZ" -append "$DMG_ICON_RESOURCE" -o "$DMG_PATH" -"$SETFILE" -a C "$DMG_PATH" - -rm -rf "$DMG_ICON_TEMP" - -echo "Custom DMG icon applied successfully." - -codesign --force --timestamp --sign "$SIGNING_IDENTITY" "$DMG" -codesign --verify --verbose=2 "$DMG" -notarize "$DMG" -xcrun stapler staple "$DMG" -xcrun stapler validate "$DMG" -spctl --assess --type open --context context:primary-signature --verbose=4 "$DMG" -shasum -a 256 "$DMG" | tee "$DMG.sha256" -echo "Release complete: $DMG" -echo "Checksum: $DMG.sha256" -echo "Log: $LOG" diff --git a/scripts/release.sh.bak-20261023-081607 b/scripts/release.sh.bak-20261023-081607 deleted file mode 100755 index b5dca31..0000000 --- a/scripts/release.sh.bak-20261023-081607 +++ /dev/null @@ -1,168 +0,0 @@ -#!/bin/zsh -set -euo pipefail -ROOT="$(cd "$(dirname "$0")/.." && pwd)" -cd "$ROOT" -APP_NAME=OrionToolbar -PROJECT="$ROOT/OrionToolbar.xcodeproj" -DERIVED="$ROOT/.build" -WORK="$ROOT/.build/release" -DIST="$ROOT/dist" -SIGNING_IDENTITY="${SIGNING_IDENTITY:-B99D353C88996866C49E4389B375645F76870A3F}" -TEAM_ID="${TEAM_ID:-39R6U3437D}" -NOTARY_PROFILE="${NOTARY_PROFILE:-orion-notary}" -mkdir -p "$ROOT/build-logs" "$DIST" -LOG="$ROOT/build-logs/release-$(date +%Y%m%d-%H%M%S).log" -exec > >(tee "$LOG") 2>&1 -command -v xcodebuild >/dev/null -command -v hdiutil >/dev/null -security find-identity -v -p codesigning | grep -q "$SIGNING_IDENTITY" || { echo 'Developer ID identity missing' >&2; exit 1; } -xcrun notarytool history --keychain-profile "$NOTARY_PROFILE" >/dev/null -rm -rf "$WORK" -mkdir -p "$WORK/export" "$WORK/dmg" -cat > "$WORK/ExportOptions.plist" < - - -methoddeveloper-id -signingStyleautomatic -teamID$TEAM_ID - -PLIST -xcodebuild -project "$PROJECT" -scheme "$APP_NAME" -configuration Release -destination 'generic/platform=macOS' -archivePath "$WORK/$APP_NAME.xcarchive" archive -xcodebuild -exportArchive -archivePath "$WORK/$APP_NAME.xcarchive" -exportPath "$WORK/export" -exportOptionsPlist "$WORK/ExportOptions.plist" -APP="$WORK/export/$APP_NAME.app" -[[ -d "$APP" ]] || { echo 'Exported app missing' >&2; exit 1; } -codesign --verify --deep --strict --verbose=2 "$APP" -ACTUAL_TEAM=$(codesign -dv --verbose=4 "$APP" 2>&1 | sed -n 's/^TeamIdentifier=//p') -[[ "$ACTUAL_TEAM" == "$TEAM_ID" ]] || { echo "Unexpected team: $ACTUAL_TEAM" >&2; exit 1; } -VERSION=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$APP/Contents/Info.plist") -[[ -n "$VERSION" ]] || { echo 'Missing marketing version' >&2; exit 1; } -DMG="$DIST/$APP_NAME-$VERSION.dmg" -ZIP="$WORK/$APP_NAME.zip" -ditto -c -k --keepParent "$APP" "$ZIP" -notarize() { - local file="$1" result status - result=$(xcrun notarytool submit "$file" --keychain-profile "$NOTARY_PROFILE" --wait --output-format json) - echo "$result" - notary_status=$(printf '%s' "$result" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("status", ""))') - [[ "$notary_status" == Accepted ]] || { echo "Notarization not accepted for $file: $notary_status" >&2; exit 1; } -} -notarize "$ZIP" -xcrun stapler staple "$APP" -xcrun stapler validate "$APP" -spctl --assess --type execute --verbose=4 "$APP" -ditto "$APP" "$WORK/dmg/$APP_NAME.app" -ln -s /Applications "$WORK/dmg/Applications" -rm -f "$DMG" -hdiutil create -volname "$APP_NAME" -srcfolder "$WORK/dmg" -ov -format UDZO "$DMG" - - -# ============================================================ -# ORION_CUSTOM_DMG_ICON -# Apply a custom Finder icon before signing/notarization. -# ============================================================ - -echo "=== APPLY CUSTOM DMG ICON ===" - -DMG_ICON_SOURCE="" - -# Prefer dedicated installer artwork. -for candidate in \ - "$ROOT_DIR/OrionToolbar/Assets.xcassets/InstallerIcon.imageset/icon.png" \ - "$ROOT_DIR/OrionToolbar/Assets.xcassets/AppIcon.appiconset/icon_512x512.png" \ - "$ROOT_DIR/OrionToolbar/Assets.xcassets/AppIcon.appiconset/icon_1024x1024.png" -do - if [[ -f "$candidate" ]]; then - DMG_ICON_SOURCE="$candidate" - break - fi -done - -# Fall back to the compiled application icon. -if [[ -z "$DMG_ICON_SOURCE" ]]; then - for candidate in \ - "$APP_PATH/Contents/Resources/AppIcon.icns" \ - "$BUILD_DIR/export/OrionToolbar.app/Contents/Resources/AppIcon.icns" - do - if [[ -f "$candidate" ]]; then - DMG_ICON_SOURCE="$candidate" - break - fi - done -fi - -if [[ -z "$DMG_ICON_SOURCE" ]]; then - echo "ERROR: No installer or application icon found." - exit 1 -fi - -echo "Icon source: $DMG_ICON_SOURCE" - -DMG_ICON_TEMP="$(mktemp -d)" -DMG_ICON_ICNS="$DMG_ICON_TEMP/OrionToolbar.icns" - -if [[ "$DMG_ICON_SOURCE" == *.icns ]]; then - cp "$DMG_ICON_SOURCE" "$DMG_ICON_ICNS" -else - ICONSET="$DMG_ICON_TEMP/OrionToolbar.iconset" - mkdir -p "$ICONSET" - - for size in 16 32 128 256 512; do - sips -s format png -z "$size" "$size" \ - "$DMG_ICON_SOURCE" \ - --out "$ICONSET/icon_${size}x${size}.png" >/dev/null - - double=$((size * 2)) - - sips -s format png -z "$double" "$double" \ - "$DMG_ICON_SOURCE" \ - --out "$ICONSET/icon_${size}x${size}@2x.png" >/dev/null - done - - iconutil -c icns "$ICONSET" -o "$DMG_ICON_ICNS" -fi - -DMG_ICON_RESOURCE="$DMG_ICON_TEMP/OrionToolbar.r" - -python3 - "$DMG_ICON_ICNS" "$DMG_ICON_RESOURCE" <<'ICONPY' -from pathlib import Path -import sys - -icon = Path(sys.argv[1]).read_bytes() - -if not icon.startswith(b"icns"): - raise SystemExit("ERROR: Invalid ICNS file.") - -hexdata = icon.hex().upper() - -with open(sys.argv[2], "w") as output: - output.write("data 'icns' (-16455) {\n") - - for index in range(0, len(hexdata), 64): - output.write( - ' $"' + hexdata[index:index + 64] + '"\n' - ) - - output.write("};\n") -ICONPY - -REZ="$(xcrun --find Rez)" -SETFILE="$(xcrun --find SetFile)" - -"$REZ" -append "$DMG_ICON_RESOURCE" -o "$DMG_PATH" -"$SETFILE" -a C "$DMG_PATH" - -rm -rf "$DMG_ICON_TEMP" - -echo "Custom DMG icon applied successfully." - -codesign --force --timestamp --sign "$SIGNING_IDENTITY" "$DMG" -codesign --verify --verbose=2 "$DMG" -notarize "$DMG" -xcrun stapler staple "$DMG" -xcrun stapler validate "$DMG" -spctl --assess --type open --context context:primary-signature --verbose=4 "$DMG" -shasum -a 256 "$DMG" | tee "$DMG.sha256" -echo "Release complete: $DMG" -echo "Checksum: $DMG.sha256" -echo "Log: $LOG" diff --git a/scripts/release.sh.bak-20261023-082114 b/scripts/release.sh.bak-20261023-082114 deleted file mode 100755 index 071e867..0000000 --- a/scripts/release.sh.bak-20261023-082114 +++ /dev/null @@ -1,170 +0,0 @@ -#!/bin/zsh -set -euo pipefail - -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")/.." && pwd)" -ROOT="$(cd "$(dirname "$0")/.." && pwd)" -cd "$ROOT" -APP_NAME=OrionToolbar -PROJECT="$ROOT/OrionToolbar.xcodeproj" -DERIVED="$ROOT/.build" -WORK="$ROOT/.build/release" -DIST="$ROOT/dist" -SIGNING_IDENTITY="${SIGNING_IDENTITY:-B99D353C88996866C49E4389B375645F76870A3F}" -TEAM_ID="${TEAM_ID:-39R6U3437D}" -NOTARY_PROFILE="${NOTARY_PROFILE:-orion-notary}" -mkdir -p "$ROOT/build-logs" "$DIST" -LOG="$ROOT/build-logs/release-$(date +%Y%m%d-%H%M%S).log" -exec > >(tee "$LOG") 2>&1 -command -v xcodebuild >/dev/null -command -v hdiutil >/dev/null -security find-identity -v -p codesigning | grep -q "$SIGNING_IDENTITY" || { echo 'Developer ID identity missing' >&2; exit 1; } -xcrun notarytool history --keychain-profile "$NOTARY_PROFILE" >/dev/null -rm -rf "$WORK" -mkdir -p "$WORK/export" "$WORK/dmg" -cat > "$WORK/ExportOptions.plist" < - - -methoddeveloper-id -signingStyleautomatic -teamID$TEAM_ID - -PLIST -xcodebuild -project "$PROJECT" -scheme "$APP_NAME" -configuration Release -destination 'generic/platform=macOS' -archivePath "$WORK/$APP_NAME.xcarchive" archive -xcodebuild -exportArchive -archivePath "$WORK/$APP_NAME.xcarchive" -exportPath "$WORK/export" -exportOptionsPlist "$WORK/ExportOptions.plist" -APP="$WORK/export/$APP_NAME.app" -[[ -d "$APP" ]] || { echo 'Exported app missing' >&2; exit 1; } -codesign --verify --deep --strict --verbose=2 "$APP" -ACTUAL_TEAM=$(codesign -dv --verbose=4 "$APP" 2>&1 | sed -n 's/^TeamIdentifier=//p') -[[ "$ACTUAL_TEAM" == "$TEAM_ID" ]] || { echo "Unexpected team: $ACTUAL_TEAM" >&2; exit 1; } -VERSION=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$APP/Contents/Info.plist") -[[ -n "$VERSION" ]] || { echo 'Missing marketing version' >&2; exit 1; } -DMG="$DIST/$APP_NAME-$VERSION.dmg" -ZIP="$WORK/$APP_NAME.zip" -ditto -c -k --keepParent "$APP" "$ZIP" -notarize() { - local file="$1" result status - result=$(xcrun notarytool submit "$file" --keychain-profile "$NOTARY_PROFILE" --wait --output-format json) - echo "$result" - notary_status=$(printf '%s' "$result" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("status", ""))') - [[ "$notary_status" == Accepted ]] || { echo "Notarization not accepted for $file: $notary_status" >&2; exit 1; } -} -notarize "$ZIP" -xcrun stapler staple "$APP" -xcrun stapler validate "$APP" -spctl --assess --type execute --verbose=4 "$APP" -ditto "$APP" "$WORK/dmg/$APP_NAME.app" -ln -s /Applications "$WORK/dmg/Applications" -rm -f "$DMG" -hdiutil create -volname "$APP_NAME" -srcfolder "$WORK/dmg" -ov -format UDZO "$DMG" - - -# ============================================================ -# ORION_CUSTOM_DMG_ICON -# Apply a custom Finder icon before signing/notarization. -# ============================================================ - -echo "=== APPLY CUSTOM DMG ICON ===" - -DMG_ICON_SOURCE="" - -# Prefer dedicated installer artwork. -for candidate in \ - "$ROOT_DIR/OrionToolbar/Assets.xcassets/InstallerIcon.imageset/icon.png" \ - "$ROOT_DIR/OrionToolbar/Assets.xcassets/AppIcon.appiconset/icon_512x512.png" \ - "$ROOT_DIR/OrionToolbar/Assets.xcassets/AppIcon.appiconset/icon_1024x1024.png" -do - if [[ -f "$candidate" ]]; then - DMG_ICON_SOURCE="$candidate" - break - fi -done - -# Fall back to the compiled application icon. -if [[ -z "$DMG_ICON_SOURCE" ]]; then - for candidate in \ - "$APP_PATH/Contents/Resources/AppIcon.icns" \ - "$BUILD_DIR/export/OrionToolbar.app/Contents/Resources/AppIcon.icns" - do - if [[ -f "$candidate" ]]; then - DMG_ICON_SOURCE="$candidate" - break - fi - done -fi - -if [[ -z "$DMG_ICON_SOURCE" ]]; then - echo "ERROR: No installer or application icon found." - exit 1 -fi - -echo "Icon source: $DMG_ICON_SOURCE" - -DMG_ICON_TEMP="$(mktemp -d)" -DMG_ICON_ICNS="$DMG_ICON_TEMP/OrionToolbar.icns" - -if [[ "$DMG_ICON_SOURCE" == *.icns ]]; then - cp "$DMG_ICON_SOURCE" "$DMG_ICON_ICNS" -else - ICONSET="$DMG_ICON_TEMP/OrionToolbar.iconset" - mkdir -p "$ICONSET" - - for size in 16 32 128 256 512; do - sips -s format png -z "$size" "$size" \ - "$DMG_ICON_SOURCE" \ - --out "$ICONSET/icon_${size}x${size}.png" >/dev/null - - double=$((size * 2)) - - sips -s format png -z "$double" "$double" \ - "$DMG_ICON_SOURCE" \ - --out "$ICONSET/icon_${size}x${size}@2x.png" >/dev/null - done - - iconutil -c icns "$ICONSET" -o "$DMG_ICON_ICNS" -fi - -DMG_ICON_RESOURCE="$DMG_ICON_TEMP/OrionToolbar.r" - -python3 - "$DMG_ICON_ICNS" "$DMG_ICON_RESOURCE" <<'ICONPY' -from pathlib import Path -import sys - -icon = Path(sys.argv[1]).read_bytes() - -if not icon.startswith(b"icns"): - raise SystemExit("ERROR: Invalid ICNS file.") - -hexdata = icon.hex().upper() - -with open(sys.argv[2], "w") as output: - output.write("data 'icns' (-16455) {\n") - - for index in range(0, len(hexdata), 64): - output.write( - ' $"' + hexdata[index:index + 64] + '"\n' - ) - - output.write("};\n") -ICONPY - -REZ="$(xcrun --find Rez)" -SETFILE="$(xcrun --find SetFile)" - -"$REZ" -append "$DMG_ICON_RESOURCE" -o "$DMG_PATH" -"$SETFILE" -a C "$DMG_PATH" - -rm -rf "$DMG_ICON_TEMP" - -echo "Custom DMG icon applied successfully." - -codesign --force --timestamp --sign "$SIGNING_IDENTITY" "$DMG" -codesign --verify --verbose=2 "$DMG" -notarize "$DMG" -xcrun stapler staple "$DMG" -xcrun stapler validate "$DMG" -spctl --assess --type open --context context:primary-signature --verbose=4 "$DMG" -shasum -a 256 "$DMG" | tee "$DMG.sha256" -echo "Release complete: $DMG" -echo "Checksum: $DMG.sha256" -echo "Log: $LOG"