Skip to content

Commit 44b301c

Browse files
committed
Build macOS DMG with dmgbuild in CI
1 parent b921151 commit 44b301c

4 files changed

Lines changed: 131 additions & 4 deletions

File tree

.github/workflows/build-release.yml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ jobs:
3434
package_cmd: cargo packager -f nsis
3535
- os: macos-15
3636
artifact_name: macos-arm64
37-
package_cmd: cargo packager -f dmg
37+
package_cmd: cargo packager -f app
3838
- os: macos-15-intel
3939
artifact_name: macos-intel
40-
package_cmd: cargo packager -f dmg
40+
package_cmd: cargo packager -f app
4141

4242
runs-on: ${{ matrix.os }}
4343
name: Build ${{ matrix.artifact_name }}
@@ -89,12 +89,20 @@ jobs:
8989
- name: Install cargo-packager
9090
run: cargo install cargo-packager --locked
9191

92+
- name: Install dmgbuild
93+
if: runner.os == 'macOS'
94+
run: python3 -m pip install --user dmgbuild
95+
9296
- name: Build binary
9397
run: cargo build --release --locked --bin linuxdo-accelerator
9498

9599
- name: Package app
96100
run: ${{ matrix.package_cmd }}
97101

102+
- name: Build DMG
103+
if: runner.os == 'macOS'
104+
run: bash ./scripts/build-macos-dmg.sh
105+
98106
- name: Upload artifacts
99107
uses: actions/upload-artifact@v4
100108
with:

.github/workflows/publish-edge-pre-release.yml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ jobs:
3636
package_cmd: cargo packager -f nsis
3737
- os: macos-15
3838
artifact_name: macos-arm64
39-
package_cmd: cargo packager -f dmg
39+
package_cmd: cargo packager -f app
4040
- os: macos-15-intel
4141
artifact_name: macos-intel
42-
package_cmd: cargo packager -f dmg
42+
package_cmd: cargo packager -f app
4343

4444
runs-on: ${{ matrix.os }}
4545
name: Build ${{ matrix.artifact_name }}
@@ -103,12 +103,20 @@ jobs:
103103
- name: Install cargo-packager
104104
run: cargo install cargo-packager --locked
105105

106+
- name: Install dmgbuild
107+
if: runner.os == 'macOS'
108+
run: python3 -m pip install --user dmgbuild
109+
106110
- name: Build binary
107111
run: cargo build --release --locked --bin linuxdo-accelerator
108112

109113
- name: Package app
110114
run: ${{ matrix.package_cmd }}
111115

116+
- name: Build DMG
117+
if: runner.os == 'macOS'
118+
run: bash ./scripts/build-macos-dmg.sh
119+
112120
- name: Upload artifacts
113121
uses: actions/upload-artifact@v4
114122
with:
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import os
2+
3+
4+
def _define(name, default=None):
5+
return defines.get(name, default)
6+
7+
8+
app_path = os.path.abspath(_define("app"))
9+
app_name = os.path.basename(app_path)
10+
volume_name = _define("volume_name", app_name[:-4] if app_name.endswith(".app") else app_name)
11+
background = os.path.abspath(_define("background", "assets/dmg/background.png"))
12+
window_width = int(_define("window_width", "720"))
13+
window_height = int(_define("window_height", "460"))
14+
app_x = int(_define("app_x", "160"))
15+
app_y = int(_define("app_y", "220"))
16+
apps_x = int(_define("apps_x", "560"))
17+
apps_y = int(_define("apps_y", "220"))
18+
19+
20+
format = "UDZO"
21+
files = [app_path]
22+
symlinks = {"Applications": "/Applications"}
23+
hide_extensions = [app_name]
24+
25+
default_view = "icon-view"
26+
show_toolbar = False
27+
show_sidebar = False
28+
show_status_bar = False
29+
show_tab_view = False
30+
show_pathbar = False
31+
show_icon_preview = False
32+
include_icon_view_settings = True
33+
34+
background = background
35+
window_rect = ((120, 120), (window_width, window_height))
36+
37+
arrange_by = None
38+
grid_spacing = 100
39+
label_pos = "bottom"
40+
text_size = 16
41+
icon_size = 128
42+
43+
icon_locations = {
44+
app_name: (app_x, app_y),
45+
"Applications": (apps_x, apps_y),
46+
}

scripts/build-macos-dmg.sh

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5+
cd "${repo_root}"
6+
7+
if [[ ! -d dist ]]; then
8+
echo "dist directory not found" >&2
9+
exit 1
10+
fi
11+
12+
app_path="$(find dist -maxdepth 1 -type d -name '*.app' | head -n 1)"
13+
if [[ -z "${app_path}" ]]; then
14+
echo "no .app bundle found in dist/" >&2
15+
exit 1
16+
fi
17+
18+
product_name="$(
19+
python3 - <<'PY'
20+
import pathlib, re
21+
content = pathlib.Path("Cargo.toml").read_text(encoding="utf-8")
22+
match = re.search(r'(?m)^product-name = "([^"]+)"$', content)
23+
if not match:
24+
raise SystemExit("failed to find package.metadata.packager.product-name")
25+
print(match.group(1))
26+
PY
27+
)"
28+
29+
package_version="$(
30+
python3 - <<'PY'
31+
import pathlib, re
32+
content = pathlib.Path("Cargo.toml").read_text(encoding="utf-8")
33+
match = re.search(r'(?m)^version = "([^"]+)"$', content)
34+
if not match:
35+
raise SystemExit("failed to find package version")
36+
print(match.group(1))
37+
PY
38+
)"
39+
40+
arch_label="$(uname -m)"
41+
case "${arch_label}" in
42+
x86_64) arch_label="x64" ;;
43+
arm64|aarch64) arch_label="aarch64" ;;
44+
esac
45+
46+
product_file_stem="${product_name// /.}"
47+
dmg_path="dist/${product_file_stem}_${package_version}_${arch_label}.dmg"
48+
rm -f "${dmg_path}"
49+
50+
python3 -m dmgbuild \
51+
-s packaging/macos/dmgbuild_settings.py \
52+
-D "app=${app_path}" \
53+
-D "volume_name=${product_name}" \
54+
-D "background=assets/dmg/background.png" \
55+
-D "window_width=720" \
56+
-D "window_height=460" \
57+
-D "app_x=160" \
58+
-D "app_y=220" \
59+
-D "apps_x=560" \
60+
-D "apps_y=220" \
61+
"${product_name}" \
62+
"${dmg_path}"
63+
64+
find dist -maxdepth 1 -type d -name '*.app' -exec rm -rf {} +
65+
echo "Built ${dmg_path}"

0 commit comments

Comments
 (0)