Disabling Homebrew in Dinosaur OS
By Christopher Burg
Since I released Dinosaur OS last September, I've had to make very few changes to my image. This is a testament to the overall stability of Bluefin, the image upon which Dinosaur OS is based. But I started receiving error notifications a couple of weeks ago whenever the automatic update service ran. The initial error was actually due to a Flatpak problem. The developer of a package I installed uploaded a new version with the same version number as my currently installed version. This cause the Flatpak update program to fail. I managed to fix that, but the service was still displaying an error because it wasn't able to update Homebrew.
Homebrew is a package manager that was originally written for macOS. It was released back when I used macOS so I tried it and discovered that it was a train wreck and opted to use MacPorts instead. Homebrew had a number of bizarre design decisions. The biggest was it wanted to install packages at a system level. Normally that's not a problem with a package manager, but Homebrew tied the system level directory to your user account's user ID number. Effectively Homebrew installed packages at a system level that only a single user account to use or modify. There was an option to install packages into your home directory, but a number of packages failed to run when you did that.
When it was announced that Homebrew was available for Linux, I dismissed it entirely. Why would I want a poorly designed package manager on a system that already has a plethora of very good package managers? My experience with Homebrew was so bad that I initially intended to remove it from Dinosaur OS. I ultimately decided that enough time had passed that I should give Homebrew another chance. My latest experience mirrored my previous experience.
Homebrew on Linux suffers the same problem as it does on macOS. It doesn't support systems with multiple user accounts well. When Bluefin installs Homebrew, it creates the /home/linuxbrew/ directory and sets its user and group IDs to 1000. Bluefin is based on Fedora and by default the first user account created on a Fedora system has the user and group IDs of 1000. All packages installed with Homebrew are installed into the /home/linuxbrew/ directory. This means Homebrew on Bluefin is configured so that only the very first user account created on the system can use it.
This is fine for most users, but I'm not most users. I have two user accounts on my system. The first is my administrator account, the second is a regular user account that I use for my day to day tasks. Administrator rights are required to create new user accounts so obviously I create my administrator account first. This means the actual account I use day to day, which has the user and group IDs of 1001 (the default on Fedora systems for the second user account created), can't use Homebrew.
There are ways around this. I could change the owner permissions on /home/linuxbrew/ to 1001. Homebrew on Bluefin is setup using the brew-setup.service systemd service, which sets the permissions. I could change that unit file in my image to set the user and group IDs to 1001. Either option would allow my day to day user account to use Homebrew installed packages, but would prevent my administrator account from using them. The bottom line is Homebrew is a poorly designed package manager.
I chose a third option: ignore Homebrew entirely. There was no downside to this option at first, but a few weeks ago changes were made to Bluefin's automatic updater that caused me to reexamine my decision. As noted at the beginning of this article, I started receiving notifications that the automatic update service failed. Checking journalctl showed me the source of the error was that the update utility, UUPD, was unable to upgrade Homebrew. This failure was caused by /home/linuxbrew/, which normally contains the brew executable used to install and update packages, being empty (I didn't investigate why it was empty since I was already done with Homebrew).
Fortunately disabling and removing Homebrew from Bluefin is straight forward. Homebrew is installed by the brew-setup.service systemd service, which is enabled by default on Bluefin. Disabling the service prevents it from automatically installing Homebrew so Dinosaur OS disables it. I also add a script, /usr/libexec/remove-brew, to the image, which removes Homebrew from a system if it's already installed. This makes Dinosaur OS nondestructive in that it won't automatically remove Homebrew from a system where it's already installed. Removing Homebrew requires manual work. It also means Homebrew can be installed again by either starting or enabling brew-setup.service.
I still had the problem where UUPD would throw an error because it was unable to update Homebrew (which was now missing entirely). UUPD on Bluefin accepts arguments that disable update modules though. The final change I made to Dinosaur OS is adding --disable-module-brew to the ExecStart line of uupd.service, which is activated by a timer periodically. uupd.service is a system file, which means the user cannot edit it. Therefore, if you're running Dinosaur OS and install Homebrew, your Homebrew packages won't be automatically updated by uupd.service. The best way to change this behavior is to copy /usr/lib/systemd/system/brew-update.service to /etc/systemd/system/uupd.service and remove --disable-module-brew from the ExecStart line.
Overall I still like Bluefin a lot. I agree with most of the design decisions and appreciate that it's been easy for me to change the decisions I dislike. I continue to run Dinosaur OS on my desktop systems and haven't faced any catastrophic problems. If you want to create your own image based on Bluefin and want an example image to get started, check the Dinosaur OS repository.