#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" BUILD_DIR="${1:-$ROOT_DIR/build}" DIST_DIR="${2:-$ROOT_DIR/dist/macos}" STAGE_DIR="$DIST_DIR/dmg-staging" INSTALL_PREFIX="$DIST_DIR/install" APP_BUNDLE="OrbitHub.app" if [[ ! -f "$BUILD_DIR/CMakeCache.txt" ]]; then echo "Build directory not configured: $BUILD_DIR" >&2 echo "Run: cmake -S \"$ROOT_DIR\" -B \"$BUILD_DIR\" -G Ninja" >&2 exit 1 fi MACDEPLOYQT="$(brew --prefix qt@6)/bin/macdeployqt" if [[ ! -x "$MACDEPLOYQT" ]]; then echo "macdeployqt not found at $MACDEPLOYQT" >&2 echo "Install it: brew install qt@6" >&2 exit 1 fi mkdir -p "$DIST_DIR" rm -rf "$STAGE_DIR" "$INSTALL_PREFIX" mkdir -p "$STAGE_DIR" # Read VERSION only after the build (which reconfigures CMakeCache.txt if # CMakeLists.txt changed since the build dir was last configured) -- # reading it beforehand risks packaging a stale version string. cmake --build "$BUILD_DIR" -j VERSION="$(sed -n 's/^CMAKE_PROJECT_VERSION:STATIC=//p' "$BUILD_DIR/CMakeCache.txt" | head -n1)" if [[ -z "$VERSION" ]]; then echo "Unable to determine project version from $BUILD_DIR/CMakeCache.txt" >&2 exit 1 fi cmake --install "$BUILD_DIR" --prefix "$INSTALL_PREFIX" if [[ ! -d "$INSTALL_PREFIX/$APP_BUNDLE" ]]; then echo "Expected app bundle not found: $INSTALL_PREFIX/$APP_BUNDLE" >&2 exit 1 fi "$MACDEPLOYQT" "$INSTALL_PREFIX/$APP_BUNDLE" # macdeployqt rewrites library load paths after bundling Qt, which # invalidates any prior signature. Re-sign (ad hoc, since we have no # Developer ID certificate) so the app passes macOS's code-integrity # check at launch. Without this, launching fails with a generic # "cannot be opened because of a problem" crash-reporter dialog rather # than the milder unidentified-developer Gatekeeper prompt. codesign --force --deep --sign - "$INSTALL_PREFIX/$APP_BUNDLE" cp -R "$INSTALL_PREFIX/$APP_BUNDLE" "$STAGE_DIR/$APP_BUNDLE" ln -s /Applications "$STAGE_DIR/Applications" cp "$ROOT_DIR/packaging/macos/orbithub.icns" "$STAGE_DIR/.VolumeIcon.icns" OUTPUT_DMG="$DIST_DIR/OrbitHub-${VERSION}.dmg" RW_DMG="$DIST_DIR/OrbitHub-rw.dmg" rm -f "$OUTPUT_DMG" "$RW_DMG" hdiutil create -volname "OrbitHub" -srcfolder "$STAGE_DIR" -ov -format UDRW "$RW_DMG" # Setting the volume's icon requires flipping a Finder attribute bit, # which needs SetFile (from Xcode's "Additional Tools", not the base # Command Line Tools) or the fileicon brew formula. Neither is # guaranteed to be installed, so this step degrades gracefully: the # dmg is still produced either way, just without a custom icon if no # tool is available. ICON_TOOL="" if command -v SetFile >/dev/null 2>&1; then ICON_TOOL="SetFile" elif [[ -x /Library/Developer/CommandLineTools/usr/bin/SetFile ]]; then ICON_TOOL="/Library/Developer/CommandLineTools/usr/bin/SetFile" elif command -v fileicon >/dev/null 2>&1; then ICON_TOOL="fileicon" fi if [[ -n "$ICON_TOOL" ]]; then MOUNT_DIR="$(mktemp -d)" hdiutil attach "$RW_DMG" -mountpoint "$MOUNT_DIR" -nobrowse -quiet if [[ "$ICON_TOOL" == "fileicon" ]]; then fileicon set "$MOUNT_DIR" "$ROOT_DIR/packaging/macos/orbithub.icns" >/dev/null else "$ICON_TOOL" -a V "$MOUNT_DIR/.VolumeIcon.icns" "$ICON_TOOL" -a C "$MOUNT_DIR" fi hdiutil detach "$MOUNT_DIR" -quiet rmdir "$MOUNT_DIR" 2>/dev/null || true else echo "Note: SetFile/fileicon not found, dmg will use the generic disk icon." >&2 echo " Install one to get a custom volume icon:" >&2 echo " brew install fileicon" >&2 echo " or download 'Additional Tools for Xcode' from developer.apple.com/download/all" >&2 fi hdiutil convert "$RW_DMG" -format UDZO -ov -o "$OUTPUT_DMG" rm -f "$RW_DMG" echo "Created $OUTPUT_DMG"