igneum/packaging/mac/build-dmg.sh
igneum-labs 38380d9035 Release: devnet v4 cut-over staged (Windows 0.2.0 packages, Mac app 0.2.0, seed igneumd-v4 unit, runbook)
Windows combined package 0.2.0 (proto-cuda/windows-app): v4 exes from target-integration, peers = seed then Mac,
fresh appdir devnet-v4, one miner and one worker per card with --identities 8, --evm-address (PAYOUT_EVM or derived
per vendor from the PC name), voting on (VOTE=0 opts out), --prepare-packs for the hot swap with --exit-on-seed-change
as the fallback, --yes on the node, STATUS regex tolerant of the v4 now= segment, version in the dashboard header.
Mac app 0.2.0 (packaging/mac): v4 binaries, Metal worker rebuilt for macOS 11, data folder devnet-v4, EVM payout,
identities in one process, synced= flag honoured. Seed (infra/seed-nodes): stage-v4.sh builds v4 on the VM as a
niced, memory-capped transient service and installs a disabled igneumd-v4 unit with a fresh data dir; switch-v4.sh
swaps the units (--back reverses); health.sh reports active-v4. Runbook: docs/plans/cutover-2026-10-04.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 01:48:56 +00:00

108 lines
6.2 KiB
Bash
Executable file

#!/bin/bash
# Builds packaging/mac/dist/Igneum-Miner-<version>.dmg: "Igneum Miner.app" + README.txt + "Stop Igneum Miner.command" +
# a link to /Applications, on a branded image (volume "Igneum Miner", coin volume icon, background with the drag arrow,
# icons placed). Reuses the binaries already built in the repo (nothing is compiled here); copies of the binaries are
# stripped and re-signed ad hoc (strip invalidates the linker signature, and arm64 macOS refuses to run an unsigned
# binary). The originals are not touched. 3 October 2026; 0.2.0 for devnet v4 on 4 October 2026.
#
# packaging/mac/build-dmg.sh build
# NODE=<path> packaging/mac/build-dmg.sh use another node binary
# 0.2.0 defaults: igneumd and igneum-miner from vendor/igneum-node/target-integration/release (the devnet-v4 integration
# build of vendor/igneum-node-v4 at dc749905) and the Metal worker rebuilt from proto-metal/main.swift (the hot-swap
# source: its ready line says "prepare 1") with `-target arm64-apple-macos11`, so the worker loads on any Apple silicon
# macOS and not only on the build machine's (the committed proto-metal/igneum-bench-hotswap carries minos 16.0).
# WORKER=<path> skips that rebuild; REBUILD_WORKER=0 uses proto-metal/igneum-bench-hotswap as is.
# Needs: brand/icons/igneum.icns and dmg-background.tiff (python3 brand/icons/make-icons.py) and dmgbuild
# (pip3 install dmgbuild) for the icon layout. Without dmgbuild a plain hdiutil image is built and said so.
set -euo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
ROOT="$(cd "$HERE/../.." && pwd)"
VERSION="0.2.0"
NODE="${NODE:-$ROOT/vendor/igneum-node/target-integration/release/igneumd}"
MINER="${MINER:-$ROOT/vendor/igneum-node/target-integration/release/igneum-miner}"
WORKER="${WORKER:-}"
REBUILD_WORKER="${REBUILD_WORKER:-1}"
ICONS="$ROOT/brand/icons"
BUILD="$HERE/build"
DIST="$HERE/dist"
DMG="$DIST/Igneum-Miner-$VERSION.dmg"
STAGE="$BUILD/dmg"
APP="$STAGE/Igneum Miner.app"
STAMP="$(date -u +%Y%m%d%H%M)"
if [ ! -x "$NODE" ]; then
if [ -x "$ROOT/vendor/igneum-node/target/release/kaspad" ]; then
echo "note: $NODE is missing; using target/release/kaspad renamed to igneumd"
NODE="$ROOT/vendor/igneum-node/target/release/kaspad"
else
echo "no node binary at $NODE"; exit 1
fi
fi
[ -x "$MINER" ] || { echo "missing: $MINER"; exit 1; }
for f in "$NODE" "$MINER"; do
file "$f" | grep -q 'arm64' || { echo "$f is not an arm64 binary"; exit 1; }
done
[ -f "$ICONS/igneum.icns" ] || { echo "no $ICONS/igneum.icns; run: python3 brand/icons/make-icons.py"; exit 1; }
rm -rf "$BUILD"
mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources/bin" "$DIST"
# the Metal worker: rebuilt from main.swift for macOS 11 and later (about 7 s), else the committed hot-swap binary
if [ -z "$WORKER" ]; then
if [ "$REBUILD_WORKER" = 1 ] && command -v swiftc >/dev/null 2>&1; then
mkdir -p "$BUILD/worker"
echo "building the Metal worker from proto-metal/main.swift with -target arm64-apple-macos11"
(cd "$ROOT/proto-metal" && nice -n 19 swiftc -O -target arm64-apple-macos11 -o "$BUILD/worker/igneum-bench" main.swift -framework Metal)
WORKER="$BUILD/worker/igneum-bench"
else
WORKER="$ROOT/proto-metal/igneum-bench-hotswap"
echo "note: using $WORKER as built (its load command says minos $(otool -l "$WORKER" | awk '/minos/ { print $2; exit }'); a rebuild with -target arm64-apple-macos11 needs swiftc)"
fi
fi
[ -x "$WORKER" ] || { echo "missing: $WORKER"; exit 1; }
file "$WORKER" | grep -q 'arm64' || { echo "$WORKER is not an arm64 binary"; exit 1; }
echo "worker: $WORKER (minos $(otool -l "$WORKER" | awk '/minos/ { print $2; exit }'))"
# the bundle
sed "s/VERSION_STAMP/$STAMP/" "$HERE/app/Info.plist" > "$APP/Contents/Info.plist"
plutil -lint "$APP/Contents/Info.plist" >/dev/null
printf 'APPL????' > "$APP/Contents/PkgInfo"
cp "$HERE/app/launcher.sh" "$APP/Contents/MacOS/Igneum Miner"
cp "$HERE/app/igneum-miner.sh" "$APP/Contents/Resources/igneum-miner.sh"
cp "$ICONS/igneum.icns" "$APP/Contents/Resources/igneum.icns"
cp "$NODE" "$APP/Contents/Resources/bin/igneumd"
cp "$MINER" "$APP/Contents/Resources/bin/igneum-miner"
cp "$WORKER" "$APP/Contents/Resources/bin/igneum-bench"
chmod 755 "$APP/Contents/MacOS/Igneum Miner" "$APP/Contents/Resources/igneum-miner.sh" "$APP/Contents/Resources/bin/"*
# strip the copies, then sign them ad hoc again
for b in "$APP/Contents/Resources/bin/"*; do
before=$(stat -f %z "$b")
strip "$b" 2>/dev/null || strip -x "$b"
codesign -s - -f "$b" 2>/dev/null
codesign -v "$b"
echo "$(basename "$b"): $before -> $(stat -f %z "$b") bytes, signed ad hoc"
done
# each copy must still run
v="$("$APP/Contents/Resources/bin/igneumd" --version 2>&1 || true)"; echo "node: ${v%%$'\n'*}"
v="$("$APP/Contents/Resources/bin/igneum-miner" 2>&1 || true)"; case "$v" in usage*) ;; *) echo "igneum-miner copy does not run: $v"; exit 1 ;; esac
v="$(echo quit | "$APP/Contents/Resources/bin/igneum-bench" --serve 2>&1)"; case "$v" in "ready metal"*) echo "worker: $v" ;; *) echo "igneum-bench copy does not serve: $v"; exit 1 ;; esac
case "$v" in *"prepare 1"*) ;; *) echo "note: this worker has no prepare support (no hot swap at the hour boundary); the miner falls back to exit 42" ;; esac
v="$("$APP/Contents/Resources/bin/igneum-miner" 2>&1 || true)"; case "$v" in *"--evm-address"*) ;; *) echo "igneum-miner copy is not the devnet-v4 miner (no --evm-address in its usage)"; exit 1 ;; esac
# the rest of the image
cp "$HERE/dmg/README.txt" "$STAGE/README.txt"
cp "$HERE/app/Stop Igneum Miner.command" "$STAGE/Stop Igneum Miner.command"
chmod 755 "$STAGE/Stop Igneum Miner.command"
rm -f "$DMG"
if command -v dmgbuild >/dev/null 2>&1; then
dmgbuild -s "$HERE/dmg/settings.py" -D "app=$APP" -D "stage=$STAGE" -D "icons=$ICONS" "Igneum Miner" "$DMG"
else
echo "note: dmgbuild is not installed (pip3 install dmgbuild); building a plain image without icon positions or background"
ln -s /Applications "$STAGE/Applications"
cp "$ICONS/igneum.icns" "$STAGE/.VolumeIcon.icns"
hdiutil create -volname "Igneum Miner" -srcfolder "$STAGE" -ov -format ULFO -fs HFS+ "$DMG" >/dev/null
fi
hdiutil verify "$DMG" >/dev/null
echo "built $DMG ($(du -h "$DMG" | cut -f1), $(stat -f %z "$DMG") bytes, version $VERSION build $STAMP)"