diff --git a/scripts/create-dmg.sh b/scripts/create-dmg.sh new file mode 100755 index 000000000..258cc7ee6 --- /dev/null +++ b/scripts/create-dmg.sh @@ -0,0 +1,161 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Create a styled DMG containing the app bundle + /Applications symlink. +# +# Usage: +# scripts/create-dmg.sh [output_dmg] +# +# Env: +# DMG_VOLUME_NAME default: CFBundleName (or "Clawdis") +# DMG_BACKGROUND_PATH default: assets/dmg-background.png +# DMG_WINDOW_BOUNDS default: "400 100 980 470" +# DMG_ICON_SIZE default: 128 +# DMG_APP_POS default: "170 190" +# DMG_APPS_POS default: "470 190" +# SKIP_DMG_STYLE=1 skip Finder styling + +APP_PATH="${1:-}" +OUT_PATH="${2:-}" + +if [[ -z "$APP_PATH" ]]; then + echo "Usage: $0 [output_dmg]" >&2 + exit 1 +fi +if [[ ! -d "$APP_PATH" ]]; then + echo "Error: App not found: $APP_PATH" >&2 + exit 1 +fi + +ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" +BUILD_DIR="$ROOT_DIR/dist" +mkdir -p "$BUILD_DIR" + +APP_NAME=$(/usr/libexec/PlistBuddy -c "Print CFBundleName" "$APP_PATH/Contents/Info.plist" 2>/dev/null || echo "Clawdis") +VERSION=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$APP_PATH/Contents/Info.plist" 2>/dev/null || echo "0.0.0") + +DMG_NAME="${APP_NAME}-${VERSION}.dmg" +DMG_VOLUME_NAME="${DMG_VOLUME_NAME:-$APP_NAME}" +DMG_BACKGROUND_PATH="${DMG_BACKGROUND_PATH:-$ROOT_DIR/assets/dmg-background.png}" + +DMG_WINDOW_BOUNDS="${DMG_WINDOW_BOUNDS:-400 100 980 470}" +DMG_ICON_SIZE="${DMG_ICON_SIZE:-128}" +DMG_APP_POS="${DMG_APP_POS:-170 190}" +DMG_APPS_POS="${DMG_APPS_POS:-470 190}" + +to_applescript_list4() { + local raw="$1" + echo "$raw" | awk '{ printf "%s, %s, %s, %s", $1, $2, $3, $4 }' +} + +to_applescript_pair() { + local raw="$1" + echo "$raw" | awk '{ printf "%s, %s", $1, $2 }' +} + +if [[ -z "$OUT_PATH" ]]; then + OUT_PATH="$BUILD_DIR/$DMG_NAME" +fi + +echo "Creating DMG: $OUT_PATH" + +# Cleanup stuck volumes. +for vol in "/Volumes/$DMG_VOLUME_NAME"* "/Volumes/$APP_NAME"*; do + if [[ -d "$vol" ]]; then + hdiutil detach "$vol" -force 2>/dev/null || true + sleep 1 + fi +done + +DMG_TEMP="$(mktemp -d /tmp/clawdis-dmg.XXXXXX)" +trap 'hdiutil detach "/Volumes/'"$DMG_VOLUME_NAME"'" -force 2>/dev/null || true; rm -rf "$DMG_TEMP" 2>/dev/null || true' EXIT + +cp -R "$APP_PATH" "$DMG_TEMP/" +ln -s /Applications "$DMG_TEMP/Applications" + +APP_SIZE_MB=$(du -sm "$APP_PATH" | awk '{print $1}') +DMG_SIZE_MB=$((APP_SIZE_MB + 80)) + +DMG_RW_PATH="${OUT_PATH%.dmg}-rw.dmg" +rm -f "$DMG_RW_PATH" "$OUT_PATH" + +hdiutil create \ + -volname "$DMG_VOLUME_NAME" \ + -srcfolder "$DMG_TEMP" \ + -ov \ + -format UDRW \ + -size "${DMG_SIZE_MB}m" \ + "$DMG_RW_PATH" + +MOUNT_POINT="/Volumes/$DMG_VOLUME_NAME" +if [[ -d "$MOUNT_POINT" ]]; then + hdiutil detach "$MOUNT_POINT" -force 2>/dev/null || true + sleep 2 +fi +hdiutil attach "$DMG_RW_PATH" -mountpoint "$MOUNT_POINT" -nobrowse + +if [[ "${SKIP_DMG_STYLE:-0}" != "1" ]]; then + mkdir -p "$MOUNT_POINT/.background" + if [[ -f "$DMG_BACKGROUND_PATH" ]]; then + cp "$DMG_BACKGROUND_PATH" "$MOUNT_POINT/.background/background.png" + else + echo "WARN: DMG background missing: $DMG_BACKGROUND_PATH" >&2 + fi + + # Volume icon: reuse the app icon if available. + ICON_SRC="$ROOT_DIR/apps/macos/Sources/Clawdis/Resources/Clawdis.icns" + if [[ -f "$ICON_SRC" ]]; then + cp "$ICON_SRC" "$MOUNT_POINT/.VolumeIcon.icns" + if command -v SetFile >/dev/null 2>&1; then + SetFile -a C "$MOUNT_POINT" 2>/dev/null || true + fi + fi + + osascript </dev/null; then + break + fi + if [[ "$i" == "3" ]]; then + hdiutil detach "$MOUNT_POINT" -force 2>/dev/null || true + fi + sleep 2 +done + +hdiutil convert "$DMG_RW_PATH" -format ULMO -o "$OUT_PATH" -ov +rm -f "$DMG_RW_PATH" + +hdiutil verify "$OUT_PATH" >/dev/null +echo "✅ DMG ready: $OUT_PATH" diff --git a/scripts/package-mac-dist.sh b/scripts/package-mac-dist.sh new file mode 100755 index 000000000..6339a389f --- /dev/null +++ b/scripts/package-mac-dist.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Build the mac app bundle, then create a zip (Sparkle) + styled DMG (humans). +# +# Output: +# - dist/Clawdis.app +# - dist/Clawdis-.zip +# - dist/Clawdis-.dmg + +ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" + +"$ROOT_DIR/scripts/package-mac-app.sh" + +APP="$ROOT_DIR/dist/Clawdis.app" +if [[ ! -d "$APP" ]]; then + echo "Error: missing app bundle at $APP" >&2 + exit 1 +fi + +VERSION=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$APP/Contents/Info.plist" 2>/dev/null || echo "0.0.0") +ZIP="$ROOT_DIR/dist/Clawdis-$VERSION.zip" +DMG="$ROOT_DIR/dist/Clawdis-$VERSION.dmg" + +echo "📦 Zip: $ZIP" +rm -f "$ZIP" +ditto -c -k --sequesterRsrc --keepParent "$APP" "$ZIP" + +echo "💿 DMG: $DMG" +"$ROOT_DIR/scripts/create-dmg.sh" "$APP" "$DMG" +