#!/usr/bin/env bash
# Builds the native Physarum Ambiance Viewer macOS .app from the SwiftPM package.
#
# Output: apple/dist/Physarum Ambiance.app (+ optional .dmg with DMG=1)
# Requires: swift (CLT), sips, iconutil, hdiutil. No full Xcode needed.
#
# NOTE: this produces an UNSIGNED app. SwiftPM resource bundles are placed at the
# .app root (where Bundle.module's generated accessor looks). That runs locally but
# is NOT code-signing-safe — before a notarised DMG release, resource loading must
# move to Contents/Resources (see docs). Signing/notarisation is a release step.
set -euo pipefail
cd "$(dirname "$0")/.." # apple/
APP_NAME="Physarum Ambiance"
BUNDLE_ID="lab.physarum.viewer"
PKG="PhysarumEngine"
EXE="PhysarumViewer"
ICON_SVG="../assets/icon-macos.svg"
OUT="dist"
APP="$OUT/$APP_NAME.app"
for tool in swift sips iconutil; do
command -v "$tool" >/dev/null 2>&1 || { echo "error: missing tool: $tool" >&2; exit 1; }
done
echo "→ swift build -c release"
( cd "$PKG" && swift build -c release )
BINDIR="$(cd "$PKG" && swift build -c release --show-bin-path)"
echo "→ assembling $APP_NAME.app"
rm -rf "$OUT"
mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources"
cp "$BINDIR/$EXE" "$APP/Contents/MacOS/$EXE"
chmod +x "$APP/Contents/MacOS/$EXE"
# Resource bundles where Bundle.module's accessor looks (.app root).
for b in "$BINDIR"/*.bundle; do
[ -e "$b" ] && cp -R "$b" "$APP/$(basename "$b")"
done
cat > "$APP/Contents/Info.plist" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key><string>$APP_NAME</string>
<key>CFBundleDisplayName</key><string>$APP_NAME</string>
<key>CFBundleIdentifier</key><string>$BUNDLE_ID</string>
<key>CFBundleExecutable</key><string>$EXE</string>
<key>CFBundleIconFile</key><string>AppIcon</string>
<key>CFBundlePackageType</key><string>APPL</string>
<key>CFBundleShortVersionString</key><string>0.1.0</string>
<key>CFBundleVersion</key><string>1</string>
<key>LSMinimumSystemVersion</key><string>14.0</string>
<key>LSApplicationCategoryType</key><string>public.app-category.graphics-design</string>
<key>NSHighResolutionCapable</key><true/>
<key>NSPrincipalClass</key><string>NSApplication</string>
<key>NSHumanReadableCopyright</key><string>AGPL-3.0-or-later</string>
</dict>
</plist>
PLIST
if [ -f "$ICON_SVG" ]; then
echo "→ rendering icon"
ICONSET="$OUT/AppIcon.iconset"
mkdir -p "$ICONSET"
r() { sips -s format png "$ICON_SVG" --out "$ICONSET/$1" -Z "$2" >/dev/null; }
r icon_16x16.png 16; r icon_16x16@2x.png 32; r icon_32x32.png 32; r icon_32x32@2x.png 64
r icon_128x128.png 128; r icon_128x128@2x.png 256; r icon_256x256.png 256
r icon_256x256@2x.png 512; r icon_512x512.png 512; r icon_512x512@2x.png 1024
iconutil -c icns "$ICONSET" -o "$APP/Contents/Resources/AppIcon.icns"
rm -rf "$ICONSET"
fi
# Ad-hoc sign so it is self-consistent locally (not notarised).
codesign --force --deep --sign - "$APP" >/dev/null 2>&1 || echo " (codesign skipped)"
echo "✓ $APP"
if [ "${DMG:-0}" = 1 ]; then
echo "→ creating DMG"
STAGE="$OUT/.stage"; mkdir -p "$STAGE"
cp -R "$APP" "$STAGE/"; ln -s /Applications "$STAGE/Applications"
hdiutil create -volname "$APP_NAME" -srcfolder "$STAGE" -ov -format UDZO "$OUT/$APP_NAME.dmg" >/dev/null
rm -rf "$STAGE"
echo "✓ $OUT/$APP_NAME.dmg"
fi