|
| 1 | +#!/usr/bin/env bash |
| 2 | +# bundles a freshly built macOS binary into a proper TLEscope.app |
| 3 | +# |
| 4 | +# does everything natively on the build machine: |
| 5 | +# - compiles AppIcon.icns from logo.png (sips + iconutil, no precompiled icon) |
| 6 | +# - generates Info.plist with the real git version baked in |
| 7 | +# - ad-hoc codesigns by default (arm64 binaries refuse to run unsigned) |
| 8 | +# |
| 9 | +# usage: scripts/macos-bundle.sh [binary] default binary: bin/TLEscope-macos |
| 10 | +# |
| 11 | +# env vars: |
| 12 | +# CODE_SIGN_IDENTITY set to e.g. "Developer ID Application: Your Name (TEAMID)" |
| 13 | +# for real signing. default is "-" (ad-hoc). |
| 14 | +set -euo pipefail |
| 15 | + |
| 16 | +APP_NAME="TLEscope" |
| 17 | +BUNDLE_ID="com.aweeri.tlescope" |
| 18 | +BIN="${1:-bin/${APP_NAME}-macos}" |
| 19 | +APP="dist/${APP_NAME}.app" |
| 20 | + |
| 21 | +GIT_VERSION=$(git describe --tags --always --dirty 2>/dev/null || echo "vUnknown") |
| 22 | + |
| 23 | +for tool in sips iconutil codesign; do |
| 24 | + command -v "$tool" >/dev/null || { echo "error: '$tool' not found - this script must run on macOS"; exit 1; } |
| 25 | +done |
| 26 | +[ -x "$BIN" ] || { echo "error: $BIN not found - run 'make macos' first"; exit 1; } |
| 27 | + |
| 28 | +rm -rf "$APP" |
| 29 | +mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources" |
| 30 | + |
| 31 | +# portable resource layout lives inside Resources (the binary chdirs there) |
| 32 | +cp -r themes "$APP/Contents/Resources/themes" |
| 33 | +cp logo.png logo_l.png "$APP/Contents/Resources/" |
| 34 | +cp settings.json "$APP/Contents/Resources/" 2>/dev/null || true |
| 35 | +cp data.tle "$APP/Contents/Resources/" 2>/dev/null || true |
| 36 | +cp "$BIN" "$APP/Contents/MacOS/$APP_NAME" |
| 37 | + |
| 38 | +# compile a multi-resolution .icns from logo.png |
| 39 | +ICONSET_DIR="$(mktemp -d)" |
| 40 | +ICONSET="$ICONSET_DIR/${APP_NAME}.iconset" |
| 41 | +mkdir -p "$ICONSET" |
| 42 | +for size in 16 32 128 256 512; do |
| 43 | + double=$((size * 2)) |
| 44 | + sips -z "$size" "$size" logo.png --out "$ICONSET/icon_${size}x${size}.png" >/dev/null |
| 45 | + sips -z "$double" "$double" logo.png --out "$ICONSET/icon_${size}x${size}@2x.png" >/dev/null |
| 46 | +done |
| 47 | +iconutil -c icns "$ICONSET" -o "$APP/Contents/Resources/AppIcon.icns" |
| 48 | +rm -rf "$ICONSET_DIR" |
| 49 | + |
| 50 | +cat > "$APP/Contents/Info.plist" <<EOF |
| 51 | +<?xml version="1.0" encoding="UTF-8"?> |
| 52 | +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| 53 | +<plist version="1.0"> |
| 54 | +<dict> |
| 55 | + <key>CFBundleExecutable</key> |
| 56 | + <string>${APP_NAME}</string> |
| 57 | + <key>CFBundleIconFile</key> |
| 58 | + <string>AppIcon</string> |
| 59 | + <key>CFBundleIdentifier</key> |
| 60 | + <string>${BUNDLE_ID}</string> |
| 61 | + <key>CFBundleName</key> |
| 62 | + <string>${APP_NAME}</string> |
| 63 | + <key>CFBundleDisplayName</key> |
| 64 | + <string>${APP_NAME}</string> |
| 65 | + <key>CFBundlePackageType</key> |
| 66 | + <string>APPL</string> |
| 67 | + <key>CFBundleShortVersionString</key> |
| 68 | + <string>${GIT_VERSION}</string> |
| 69 | + <key>CFBundleVersion</key> |
| 70 | + <string>${GIT_VERSION}</string> |
| 71 | + <key>NSHighResolutionCapable</key> |
| 72 | + <true/> |
| 73 | + <key>LSMinimumSystemVersion</key> |
| 74 | + <string>11.0</string> |
| 75 | + <key>NSHumanReadableCopyright</key> |
| 76 | + <string>See LICENSE</string> |
| 77 | +</dict> |
| 78 | +</plist> |
| 79 | +EOF |
| 80 | + |
| 81 | +# signing: ad-hoc by default so the app actually launches on Apple Silicon. |
| 82 | +# with CODE_SIGN_IDENTITY set we also opt into hardened runtime (needed for notarization). |
| 83 | +# note: settings.json lives inside Resources, so editing it in-place after |
| 84 | +# signing invalidates the signature - Gatekeeper only cares on first launch tho |
| 85 | +if [ "${CODE_SIGN_IDENTITY:--}" = "-" ]; then |
| 86 | + echo "ad-hoc signing $APP (set CODE_SIGN_IDENTITY for real signing)" |
| 87 | + codesign --force --deep --sign - "$APP" |
| 88 | +else |
| 89 | + codesign --force --deep --sign "$CODE_SIGN_IDENTITY" --options runtime "$APP" |
| 90 | +fi |
| 91 | +codesign --verify --strict "$APP" |
| 92 | + |
| 93 | +echo "built $APP (${GIT_VERSION})" |
0 commit comments