chore(brew): Use ublue-os Brew tarball & unlink some crucial system dependencies (#402)

* chore(brew): Use ublue-os Brew tarball & unlink some crucial system dependencies

* chore(brew): Adjust logs

* fix(brew): Don't fail `upgrade` if `systemd` or `dbus` don't exist

* docs(brew): Slight fix

* docs(brew): Fix grammar
This commit is contained in:
fiftydinar 2025-03-20 00:11:23 +01:00 committed by GitHub
parent 8a040edfae
commit b99fc2890b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 32 additions and 45 deletions

View file

@ -3,35 +3,30 @@
The brew module installs [Homebrew / Linuxbrew](https://brew.sh/) on your system and ensures the package manager remains updated and maintained. This module also sets up systemd services to periodically update the installed Brew packages.
## Features
- Installs Brew at build-time.
- Downloads Brew in build-time & installs it in run-time.
- Sets up systemd services to automatically update Brew to the latest version.
- Sets up systemd services to automatically upgrade Brew packages.
- Sets up bash and fish completions for Brew.
## How it works
### Directory paths glossary:
- `/home/` is a symlink to `/var/home/`
- `/root/` is a symlink to `/var/roothome/`
### Build-time:
- Necessary Brew package dependency `gcc` is installed if not present in the base image
- Directories `/home/` & `/root/` are created
- Empty `.dockerenv` file is created in the root of the image-builder, to convince official Brew installation script that we are **not** running as root
- Official brew installation script is downloaded & executed
- Brew is extracted to `/home/linuxbrew/` by the official script (`/root/` is needed, since image-builds are running as root)
- Brew in `/home/linuxbrew/` is compressed in tar, copied to `/usr/share/homebrew/` & permissions to it are set to default user (UID 1000)
- `brew-update` & `brew-upgrade` SystemD service timers are enabled (by default)
- Necessary Brew package dependency `gcc` & `zstd` is installed if not present in the base image.
- Brew tarball is downloaded from [Universal Blue 'packages' GitHub releases](https://github.com/ublue-os/packages/releases).
- Brew tarball is extracted to `/usr/share/homebrew/`.
- `/usr/share/homebrew/` permissions are set to the default user (UID/GID 1000).
- `brew-update` & `brew-upgrade` SystemD service timers are enabled (by default).
- A fix for path conflicts between system & brew packages with the same name is applied by adding Brew to path only in interactive shells, unlike what Brew does by default.
- Brew bash & fish shell completions are copied to `/etc/profile.d/brew-bash-completions.sh` & `/usr/share/fish/vendor_conf.d/brew-fish-completions.fish`
- Set option that Brew's shell environment can't be ran as root, respecting Homebrew's recommendation that only user with UID/GID 1000 can manage Brew.
- Brew bash & fish shell completions are copied to `/etc/profile.d/brew-bash-completions.sh` & `/usr/share/fish/vendor_conf.d/brew-fish-completions.fish`.
- `tmpfiles.d` configuration `homebrew.conf` is written with these directory locations:
- `/var/lib/homebrew/`
- `/var/cache/homebrew/`
- `/home/linuxbrew/`
- `brew-setup` service is enabled
- `brew-setup` service is enabled.
### Boot-time:
### Run-time:
**`tmpfiles.d homebrew.conf`:**
- This configuration is telling SystemD to: automatically create these necessary directories on every system boot if not available & to give them permissions of the default user (UID 1000):
@ -40,16 +35,16 @@ The brew module installs [Homebrew / Linuxbrew](https://brew.sh/) on your system
- `/home/linuxbrew/`
**`brew-setup`:**
- `brew-setup` SystemD service checks if main directory used by Brew exists (`/home/linuxbrew/.linuxbrew/`)
& if `brew-setup` state file exists (`/etc/.linuxbrew`)
- If one of those paths don't exist, then Homebrew tar is extracted from `/usr/share/homebrew/homebrew.tar.zst` to `/tmp/homebrew/`
- Extracted Homebrew is then copied from `/tmp/homebrew/` to `/home/linuxbrew/` & permissions to it are set to default user (UID 1000)
- Temporary directory `/tmp/homebrew/` is removed
- Empty file `/etc/.linuxbrew` is created, which indicates that brew-setup (installation) is successful & which allows setup to run again on next boot when removed
- `brew-setup` installs `brew` in runtime.
SystemD service checks if main directory used by Brew exists (`/home/linuxbrew/.linuxbrew/`) & if `brew-setup` state file exists (`/etc/.linuxbrew`).
- If one of those paths don't exist, then extracted Brew tarball is copied from `/usr/share/homebrew/` to `/home/linuxbrew/`.
- Permissions to `/home/linuxbrew/` are set to the default user (UID/GID 1000).
- Empty file `/etc/.linuxbrew` is created, which indicates that brew-setup (installation) is successful & which allows setup to run again on next boot when removed.
**Rest of the setup:**
- `brew-update` runs at the specified time to update Brew to the latest version
- `brew-upgrade` runs at the specified time to upgrade Brew packages
- `brew-update` runs at the specified time to update Brew to the latest version.
- `brew-upgrade` runs at the specified time to upgrade Brew packages.
It additionally unlinks conflicting Brew dependencies if installed, like systemd & dbus, to prevent crucial system programs being preferred by Brew.
## Development
Setting `DEBUG=true` inside `brew.sh` will enable additional output for debugging purposes during development.

View file

@ -85,24 +85,18 @@ if [[ -z "${BREW_ANALYTICS}" || "${BREW_ANALYTICS}" == "null" ]]; then
BREW_ANALYTICS=true
fi
# Create necessary directories
mkdir -p /var/home
mkdir -p /var/roothome
# Download Brew
BREW_TARBALL_LINK="$(curl -fLs https://api.github.com/repos/ublue-os/packages/releases | jq -r '.[] | .assets[] | select(.name? | match("homebrew-x86_64.tar.zst")) | .browser_download_url' | head -n 1)"
echo "Downloading Brew tarball..."
curl -fLs --create-dirs "${BREW_TARBALL_LINK}" -o "/tmp/homebrew-tarball.tar.zst"
echo "Downloaded Brew tarball"
# Convince the installer that we are in CI
touch /.dockerenv
# Always install Brew
echo "Downloading and installing Brew..."
curl -fLs --create-dirs https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh -o /tmp/brew-install
echo "Downloaded Brew install script"
chmod +x /tmp/brew-install
/tmp/brew-install
# Move Brew installation and set ownership to default user (UID 1000)
tar --zstd -cvf /usr/share/homebrew.tar.zst /home/linuxbrew/.linuxbrew
cp -R /home/linuxbrew /usr/share/homebrew
chown -R 1000:1000 /usr/share/homebrew
# Extract Brew tarball to /usr/share/homebrew/ and set ownership to default user (UID 1000)
echo "Extracting Brew tarball to '/usr/share/homebrew/'"
mkdir -p "/usr/share/homebrew/"
tar -I zstd --preserve-permissions -xf "/tmp/homebrew-tarball.tar.zst" -C "/usr/share/homebrew/"
echo "Setting '/usr/share/homebrew/' permissions to UID/GID 1000"
chown -R 1000:1000 "/usr/share/homebrew/"
# Write systemd service files dynamically
echo "Writing brew-setup service"
@ -116,11 +110,8 @@ ConditionPathExists=!/var/home/linuxbrew/.linuxbrew
[Service]
Type=oneshot
ExecStart=/usr/bin/mkdir -p /tmp/homebrew
ExecStart=/usr/bin/tar --zstd -xvf /usr/share/homebrew.tar.zst -C /tmp/homebrew
ExecStart=/usr/bin/cp -R -n /tmp/homebrew/home/linuxbrew/.linuxbrew /var/home/linuxbrew
ExecStart=/usr/bin/cp -R -n /usr/share/homebrew/home/linuxbrew/.linuxbrew /var/home/linuxbrew
ExecStart=/usr/bin/chown -R 1000:1000 /var/home/linuxbrew
ExecStart=/usr/bin/rm -rf /tmp/homebrew
ExecStart=/usr/bin/touch /etc/.linuxbrew
[Install]
@ -159,6 +150,7 @@ Environment=HOMEBREW_CELLAR=/home/linuxbrew/.linuxbrew/Cellar
Environment=HOMEBREW_PREFIX=/home/linuxbrew/.linuxbrew
Environment=HOMEBREW_REPOSITORY=/home/linuxbrew/.linuxbrew/Homebrew
ExecStart=/usr/bin/bash -c "/home/linuxbrew/.linuxbrew/bin/brew upgrade"
ExecStartPost=/usr/bin/bash -c "if [[ -n \"\$(/home/linuxbrew/.linuxbrew/bin/brew list --formulae | awk '/(^|\\s)(dbus)($|\\s)/')\" ]]; then /home/linuxbrew/.linuxbrew/bin/brew unlink dbus; fi; if [[ -n \"\$(/home/linuxbrew/.linuxbrew/bin/brew list --formulae | awk '/(^|\\s)(systemd)($|\\s)/')\" ]]; then /home/linuxbrew/.linuxbrew/bin/brew unlink systemd; fi"
EOF
# Write systemd timer files dynamically
@ -236,7 +228,7 @@ d /var/home/linuxbrew 0755 1000 1000 - -
EOF
# Enable the setup service
echo "Enabling brew-setup service"
echo "Enabling brew-setup service to install Brew in run-time"
systemctl enable brew-setup.service
# Always enable or disable update and upgrade services for consistency