lmorg / murex

A smarter shell and scripting environment with advanced features designed for usability, safety and productivity (eg smarter DevOps tooling)
https://murex.rocks
GNU General Public License v2.0
1.46k stars 27 forks source link

Homebrew install location differs on Intel #706

Closed orefalo closed 11 months ago

orefalo commented 1 year ago

Describe the bug: murex-module's dependency validation can't find executables, I can confirm they are in PATH Looks like Murex does not re-read the ENV variables post .murex_preload evaluation

Expected behaviour: A clear and concise description of what you expected to happen.

Screenshots:

Loading profile `.murex_preload`
Before /usr/bin:/bin:/usr/sbin:/sbin
After /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
Loading module `murex-module-free/free`
Loading module `murex-module-homeendkey/home-end-keys`
Loading module `murex-module-javahome/javahome`
Loading module `murex-module-orefalo/profile`
Loading module `murex-module-orefalo/sublime-link`
Loading module `murex-module-orefalo/k9s`
Loading module `murex-module-orefalo/starship-config`
Loading module `murex-module-orefalo/local-docker`
There were problems loading modules `/Users/orefalo/.murex_modules/`:
Error loading module `jump` in path `/Users/orefalo/.murex_modules/jump/jump.mx`:
  * Missing required executable, builtin or murex function: `jump`
Error loading module `docker-compose` in path `/Users/orefalo/.murex_modules/murex-module-dockercompose/docker-compose.mx`:
  * Missing required executable, builtin or murex function: `docker-compose`
Error loading module `grc` in path `/Users/orefalo/.murex_modules/murex-module-grc/grc.mx`:
  * Missing required executable, builtin or murex function: `grc`
Error loading module `starship` in path `/Users/orefalo/.murex_modules/murex-module-starship/starship.mx`:
  * Missing required executable, builtin or murex function: `starship`
Loading profile `.murex_profile`

Additional context

So this is a weird issue, which seems to be platform dependent. I won't call it a bug, b/c I can't confirm the issue is murex.

I have two mac on the same OS version. one is Arm M1, the other Intel. the major difference between the two is that brew installs in different folders ... and also configures the default path differently - I just figured out the source of the issue ;-)

But here is the core of the issue... While debugging, I created this script

>> cat .murex_preload
# This file is loaded before any murex modules. It should only contain
# environmental variables required for the modules to work eg:
#
#     export PATH=...
#
# Any other profile config belongs in your profile script instead:
# /Users/orefalo/.murex_profile

out Before $PATH
$PATH -> :paths: prepend /usr/local/bin -> export PATH
out After $PATH

turns out, it didn't solve the issue. like if murex didn't read the new environment variable.

lmorg commented 1 year ago

This is likely an issue with homebrew where it stores things in weird locations and then updates $PATH itself. I bet if you launch murex from zsh then it will work (because murex would inherit $PATH from zsh)

I've got a workaround https://github.com/lmorg/murex/blob/master/config/defaults/profile_preload.mx but if you're experiencing this issue then it's likely one of those conditions isn't being met.

If you take a look at the above script and see what's failing, I can apply that fix to Murex.

orefalo commented 1 year ago

Right, I can confirm an environment issue with brew, that's fine.

What I am pointing at, is that when .murex_preload is evaluated, if it changes a env variable, the rest of the scripts are not picking it up.

lmorg commented 1 year ago

They definitely are. This is exactly why .murex_preload was created and is how I have all my machines set up.

For me, on macOS, jump points to /opt/homebrew/bin/jump, which isn't in either of your $PATH's. Which would be why Murex cannot find those executables.

orefalo commented 1 year ago

Laurence,

You have a M1 Mac, murex works also perfectly for me on this machine -

But on Intel Mac, brew installs its executables under /usr/local/bin - which for some reason is not set by default. This by itself will most likely solve the issue... but still, I can't explain why murex can't find the executable once PATH is properly set.

By now, I have confirmed that

  1. /usr/local/bin/starship is there
  2. I have added /usr/local/bin in the PATH using the .murex_preload script
  3. I can even confirm, you are right, that the PATH is properly exported. I changed the jump module, and did an out $PATH. It's fine..

Now, for some weird reasons, this validation fails

    for _, cmd := range m.Dependencies.Required {
        if !(*autocomplete.GlobalExes.Get())[cmd] && lang.GoFunctions[cmd] == nil && !lang.MxFunctions.Exists(cmd) {
            message += "  * Missing required executable, builtin or murex function: `" + cmd + "`" + utils.NewLineString
        }
    }
orefalo commented 1 year ago

I still believe you have a bug.. but I am making progress

I now understand why it works on M1 and not Intel. For some obscure reason, I have this file on M1 and not on Intel...

# ~/.profile
eval "$(/opt/homebrew/bin/brew shellenv)"

when running the command you get

➜  /opt/homebrew/bin/brew shellenv
export HOMEBREW_PREFIX="/opt/homebrew";
export HOMEBREW_CELLAR="/opt/homebrew/Cellar";
export HOMEBREW_REPOSITORY="/opt/homebrew";
export PATH="/opt/homebrew/bin:/opt/homebrew/sbin${PATH+:$PATH}";
export MANPATH="/opt/homebrew/share/man${MANPATH+:$MANPATH}:";
export INFOPATH="/opt/homebrew/share/info:${INFOPATH:-}";
lmorg commented 1 year ago

that'll be your problem. You can see homebrew is updating your $PATH and that path isn't being set by your murex profiles. So it's not that the profiles aren't retaining $PATH env correctly, it's that they don't include every required path.

Murex should detect homebrew and run that shellenv function automatically though. Can you run the following:

if { os darwin && g /opt/homebrew/bin/brew } then {
    out "woopwoop"
}
orefalo commented 1 year ago

I had to change the PATH

if { os darwin && g /usr/local/bin/brew } then {
    out "woopwoop"
}
woopwoop

At this point, I believe it's an OSX security feature. there is a good reason brew went from /usr/local/bin to /opt/homebrew/bin

anyways.. think I will just remove the dependencies to let it pass on this platform.

lmorg commented 1 year ago

leave the dependencies in. I'll just update the above code to check in both /opt and /usr/local

orefalo commented 1 year ago

https://www.reddit.com/r/MacOS/comments/jw9guu/why_did_homebrew_move_from_usrlocalto_opthomebrew/

I am running out of ideas....

lmorg commented 1 year ago

Right, try now. The homebrew compatibility layer is this:

if { os darwin && %[ /usr/local/bin/brew ] -> f +x } then {
    /bin/zsh -c 'eval "$(/usr/local/bin/brew shellenv)"; env' \
    -> grep -Ei "(HOMEBREW|PATH)" \
    -> prefix "export " \
    -> source
}

if { os darwin && %[ /opt/homebrew/bin/brew ] -> f +x } then {
    /bin/zsh -c 'eval "$(/opt/homebrew/bin/brew shellenv)"; env' \
    -> grep -Ei "(HOMEBREW|PATH)" \
    -> prefix "export " \
    -> source
}

I don't have an intel mac to test this on so relying on your feedback

orefalo commented 1 year ago

it works! thanks for the quick fix.

it's not old versions of osx, I am on the latest Ventura 13.5.1. As per the link above - brew executables are not universal. For this reason they picked a different folder for the two different architectures - intel and arm

lmorg commented 1 year ago

ahhhh

orefalo commented 1 year ago

I am reopening this ticket. I may have found a way around zsh

 brew shellenv -> sed 's/${PATH+:$PATH}/:$PATH/' -> \
 sed 's/${MANPATH+:$MANPATH}:/:$MANPATH/' -> \
 sed 's/${INFOPATH:-}/$INFOPATH/' -> source

PS1: can't believe it was so simple PS2: the following code doesn't work with regexp, can't explain why

 brew shellenv -> regexp 's/${PATH+:$PATH}/:$PATH/' -> \
 regexp 's/${MANPATH+:$MANPATH}:/:$MANPATH/' -> \
 regexp 's/${INFOPATH:-}/$INFOPATH/' -> source
lmorg commented 1 year ago

Seems it doesn't run if it detects it's already run. Also it tries to detect what shell you're using, if you don't specify one yourself.

% /opt/homebrew/bin/brew help shellenv
Usage: brew shellenv [bash|csh|fish|pwsh|sh|tcsh|zsh]

Print export statements. When run in a shell, this installation of Homebrew will
be added to your PATH, MANPATH, and INFOPATH.

The variables HOMEBREW_PREFIX, HOMEBREW_CELLAR and HOMEBREW_REPOSITORY are
also exported to avoid querying them multiple times. To help guarantee
idempotence, this command produces no output when Homebrew's bin and sbin
directories are first and second respectively in your PATH. Consider adding
evaluation of this command's output to your dotfiles (e.g. ~/.profile,
~/.bash_profile, or ~/.zprofile) with: eval "$(brew shellenv)"

The shell can be specified explicitly with a supported shell name parameter.
Unknown shells will output POSIX exports.

I think the best option would be seeing if we can get murex added to shellenv so then it's as simple as:

/path/to/brew shellenv murex -> source
lmorg commented 11 months ago

I am reopening this ticket. I may have found a way around zsh

 brew shellenv -> sed 's/${PATH+:$PATH}/:$PATH/' -> \
 sed 's/${MANPATH+:$MANPATH}:/:$MANPATH/' -> \
 sed 's/${INFOPATH:-}/$INFOPATH/' -> source

PS1: can't believe it was so simple PS2: the following code doesn't work with regexp, can't explain why

 brew shellenv -> regexp 's/${PATH+:$PATH}/:$PATH/' -> \
 regexp 's/${MANPATH+:$MANPATH}:/:$MANPATH/' -> \
 regexp 's/${INFOPATH:-}/$INFOPATH/' -> source

possibly because $, + and {} tokens have special meanings in regex:

eg

So if you want $, + and {} to be matched as characters rather than tokens, you need to escape them, eg '\$\{MANPATH\+:\$MANPATH\}:

As for why it worked in sed, I don't know about that. It's a different regex engine so it might be more lenient with malformed regex expressions. eg having $ at the start of the line and {...} that contain non-numeric characters. This might also be a behaviour that isn't portable (GNU sed does behave differently to BSD sed in a number of ways).