|
| 1 | +name: macOS DMG |
| 2 | + |
| 3 | +on: |
| 4 | + workflow_dispatch: |
| 5 | + push: |
| 6 | + branches: [ master ] |
| 7 | + tags: [ '[0-9]*.[0-9]*.[0-9]*' ] |
| 8 | + pull_request: |
| 9 | + paths: |
| 10 | + - '.github/workflows/macos-dmg.yml' |
| 11 | + - 'meson.build' |
| 12 | + - 'data/**' |
| 13 | + - 'src/**' |
| 14 | + |
| 15 | +jobs: |
| 16 | + build-dmg: |
| 17 | + strategy: |
| 18 | + matrix: |
| 19 | + os: [macos-13, macos-14] |
| 20 | + runs-on: ${{ matrix.os }} |
| 21 | + |
| 22 | + steps: |
| 23 | + - name: Checkout |
| 24 | + uses: actions/checkout@v4 |
| 25 | + |
| 26 | + - name: Show runner info |
| 27 | + run: | |
| 28 | + uname -a |
| 29 | + sw_vers |
| 30 | + sysctl -n machdep.cpu.brand_string || true |
| 31 | +
|
| 32 | + - name: Setup Homebrew and dependencies |
| 33 | + run: | |
| 34 | + brew update-reset |
| 35 | + brew install meson ninja pkg-config glib gtk4 libadwaita pygobject3 gtksourceview5 [email protected] |
| 36 | + brew --version |
| 37 | + brew list --versions |
| 38 | +
|
| 39 | + - name: Build blueprint-compiler from git (v0.18.0) |
| 40 | + run: | |
| 41 | + set -euxo pipefail |
| 42 | + git clone --depth 1 --branch v0.18.0 https://gitlab.gnome.org/GNOME/blueprint-compiler.git |
| 43 | + cd blueprint-compiler |
| 44 | + meson setup build --prefix "$PWD/../bp_prefix" --buildtype=release |
| 45 | + meson compile -C build |
| 46 | + meson install -C build |
| 47 | + echo "$GITHUB_WORKSPACE/bp_prefix/bin" >> "$GITHUB_PATH" |
| 48 | +
|
| 49 | + - name: Build project (Meson) |
| 50 | + run: | |
| 51 | + set -euxo pipefail |
| 52 | + PY_BIN="$(brew --prefix [email protected])/bin/python3" |
| 53 | + echo "Using Python: ${PY_BIN}" |
| 54 | + export PYTHON="${PY_BIN}" |
| 55 | + meson setup build --prefix "$PWD/stage" --buildtype=release |
| 56 | + meson compile -C build |
| 57 | + meson install -C build |
| 58 | +
|
| 59 | + - name: Prepare .app bundle |
| 60 | + run: | |
| 61 | + set -euxo pipefail |
| 62 | + APP_NAME="SSH Studio" |
| 63 | + APP_ID="io.github.BuddySirJava.SSH-Studio" |
| 64 | + VER=$(sed -n "s/.*version: '\([^']*\)'.*/\1/p" meson.build) |
| 65 | + ARCH=$(uname -m) |
| 66 | + APP_ROOT="$PWD/dist/${APP_NAME}.app/Contents" |
| 67 | + mkdir -p "$APP_ROOT/MacOS" "$APP_ROOT/Resources/python" |
| 68 | +
|
| 69 | + # Copy Python sources into bundle |
| 70 | + mkdir -p "$APP_ROOT/Resources/python/ssh_studio/ui" |
| 71 | + cp -R src/__init__.py "$APP_ROOT/Resources/python/ssh_studio/__init__.py" |
| 72 | + cp -R src/main.py "$APP_ROOT/Resources/python/ssh_studio/main.py" |
| 73 | + cp -R src/ssh_config_parser.py "$APP_ROOT/Resources/python/ssh_studio/ssh_config_parser.py" |
| 74 | + cp -R src/ui/__init__.py "$APP_ROOT/Resources/python/ssh_studio/ui/__init__.py" |
| 75 | + cp -R src/ui/*.py "$APP_ROOT/Resources/python/ssh_studio/ui/" |
| 76 | +
|
| 77 | + # Copy compiled resources into bundle |
| 78 | + cp -R "stage/share/${APP_ID}/ssh-studio-resources.gresource" "$APP_ROOT/Resources/ssh-studio-resources.gresource" |
| 79 | +
|
| 80 | + # Generate .icns from existing PNGs |
| 81 | + ICON_SRC="data/media/icon_512.png" |
| 82 | + ICONSET_DIR="$APP_ROOT/Resources/AppIcon.iconset" |
| 83 | + mkdir -p "$ICONSET_DIR" |
| 84 | + sips -z 16 16 "$ICON_SRC" --out "$ICONSET_DIR/icon_16x16.png" |
| 85 | + sips -z 32 32 "$ICON_SRC" --out "$ICONSET_DIR/[email protected]" |
| 86 | + sips -z 32 32 "$ICON_SRC" --out "$ICONSET_DIR/icon_32x32.png" |
| 87 | + sips -z 64 64 "$ICON_SRC" --out "$ICONSET_DIR/[email protected]" |
| 88 | + sips -z 128 128 "$ICON_SRC" --out "$ICONSET_DIR/icon_128x128.png" |
| 89 | + sips -z 256 256 "$ICON_SRC" --out "$ICONSET_DIR/[email protected]" |
| 90 | + sips -z 256 256 "$ICON_SRC" --out "$ICONSET_DIR/icon_256x256.png" |
| 91 | + sips -z 512 512 "$ICON_SRC" --out "$ICONSET_DIR/[email protected]" |
| 92 | + cp "$ICON_SRC" "$ICONSET_DIR/icon_512x512.png" |
| 93 | + sips -z 1024 1024 "$ICON_SRC" --out "$ICONSET_DIR/[email protected]" |
| 94 | + iconutil -c icns "$ICONSET_DIR" -o "$APP_ROOT/Resources/AppIcon.icns" |
| 95 | + rm -rf "$ICONSET_DIR" |
| 96 | +
|
| 97 | + # Create launcher (Python) that registers resources then runs main |
| 98 | + cat > "$APP_ROOT/Resources/ssh-studio-launch.py" << 'PY' |
| 99 | + #!/usr/bin/env python3 |
| 100 | + import os, sys |
| 101 | + from gi.repository import Gio |
| 102 | + resource_path = os.path.join(os.path.dirname(__file__), 'ssh-studio-resources.gresource') |
| 103 | + Gio.resources_register(Gio.Resource.load(resource_path)) |
| 104 | + from ssh_studio import main as _main |
| 105 | + sys.exit(_main.main()) |
| 106 | + PY |
| 107 | + chmod 0755 "$APP_ROOT/Resources/ssh-studio-launch.py" |
| 108 | +
|
| 109 | + # Info.plist |
| 110 | + cat > "$APP_ROOT/Info.plist" << PLIST |
| 111 | + <?xml version="1.0" encoding="UTF-8"?> |
| 112 | + <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| 113 | + <plist version="1.0"> |
| 114 | + <dict> |
| 115 | + <key>CFBundleName</key><string>${APP_NAME}</string> |
| 116 | + <key>CFBundleIdentifier</key><string>${APP_ID}</string> |
| 117 | + <key>CFBundleVersion</key><string>${VER}</string> |
| 118 | + <key>CFBundleShortVersionString</key><string>${VER}</string> |
| 119 | + <key>CFBundleExecutable</key><string>ssh-studio</string> |
| 120 | + <key>CFBundlePackageType</key><string>APPL</string> |
| 121 | + <key>CFBundleIconFile</key><string>AppIcon</string> |
| 122 | + <key>LSMinimumSystemVersion</key><string>11.0</string> |
| 123 | + <key>LSApplicationCategoryType</key><string>public.app-category.developer-tools</string> |
| 124 | + </dict> |
| 125 | + </plist> |
| 126 | + PLIST |
| 127 | +
|
| 128 | + # App executable that wires Python and PYTHONPATH |
| 129 | + PY_BIN="$(brew --prefix [email protected])/bin/python3" |
| 130 | + cat > "$APP_ROOT/MacOS/ssh-studio" << 'SH' |
| 131 | + #!/bin/bash |
| 132 | + SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" |
| 133 | + RES_DIR="${SCRIPT_DIR}/../Resources" |
| 134 | + export PYTHONPATH="${RES_DIR}/python" |
| 135 | + # Use Homebrew Python 3.13 explicitly |
| 136 | + PY_BIN="$(brew --prefix [email protected])/bin/python3" |
| 137 | + exec "${PY_BIN}" "${RES_DIR}/ssh-studio-launch.py" "$@" |
| 138 | + SH |
| 139 | + chmod 0755 "$APP_ROOT/MacOS/ssh-studio" |
| 140 | +
|
| 141 | + - name: Create DMG |
| 142 | + run: | |
| 143 | + set -euxo pipefail |
| 144 | + VER=$(sed -n "s/.*version: '\([^']*\)'.*/\1/p" meson.build) |
| 145 | + ARCH=$(uname -m) |
| 146 | + mkdir -p dmgroot |
| 147 | + cp -R "dist/SSH Studio.app" dmgroot/ |
| 148 | + ln -s /Applications dmgroot/Applications |
| 149 | + hdiutil create -volname "SSH Studio" -srcfolder dmgroot -ov -fs HFS+ "ssh-studio-${VER}-${ARCH}.dmg" |
| 150 | +
|
| 151 | + - name: Upload artifact |
| 152 | + uses: actions/upload-artifact@v4 |
| 153 | + with: |
| 154 | + name: ssh-studio-dmg-${{ matrix.os }} |
| 155 | + path: | |
| 156 | + *.dmg |
| 157 | +
|
| 158 | +
|
0 commit comments