diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a729ee323b..53c28595ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -423,8 +423,8 @@ jobs: - name: Build sasview installer dmg file (OSX) if: ${{ startsWith(matrix.os, 'macos') }} run: | - cd installers/dist - hdiutil create $MACOS_DMG_NAME -srcfolder SasView6.app -ov -format UDZO + uv pip install dmgbuild + installers/macos/create_dmg.sh "$MACOS_DMG_NAME" - name: Build sasview installer tarball (Linux) if: ${{ startsWith(matrix.os, 'ubuntu') }} @@ -450,7 +450,8 @@ jobs: python ../../build_tools/fix_qt_folder_names_for_codesign.py SasView6.app python ../../build_tools/code_sign_osx.py codesign --verify --options=runtime --entitlements ../../build_tools/entitlements.plist --timestamp --deep --verbose=4 --force --sign "Developer ID Application: The International Scattering Alliance (8CX8K63BQM)" SasView6.app - hdiutil create $MACOS_DMG_NAME -srcfolder SasView6.app -ov -format UDZO + uv pip install dmgbuild + ../../installers/macos/create_dmg.sh "$MACOS_DMG_NAME" codesign -s "Developer ID Application: The International Scattering Alliance (8CX8K63BQM)" $MACOS_DMG_NAME - name: Notarize Release Build (OSX) diff --git a/installers/macos/create_dmg.sh b/installers/macos/create_dmg.sh new file mode 100755 index 0000000000..293c2edab5 --- /dev/null +++ b/installers/macos/create_dmg.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +# Build a drag-to-Applications DMG for SasView on macOS. +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" +DIST_DIR="${REPO_ROOT}/installers/dist" +STAGING_DIR="${DIST_DIR}/dmg-staging" +APP_NAME="SasView6.app" +DMG_NAME="${1:-SasView6.dmg}" +VOLUME_NAME="SasView6" +BACKGROUND="${SCRIPT_DIR}/dmg_background.png" +BACKGROUND_2X="${SCRIPT_DIR}/dmg_background@2x.png" + +if [[ "$(uname -s)" != "Darwin" ]]; then + echo "create_dmg.sh must be run on macOS." >&2 + exit 1 +fi + +if [[ ! -d "${DIST_DIR}/${APP_NAME}" ]]; then + echo "Expected ${DIST_DIR}/${APP_NAME} to exist. Build the app bundle first." >&2 + exit 1 +fi + +if [[ ! -f "${BACKGROUND}" ]]; then + echo "Missing ${BACKGROUND}." >&2 + exit 1 +fi + +if [[ ! -f "${BACKGROUND_2X}" ]]; then + echo "Missing ${BACKGROUND_2X} (HiDPI companion for dmg_background.png)." >&2 + exit 1 +fi + +if ! command -v dmgbuild >/dev/null 2>&1; then + echo "dmgbuild is required. Install with: pip install dmgbuild" >&2 + exit 1 +fi + +rm -rf "${STAGING_DIR}" +mkdir -p "${STAGING_DIR}" +cp -R "${DIST_DIR}/${APP_NAME}" "${STAGING_DIR}/" + +rm -f "${DIST_DIR}/${DMG_NAME}" + +# Eject any previously mounted copy so Finder does not reuse a cached layout. +if mount | grep -q "/Volumes/${VOLUME_NAME}"; then + hdiutil detach "/Volumes/${VOLUME_NAME}" >/dev/null 2>&1 || true +fi + +dmgbuild -s "${SCRIPT_DIR}/dmg_settings.py" \ + -D "settings_dir=${SCRIPT_DIR}" \ + -D "staging_dir=${STAGING_DIR}" \ + -D "app_name=${APP_NAME}" \ + "${VOLUME_NAME}" \ + "${DIST_DIR}/${DMG_NAME}" + +echo "Created ${DIST_DIR}/${DMG_NAME}" diff --git a/installers/macos/dmg_background.png b/installers/macos/dmg_background.png new file mode 100644 index 0000000000..d0ef41215d Binary files /dev/null and b/installers/macos/dmg_background.png differ diff --git a/installers/macos/dmg_background@2x.png b/installers/macos/dmg_background@2x.png new file mode 100644 index 0000000000..9e56344bb1 Binary files /dev/null and b/installers/macos/dmg_background@2x.png differ diff --git a/installers/macos/dmg_settings.py b/installers/macos/dmg_settings.py new file mode 100644 index 0000000000..90ffde36f9 --- /dev/null +++ b/installers/macos/dmg_settings.py @@ -0,0 +1,29 @@ +import os + +_settings_dir = defines["settings_dir"] # noqa: F821 + +app_name = defines.get("app_name", "SasView6.app") # noqa: F821 +staging_dir = defines["staging_dir"] # noqa: F821 + +format = "UDBZ" + +files = [os.path.join(staging_dir, app_name)] +symlinks = {"Applications": "/Applications"} +hide_extensions = [app_name] + +background = os.path.join(_settings_dir, "dmg_background.png") + +window_rect = ((200, 120), (640, 280)) +default_view = "icon-view" +include_icon_view_settings = True +show_status_bar = False +show_tab_view = False +show_toolbar = False +show_pathbar = False +show_sidebar = False +icon_size = 128 + +icon_locations = { + app_name: (140, 120), + "Applications": (500, 120), +}