# Default \`PATH\` hierarchy: Homebrew and user binaries

**URL:** <https://universal-blue.discourse.group/t/default-path-hierarchy-homebrew-and-user-binaries/4243>\
**Category:** Bluefin\
**Tags:** developer-experience\
**Created:** [September 24, 2024, 11:37pm UTC](https://universal-blue.discourse.group/t/default-path-hierarchy-homebrew-and-user-binaries/4243 "2024-09-24T23:37:18Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![salim](https://yyz2.discourse-cdn.com/free1/user_avatar/universal-blue.discourse.group/salim/32/3536_2.png) [@salim](https://universal-blue.discourse.group/u/salim)\
**Post date:** [September 24, 2024, 11:37pm UTC](https://universal-blue.discourse.group/t/default-path-hierarchy-homebrew-and-user-binaries/4243/1 "2024-09-24T23:37:18Z")

</div>

Well, first of all: 🙇‍♂️ – Bluefin is a dream come true!

While getting accustomed with all those immutability features/oddities, I stumbled upon a quite annoying issue, at least for newcomers:

Running the bare [`gsettings`](https://manpages.debian.org/unstable/libglib2.0-bin/gsettings.1.en.html)\[1\] command just didn’t reflect my Gnome desktop settings! Whenever I changed a setting via `gsettings set <key> <value>`, it had no effect on my desktop. And settings changed via the GUI weren’t reflected in `gsettings get <key>`.

This confused me so much that I even [seeked the attention of a Gnome dev](https://gitlab.gnome.org/GNOME/gsettings-desktop-schemas/-/issues/24#note_2222703) – and wasted some of their time.

As I figured out today, Homebrew knows its own `gsettings` binary (probably pulled as a dependency of some tool I installed, I dunno). In combination with **Bluefin’s default `PATH` hierarchy** of

```sh
/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/var/home/salim/.local/bin:/var/home/salim/bin:/usr/lib64/ccache:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin

```

this lead to

```sh
> which gsettings
/home/linuxbrew/.linuxbrew/bin/gsettings

```

🤯

While I understand that Homebrew’s binaries generally are supposed to take precedence over the immutable system ones in `/usr/bin/` & Co., I’m wondering:

1. Why does Homebrew’s bin paths come before (i.e. mask) the _ **user’s** _ bin paths (`~/.local/bin` and `~/bin`)? This seems just wrong to me.

2. Is there an easy way to stop Homebrew from polluting my `PATH` (i.e. masking arbitrary system binaries) with transitive dependencies like the `gsettings` CLI\[2\] _without_ altering the general `PATH` hierarchy?

* * *

**tl;dr** : If you wanna change your desktop’s settings via the commandline, always use **`/usr/bin/gsettings`**!

* * *

1. This links to the Debian manpage, which isn’t completely accurate for our Fedora builds. But [debiman](https://github.com/Debian/debiman) renders manpages in such a perfect way that it’s hard to resist linking to them. 

2. Which doesn’t even exist as a formula itself. 

3. Which only ships a carefully selected palette of CLIs.

---

<div class="post-metadata">

**Author:** ![j0rge](https://yyz2.discourse-cdn.com/free1/user_avatar/universal-blue.discourse.group/j0rge/32/8_2.png) [@j0rge](https://universal-blue.discourse.group/u/j0rge)\
**Post date:** [September 25, 2024, 12:06am UTC](https://universal-blue.discourse.group/t/default-path-hierarchy-homebrew-and-user-binaries/4243/2 "2024-09-25T00:06:35Z")

</div>

Look in `/etc/profile.d/brew.sh` if you want to mess with the order.

1. That’s what it does by default.
2. Yeah it would be nice if we could find a way to do this. Similarly if you pull in something with systemd you’ll have a `systemctl` command in brew on the system, which is also bad. There’s probably a good list of things we could denylist.

It might be worth flipping the path to see how that works, though I suspect something else would break lol. I noticed this on my system as well:

```auto
❯ which gsettings
/home/linuxbrew/.linuxbrew/bin/gsettings

```

I guess that’s been there this whole time but I stopped doing runtime customization long ago. 😄 It would be great if someone found some time to dig into this and make a recommendation.

---

<div class="post-metadata">

**Author:** ![salim](https://yyz2.discourse-cdn.com/free1/user_avatar/universal-blue.discourse.group/salim/32/3536_2.png) [@salim](https://universal-blue.discourse.group/u/salim)\
**Post date:** [September 25, 2024, 2:52am UTC](https://universal-blue.discourse.group/t/default-path-hierarchy-homebrew-and-user-binaries/4243/3 "2024-09-25T02:52:03Z")

</div>

> There’s probably a good list of things we could denylist.

Although such a denylist sounds a lot like the poorly scaling practice of [_enumerating badness_](https://privsec.dev/posts/knowledge/badness-enumeration/), I’m afraid it’d be the only sane option if we wanna stick with Homebrew.

At least that’s my impression after reading up on [this earlier Bluefin issue where Homebrew’s bins broke Flatpaks](https://github.com/ublue-os/bluefin/issues/687). This specific issue has been “fixed” (or rather worked around) by only adding Homebrew’s bin dir to `PATH` in interactive shells.

> It might be worth flipping the path to see how that works, though I suspect something else would break lol.

I think you [already answered this](https://github.com/ublue-os/bluefin/issues/687#issuecomment-1827064427) some while ago in the aforementioned issue: Flipping the `PATH`

> (…) solves the problem, but then the issue gets flipped, if something installed via brew installs a dependency that also happens to be on the host, the host’s version will take precedence, which could be a problem.

Since Homebrew behaves like a kind of “centre of the universe” – i.e. doesn’t care about system binaries and at the same time has no concept of isolation – a denylist approach seems the only way out\[1\].

* * *

1. I sincerely hope I’m mistaken and someone more proficient comes up with a real solution to the problem… 😅🤞

---

<div class="post-metadata">

**Author:** ![ethanjli](https://yyz2.discourse-cdn.com/free1/user_avatar/universal-blue.discourse.group/ethanjli/32/479_2.png) [@ethanjli](https://universal-blue.discourse.group/u/ethanjli)\
**Post date:** [September 25, 2024, 5:48pm UTC](https://universal-blue.discourse.group/t/default-path-hierarchy-homebrew-and-user-binaries/4243/4 "2024-09-25T17:48:18Z")

</div>

Conceptually speaking, the allowlist approach (enumerating goodness) would be to install homebrew in a distrobox container in order to isolate it, and only `distrobox export` selected binaries from the distrobox container, right? I imagine there’s an important reason I’m forgetting about why we used to do that but then moved to just running homebrew on the host…after reviewing [Bluefin is feature complete - #6 by j0rge](https://universal-blue.discourse.group/t/bluefin-is-feature-complete/703/6) , it seems like the initial reasoning at the time for going back the homebrew on the host (after the discovery of the workaround to only change PATH in interactive shells) was to keep the UX and system architecture simpler to understand?

---

<div class="post-metadata">

**Author:** ![j0rge](https://yyz2.discourse-cdn.com/free1/user_avatar/universal-blue.discourse.group/j0rge/32/8_2.png) [@j0rge](https://universal-blue.discourse.group/u/j0rge)\
**Post date:** [September 25, 2024, 7:02pm UTC](https://universal-blue.discourse.group/t/default-path-hierarchy-homebrew-and-user-binaries/4243/5 "2024-09-25T19:02:59Z")

</div>

> [@ethanjli](#):
>
> keep the UX and system architecture simpler to understand?

Yeah. I tried brew-in-a-distrobox the other day and I couldn’t stand it haha. I think maybe some best practices to put in the docs will get us there, it’s been a long time and we’re only seeing this one now so it shouldn’t be hard for me to toss it into the docs this weekend.

(Also what is gsettings even doing in brew to begin with lol that makes no sense to me.)

---

<div class="post-metadata">

**Author:** ![salim](https://yyz2.discourse-cdn.com/free1/user_avatar/universal-blue.discourse.group/salim/32/3536_2.png) [@salim](https://universal-blue.discourse.group/u/salim)\
**Post date:** [September 25, 2024, 8:03pm UTC](https://universal-blue.discourse.group/t/default-path-hierarchy-homebrew-and-user-binaries/4243/6 "2024-09-25T20:03:32Z")

</div>

> [@ethanjli](#):
>
> the allowlist approach (enumerating goodness) would be to install homebrew in a distrobox container in order to isolate it, and only `distrobox export` selected binaries from the distrobox container

That sounds like a sane approach to me, actually. As long as the `distrobox export` could be made automatic based on _what the user really intended to install (and thus expose to the host)_, rather than all of the (transitive) dependencies brew pulls in.

> [@ethanjli](#):
>
> it seems like the initial reasoning at the time for going back the homebrew on the host (…) was to keep the UX and system architecture simpler to understand?

I don’t think the current situation is particularly _simple to understand_… 😅 IMHO, it’s not at all clear to the user what (transitive) dependencies get pulled in – masking commands on the host – when they run a simple `brew install TOOL`.

> [@j0rge](#):
>
> (Also what is gsettings even doing in brew to begin with lol that makes no sense to me.)

Try `brew install netlify-cli`…

> **Spoiler**
>
> ```raw
> ==> Installing dependencies for netlify-cli: cfitsio, cgif, liblqr, jasper, libraw, imagemagick, libexif, libaec, pkg-config, hdf5, libmatio, gdk-pixbuf, librsvg, libspng, mozjpeg, uthash, libdicom, openslide, libassuan, libksba, systemd, libusb, npth, libsecret, pinentry, gnupg, gpgme, nspr, nss, poppler, vips and xsel 
> 
> ```

Currently, my Bluefin gives

> **brew list**
>
> ```raw
> ==> Formulae
> age ca-certificates erdtree gh img2pdf libb2 libmatio libssh2 libxfixes mpfr openssl@3 pycparser srt vips
> alsa-lib cairo expat ghostscript isl libbluray libmicrohttpd libtasn1 libxi mpg123 opus python-packaging svt-av1 webp
> aom certifi eza giflib jasper libcap libmpc libtiff libxinerama ncurses orc python@3.12 syncthing x264
> apr cffi fd git-sizer jbig2dec libde265 libnghttp2 libtirpc libxml2 neonctl p11-kit qpdf systemd x265
> apr-util cfitsio ffmpeg glab jbig2enc libdicom libnsl libtool libxrandr netlify-cli pandoc rav1e taplo xinput
> argon2 cgif fftw glib jpeg-turbo libedit libogg libunibreak libxrender nettle pandoc-crossref readline tcl-tk xorgproto
> aribb24 cjson flac gmp jpeg-xl libevent libpng libunistring libxscrnsaver nixpacks pango ripgrep tealdeer xsel
> aspell cryptography flyctl gnupg jq libexif libpq libusb libxslt node pcre2 rtmpdump tesseract xvid
> ast-grep curl fnm gnutls krb5 libffi libraqm libuv libxv npth perl rubberband theora xz
> atuin dart fontconfig go ladspa-sdk libgcrypt libraw libvidstab libxxf86vm nspr phoronix-test-suite rustup tidy-html5 yq
> autoconf dasel freetds gpgme lame libgit2 librespeed-cli libvmaf libzip nss php s5cmd ugrep zeromq
> b2-tools dav1d freetype graphite2 lazydocker libgit2@1.7 librist libvorbis little-cms2 ocrmypdf pillow sass unbound zimg
> bash dbus frei0r harfbuzz lazygit libgpg-error librsvg libvpx lz4 ollama pinentry sd uni zlib
> bat device-mapper fribidi hdf5 leptonica libheif libsamplerate libx11 lzo oniguruma pixman sdl2 unixodbc zoxide
> berkeley-db@5 diceware fzf highway libaec libice libsecret libxau m4 open-mpi pkg-config shared-mime-info unpaper zstd
> binutils diffr gcc hugo libaio libidn libsndfile libxcb mawk opencore-amr pmix shellcheck unzip
> brotli direnv gd hwloc libarchive libidn2 libsodium libxcrypt mbedtls openexr pngquant snappy uthash
> buf dive gdbm icu4c libass libimagequant libsoxr libxcursor micro openjpeg poppler speex util-linux
> bzip2 dnsping gdk-pixbuf imagemagick libassuan libksba libspng libxdmcp mozjpeg openldap pulseaudio speexdsp uv
> c-ares dysk gettext imath libavif liblqr libssh libxext mpdecimal openslide pybind11 sqlite vamp-plugin-sdk 
> 
> ```

[`ls -1 /home/linuxbrew/.linuxbrew/bin`](https://gist.github.com/salim-b/822e1c5fc4fe6044a39c1d18c52016b0)

[`ls -1 /home/linuxbrew/.linuxbrew/sbin`](https://gist.github.com/salim-b/5653f4361a274c10141c151d408d817b)

(output of the last two commands exceeded Discourse’s max allowed chars per post, hence the links)

So I guess `gsettings` appears to be the least of the worries, compared to the stuff from the `util-linux` cellar… 😵

---

<div class="post-metadata">

**Author:** ![marlowe221](https://yyz2.discourse-cdn.com/free1/user_avatar/universal-blue.discourse.group/marlowe221/32/1459_2.png) [@marlowe221](https://universal-blue.discourse.group/u/marlowe221)\
**Post date:** [September 25, 2024, 10:01pm UTC](https://universal-blue.discourse.group/t/default-path-hierarchy-homebrew-and-user-binaries/4243/7 "2024-09-25T22:01:53Z")

</div>

Shoot, I’m still not sure if I should be using Hombrew on the host or the `bluefin-cli`… or how to know when I would want to use one or the other of those!

---

<div class="post-metadata">

**Author:** ![j0rge](https://yyz2.discourse-cdn.com/free1/user_avatar/universal-blue.discourse.group/j0rge/32/8_2.png) [@j0rge](https://universal-blue.discourse.group/u/j0rge)\
**Post date:** [September 25, 2024, 10:08pm UTC](https://universal-blue.discourse.group/t/default-path-hierarchy-homebrew-and-user-binaries/4243/8 "2024-09-25T22:08:44Z")

</div>

> [@marlowe221](#):
>
> how to know when I would want to use one or the other of those!

The docs don’t mention the container, you only need that if you’re looking for it and want it.

---

<div class="post-metadata">

**Author:** ![marlowe221](https://yyz2.discourse-cdn.com/free1/user_avatar/universal-blue.discourse.group/marlowe221/32/1459_2.png) [@marlowe221](https://universal-blue.discourse.group/u/marlowe221)\
**Post date:** [September 25, 2024, 10:11pm UTC](https://universal-blue.discourse.group/t/default-path-hierarchy-homebrew-and-user-binaries/4243/9 "2024-09-25T22:11:20Z")

</div>

Ok, cool. I have kind of been treating brew on the host as the “default” for things I want system-wide. Stuff I need in a particular container for development purposes… I install in that container.

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/univeral_blue/original/2X/e/e39f7d1952979cf23b0f8d634e025fb38da50026.png) [@system](https://universal-blue.discourse.group/u/system)\
**Post date:** [December 24, 2024, 10:12pm UTC](https://universal-blue.discourse.group/t/default-path-hierarchy-homebrew-and-user-binaries/4243/10 "2024-12-24T22:12:08Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
