fix(mac): retry DMG detach

This commit is contained in:
Vincent Koc
2026-06-21 11:03:35 +08:00
parent 51d1789cea
commit 2ca5b7c93e
2 changed files with 50 additions and 14 deletions

View File

@@ -91,6 +91,23 @@ cleanup_dmg() {
}
trap cleanup_dmg EXIT
detach_dmg() {
local attempt
for attempt in {1..15}; do
if hdiutil detach "$MOUNT_POINT" -quiet 2>/dev/null; then
MOUNTED=0
return
fi
if (( attempt >= 3 )) && hdiutil detach "$MOUNT_POINT" -force 2>/dev/null; then
MOUNTED=0
return
fi
# Finder can retain the just-closed volume briefly on macOS runners.
sleep 2
done
return 1
}
mkdir -p "$DMG_SOURCE" "$MOUNT_POINT"
cp -R "$APP_PATH" "$DMG_SOURCE/"
ln -s /Applications "$DMG_SOURCE/Applications"
@@ -161,20 +178,7 @@ end tell
EOF
fi
for i in {1..5}; do
if hdiutil detach "$MOUNT_POINT" -quiet 2>/dev/null; then
MOUNTED=0
break
fi
if [[ "$i" == "3" ]]; then
if hdiutil detach "$MOUNT_POINT" -force 2>/dev/null; then
MOUNTED=0
break
fi
fi
sleep 2
done
if [[ "$MOUNTED" == "1" ]]; then
if ! detach_dmg; then
echo "Error: Failed to detach DMG mount: $MOUNT_POINT" >&2
exit 1
fi

View File

@@ -88,6 +88,16 @@ case "$command_name" in
if [[ "\${HDIUTIL_DETACH_FAIL:-0}" == "1" ]]; then
exit 9
fi
detach_attempts_file="\${HDIUTIL_LOG}.detach-attempts"
detach_attempts=0
if [[ -f "$detach_attempts_file" ]]; then
detach_attempts="$(cat "$detach_attempts_file")"
fi
detach_attempts=$((detach_attempts + 1))
printf '%s' "$detach_attempts" > "$detach_attempts_file"
if (( detach_attempts <= \${HDIUTIL_DETACH_FAIL_COUNT:-0} )); then
exit 9
fi
;;
resize)
if [[ "\${1:-}" == "-limits" ]]; then
@@ -300,6 +310,28 @@ describe.runIf(process.platform === "darwin")("create-dmg ownership boundaries",
rmSync(path.dirname(mountPoint as string), { recursive: true, force: true });
});
it("retries a delayed DMG detach before finalizing the artifact", () => {
const app = makeValidApp();
const outputDir = mkdtempSync(path.join(tmpdir(), "openclaw-create-dmg-output-"));
tempDirs.push(outputDir);
const output = path.join(outputDir, "OpenClaw.dmg");
const tools = makeFakeDmgTools();
const result = runScript([app, output], {
...tools.env,
HDIUTIL_DETACH_FAIL_COUNT: "6",
});
expect(result.status).toBe(0);
expect(readFileSync(output, "utf8")).toBe("converted");
const log = readFileSync(tools.hdiutilLog, "utf8");
expect(log.match(/^detach /gm)).toHaveLength(7);
expect(log).toContain("detach ");
expect(log).toContain("-force");
expect(log).toContain("resize");
expect(log).toContain("convert ");
});
it("styles the private mount without closing unrelated Finder windows", () => {
const app = makeValidApp();
const outputDir = mkdtempSync(path.join(tmpdir(), "openclaw-create-dmg-output-"));