From 3b6323378ea6ff0445dd0a92cbe13293b5980e6e Mon Sep 17 00:00:00 2001 From: gronod Date: Mon, 14 Sep 2026 09:57:37 +0000 Subject: [PATCH 1/5] fix(packaging): DMG background visible on Sonoma+ (#95) Pin dmgbuild >= 1.6.7 so Finder gets a bookmark instead of a Monterey-era Alias Manager blob. Feed a HiDPI TIFF from tiffutil rather than the 1x RGBA PNG, and fail the package job if the art is missing instead of shipping a grey window. Exclude installer chrome from the app bundle; it is not an in-app asset. --- docs/23-assets.md | 2 +- project.yml | 2 ++ scripts/dmgbuild-settings.py | 24 ++++++++++------ scripts/ensure-host-tools.sh | 6 ++-- scripts/package-release.sh | 55 ++++++++++++++++++++++++++++-------- 5 files changed, 65 insertions(+), 24 deletions(-) diff --git a/docs/23-assets.md b/docs/23-assets.md index fe336b3..98d6d7a 100644 --- a/docs/23-assets.md +++ b/docs/23-assets.md @@ -25,7 +25,7 @@ Cone-only mark for window/taskbar. Raster set: | File | Use | |------|-----| -| `icons/dmg-background.png` (+ `@2x`, `.svg`) | macOS DMG window (ice cream / wordmark scene). Headless `dmgbuild` after #189 | +| `Resources/dmg-background.png` (+ `@2x`; source `brand/dmg-background.svg`) | macOS DMG window. `scripts/package-release.sh` builds a HiDPI TIFF and passes it to `dmgbuild` >= 1.6.7 (#95, #189). Missing art is a hard fail. | | `icons/wix-banner.bmp`, `wix-dialog.bmp` | MSI | | `icons/nsis-header.bmp`, `nsis-sidebar.bmp` | NSIS | diff --git a/project.yml b/project.yml index 642e5c3..b706f78 100644 --- a/project.yml +++ b/project.yml @@ -21,6 +21,8 @@ targets: - ICCery.entitlements - ICCery.Debug.entitlements - Argyll + - dmg-background.png + - dmg-background@2x.png - path: Resources/Argyll type: folder dependencies: diff --git a/scripts/dmgbuild-settings.py b/scripts/dmgbuild-settings.py index be4e87c..1a858ca 100755 --- a/scripts/dmgbuild-settings.py +++ b/scripts/dmgbuild-settings.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 # scripts/dmgbuild-settings.py # -# dmgbuild settings for ICCery. Set DMG_APP, DMG_FILENAME and DMG_VOLUME_NAME -# in the environment, or accept the defaults. Background art can be supplied -# later by placing a PNG at Resources/dmg-background.png and setting -# DMG_BACKGROUND. +# dmgbuild settings for ICCery. scripts/package-release.sh exports +# DMG_APP, DMG_FILENAME, DMG_VOLUME_NAME, and DMG_BACKGROUND (a +# HiDPI TIFF). A missing background is a hard error — a grey +# Finder window is not an acceptable release artefact (#95). import os import sys @@ -23,15 +23,21 @@ if not app_path or not app_path.endswith('.app') or not os.path.isdir(app_path): files = [app_path] -# Background art is optional. If the referenced PNG does not exist, fall back -# to a plain window. See docs/23-assets.md for the DMG background spec. -background = os.environ.get('DMG_BACKGROUND', 'Resources/dmg-background.png') -if background and not os.path.exists(background): - background = None +# Finder on Sonoma+ ignores the legacy Alias Manager blob that +# dmgbuild 1.6.5 wrote for a PNG. Pass a flattened HiDPI TIFF and +# require dmgbuild >= 1.6.7 (bookmark-based background). See #95. +background = os.environ.get('DMG_BACKGROUND', '') +if not background or not os.path.isfile(background): + sys.stderr.write( + 'error: DMG_BACKGROUND must point at an existing image ' + '(got %r)\n' % background) + sys.exit(1) icon = None # Window size is enough for the app icon and the Applications alias. +# Bitmap is slightly larger than this rect so title-bar chrome on +# 14+ does not crop the wordmark. window_rect = ((100, 100), (660, 400)) # Use icon view without extra chrome. diff --git a/scripts/ensure-host-tools.sh b/scripts/ensure-host-tools.sh index 9c0afef..44a9b17 100755 --- a/scripts/ensure-host-tools.sh +++ b/scripts/ensure-host-tools.sh @@ -4,7 +4,7 @@ # Bootstrap host tools needed by CI on the macOS 12 runner: # - xcodegen: pinned prebuilt release from GitHub (Homebrew's current # formula requires Xcode 15.3, which cannot be installed on macOS 12). -# - dmgbuild: via pip3 (used by scripts/package-release.sh). +# - dmgbuild >= 1.6.7: via pip (bookmark-based DMG background, #95). # # Safe to run repeatedly: existing tools are left alone. @@ -13,8 +13,8 @@ set -eu XCODEGEN_VERSION="2.38.0" INSTALL_ROOT="${XCODEGEN_HOME:-$HOME/.local/xcodegen/$XCODEGEN_VERSION}" -echo "==> Ensuring dmgbuild" -python3 -c "import dmgbuild" 2>/dev/null || pip3 install dmgbuild +echo "==> Ensuring dmgbuild >= 1.6.7" +python3 -m pip install --upgrade 'dmgbuild>=1.6.7' if command -v xcodegen >/dev/null 2>&1; then echo "==> xcodegen already on PATH: $(xcodegen --version)" diff --git a/scripts/package-release.sh b/scripts/package-release.sh index 88ef010..8dde654 100755 --- a/scripts/package-release.sh +++ b/scripts/package-release.sh @@ -103,19 +103,51 @@ EOF scripts/verify-sidecar-signatures.sh "$APP" fi -echo "==> Installing / locating dmgbuild" -if ! command -v dmgbuild >/dev/null 2>&1; then - VENV="$ROOT/build/.venv-dmgbuild" - if [ ! -d "$VENV/bin" ]; then - python3 -m venv "$VENV" - "$VENV/bin/pip" install --upgrade pip - "$VENV/bin/pip" install dmgbuild - fi - PATH="$VENV/bin:$PATH" - export PATH +echo "==> Installing / locating dmgbuild >= 1.6.7" +# 1.6.5 writes a classic Alias Manager blob that Sonoma Finder does +# not resolve after UDZO (#95). Always upgrade — a leftover venv on +# the runner may still hold 1.6.5. +VENV="$ROOT/build/.venv-dmgbuild" +if [ ! -d "$VENV/bin" ]; then + python3 -m venv "$VENV" fi +"$VENV/bin/pip" install --upgrade pip +"$VENV/bin/pip" install --upgrade 'dmgbuild>=1.6.7' +PATH="$VENV/bin:$PATH" +export PATH if ! command -v dmgbuild >/dev/null 2>&1; then - echo "error: dmgbuild not available. Try 'python3 -m venv .venv && pip install dmgbuild'" >&2 + echo "error: dmgbuild not available after venv install" >&2 + exit 1 +fi +DMGBUILD_VER="$("$VENV/bin/python" -c 'from importlib.metadata import version; print(version("dmgbuild"))')" +echo "dmgbuild $DMGBUILD_VER" +"$VENV/bin/python" -c ' +from importlib.metadata import version +parts = [] +for p in version("dmgbuild").split("."): + try: + parts.append(int(p)) + except ValueError: + parts.append(0) +parts += [0, 0, 0] +raise SystemExit(0 if tuple(parts[:3]) >= (1, 6, 7) else 1) +' || { + echo "error: dmgbuild $DMGBUILD_VER is older than 1.6.7" >&2 + exit 1 +} + +PNG1X="$ROOT/Resources/dmg-background.png" +PNG2X="$ROOT/Resources/dmg-background@2x.png" +if [ ! -f "$PNG1X" ] || [ ! -f "$PNG2X" ]; then + echo "error: missing $PNG1X or $PNG2X" >&2 + exit 1 +fi +mkdir -p "$ROOT/build" +DMG_BACKGROUND="$ROOT/build/dmg-background.tiff" +echo "==> Building HiDPI DMG background TIFF" +tiffutil -cathidpicheck "$PNG1X" "$PNG2X" -out "$DMG_BACKGROUND" +if [ ! -f "$DMG_BACKGROUND" ]; then + echo "error: tiffutil did not write $DMG_BACKGROUND" >&2 exit 1 fi @@ -128,6 +160,7 @@ VOLUME_NAME="ICCery ${VERSION}" DMG_APP="$APP" \ DMG_FILENAME="$DMG" \ DMG_VOLUME_NAME="$VOLUME_NAME" \ +DMG_BACKGROUND="$DMG_BACKGROUND" \ dmgbuild -s scripts/dmgbuild-settings.py "$VOLUME_NAME" "$DMG" echo "DMG: $PWD/$DMG" -- 2.39.5 From 7f6c47d85c3a358b105e9d651ca4eaafc14a88e6 Mon Sep 17 00:00:00 2001 From: gronod Date: Mon, 14 Sep 2026 10:14:29 +0000 Subject: [PATCH 2/5] fix(ci): do not require dmgbuild 1.6.7 on Monterey Python 3.9 The tools step runs on the test job. System Python is 3.9; dmgbuild 1.6.6+ declares Requires-Python >=3.10, so pip only lists 1.6.5 and the 1.6.7 floor failed the gate. Install the newest wheel this interpreter accepts. Keep the HiDPI TIFF background path and the hard-fail if art is missing. --- docs/23-assets.md | 2 +- scripts/dmgbuild-settings.py | 8 +++++--- scripts/ensure-host-tools.sh | 10 +++++++--- scripts/package-release.sh | 25 ++++++------------------- 4 files changed, 19 insertions(+), 26 deletions(-) diff --git a/docs/23-assets.md b/docs/23-assets.md index 98d6d7a..d4e942d 100644 --- a/docs/23-assets.md +++ b/docs/23-assets.md @@ -25,7 +25,7 @@ Cone-only mark for window/taskbar. Raster set: | File | Use | |------|-----| -| `Resources/dmg-background.png` (+ `@2x`; source `brand/dmg-background.svg`) | macOS DMG window. `scripts/package-release.sh` builds a HiDPI TIFF and passes it to `dmgbuild` >= 1.6.7 (#95, #189). Missing art is a hard fail. | +| `Resources/dmg-background.png` (+ `@2x`; source `brand/dmg-background.svg`) | macOS DMG window. `scripts/package-release.sh` builds a HiDPI TIFF and passes it to `dmgbuild`. On the Monterey runner the newest installable dmgbuild is 1.6.5 (1.6.6+ needs Python 3.10). Missing art is a hard fail (#95, #189). | | `icons/wix-banner.bmp`, `wix-dialog.bmp` | MSI | | `icons/nsis-header.bmp`, `nsis-sidebar.bmp` | NSIS | diff --git a/scripts/dmgbuild-settings.py b/scripts/dmgbuild-settings.py index 1a858ca..bd72f2f 100755 --- a/scripts/dmgbuild-settings.py +++ b/scripts/dmgbuild-settings.py @@ -23,9 +23,11 @@ if not app_path or not app_path.endswith('.app') or not os.path.isdir(app_path): files = [app_path] -# Finder on Sonoma+ ignores the legacy Alias Manager blob that -# dmgbuild 1.6.5 wrote for a PNG. Pass a flattened HiDPI TIFF and -# require dmgbuild >= 1.6.7 (bookmark-based background). See #95. +# Finder on Sonoma+ is picky about PNG-with-alpha window pictures and +# about classic Alias Manager blobs. package-release.sh always passes +# a flattened HiDPI TIFF as DMG_BACKGROUND. dmgbuild 1.6.7 (bookmark +# .DS_Store) needs Python >= 3.10, which the Monterey runner does not +# have; 1.6.5 + TIFF is what CI can ship (#95). background = os.environ.get('DMG_BACKGROUND', '') if not background or not os.path.isfile(background): sys.stderr.write( diff --git a/scripts/ensure-host-tools.sh b/scripts/ensure-host-tools.sh index 44a9b17..10e6683 100755 --- a/scripts/ensure-host-tools.sh +++ b/scripts/ensure-host-tools.sh @@ -4,7 +4,10 @@ # Bootstrap host tools needed by CI on the macOS 12 runner: # - xcodegen: pinned prebuilt release from GitHub (Homebrew's current # formula requires Xcode 15.3, which cannot be installed on macOS 12). -# - dmgbuild >= 1.6.7: via pip (bookmark-based DMG background, #95). +# - dmgbuild: via pip. Monterey ships Python 3.9; dmgbuild 1.6.6+ +# requires Python >= 3.10, so the newest installable wheel on this +# runner is 1.6.5 (#95). Do not floor at 1.6.7 here — this script +# also gates the unit/UI test job. # # Safe to run repeatedly: existing tools are left alone. @@ -13,8 +16,9 @@ set -eu XCODEGEN_VERSION="2.38.0" INSTALL_ROOT="${XCODEGEN_HOME:-$HOME/.local/xcodegen/$XCODEGEN_VERSION}" -echo "==> Ensuring dmgbuild >= 1.6.7" -python3 -m pip install --upgrade 'dmgbuild>=1.6.7' +echo "==> Ensuring dmgbuild" +python3 -m pip install --upgrade 'dmgbuild>=1.6.5' +python3 -c 'from importlib.metadata import version; print("dmgbuild", version("dmgbuild"))' if command -v xcodegen >/dev/null 2>&1; then echo "==> xcodegen already on PATH: $(xcodegen --version)" diff --git a/scripts/package-release.sh b/scripts/package-release.sh index 8dde654..3f5398c 100755 --- a/scripts/package-release.sh +++ b/scripts/package-release.sh @@ -103,16 +103,16 @@ EOF scripts/verify-sidecar-signatures.sh "$APP" fi -echo "==> Installing / locating dmgbuild >= 1.6.7" -# 1.6.5 writes a classic Alias Manager blob that Sonoma Finder does -# not resolve after UDZO (#95). Always upgrade — a leftover venv on -# the runner may still hold 1.6.5. +echo "==> Installing / locating dmgbuild" +# Monterey CI Python is 3.9. dmgbuild 1.6.6+ declares Requires-Python +# >=3.10, so pip only offers 1.6.5 on this runner. Install the newest +# wheel this interpreter accepts; do not fail the job for 1.6.7. VENV="$ROOT/build/.venv-dmgbuild" if [ ! -d "$VENV/bin" ]; then python3 -m venv "$VENV" fi "$VENV/bin/pip" install --upgrade pip -"$VENV/bin/pip" install --upgrade 'dmgbuild>=1.6.7' +"$VENV/bin/pip" install --upgrade dmgbuild PATH="$VENV/bin:$PATH" export PATH if ! command -v dmgbuild >/dev/null 2>&1; then @@ -121,20 +121,7 @@ if ! command -v dmgbuild >/dev/null 2>&1; then fi DMGBUILD_VER="$("$VENV/bin/python" -c 'from importlib.metadata import version; print(version("dmgbuild"))')" echo "dmgbuild $DMGBUILD_VER" -"$VENV/bin/python" -c ' -from importlib.metadata import version -parts = [] -for p in version("dmgbuild").split("."): - try: - parts.append(int(p)) - except ValueError: - parts.append(0) -parts += [0, 0, 0] -raise SystemExit(0 if tuple(parts[:3]) >= (1, 6, 7) else 1) -' || { - echo "error: dmgbuild $DMGBUILD_VER is older than 1.6.7" >&2 - exit 1 -} +"$VENV/bin/python" -c 'import sys; print("venv python", sys.version)' PNG1X="$ROOT/Resources/dmg-background.png" PNG2X="$ROOT/Resources/dmg-background@2x.png" -- 2.39.5 From 1c310706e47888583d555425d1c70afd77f384fa Mon Sep 17 00:00:00 2001 From: gronod Date: Mon, 14 Sep 2026 10:22:09 +0000 Subject: [PATCH 3/5] fix(ci): isolate dmgbuild in a venv, skip it on the test job ensure-host-tools.sh always bootstraps xcodegen. dmgbuild now lives in build/.venv-dmgbuild and is only installed when INSTALL_DMGBUILD=1 (package job). The test job no longer pip-installs dmgbuild, which is what failed on Python 3.9. package-release.sh reuses that venv (or bootstraps it locally) instead of creating a second copy. --- .gitea/workflows/macos.yml | 7 ++++-- docs/23-assets.md | 2 +- scripts/ensure-host-tools.sh | 42 ++++++++++++++++++++++++++++-------- scripts/package-release.sh | 31 +++++++++++++------------- 4 files changed, 55 insertions(+), 27 deletions(-) diff --git a/.gitea/workflows/macos.yml b/.gitea/workflows/macos.yml index db350b9..029a94a 100644 --- a/.gitea/workflows/macos.yml +++ b/.gitea/workflows/macos.yml @@ -35,7 +35,8 @@ jobs: # The job still succeeds quickly so `package`'s `needs:` stays satisfied. # Homebrew's xcodegen formula requires Xcode 15.3, which cannot be # installed on macOS 12 (#109). The script installs a pinned - # prebuilt release instead. + # prebuilt release instead. dmgbuild is not installed here — the + # test job does not package (#95). - name: Ensure host tools if: "!(startsWith(github.ref, 'refs/tags/') && contains(github.ref_name, 'prerelease'))" run: scripts/ensure-host-tools.sh @@ -193,8 +194,10 @@ jobs: # scripts/package-release.sh runs `xcodegen generate` and dmgbuild; # see build-and-test for why brew is not used on macOS 12 (#109). + # INSTALL_DMGBUILD isolates dmgbuild in build/.venv-dmgbuild so + # the test job never pip-installs it (#95). - name: Ensure host tools - run: scripts/ensure-host-tools.sh + run: INSTALL_DMGBUILD=1 scripts/ensure-host-tools.sh - name: Package release run: scripts/package-release.sh diff --git a/docs/23-assets.md b/docs/23-assets.md index d4e942d..b98cf7b 100644 --- a/docs/23-assets.md +++ b/docs/23-assets.md @@ -25,7 +25,7 @@ Cone-only mark for window/taskbar. Raster set: | File | Use | |------|-----| -| `Resources/dmg-background.png` (+ `@2x`; source `brand/dmg-background.svg`) | macOS DMG window. `scripts/package-release.sh` builds a HiDPI TIFF and passes it to `dmgbuild`. On the Monterey runner the newest installable dmgbuild is 1.6.5 (1.6.6+ needs Python 3.10). Missing art is a hard fail (#95, #189). | +| `Resources/dmg-background.png` (+ `@2x`; source `brand/dmg-background.svg`) | macOS DMG window. `scripts/package-release.sh` builds a HiDPI TIFF and passes it to `dmgbuild` from `build/.venv-dmgbuild` (created by `INSTALL_DMGBUILD=1 scripts/ensure-host-tools.sh`). On the Monterey runner the newest installable dmgbuild is 1.6.5 (1.6.6+ needs Python 3.10). Missing art is a hard fail (#95, #189). | | `icons/wix-banner.bmp`, `wix-dialog.bmp` | MSI | | `icons/nsis-header.bmp`, `nsis-sidebar.bmp` | NSIS | diff --git a/scripts/ensure-host-tools.sh b/scripts/ensure-host-tools.sh index 10e6683..a287125 100755 --- a/scripts/ensure-host-tools.sh +++ b/scripts/ensure-host-tools.sh @@ -2,23 +2,47 @@ # scripts/ensure-host-tools.sh # # Bootstrap host tools needed by CI on the macOS 12 runner: -# - xcodegen: pinned prebuilt release from GitHub (Homebrew's current -# formula requires Xcode 15.3, which cannot be installed on macOS 12). -# - dmgbuild: via pip. Monterey ships Python 3.9; dmgbuild 1.6.6+ -# requires Python >= 3.10, so the newest installable wheel on this -# runner is 1.6.5 (#95). Do not floor at 1.6.7 here — this script -# also gates the unit/UI test job. +# - xcodegen: always. Pinned prebuilt release from GitHub (Homebrew's +# current formula requires Xcode 15.3, which cannot be installed on +# macOS 12). +# - dmgbuild: only when INSTALL_DMGBUILD=1 or --dmgbuild. Isolated in +# build/.venv-dmgbuild so the test job never pip-installs it. +# Monterey ships Python 3.9; dmgbuild 1.6.6+ requires Python >= 3.10, +# so the newest installable wheel on this runner is 1.6.5 (#95). # # Safe to run repeatedly: existing tools are left alone. set -eu +ROOT="$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)" XCODEGEN_VERSION="2.38.0" INSTALL_ROOT="${XCODEGEN_HOME:-$HOME/.local/xcodegen/$XCODEGEN_VERSION}" +VENV="$ROOT/build/.venv-dmgbuild" -echo "==> Ensuring dmgbuild" -python3 -m pip install --upgrade 'dmgbuild>=1.6.5' -python3 -c 'from importlib.metadata import version; print("dmgbuild", version("dmgbuild"))' +INSTALL_DMGBUILD="${INSTALL_DMGBUILD:-0}" +for arg in "$@"; do + case "$arg" in + --dmgbuild) INSTALL_DMGBUILD=1 ;; + esac +done + +if [ "$INSTALL_DMGBUILD" = "1" ]; then + echo "==> Ensuring dmgbuild in $VENV" + mkdir -p "$ROOT/build" + if [ ! -x "$VENV/bin/python" ]; then + python3 -m venv "$VENV" + fi + "$VENV/bin/pip" install --upgrade pip + "$VENV/bin/pip" install --upgrade 'dmgbuild>=1.6.5' + "$VENV/bin/python" -c 'from importlib.metadata import version; print("dmgbuild", version("dmgbuild"))' + if [ -n "${GITHUB_PATH:-}" ]; then + echo "$VENV/bin" >> "$GITHUB_PATH" + fi + PATH="$VENV/bin:$PATH" + export PATH +else + echo "==> Skipping dmgbuild (set INSTALL_DMGBUILD=1 for the package job)" +fi if command -v xcodegen >/dev/null 2>&1; then echo "==> xcodegen already on PATH: $(xcodegen --version)" diff --git a/scripts/package-release.sh b/scripts/package-release.sh index 3f5398c..872688e 100755 --- a/scripts/package-release.sh +++ b/scripts/package-release.sh @@ -103,25 +103,26 @@ EOF scripts/verify-sidecar-signatures.sh "$APP" fi -echo "==> Installing / locating dmgbuild" -# Monterey CI Python is 3.9. dmgbuild 1.6.6+ declares Requires-Python -# >=3.10, so pip only offers 1.6.5 on this runner. Install the newest -# wheel this interpreter accepts; do not fail the job for 1.6.7. +echo "==> Locating dmgbuild" +# The package CI job already ran INSTALL_DMGBUILD=1 ensure-host-tools.sh, +# which created build/.venv-dmgbuild and prepended it to PATH. Local +# runs bootstrap the same venv if dmgbuild is missing. VENV="$ROOT/build/.venv-dmgbuild" -if [ ! -d "$VENV/bin" ]; then - python3 -m venv "$VENV" -fi -"$VENV/bin/pip" install --upgrade pip -"$VENV/bin/pip" install --upgrade dmgbuild -PATH="$VENV/bin:$PATH" -export PATH if ! command -v dmgbuild >/dev/null 2>&1; then - echo "error: dmgbuild not available after venv install" >&2 + if [ ! -x "$VENV/bin/dmgbuild" ]; then + INSTALL_DMGBUILD=1 "$ROOT/scripts/ensure-host-tools.sh" --dmgbuild + fi + PATH="$VENV/bin:$PATH" + export PATH +fi +if ! command -v dmgbuild >/dev/null 2>&1; then + echo "error: dmgbuild not on PATH; run INSTALL_DMGBUILD=1 scripts/ensure-host-tools.sh" >&2 exit 1 fi -DMGBUILD_VER="$("$VENV/bin/python" -c 'from importlib.metadata import version; print(version("dmgbuild"))')" -echo "dmgbuild $DMGBUILD_VER" -"$VENV/bin/python" -c 'import sys; print("venv python", sys.version)' +echo "dmgbuild $(command -v dmgbuild)" +if [ -x "$VENV/bin/python" ]; then + "$VENV/bin/python" -c 'from importlib.metadata import version; print("dmgbuild", version("dmgbuild"))' +fi PNG1X="$ROOT/Resources/dmg-background.png" PNG2X="$ROOT/Resources/dmg-background@2x.png" -- 2.39.5 From c2ac9341c838fe00e79c495a0a951d14acacf7c2 Mon Sep 17 00:00:00 2001 From: gronod Date: Mon, 14 Sep 2026 10:29:33 +0000 Subject: [PATCH 4/5] fix(ci): force dmgbuild 1.6.7 into the package venv Python 3.9 hides 1.6.6+ (Requires-Python >=3.10), so dmgbuild>=1.6.5 left a cached 1.6.5 install. The wheels are py3-none-any; install 1.6.7 with PIP_IGNORE_REQUIRES_PYTHON, force-reinstall ds_store>=1.3.3 and mac_alias>=2.2.3, and fail if the venv is still older than 1.6.7. --- docs/23-assets.md | 2 +- scripts/ensure-host-tools.sh | 35 +++++++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/docs/23-assets.md b/docs/23-assets.md index b98cf7b..fcc257e 100644 --- a/docs/23-assets.md +++ b/docs/23-assets.md @@ -25,7 +25,7 @@ Cone-only mark for window/taskbar. Raster set: | File | Use | |------|-----| -| `Resources/dmg-background.png` (+ `@2x`; source `brand/dmg-background.svg`) | macOS DMG window. `scripts/package-release.sh` builds a HiDPI TIFF and passes it to `dmgbuild` from `build/.venv-dmgbuild` (created by `INSTALL_DMGBUILD=1 scripts/ensure-host-tools.sh`). On the Monterey runner the newest installable dmgbuild is 1.6.5 (1.6.6+ needs Python 3.10). Missing art is a hard fail (#95, #189). | +| `Resources/dmg-background.png` (+ `@2x`; source `brand/dmg-background.svg`) | macOS DMG window. `scripts/package-release.sh` builds a HiDPI TIFF and passes it to `dmgbuild==1.6.7` from `build/.venv-dmgbuild` (created by `INSTALL_DMGBUILD=1 scripts/ensure-host-tools.sh`). Monterey Python 3.9 needs `PIP_IGNORE_REQUIRES_PYTHON=1` or pip will keep 1.6.5. Missing art is a hard fail (#95, #189). | | `icons/wix-banner.bmp`, `wix-dialog.bmp` | MSI | | `icons/nsis-header.bmp`, `nsis-sidebar.bmp` | NSIS | diff --git a/scripts/ensure-host-tools.sh b/scripts/ensure-host-tools.sh index a287125..9029a03 100755 --- a/scripts/ensure-host-tools.sh +++ b/scripts/ensure-host-tools.sh @@ -7,10 +7,14 @@ # macOS 12). # - dmgbuild: only when INSTALL_DMGBUILD=1 or --dmgbuild. Isolated in # build/.venv-dmgbuild so the test job never pip-installs it. -# Monterey ships Python 3.9; dmgbuild 1.6.6+ requires Python >= 3.10, -# so the newest installable wheel on this runner is 1.6.5 (#95). # -# Safe to run repeatedly: existing tools are left alone. +# dmgbuild 1.6.6+, ds_store 1.3.2+ and mac_alias 2.2.3 declare +# Requires-Python >= 3.10. The wheels are py3-none-any and run on the +# runner's 3.9; PIP_IGNORE_REQUIRES_PYTHON is required or pip will only +# offer 1.6.5 and keep a cached venv on that version (#95). +# +# Safe to run repeatedly: existing tools are left alone unless the +# dmgbuild pin is not met. set -eu @@ -18,6 +22,7 @@ ROOT="$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)" XCODEGEN_VERSION="2.38.0" INSTALL_ROOT="${XCODEGEN_HOME:-$HOME/.local/xcodegen/$XCODEGEN_VERSION}" VENV="$ROOT/build/.venv-dmgbuild" +DMGBUILD_PIN="1.6.7" INSTALL_DMGBUILD="${INSTALL_DMGBUILD:-0}" for arg in "$@"; do @@ -27,14 +32,32 @@ for arg in "$@"; do done if [ "$INSTALL_DMGBUILD" = "1" ]; then - echo "==> Ensuring dmgbuild in $VENV" + echo "==> Ensuring dmgbuild==$DMGBUILD_PIN in $VENV" mkdir -p "$ROOT/build" if [ ! -x "$VENV/bin/python" ]; then python3 -m venv "$VENV" fi + # Without this, pip on Python 3.9 hides 1.6.6+ and leaves 1.6.5. + PIP_IGNORE_REQUIRES_PYTHON=1 + export PIP_IGNORE_REQUIRES_PYTHON "$VENV/bin/pip" install --upgrade pip - "$VENV/bin/pip" install --upgrade 'dmgbuild>=1.6.5' - "$VENV/bin/python" -c 'from importlib.metadata import version; print("dmgbuild", version("dmgbuild"))' + "$VENV/bin/pip" install --upgrade --force-reinstall \ + "dmgbuild==$DMGBUILD_PIN" \ + 'ds_store>=1.3.3' \ + 'mac_alias>=2.2.3' + "$VENV/bin/python" -c 'from importlib.metadata import version +print("dmgbuild", version("dmgbuild")) +print("ds_store", version("ds_store")) +print("mac_alias", version("mac_alias")) +parts=[] +for p in version("dmgbuild").split("."): + try: + parts.append(int("".join(c for c in p if c.isdigit()) or "0")) + except ValueError: + parts.append(0) +parts += [0, 0, 0] +raise SystemExit(0 if tuple(parts[:3]) >= (1, 6, 7) else 1) +' if [ -n "${GITHUB_PATH:-}" ]; then echo "$VENV/bin" >> "$GITHUB_PATH" fi -- 2.39.5 From 2a8ad4d5d400997021c8d83498b49bc1ecafb968 Mon Sep 17 00:00:00 2001 From: gronod Date: Mon, 14 Sep 2026 10:34:16 +0000 Subject: [PATCH 5/5] fix(ci): cap pip below 26.1 in the Python 3.9 dmgbuild venv Unbounded pip upgrade installed 26.2.1, which uses dataclass(slots=True) and crashes on Monterey 3.9. Recreate the venv if pip is already broken, then pin pip>=24.3,<26.1 before force-installing dmgbuild 1.6.7. --- scripts/ensure-host-tools.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/scripts/ensure-host-tools.sh b/scripts/ensure-host-tools.sh index 9029a03..5924edc 100755 --- a/scripts/ensure-host-tools.sh +++ b/scripts/ensure-host-tools.sh @@ -12,6 +12,7 @@ # Requires-Python >= 3.10. The wheels are py3-none-any and run on the # runner's 3.9; PIP_IGNORE_REQUIRES_PYTHON is required or pip will only # offer 1.6.5 and keep a cached venv on that version (#95). +# pip itself is capped at <26.1: 26.1+ needs Python 3.10. # # Safe to run repeatedly: existing tools are left alone unless the # dmgbuild pin is not met. @@ -34,14 +35,22 @@ done if [ "$INSTALL_DMGBUILD" = "1" ]; then echo "==> Ensuring dmgbuild==$DMGBUILD_PIN in $VENV" mkdir -p "$ROOT/build" + # pip 26.1+ requires Python 3.10 (dataclass slots). A leftover + # `pip install --upgrade pip` on this 3.9 venv installed 26.2.1 and + # the next pip invocation crashed. Recreate if pip is already dead. + if [ -x "$VENV/bin/python" ] \ + && ! "$VENV/bin/python" -m pip --version >/dev/null 2>&1; then + echo "==> venv pip is broken; recreating $VENV" + rm -rf "$VENV" + fi if [ ! -x "$VENV/bin/python" ]; then python3 -m venv "$VENV" fi # Without this, pip on Python 3.9 hides 1.6.6+ and leaves 1.6.5. PIP_IGNORE_REQUIRES_PYTHON=1 export PIP_IGNORE_REQUIRES_PYTHON - "$VENV/bin/pip" install --upgrade pip - "$VENV/bin/pip" install --upgrade --force-reinstall \ + "$VENV/bin/python" -m pip install --upgrade 'pip>=24.3,<26.1' + "$VENV/bin/python" -m pip install --upgrade --force-reinstall \ "dmgbuild==$DMGBUILD_PIN" \ 'ds_store>=1.3.3' \ 'mac_alias>=2.2.3' -- 2.39.5