Files
Gaze/build_dmg
2026-01-11 18:08:15 -05:00

176 lines
6.5 KiB
Bash
Executable File

#!/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.1.1"
fi
if [ -z "$BUILD_NUMBER" ]; then
echo "⚠️ Could not extract CURRENT_PROJECT_VERSION from project, using fallback"
BUILD_NUMBER="1"
fi
echo "📦 Building Gaze 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 "Copying DMG to releases directory..."
cp "$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|<enclosure url=\"https://freno.me/downloads/$DMG_NAME\" length=\"[0-9]*\"|<enclosure url=\"https://freno.me/downloads/$DMG_NAME\" sparkle:edSignature=\"$ED_SIGNATURE\" length=\"$FILE_LENGTH\"|g" "$APPCAST_OUTPUT"
# Verify signature was added
if grep -q "edSignature" "$APPCAST_OUTPUT"; then
echo "✅ EdDSA signature added to appcast"
else
echo "❌ ERROR: Failed to add signature to appcast!"
exit 1
fi
else
echo "❌ ERROR: Failed to generate signature with sign_update"
echo "Output: $SIGNATURE_OUTPUT"
exit 1
fi
fi
else
echo "❌ Failed to generate appcast"
exit 1
fi
else
echo ""
echo "⚠️ Skipping appcast generation (Sparkle tools not found)"
echo "To generate appcast manually, run:"
echo " ./generate_appcast --ed-key-file ~/sparkle_private_key_backup.pem --download-url-prefix 'https://freno.me/downloads/' '$RELEASES_DIR'"
fi
# Upload to AWS S3 if environment variables are set
if [ -n "$AWS_ACCESS_KEY_ID" ] && [ -n "$AWS_SECRET_ACCESS_KEY" ] && [ -n "$AWS_BUCKET_NAME" ] && [ -n "$AWS_REGION" ]; then
echo ""
echo "Uploading to S3 bucket: $AWS_BUCKET_NAME..."
# Export AWS credentials for aws-cli
export AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID"
export AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY"
export AWS_DEFAULT_REGION="$AWS_REGION"
# Upload DMG to S3
aws s3 cp "$RELEASES_DIR/$DMG_NAME" "s3://$AWS_BUCKET_NAME/downloads/$DMG_NAME" --region "$AWS_REGION"
# Upload appcast if it exists
if [ -f "$APPCAST_OUTPUT" ]; then
aws s3 cp "$APPCAST_OUTPUT" "s3://$AWS_BUCKET_NAME/api/Gaze/appcast.xml" --region "$AWS_REGION"
echo "✅ Appcast uploaded to S3"
fi
echo "✅ Upload complete!"
echo " DMG: s3://$AWS_BUCKET_NAME/downloads/$DMG_NAME"
echo " Appcast: s3://$AWS_BUCKET_NAME/api/Gaze/appcast.xml"
else
echo ""
echo "⚠️ Skipping S3 upload - AWS credentials not found in .env"
fi
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Release artifacts created:"
echo " 📦 DMG: $RELEASES_DIR/$DMG_NAME"
if [ -f "$APPCAST_OUTPUT" ]; then
echo " 📋 Appcast: $APPCAST_OUTPUT"
fi
echo ""
echo "Next steps:"
echo " 1. Upload DMG to: https://freno.me/downloads/$DMG_NAME"
echo " 2. Upload appcast to: $FEED_URL"
echo " 3. Verify appcast is accessible and valid"
echo " 4. Test update from previous version"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"