brew (bundle|) sh: use user's configuration but override prompts.

This was more painful that I expected but will allow `brew bundle sh`
and `brew sh` to use the user's configuration but use our custom prompt
for Bash and ZSH.
This commit is contained in:
Mike McQuaid 2025-06-05 15:43:34 +01:00
parent 485f1abbee
commit 5fe43ed3f2
No known key found for this signature in database
6 changed files with 80 additions and 23 deletions

View File

@ -170,6 +170,18 @@ module Homebrew
end
end
return
elsif subcommand == "sh"
preferred_path = Utils::Shell.preferred_path(default: "/bin/bash")
notice = unless Homebrew::EnvConfig.no_env_hints?
<<~EOS
Your shell has been configured to use a build environment from your `Brewfile`.
This should help you build stuff.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
When done, type `exit`.
EOS
end
ENV["HOMEBREW_FORCE_API_AUTO_UPDATE"] = nil
args = [Utils::Shell.shell_with_prompt("brew bundle", preferred_path:, notice:)]
end
if services

View File

@ -276,17 +276,7 @@ module Homebrew
_subcommand, *named_args = args.named
named_args
when "sh"
preferred_path = Utils::Shell.preferred_path(default: "/bin/bash")
notice = unless Homebrew::EnvConfig.no_env_hints?
<<~EOS
Your shell has been configured to use a build environment from your `Brewfile`.
This should help you build stuff.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
When done, type `exit`.
EOS
end
ENV["HOMEBREW_FORCE_API_AUTO_UPDATE"] = nil
[Utils::Shell.shell_with_prompt("brew bundle", preferred_path:, notice:)]
["sh"]
when "env"
["env"]
end

View File

@ -107,18 +107,34 @@ RSpec.describe Utils::Shell do
end
describe "::shell_with_prompt" do
let(:home) { HOMEBREW_TEMP }
let(:notice) { "" }
let(:prompt) { "test" }
let(:path) { "/some/path" }
it "returns zsh-specific prompt configuration" do
ENV["SHELL"] = "/bin/zsh"
expect(described_class.shell_with_prompt("test", preferred_path: "/bin/zsh", notice: "")).to eq(
"PROMPT='%B%F{green}test%f %F{blue}$%f%b ' RPROMPT='[%B%F{red}%~%f%b]' /bin/zsh -f",
)
preferred_path = "/bin/zsh"
ENV["SHELL"] = preferred_path
ENV["PATH"] = path
zdotdir = "#{HOMEBREW_TEMP}/brew-zsh-prompt-#{Process.euid}"
expect(described_class.shell_with_prompt(prompt, preferred_path:, notice:, home:)).to eq \
"BREW_PROMPT_PATH=\"#{path}\" BREW_PROMPT_TYPE=\"#{prompt}\" ZDOTDIR=\"#{zdotdir}\" #{preferred_path}"
end
it "returns bash-specific prompt configuration" do
preferred_path = "/bin/bash"
ENV["SHELL"] = "/bin/bash"
ENV["PATH"] = path
rcfile = "#{HOMEBREW_LIBRARY_PATH}/utils/bash/brew-sh-prompt-bashrc.bash"
expect(described_class.shell_with_prompt(prompt, preferred_path:, notice:, home:)).to eq \
"BREW_PROMPT_PATH=\"#{path}\" BREW_PROMPT_TYPE=\"#{prompt}\" #{preferred_path} --rcfile \"#{rcfile}\""
end
it "returns generic shell prompt configuration" do
ENV["SHELL"] = "/bin/bash"
expect(described_class.shell_with_prompt("test", preferred_path: "/bin/bash", notice: "")).to eq(
"PS1=\"\\[\\033[1;32m\\]brew \\[\\033[1;31m\\]\\w \\[\\033[1;34m\\]$\\[\\033[0m\\] \" /bin/bash",
)
preferred_path = "/bin/dash"
ENV["SHELL"] = preferred_path
expect(described_class.shell_with_prompt(prompt, preferred_path:, notice:, home:)).to eq \
"PS1=\"\\[\\033[1;32m\\]#{prompt} \\[\\033[1;31m\\]\\w \\[\\033[1;34m\\]$\\[\\033[0m\\] \" #{preferred_path}"
end
it "outputs notice when provided" do

View File

@ -0,0 +1,12 @@
# Read the user's ~/.bashrc first
if [[ -f "${HOME}/.bashrc" ]]
then
source "${HOME}/.bashrc"
fi
# Override the user's Bash prompt with our custom prompt
export PS1="\\[\\033[1;32m\\]${BREW_PROMPT_TYPE} \\[\\033[1;31m\\]\\w \\[\\033[1;34m\\]$\\[\\033[0m\\] "
# Add the Homebrew PATH in front of the user's PATH
export PATH="${BREW_PROMPT_PATH}:${PATH}"
unset BREW_PROMPT_TYPE BREW_PROMPT_PATH

View File

@ -153,14 +153,28 @@ module Utils
str
end
sig { params(type: String, preferred_path: String, notice: T.nilable(String)).returns(String) }
def shell_with_prompt(type, preferred_path:, notice:)
sig { params(type: String, preferred_path: String, notice: T.nilable(String), home: String).returns(String) }
def shell_with_prompt(type, preferred_path:, notice:, home: Dir.home)
preferred = from_path(preferred_path)
path = ENV.fetch("PATH")
subshell = case preferred
when :zsh
"PROMPT='%B%F{green}#{type}%f %F{blue}$%f%b ' RPROMPT='[%B%F{red}%~%f%b]' #{preferred_path} -f"
zdotdir = Pathname.new(HOMEBREW_TEMP/"brew-zsh-prompt-#{Process.euid}")
zdotdir.mkpath
FileUtils.chmod_R(0700, zdotdir)
FileUtils.cp(HOMEBREW_LIBRARY_PATH/"utils/zsh/brew-sh-prompt-zshrc.zsh", zdotdir/".zshrc")
%w[.zcompdump .zsh_history .zsh_sessions].each do |file|
FileUtils.ln_sf("#{home}/#{file}", zdotdir/file)
end
<<~ZSH.strip
BREW_PROMPT_PATH="#{path}" BREW_PROMPT_TYPE="#{type}" ZDOTDIR="#{zdotdir}" #{preferred_path}
ZSH
when :bash
<<~BASH.strip
BREW_PROMPT_PATH="#{path}" BREW_PROMPT_TYPE="#{type}" #{preferred_path} --rcfile "#{HOMEBREW_LIBRARY_PATH}/utils/bash/brew-sh-prompt-bashrc.bash"
BASH
else
"PS1=\"\\[\\033[1;32m\\]brew \\[\\033[1;31m\\]\\w \\[\\033[1;34m\\]$\\[\\033[0m\\] \" #{preferred_path}"
"PS1=\"\\[\\033[1;32m\\]#{type} \\[\\033[1;31m\\]\\w \\[\\033[1;34m\\]$\\[\\033[0m\\] \" #{preferred_path}"
end
puts notice if notice.present?

View File

@ -0,0 +1,13 @@
# Read the user's ~/.zshrc first
if [[ -f "${HOME}/.zshrc" ]]
then
source "${HOME}/.zshrc"
fi
# Override the user's ZSH prompt with our custom prompt
export PROMPT="%B%F{green}${BREW_PROMPT_TYPE}%f %F{blue}$%f%b "
export RPROMPT="[%B%F{red}%~%f%b]"
# Add the Homebrew PATH in front of the user's PATH
export PATH="${BREW_PROMPT_PATH}:${PATH}"
unset BREW_PROMPT_TYPE BREW_PROMPT_PATH