#!/usr/bin/env bash # # Inject Sparkle framework into a macOS .app bundle for auto-updates # Usage: inject_sparkle.sh # # Environment variables (required): # SPARKLE_EDDSA_PUBLIC_KEY - EdDSA public key for verifying updates # # Optional environment variables: # SPARKLE_FEED_URL - Appcast URL (default: https://assets.eagle0.net/mac/appcast.xml) # SPARKLE_VERSION - Sparkle version to use (default: 2.9.3) set -euxo pipefail APP_PATH="$1" SPARKLE_VERSION="${SPARKLE_VERSION:-2.9.3}" SPARKLE_FEED_URL="${SPARKLE_FEED_URL:-https://assets.eagle0.net/mac/appcast.xml}" SPARKLE_CACHE_DIR="/tmp/sparkle-cache" if [ ! -d "$APP_PATH" ]; then echo "ERROR: App not found at $APP_PATH" exit 1 fi if [ -z "${SPARKLE_EDDSA_PUBLIC_KEY:-}" ]; then echo "ERROR: SPARKLE_EDDSA_PUBLIC_KEY environment variable not set" exit 1 fi # Always use a fresh Sparkle download to avoid cache corruption issues SPARKLE_DIR="$SPARKLE_CACHE_DIR/Sparkle-$SPARKLE_VERSION" echo "=== Clearing Sparkle cache and downloading fresh copy ===" rm -rf "$SPARKLE_DIR" mkdir -p "$SPARKLE_DIR" SPARKLE_URL="https://github.com/sparkle-project/Sparkle/releases/download/${SPARKLE_VERSION}/Sparkle-${SPARKLE_VERSION}.tar.xz" echo "Downloading from: $SPARKLE_URL" curl -L "$SPARKLE_URL" -o /tmp/sparkle.tar.xz tar -xJf /tmp/sparkle.tar.xz -C "$SPARKLE_DIR" rm /tmp/sparkle.tar.xz # Show what was extracted echo "=== Extracted contents ===" ls -la "$SPARKLE_DIR/" # The tarball extracts files directly, not into a subdirectory # Verify the framework has proper symlink structure echo "=== Verifying Sparkle.framework structure ===" ls -la "$SPARKLE_DIR/Sparkle.framework/" if [ ! -L "$SPARKLE_DIR/Sparkle.framework/Sparkle" ]; then echo "ERROR: Sparkle.framework/Sparkle is not a symlink" file "$SPARKLE_DIR/Sparkle.framework/Sparkle" exit 1 fi if [ ! -L "$SPARKLE_DIR/Sparkle.framework/Versions/Current" ]; then echo "ERROR: Sparkle.framework/Versions/Current is not a symlink" ls -la "$SPARKLE_DIR/Sparkle.framework/Versions/" exit 1 fi echo "Sparkle framework structure verified OK" echo "=== Injecting Sparkle framework ===" FRAMEWORKS_DIR="$APP_PATH/Contents/Frameworks" mkdir -p "$FRAMEWORKS_DIR" # Remove any existing Sparkle.framework in the app rm -rf "$FRAMEWORKS_DIR/Sparkle.framework" # Copy Sparkle framework (use ditto to preserve symlinks and bundle structure) ditto "$SPARKLE_DIR/Sparkle.framework" "$FRAMEWORKS_DIR/Sparkle.framework" # Verify the copied framework still has proper structure echo "=== Verifying copied Sparkle.framework structure ===" ls -la "$FRAMEWORKS_DIR/Sparkle.framework/" if [ ! -L "$FRAMEWORKS_DIR/Sparkle.framework/Sparkle" ]; then echo "ERROR: Copied framework lost symlink structure" exit 1 fi echo "Copied framework structure OK" echo "=== Updating Info.plist ===" PLIST_PATH="$APP_PATH/Contents/Info.plist" # Add Sparkle configuration to Info.plist /usr/libexec/PlistBuddy -c "Delete :SUFeedURL" "$PLIST_PATH" 2>/dev/null || true /usr/libexec/PlistBuddy -c "Add :SUFeedURL string '$SPARKLE_FEED_URL'" "$PLIST_PATH" /usr/libexec/PlistBuddy -c "Delete :SUPublicEDKey" "$PLIST_PATH" 2>/dev/null || true /usr/libexec/PlistBuddy -c "Add :SUPublicEDKey string '$SPARKLE_EDDSA_PUBLIC_KEY'" "$PLIST_PATH" /usr/libexec/PlistBuddy -c "Delete :SUEnableAutomaticChecks" "$PLIST_PATH" 2>/dev/null || true /usr/libexec/PlistBuddy -c "Add :SUEnableAutomaticChecks bool true" "$PLIST_PATH" # Set bundle version from git for Sparkle version comparison # Use commit count for automatic incrementing versions (e.g., 1.0.9548) BUILD_NUMBER=$(git rev-list --count HEAD 2>/dev/null || echo "1") VERSION="1.0.${BUILD_NUMBER}" echo "Setting version: $VERSION (build $BUILD_NUMBER)" /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION" "$PLIST_PATH" 2>/dev/null || \ /usr/libexec/PlistBuddy -c "Add :CFBundleShortVersionString string '$VERSION'" "$PLIST_PATH" /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_NUMBER" "$PLIST_PATH" 2>/dev/null || \ /usr/libexec/PlistBuddy -c "Add :CFBundleVersion string '$BUILD_NUMBER'" "$PLIST_PATH" # Add URL scheme for invitation codes (eagle0://invite?code=XXXX) echo "=== Adding URL scheme for invitation codes ===" /usr/libexec/PlistBuddy -c "Delete :CFBundleURLTypes" "$PLIST_PATH" 2>/dev/null || true /usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes array" "$PLIST_PATH" /usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:0 dict" "$PLIST_PATH" /usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:0:CFBundleURLName string 'net.eagle0.eagle0'" "$PLIST_PATH" /usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:0:CFBundleURLSchemes array" "$PLIST_PATH" /usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:0:CFBundleURLSchemes:0 string 'eagle0'" "$PLIST_PATH" echo "=== Sparkle injection complete ===" echo "App: $APP_PATH" echo "Feed URL: $SPARKLE_FEED_URL" echo "Version: $VERSION (build $BUILD_NUMBER)"