brew icon indicating copy to clipboard operation
brew copied to clipboard

add option to favor brew-installed programs

Open todd-dsm opened this issue 1 year ago • 8 comments

Verification

  • [X] This issue's title and/or description do not reference a single formula e.g. brew install wget. If they do, open an issue at https://github.com/Homebrew/homebrew-core/issues/new/choose instead.

Provide a detailed description of the proposed feature

Request for Enhancement

Would it be possible to add paths as a final step in the install process? Something like:

brew install gnu-sed --override-os=true

This is particularly useful being on macOS using the UNIX version of sed. But, the target OS is typically Linux, so the GNU version of sed will actually execute the script. These 2 programs have a majority overlap but there are subtle differences that are a bit confusing for newer users.

What is the motivation for the feature?

I've had to setup automation to install all of my homebrew programs because it's become fairly routine/monotonous.

The macOS versions of the programs work well enough but they're typically out of date and if we only used those we'd miss new features when they actually arrive.

When writing this automation, the gluey bits that need to occur (sed) so macOS favors the homebrew versions over the ones that come with the OS will find them first and use them. The sed expression would look like:

sudo sed -i "\|/usr/local/bin|i /path/to/bin" /etc/paths

For Example, my paths looks like this:

% cat /etc/paths
/opt/homebrew/opt/gnu-sed/libexec/gnubin
/opt/homebrew/opt/grep/libexec/gnubin
/opt/homebrew/opt/findutils/libexec/gnubin
/opt/homebrew/opt/coreutils/libexec/gnubin
/opt/homebrew/opt/gnu-which/libexec/gnubin
/opt/homebrew/opt/make/libexec/gnubin
/opt/homebrew/opt/gnu-tar/libexec/gnubin
/opt/homebrew/opt/gnu-time/libexec/gnubin
/opt/homebrew/opt/gnu-indent/libexec/gnubin
/opt/homebrew/opt/gnu-sed/libexec/gnubin
/opt/homebrew/opt/grep/libexec/gnubin
/opt/homebrew/opt/findutils/libexec/gnubin
/opt/homebrew/opt/coreutils/libexec/gnubin
/opt/homebrew/opt/gnu-which/libexec/gnubin
/opt/homebrew/opt/make/libexec/gnubin
/opt/homebrew/opt/gnu-tar/libexec/gnubin
/opt/homebrew/opt/gnu-time/libexec/gnubin
/opt/homebrew/opt/gnu-indent/libexec/gnubin
/opt/homebrew/opt/ssh-copy-id/bin
/opt/homebrew/opt/[email protected]/libexec/bin/python
/usr/local/bin
/usr/local/sbin
/usr/bin
/bin
/usr/sbin
/sbin

This is the painful part. Especially where the Python line is concerned; that line needs to be updated periodically because of the version number.

How will the feature be relevant to at least 90% of Homebrew users?

This will allow everyone to

  1. write a configuration script to setup a new laptop easily
  2. favor the home-brewed versions of programs
  3. get back to work

This may be the missing bit that allows the community to start creating/sharing modules 🤞

What alternatives to the feature have been considered?

There are no alternatives with the one exception of wroting it all out long-hand; here's an example.

Been manicuring this for years. It's painful but this update would nullify the most painful part of the process.

todd-dsm avatar Feb 08 '24 01:02 todd-dsm

Thanks for the issue!

brew install gnu-sed --override-os=true

We used to have homebrew-core options like this in the past but we can't/won't add them back, sorry.


Does brew link gnu-sed do anything close to what you want?

MikeMcQuaid avatar Feb 12 '24 14:02 MikeMcQuaid

Not really, the only useful moves are:

  1. insert each of the program's paths into /etc/paths (as above), or
  2. export the path so subsequent scripting can take place.

Anything that leaves /etc/paths unconfigured won't really work. I'm already doing those acrobatics; if no change then I'll just have to continue doing all of that work.


But, as an exploratory, here's an example:

Homebrew is already capturing the path /opt/homebrew/opt/gnu-sed/libexec/gnubin.

% brew reinstall gnu-sed
==> Downloading https://ghcr.io/v2/homebrew/core/gnu-sed/manifests/4.9
################################################################################################################################################################################################# 100.0%
==> Fetching gnu-sed
==> Downloading https://ghcr.io/v2/homebrew/core/gnu-sed/blobs/sha256:1c4c92a7683dcbd3d251bf2e541ed46151401423cc9cbf30db9ce7185dc218a3
################################################################################################################################################################################################# 100.0%
==> Reinstalling gnu-sed 
==> Pouring gnu-sed--4.9.arm64_sonoma.bottle.tar.gz
==> Caveats
GNU "sed" has been installed as "gsed".
If you need to use it as "sed", you can add a "gnubin" directory
to your PATH from your bashrc like:

    PATH="/opt/homebrew/opt/gnu-sed/libexec/gnubin:$PATH"
==> Summary
🍺  /opt/homebrew/Cellar/gnu-sed/4.9: 12 files, 613.8KB

Given the project doesn't want to get into modifying /etc/paths, the request would then be to export that path so it can be reused:

export pathSed=/opt/homebrew/opt/gnu-sed/libexec/gnubin

Then, folks with subsequent projects (like mine) could simply:

sudo sed -i "\|/usr/local/bin|i /${pathSed}" /etc/paths


Would exposing that variable to the rest of us be within reach?

todd-dsm avatar Feb 15 '24 20:02 todd-dsm

the request would then be to export that path so it can be reused:

Where would/could it be exported to? A file somewhere or do you mean in the environment?

Would you want to do this unconditionally for everything installed or just select packages? If select packages: how would/do you select these?

MikeMcQuaid avatar Feb 16 '24 08:02 MikeMcQuaid

The basic idea is to favor GNU versions of programs over the macOS/UNIX ones but I suppose there would be other (like git and curl) as well.

They could be exported as above, or written to a file: (just spit-balling)

% tree /tmp/brewed-program-*
/tmp/brewed-date.path
/tmp/brewed-grep.path
/tmp/brewed-sed.path

Could try a few as a quick pilot, like the ones listed above in the /etc/paths file:

sed, awk, grep, findutils, coreutils, which, make, tar, time, indent, curl, git, etc.

one or 2 would do it.

Then, those paths could be picked up by:

paths=(/tmp/brewed-*.path)

From there it's a while loop away from configuring the paths file.

On second thought, exporting might get a little weird, spawning child-shells and all of that. Could try it though 🤷

todd-dsm avatar Feb 16 '24 21:02 todd-dsm

The basic idea is to favor GNU versions of programs over the macOS/UNIX ones

Just to note: one of the reasons this isn't done by default/overly easily in Homebrew is this tends to break scripts on macOS which expect the macOS tools, not the GNU ones.

I suppose there would be other (like git and curl) as well.

These don't have a gnubin folder and git isn't keg-only (i.e. is linked by default) so not sure I understand this bit?

written to a file: (just spit-balling)

What would be in the file? How would reading this file be different to adding /opt/homebrew/opt/gnu-sed/libexec/gnubin to a file if you're not wanting to add every installed Homebrew formula in here?

exporting might get a little weird

Yes. Homebrew cannot export. You'd have to source a file from Homebrew to have it export anything.

MikeMcQuaid avatar Feb 19 '24 13:02 MikeMcQuaid

Just to note: one of the reasons this isn't done by default/overly easily in Homebrew is this tends to break scripts on macOS which expect the macOS tools, not the GNU ones.

I've been doing this for years(2015?), hence all of the scripting. There's never been an issue with the system failing to perform some administrative task, upgrades, etc. My MBP is monitored fairly closely and no signs of that being a real issue.

These don't have a gnubin folder and git isn't keg-only (i.e. is linked by default) so not sure I understand this bit?

This is likely my Homebrew ignorance. I've been using it since the beginning and I still have no idea what keg-only is 😂 However, if it's auto-linked or somehow takes precedence over the binary that ships with macOS, then perfect. No need to do anything.

Yes. Homebrew cannot export. You'd have to source a file from Homebrew to have it export anything.

Sorry, I never shared the file contents; if Homebrew left something like this behind:

OPTION-A
% cat /tmp/brewed-date.path
export brewdGNUDate='/opt/homebrew/opt/gnu-time/libexec/gnubin'
OPTION-B
% cat /tmp/brewed-programs.path
export brewdGNUDate='/opt/homebrew/opt/gnu-time/libexec/gnubin'
export brewdGNUSed='/opt/homebrew/opt/gnu-sed/libexec/gnubin'
export brewdGNUFind='/opt/homebrew/opt/findutils/libexec/gnubin'
...

I imagine all programs that fit whatever profile this is could be:

  • lumped into one file: less scripting on our part
  • individual files: a bit more scripting on my part

Either way, it would be a huge improvement. As long as the variable names don't change, AND there may be a need for a new assignment (E.G.: /usr/local -> /opt/homebrew), the automation would continue to run without any need for updates.

Bonus, if there was a argument to the install option, like --paths-file=true then I'm sure stats could (lter) be collected to see how adoption unfolds.

todd-dsm avatar Feb 20 '24 21:02 todd-dsm

I've been doing this for years(2015?), hence all of the scripting. There's never been an issue with the system failing to perform some administrative task, upgrades, etc. My MBP is monitored fairly closely and no signs of that being a real issue.

Similarly: I've been maintaining Homebrew since 2009 and working on open source on macOS since 2008 and can tell you: this definitely breaks things for a non-trivial number of scripts/people.

Not telling you to do anything differently, just noting why Homebrew may be unable/unwilling to support a flow that has known issues.

However, if it's auto-linked or somehow takes precedence over the binary that ships with macOS, then perfect. No need to do anything.

Yeah, this is the case for Git 👍🏻

  • lumped into one file: less scripting on our part

I guess my question is: would you want to unconditionally always add every gnubin folder to your PATH without any filtering?

  • individual files: a bit more scripting on my part

On this: individual files feels like it wouldn't really save any time over just having to add these gnubin folders manually or e.g. with a glob.

MikeMcQuaid avatar Feb 22 '24 08:02 MikeMcQuaid

FWIW, I run a mixed macOS/Linux environment, and the vast majority of my scripts are cross-platform and expect a GNU userland. Since all my scripts source a common shell library, I simply do this in the library:

my_platform=$(uname -sm | tr ' ' -)
[[ $my_platform == Darwin-* ]] && GNU_PREFIX=g

# need_progs: Checks for command dependencies
# USAGE: need_progs <cmd> ...
need_progs() {
  local missing=()
  local i
  for i in "$@"; do
    type -P "$i" &>/dev/null || missing+=("$i")
  done
  if [[ ${#missing[@]} -gt 0 ]]; then
    fatal "Commands missing: ${missing[*]}"
  fi
}

while the scripts do stuff like this:

# important progs get set in vars (can be overridden further down if needed)
sed=${GNU_PREFIX}sed
realpath=${GNU_PREFIX}realpath

need_progs $realpath rsync $sed

$sed -e 's!%%basepath%%!'"$($realpath /path/to/my.cfg)"'!g'

Do it enough times and it becomes second nature.

gromgit avatar Feb 22 '24 09:02 gromgit

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

github-actions[bot] avatar Mar 15 '24 00:03 github-actions[bot]

Sorry, don't think there's a good solution we can do in Homebrew for your specific case and it seems you have a workaround. We'll consider in future.

MikeMcQuaid avatar Mar 15 '24 08:03 MikeMcQuaid

@gromgit no question, we can script around it.

The whole point was to request a bit of plumbing (/tmp/file) containing file paths - all so we don't have to script around it.

If the result of Process-A does not form it's outputs so that Process-B can use them for inputs, that leaves the human to do some (in this case) unnecessary scripting.

todd-dsm avatar Mar 19 '24 18:03 todd-dsm

@MikeMcQuaid it's simply writing paths to a file - and only for programs where you'd want them to override the system provided ones. Within the scope of the Homebrew-verse, very few.

The variables are already defined and being used; we see them being printed to the terminal. It seems to be a matter of taking the one variable that represents a path and writing it to a file.

I guess I'm missing the part where that's challenging?

todd-dsm avatar Mar 19 '24 18:03 todd-dsm

I guess I'm missing the part where that's challenging?

Yes. We'll need to define which formulae use this and which don't, add a Formula DSL, decide on file location, document file location, support modifications in future (people will want to add/remove additional files) all for an end result that looks a lot like your scripting already achieves and is unclear if many people will use it except yourself (and the code needs maintained regardless).

These sorts of things that are easy for users to build outside Homebrew are best done that way, sorry. We had a decent back-and-forth here and dug into your problem and it just isn't a compelling feature for Homebrew right now.

MikeMcQuaid avatar Mar 20 '24 08:03 MikeMcQuaid