make-release.sh (6710B)
1 #!/usr/bin/env bash 2 # make-release.sh — build a distributable Hydra release: a .dmg containing the prebuilt 3 # binaries + installer, plus a source tarball. Hydra is a CLI-first tool, so the .dmg is a 4 # tidy "download, open, run ./install.sh" payload — NOT a drag-to-Applications app. 5 # 6 # ./scripts/make-release.sh [version] # version defaults to the workspace Cargo.toml 7 # 8 # Output (in dist/release/): 9 # Hydra-<ver>.dmg prebuilt arm64+x86_64 binaries + driver + install.sh + themes 10 # hydra-<ver>-src.tar.gz pristine source (for the build-it-yourself crowd) 11 # 12 # NOT notarized (no Apple Developer ID). On another Mac, Gatekeeper will require 13 # right-click → Open, and the entitled daemon / HAL driver may need manual TCC approval. 14 # Set HYDRA_SIGN_ID to a Developer ID and this same layout becomes notarizable later. 15 set -euo pipefail 16 17 ROOT="$(cd "$(dirname "$0")/.." && pwd)" 18 VER="${1:-$(grep -m1 '^version' "$ROOT/Cargo.toml" | sed 's/.*"\(.*\)".*/\1/')}" 19 OUT="$ROOT/dist/release" 20 STAGE="$OUT/Hydra-$VER" 21 22 say() { printf '\n\033[1;36m▸ %s\033[0m\n' "$1"; } 23 24 say "Hydra release $VER" 25 rm -rf "$OUT" 26 mkdir -p "$STAGE" 27 28 say "1/5 Building release binaries (universal where possible)" 29 # Build both arches so the download runs on Apple Silicon + Intel. If a target isn't 30 # installed, fall back to the host arch only (noted in the README inside the dmg). 31 ARCHES=() 32 for t in aarch64-apple-darwin x86_64-apple-darwin; do 33 if rustup target list --installed 2>/dev/null | grep -qx "$t"; then ARCHES+=("$t"); fi 34 done 35 if [ ${#ARCHES[@]} -eq 0 ]; then 36 cargo build --manifest-path "$ROOT/Cargo.toml" --release -p hydra -p hydrad 37 lipo_or_copy() { cp "$ROOT/target/release/$1" "$STAGE/bin/$1"; } 38 else 39 for t in "${ARCHES[@]}"; do 40 cargo build --manifest-path "$ROOT/Cargo.toml" --release --target "$t" -p hydra -p hydrad 41 done 42 lipo_or_copy() { 43 local out="$STAGE/bin/$1"; local ins=() 44 for t in "${ARCHES[@]}"; do ins+=("$ROOT/target/$t/release/$1"); done 45 if [ ${#ins[@]} -gt 1 ]; then lipo -create "${ins[@]}" -output "$out"; else cp "${ins[0]}" "$out"; fi 46 } 47 fi 48 mkdir -p "$STAGE/bin" 49 lipo_or_copy hydra 50 lipo_or_copy hydrad 51 52 say "2/5 Building the driver" 53 "$ROOT/scripts/build-driver.sh" >/dev/null 54 cp -R "$ROOT/driver/build/Hydra.driver" "$STAGE/Hydra.driver" 55 56 say "3/5 Staging installer + assets" 57 # A self-contained installer that uses the prebuilt bin/ instead of rebuilding from source. 58 cp "$ROOT/scripts/install-driver.sh" "$STAGE/" 59 cp "$ROOT/scripts/install-agent.sh" "$STAGE/" 60 cp "$ROOT/scripts/Info.plist" "$ROOT/scripts/hydrad.entitlements" "$STAGE/" 61 cp -R "$ROOT/themes" "$STAGE/themes" 62 cp "$ROOT/LICENSE" "$STAGE/LICENSE" 2>/dev/null || true 63 # The release-flavoured installer: signs the prebuilt daemon into Hydra.app, loads the 64 # agent, installs the driver, symlinks `hydra`. No cargo/rustc needed on the user's machine. 65 cat > "$STAGE/install.sh" <<'INSTALL' 66 #!/usr/bin/env bash 67 # Hydra installer (prebuilt release). Run from the mounted .dmg / unzipped folder. 68 # ./install.sh full install (driver needs sudo; restarts coreaudiod ~1s) 69 # ./install.sh --no-driver 70 set -euo pipefail 71 HERE="$(cd "$(dirname "$0")" && pwd)" 72 WITH_DRIVER=1; [ "${1:-}" = "--no-driver" ] && WITH_DRIVER=0 73 SIGN_ID="${HYDRA_SIGN_ID:--}" 74 say() { printf '\n\033[1;36m▸ %s\033[0m\n' "$1"; } 75 76 say "Assembling + signing Hydra.app" 77 APP="$HOME/Applications/Hydra.app" 78 mkdir -p "$APP/Contents/MacOS" 79 cp "$HERE/bin/hydrad" "$APP/Contents/MacOS/hydrad" 80 cp "$HERE/Info.plist" "$APP/Contents/Info.plist" 81 codesign --force --options runtime --sign "$SIGN_ID" --identifier com.ganten.hydra \ 82 --entitlements "$HERE/hydrad.entitlements" "$APP" 83 84 say "Installing the 'hydra' command to /usr/local/bin (sudo)" 85 sudo install -m 755 "$HERE/bin/hydra" /usr/local/bin/hydra 86 87 say "Loading the daemon LaunchAgent" 88 LABEL="com.ganten.hydrad"; PLIST="$HOME/Library/LaunchAgents/$LABEL.plist" 89 mkdir -p "$HOME/Library/LaunchAgents" 90 cat > "$PLIST" <<PLIST_EOF 91 <?xml version="1.0" encoding="UTF-8"?> 92 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 93 <plist version="1.0"><dict> 94 <key>Label</key><string>$LABEL</string> 95 <key>ProgramArguments</key><array><string>$APP/Contents/MacOS/hydrad</string></array> 96 <key>RunAtLoad</key><true/><key>KeepAlive</key><true/> 97 <key>StandardErrorPath</key><string>/tmp/hydrad.err.log</string> 98 <key>StandardOutPath</key><string>/tmp/hydrad.out.log</string> 99 </dict></plist> 100 PLIST_EOF 101 launchctl bootout "gui/$(id -u)/$LABEL" 2>/dev/null || true 102 launchctl bootstrap "gui/$(id -u)" "$PLIST" 103 launchctl kickstart -k "gui/$(id -u)/$LABEL" 104 105 say "Installing themes to ~/.config/hydra/themes" 106 mkdir -p "$HOME/.config/hydra/themes" 107 cp "$HERE/themes/"*.toml "$HOME/.config/hydra/themes/" 2>/dev/null || true 108 109 if [ "$WITH_DRIVER" = "1" ]; then 110 say "Installing the virtual-audio driver (sudo; restarts coreaudiod ~1s)" 111 HAL="/Library/Audio/Plug-Ins/HAL" 112 sudo rm -rf "$HAL/Hydra.driver" 113 sudo cp -R "$HERE/Hydra.driver" "$HAL/Hydra.driver" 114 MAN="/Library/Application Support/hydra" 115 sudo mkdir -p "$MAN"; sudo chgrp admin "$MAN"; sudo chmod 775 "$MAN" 116 sudo killall coreaudiod 2>/dev/null || true 117 fi 118 119 cat <<DONE 120 121 ✓ Hydra installed. Launch the control panel: hydra 122 In another app, pick "Hydra" as the microphone to receive routed audio. 123 Uninstall: see the project README. 124 DONE 125 INSTALL 126 chmod +x "$STAGE/install.sh" "$STAGE/install-driver.sh" "$STAGE/install-agent.sh" 127 128 # A short read-me-first inside the download. 129 cat > "$STAGE/README.txt" <<TXT 130 Hydra $VER — terminal-native virtual audio router for macOS 131 132 INSTALL 133 1. Open Terminal, cd into this folder. 134 2. ./install.sh (the driver step needs your admin password and 135 briefly restarts audio; or ./install.sh --no-driver) 136 3. Run: hydra 137 138 NOTE: this build is NOT notarized. macOS Gatekeeper may warn; if a binary is 139 blocked, right-click → Open once, or clear quarantine: 140 xattr -dr com.apple.quarantine . 141 142 macOS 14.4+ required (Core Audio process taps). GPL-3.0-or-later. Source: 143 https://ganten.neocities.org/git/ (or the bundled hydra-$VER-src.tar.gz) 144 TXT 145 146 say "4/5 Building the .dmg" 147 DMG="$OUT/Hydra-$VER.dmg" 148 hdiutil create -volname "Hydra $VER" -srcfolder "$STAGE" -ov -format UDZO "$DMG" >/dev/null 149 echo " → $DMG" 150 151 say "5/5 Source tarball" 152 TARBALL="$OUT/hydra-$VER-src.tar.gz" 153 git -C "$ROOT" archive --format=tar.gz --prefix="hydra-$VER/" -o "$TARBALL" HEAD 154 echo " → $TARBALL" 155 156 say "Done — release artifacts in $OUT" 157 ls -lh "$OUT" | grep -E "\.dmg|\.tar\.gz" 158 echo 159 echo "Checksums:" 160 ( cd "$OUT" && shasum -a 256 "Hydra-$VER.dmg" "hydra-$VER-src.tar.gz" )