From c216b389aefb4b22d7c72f4dcf934e66701d26a1 Mon Sep 17 00:00:00 2001 From: l0ng-ai Date: Mon, 10 Aug 2026 22:31:23 +0800 Subject: [PATCH] fix(macos): size the DMG ourselves, and stop blaming the runner's disk (#477) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The nightly channel has been frozen since 06:32 on 2026-08-10: every run dies in bundle-macos.sh with "hdiutil: create failed - No space left on device", on macos-15-intel, after the build, the signing and the notarization have all succeeded. The host disk was never full. #476 read that message as the runner running out of room and freed space for it; the `df -h` it added to prove the point disproved it instead — 105 GiB available, and the run failed anyway. The path in the error is under /Volumes/tty7, which is the image being created, not the runner: the volume ran out, not the disk. `hdiutil create -srcfolder` sizes the image from the bytes it is about to copy and does not cover what the filesystem spends carrying them, so a bundle that fits by measurement still runs the volume dry partway through the copy. It is a threshold rather than a cliff, which is why this began without anyone touching packaging: the binaries grew over edfadb7..fafcaa0, the x86_64 pair is the larger one and crossed it first, and arm64 kept building fine just underneath. Ask for the room explicitly — twice the content plus 64 MiB. The image is compressed on the way out, so the slack is nearly free: on a stage of this shape, 127 MiB of empty volume cost 672 KiB in the published DMG. Also drop #476's deletion of the build tree. It was paying for a problem that did not exist, and the bill was rust-cache finding nothing to save and every macOS build recompiling the dependency graph. The `mv` from that commit stays: a second full copy of the bundle is genuinely redundant, and nothing reads dist/tty7.app after this point. Verified locally against a staged bundle of the real shape (73 MiB, 101 files): the image is created, mounts with every file present, and detaches clean. The remaining unknown is only whether CI agrees, which the next nightly answers. Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> --- .github/scripts/bundle-macos.sh | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/.github/scripts/bundle-macos.sh b/.github/scripts/bundle-macos.sh index f602d21d..632a3c3a 100755 --- a/.github/scripts/bundle-macos.sh +++ b/.github/scripts/bundle-macos.sh @@ -210,12 +210,6 @@ if [[ "$PACKAGE_UPDATE_ZIP" != "0" ]]; then fi # Package the (now stapled) bundle as a drag-to-Applications DMG. -# -# `hdiutil` needs room for the whole image beside the staged bundle, and the -# hosted Intel runners stopped having it — three nightlies in a row died right -# here on 2026-08-10 with "hdiutil: create failed - No space left on device", -# across two different commits. The arm64 runners have never hit it. So the two -# steps below give the image somewhere to go rather than assuming there is room. DMG="dist/tty7-${VERSION}-macos-${ARCH}.dmg" STAGE="dist/dmg-stage" rm -rf "$STAGE" @@ -227,17 +221,22 @@ mkdir "$STAGE" # knows about tty7.app as an intermediate to keep out of the upload globs. mv "$APP" "$STAGE/" ln -s /Applications "$STAGE/Applications" -# The build tree is dead weight from here on: every binary it produced is -# already inside the bundle, and no later step in either workflow reads it. -# The cost is that rust-cache finds little left to save, so the next macOS -# build recompiles the dependency graph. That is a slower nightly; the -# alternative is no nightly at all. `df` first so the next person to look at -# this has the number that made it necessary. -df -h . || true -rm -rf "target/${TARGET}/release/deps" \ - "target/${TARGET}/release/build" \ - "target/${TARGET}/release/incremental" -hdiutil create -volname "tty7" -srcfolder "$STAGE" -ov -format UDZO "$DMG" +# Size the image explicitly. Left to itself, `-srcfolder` measures the bytes it +# is about to copy and asks for about that much, which does not cover what the +# filesystem spends carrying them — so the copy runs the *volume* out of room +# partway through and hdiutil reports "No space left on device". The path in +# that message is under /Volumes/tty7, not on the host: three nightlies died +# here on 2026-08-10 with 105 GiB free on the runner. It is a threshold, not a +# cliff — the x86_64 binaries are the larger pair and crossed it first, while +# arm64 went on building fine just underneath. +# +# Doubling the content and adding 64 MiB is far more slack than the shortfall +# needs, and it is close to free: the image is compressed on the way out, so +# measured against a stage of this shape, 127 MiB of empty volume cost 672 KiB +# in the published DMG. +STAGE_KB="$(du -sk "$STAGE" | awk '{print $1}')" +hdiutil create -volname "tty7" -srcfolder "$STAGE" -ov -format UDZO \ + -size "$(( STAGE_KB * 2 + 65536 ))k" "$DMG" rm -rf "$STAGE" if [[ -n "$SIGN_ID" && -n "${APPLE_CERTIFICATE:-}" ]]; then codesign --force --timestamp --sign "$SIGN_ID" "$DMG"