Homebrew on the lab machines
The PLSE-managed machines (whale and pipsqueak) keep their system
packages minimal on purpose: patching, endpoint protection, a compiler,
and a handful of basics. Nobody gets sudo for a research project, and
nobody should need it. Instead, each user can run their own
Homebrew in their home directory. It gives you
current versions of git, python, node, rust, tmux, vim, and
a few thousand other packages, and nobody else’s setup can break yours.
This page is the recipe. It takes a few minutes, and it works without
sudo.
Install
Run these four commands, exactly as written:
git clone https://github.com/Homebrew/brew ~/.brew/Homebrew
mkdir -p ~/.brew/bin ~/.brew/etc/homebrew
ln -s ../Homebrew/bin/brew ~/.brew/bin/brew
echo "HOMEBREW_MAKE_JOBS=$(( ($(nproc) + 1) / 2 ))" \
> ~/.brew/etc/homebrew/brew.env
That’s it. The first line is Homebrew itself. The symlink is the trick:
brew decides where its packages live from the path it was run by, so
~/.brew/bin/brew makes ~/.brew the prefix. The last line caps how
many parallel jobs a source build may use (more on that below).
Then put it on your PATH. Add this line to the end of ~/.bashrc (or
~/.zshrc if you use zsh):
eval "$(~/.brew/bin/brew shellenv)"
Log out and back in, then check:
brew --prefix # prints /home/<you>/.brew
brew update
brew analytics off
brew install ripgrep
rg --version
The first brew command you run downloads Homebrew’s own portable Ruby,
so it takes a little while. After that, most installs are “bottles”:
prebuilt binaries that unpack in seconds.
Why exactly ~/.brew
Homebrew’s Linux bottles are built for /home/linuxbrew/.linuxbrew,
and that path is baked into their binaries. Homebrew can relocate a
bottle to a different prefix, but only one that is no longer than the
original, 26 characters. /home/<you>/.brew fits for any username up
to fourteen characters. Pick a longer path and every bottle that needs
relocating builds from source instead, turning a ten-second install
into one that takes minutes or hours.
So: do not rename it, and do not run brew through the repository
path (~/.brew/Homebrew/bin/brew), which would make the repository the
prefix and hit the same problem. Always ~/.brew/bin/brew, or just
brew once it is on your PATH.
Be a good neighbor
These are shared machines with no scheduler and no quotas. A few packages have no bottle and must build from source, and a big build at full parallelism can eat a 128-thread box. Two things keep that in check:
- The
brew.envline from the install caps a build at half the machine’s threads, for the build systems that honor Homebrew’s job count (makeand friends; not every formula’s does). Homebrew reads that file on every run, so it applies in scripts and oversshtoo, not just in your shell. -
Run long builds under
nice, as with any big job here, which covers the builds the cap does not:nice brew install some-big-formula
What to expect
- Disk. A prefix with a few dozen packages runs to about a
gigabyte. A compiler toolchain or TeX runs to several. Homes on these
machines have plenty of room, but
brew cleanupnow and then keeps old versions from piling up. - Wipes. These machines are disposable. When one is reinstalled,
home directories go with it, and so does your
~/.brew. That is by design: your setup is yours to rebuild in a few minutes with the recipe above, and nobody has to reconstruct a shared toolchain. - Doctor.
brew doctorshould report “Your system is ready to brew.” If installs keep building from source, check thatbrew --prefixprints exactly/home/<you>/.brew. - Starting over. Everything lives under
~/.brew, plus a download cache in~/.cache/Homebrew. Remove both and theevalline from your shell startup, and it is gone.
Other machines
The same recipe works on the CSE-managed research machines
(recycle, bicycle, and friends), where you also cannot install
system packages. Their homes live under /homes/<group>/<you>, which
with a three-letter group like gws leaves room for a nine-character
username inside the 26-character budget. Longer than that, and the
bottles that need relocating build from source.