From 5d5139861642f4cadac8f16d90909300414819b1 Mon Sep 17 00:00:00 2001 From: Lee Rosen <96027741+tsconfigdotjson@users.noreply.github.com> Date: Thu, 9 Apr 2026 19:47:49 -0400 Subject: [PATCH] Create package-dmg.sh --- scripts/package-dmg.sh | 106 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100755 scripts/package-dmg.sh diff --git a/scripts/package-dmg.sh b/scripts/package-dmg.sh new file mode 100755 index 0000000..c2e72a8 --- /dev/null +++ b/scripts/package-dmg.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ── Configuration ──────────────────────────────────────────────────── +APP_NAME="Devtail" +BUNDLE_ID="com.leerosen.devtail" +EXECUTABLE="devtail" +VERSION="${VERSION:-1.0.0}" +SIGNING_IDENTITY="${SIGNING_IDENTITY:-Developer ID Application: Lee Rosen (RQ4599WP39)}" + +# ── Paths ──────────────────────────────────────────────────────────── +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" +BUILD_DIR="$PROJECT_DIR/.build/release" +STAGING_DIR="$PROJECT_DIR/.build/package" +APP_BUNDLE="$STAGING_DIR/$APP_NAME.app" +DMG_DIR="$STAGING_DIR/dmg" +DMG_OUTPUT="$STAGING_DIR/$APP_NAME-$VERSION.dmg" + +# ── Clean previous packaging artifacts ─────────────────────────────── +rm -rf "$STAGING_DIR" +mkdir -p "$STAGING_DIR" + +# ── Step 1: Build release binary ───────────────────────────────────── +echo "▸ Building release binary…" +swift build -c release --package-path "$PROJECT_DIR" + +if [ ! -f "$BUILD_DIR/$EXECUTABLE" ]; then + echo "✗ Build failed — binary not found at $BUILD_DIR/$EXECUTABLE" >&2 + exit 1 +fi + +# ── Step 2: Assemble .app bundle ───────────────────────────────────── +echo "▸ Assembling $APP_NAME.app bundle…" +mkdir -p "$APP_BUNDLE/Contents/MacOS" +mkdir -p "$APP_BUNDLE/Contents/Resources" + +cp "$BUILD_DIR/$EXECUTABLE" "$APP_BUNDLE/Contents/MacOS/$EXECUTABLE" + +cat > "$APP_BUNDLE/Contents/Info.plist" << PLIST + + + + + CFBundleName + $APP_NAME + CFBundleDisplayName + $APP_NAME + CFBundleIdentifier + $BUNDLE_ID + CFBundleVersion + $VERSION + CFBundleShortVersionString + $VERSION + CFBundleExecutable + $EXECUTABLE + CFBundlePackageType + APPL + LSMinimumSystemVersion + 14.0 + LSUIElement + + NSHighResolutionCapable + + + +PLIST + +# ── Step 3: Code sign ─────────────────────────────────────────────── +echo "▸ Signing with \"$SIGNING_IDENTITY\"…" +codesign --force --options runtime --timestamp \ + --sign "$SIGNING_IDENTITY" \ + "$APP_BUNDLE" + +echo "▸ Verifying signature…" +codesign --verify --verbose=2 "$APP_BUNDLE" + +# ── Step 4: Create DMG ────────────────────────────────────────────── +echo "▸ Creating DMG…" +mkdir -p "$DMG_DIR" +cp -R "$APP_BUNDLE" "$DMG_DIR/" +ln -s /Applications "$DMG_DIR/Applications" + +hdiutil create \ + -volname "$APP_NAME" \ + -srcfolder "$DMG_DIR" \ + -ov -format UDZO \ + "$DMG_OUTPUT" + +# Sign the DMG itself +codesign --force --timestamp \ + --sign "$SIGNING_IDENTITY" \ + "$DMG_OUTPUT" + +# ── Done ───────────────────────────────────────────────────────────── +echo "" +echo "✔ $DMG_OUTPUT" +echo "" +echo "To notarize (required for Gatekeeper on other machines):" +echo " xcrun notarytool submit \"$DMG_OUTPUT\" \\" +echo " --apple-id YOUR_APPLE_ID \\" +echo " --team-id RQ4599WP39 \\" +echo " --password YOUR_APP_SPECIFIC_PASSWORD \\" +echo " --wait" +echo " xcrun stapler staple \"$DMG_OUTPUT\""