#!/bin/bash set -e # Load environment variables from .env file if [ -f .env ]; then export $(grep -v '^#' .env | xargs) fi # Extract version from Xcode project (Release configuration) PROJECT_FILE="Gaze.xcodeproj/project.pbxproj" VERSION=$(grep -A 1 "MARKETING_VERSION" "$PROJECT_FILE" | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1) BUILD_NUMBER=$(grep -A 1 "CURRENT_PROJECT_VERSION" "$PROJECT_FILE" | grep -o '[0-9]\+' | head -1) # Fallback to manual values if extraction fails if [ -z "$VERSION" ]; then echo "⚠️ Could not extract MARKETING_VERSION from project, using fallback" VERSION="0.2.0" fi if [ -z "$BUILD_NUMBER" ]; then echo "⚠️ Could not extract CURRENT_PROJECT_VERSION from project, using fallback" BUILD_NUMBER="1" fi echo "📦 Building Gaze DMG for v${VERSION} (build ${BUILD_NUMBER})" RELEASES_DIR="./releases" APPCAST_OUTPUT="${RELEASES_DIR}/appcast.xml" FEED_URL="https://freno.me/api/Gaze/appcast.xml" DMG_NAME="Gaze-${VERSION}.dmg" # Find Sparkle generate_appcast tool SPARKLE_BIN=$(find ~/Library/Developer/Xcode/DerivedData/Gaze-* -path "*/artifacts/sparkle/Sparkle/bin" -type d 2>/dev/null | head -1) if [ -z "$SPARKLE_BIN" ]; then echo "⚠️ Warning: Sparkle bin directory not found" echo "Appcast generation will be skipped" SPARKLE_BIN="" fi # Create releases directory mkdir -p "$RELEASES_DIR" # Remove old DMG if exists rm -f "$DMG_NAME" echo "Creating DMG..." create-dmg \ --volname "Gaze Installer" \ --eula "./LICENSE" \ --window-pos 200 120 \ --window-size 600 400 \ --icon-size 100 \ --background "./dmg_background.png" \ --icon "Gaze.app" 160 200 \ --app-drop-link 440 200 \ "$DMG_NAME" \ "./Gaze.app" # Copy DMG to releases directory echo "Moving DMG to releases directory..." mv "$DMG_NAME" "$RELEASES_DIR/" # Generate appcast if Sparkle tools are available if [ -n "$SPARKLE_BIN" ] && [ -d "$SPARKLE_BIN" ]; then echo "" echo "Generating appcast..." # Check for private key (Keychain or file) PRIVATE_KEY_FILE="$HOME/sparkle_private_key_backup.pem" KEY_OPTION="" if [ -f "$PRIVATE_KEY_FILE" ]; then echo "Using private key from: $PRIVATE_KEY_FILE" KEY_OPTION="--ed-key-file $PRIVATE_KEY_FILE" else echo "Using private key from Keychain (account: ed25519)" KEY_OPTION="--account ed25519" fi # Generate appcast with download URL prefix and key "$SPARKLE_BIN/generate_appcast" \ --download-url-prefix "https://freno.me/downloads/" \ $KEY_OPTION \ "$RELEASES_DIR" # Verify appcast was generated if [ -f "$APPCAST_OUTPUT" ]; then echo "✅ Appcast generated successfully" echo "📋 Appcast location: $APPCAST_OUTPUT" # Check for signature - if missing, add it manually if grep -q "edSignature" "$APPCAST_OUTPUT"; then echo "✅ EdDSA signature verified in appcast" else echo "⚠️ No signature found, generating manually with sign_update..." # Get signature for the DMG SIGNATURE_OUTPUT=$("$SPARKLE_BIN/sign_update" "$RELEASES_DIR/$DMG_NAME" 2>&1) if echo "$SIGNATURE_OUTPUT" | grep -q "edSignature"; then # Extract the signature ED_SIGNATURE=$(echo "$SIGNATURE_OUTPUT" | grep -o 'sparkle:edSignature="[^"]*"' | sed 's/sparkle:edSignature="\([^"]*\)"/\1/') FILE_LENGTH=$(echo "$SIGNATURE_OUTPUT" | grep -o 'length="[^"]*"' | sed 's/length="\([^"]*\)"/\1/') echo "✅ Generated signature: ${ED_SIGNATURE:0:20}..." # Add signature to appcast XML # Find the enclosure line and add sparkle:edSignature attribute sed -i '' "s|