class Macdeploycheck < Formula desc "Sanity checks a macOS .app bundle for accidental Homebrew runtime dependencies" homepage "https://github.com/strawberrymusicplayer/strawberry" url "file://#{__FILE__}" version "0.1.0" sha256 :no_check license "MIT" depends_on :macos def install (bin/"macdeploycheck").write <<~'EOS' #!/usr/bin/env bash set -euo pipefail app="${1:-}" if [[ -z "$app" ]]; then echo "Usage: macdeploycheck " >&2 exit 2 fi if [[ ! -d "$app" ]]; then echo "Error: app bundle not found: $app" >&2 exit 2 fi if [[ ! -d "$app/Contents" ]]; then echo "Error: not a macOS app bundle (missing Contents/): $app" >&2 exit 2 fi fail=0 tmp="$(mktemp -t macdeploycheck.XXXXXX)" trap 'rm -f "$tmp"' EXIT # Collect Mach-O files (executables + dylibs) inside the bundle. while IFS= read -r -d '' f; do if file "$f" | grep -q "Mach-O"; then echo "$f" >>"$tmp" fi done < <(find "$app/Contents" -type f \( -perm -111 -o -name "*.dylib" -o -name "*.so" \) -print0 2>/dev/null) if [[ ! -s "$tmp" ]]; then echo "Warning: no Mach-O files found under $app/Contents" >&2 exit 0 fi echo "macdeploycheck: scanning for external (Homebrew) runtime deps..." while IFS= read -r f; do # otool -L prints: # : # (compatibility version ..., current version ...) deps="$(otool -L "$f" 2>/dev/null | tail -n +2 | awk '{print $1}' || true)" while IFS= read -r dep; do [[ -z "$dep" ]] && continue # Ignore system and rpath/loader/executable paths. case "$dep" in /System/*|/usr/lib/*|@rpath/*|@loader_path/*|@executable_path/*) continue ;; esac # These are the common accidental runtime deps that will break distribution. if [[ "$dep" == /opt/homebrew/* || "$dep" == /usr/local/* || "$dep" == /opt/local/* ]]; then echo "ERROR: $f links to external path: $dep" >&2 fail=1 fi done <<<"$deps" done <"$tmp" if [[ "$fail" -ne 0 ]]; then cat >&2 <<'EOM' One or more binaries in your .app link to a Homebrew (or MacPorts) path. That usually means the bundle is not self-contained and will fail on other machines, or will fail notarization/codesigning validation. Fix: re-run your deploy step (e.g. macdeployqt) so frameworks/dylibs are bundled and their install names are rewritten to @rpath/@loader_path. EOM exit 1 fi echo "OK: no external Homebrew/MacPorts runtime deps detected." exit 0 EOS chmod 0755, bin/"macdeploycheck" end test do # Basic smoke test: tool runs and prints usage. system bin/"macdeploycheck" end end