1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
#!/usr/bin/env bash
#
# Install wrong architecture packages on macOS
# - Can only install one package at a time, unless using "brew bundle"
# - Uses `brew deps --tree` to loop over dependencies
# - For speed, tries to NOT upgrade a package automatically
# - To upgrade a package, use wrongbrew.sh uninstall <packagename> && wrongbrew.sh install <packagename>
# - Based on the example from @maxirmx https://stackoverflow.com/a/70822921/3196753
#
# https://gist.github.com/tresf/9a45e1400a91f4c9c14a2240967094ff
# Halt on first error
set -e
export HOMEBREW_NO_AUTO_UPDATE=1
# The location of wrongbrew. (if you like to live in danger, set to /usr/local or /opt/homebrew)
WRONGBREW_DIR="$HOME/wrongbrew"
# The foreign arch (x86_64 or arm64)
echo "==> Host CPU: $(sysctl -n machdep.cpu.brand_string)"
if [[ $(sysctl -n machdep.cpu.brand_string) =~ "Apple" ]]; then
WRONGBREW_ARCH=x86_64
else
WRONGBREW_ARCH=arm64
fi
# Determine the current os codename (e.g. "bigsur")
# WRONGBREW_OS=bigsur
WRONGBREW_OS=$(cat '/System/Library/CoreServices/Setup Assistant.app/Contents/Resources/en.lproj/OSXSoftwareLicense.rtf' |grep 'SOFTWARE LICENSE AGREEMENT FOR ' | awk -F ' FOR ' '{print $2}' | awk -F 'OS X |macOS ' '{print $2}' | tr '[:upper:]' '[:lower:]' | awk -F '\' '{print $1}')
if [ "$WRONGBREW_ARCH" = "arm64" ]; then
WRONGBREW_BOTTLE_TAG="${WRONGBREW_ARCH}_${WRONGBREW_OS}"
else
# Intel does not have arch suffix
WRONGBREW_BOTTLE_TAG="${WRONGBREW_OS}"
fi
if [ ! -d "$WRONGBREW_DIR" ]; then
echo "==> Configuring $WRONGBREW_DIR for $WRONGBREW_ARCH using bottle \"$WRONGBREW_BOTTLE_TAG\"..."
# Prepare our directory
rm -rf "$WRONGBREW_DIR"
mkdir "$WRONGBREW_DIR" && curl -sL https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C "$WRONGBREW_DIR"
fi
WRONGBREW_BIN="$WRONGBREW_DIR/bin/brew"
# Install a package manually by bottle tag
install_single_package() {
response=$("$WRONGBREW_BIN" fetch --force --bottle-tag="${WRONGBREW_BOTTLE_TAG}" "$1" | grep "Downloaded to")
parsed=$(echo "$response" | awk -F ' to: ' '{print $2}')
"$WRONGBREW_BIN" install "$parsed" || true # force continue because python
}
# Build a depenency tree
install() {
linkbin=false
for param in "$@"; do
if [ "$param" = "--link-bin" ]; then
linkbin=true
continue
fi
# Convert deps --tree to something sortable to install in natural order
deps=($("$WRONGBREW_BIN" deps --tree "$param" | tr -c '[:alnum:]._-@\n' ' ' |sort |tr -d ' ' |uniq))
for dep in "${deps[@]}"; do
# Check using "brew list"
if "$WRONGBREW_BIN" list "$dep" &>/dev/null ; then
# By default install will check for updates for already installed packages
# Save some time by skipping a package if it's already installed
echo "==> Skipping \"$dep\", already installed"
continue
fi
install_single_package "$dep"
done
# Only link the original package
if $linkbin ; then
link_bin "$param"
fi
done
}
# Loop over a Brewfile
bundle_install() {
if [ -f "$1" ]; then
echo "==> Brewfile found: $1"
deps=($(cat Brewfile |xargs -L1 echo | awk -F 'brew ' '{print $2}'))
for dep in "${deps[@]}"; do
install "$dep"
done
else
# Shamelessly trigger the native command's error message
"$WRONGBREW_BIN" bundle
fi
}
# Moves a wrong-arch "bin" directory out of the way, symlinks the native one provided by the native
# version of brew.
#
# The "right" way to do this with CMake is to leverage CMAKE_FIND_ROOT... and friends
# but this only fixes tools in "bin". Nested tools like "qmake" still can't be found.
link_bin() {
for param in "$@"; do
# First, install the native tool(s)
brew install "$param"
# Second, rename the foriegn tool (e.g. bin_arm64)
before="$("$WRONGBREW_BIN" --prefix "$param")/bin"
after="${before}_${WRONGBREW_ARCH}"
new="$(brew --prefix "$param")/bin"
echo "==> Moving $before -> $after"
mv "$before" "$after"
# Last, link the native tool to the foriegn tool
echo "==> Linking $before -> $new"
ln -s "$new" "$before"
done
}
# Backup params
params="$@"
# For sanity reasons, let's only install one package at a time
while test $# -gt 0; do
case "$1" in
install)
shift
install $@
exit 0
;;
bundle)
if [ "$2" = "install" ]; then
if [ ! -z "$3" ]; then
bundle_install "$3"
else
bundle_install "$(pwd)/Brewfile"
fi
exit 0
fi
;;
*)
shift
;;
esac
done
# We're not installing a package, just pass the params to brew, I guess :)
"$WRONGBREW_BIN" $params
|