diff --git a/Library/Homebrew/bundle/commands/exec.rb b/Library/Homebrew/bundle/commands/exec.rb index 9f73eadc01..b9251cd2a6 100644 --- a/Library/Homebrew/bundle/commands/exec.rb +++ b/Library/Homebrew/bundle/commands/exec.rb @@ -11,47 +11,9 @@ module Homebrew module Bundle module Commands module Exec - # Homebrew's global environment variables that we don't want to leak into - # the `brew bundle exec` environment. - HOMEBREW_ENV_CLEANUP = %w[ - HOMEBREW_HELP_MESSAGE - HOMEBREW_API_DEFAULT_DOMAIN - HOMEBREW_BOTTLE_DEFAULT_DOMAIN - HOMEBREW_BREW_DEFAULT_GIT_REMOTE - HOMEBREW_CORE_DEFAULT_GIT_REMOTE - HOMEBREW_DEFAULT_CACHE - HOMEBREW_DEFAULT_LOGS - HOMEBREW_DEFAULT_TEMP - HOMEBREW_REQUIRED_RUBY_VERSION - HOMEBREW_PRODUCT - HOMEBREW_SYSTEM - HOMEBREW_PROCESSOR - HOMEBREW_PHYSICAL_PROCESSOR - HOMEBREW_BREWED_CURL_PATH - HOMEBREW_USER_AGENT_CURL - HOMEBREW_USER_AGENT - HOMEBREW_GENERIC_DEFAULT_PREFIX - HOMEBREW_GENERIC_DEFAULT_REPOSITORY - HOMEBREW_DEFAULT_PREFIX - HOMEBREW_DEFAULT_REPOSITORY - HOMEBREW_AUTO_UPDATE_COMMAND - HOMEBREW_BREW_GIT_REMOTE - HOMEBREW_COMMAND_DEPTH - HOMEBREW_CORE_GIT_REMOTE - HOMEBREW_MACOS_VERSION_NUMERIC - HOMEBREW_MINIMUM_GIT_VERSION - HOMEBREW_MACOS_NEWEST_UNSUPPORTED - HOMEBREW_MACOS_OLDEST_SUPPORTED - HOMEBREW_MACOS_OLDEST_ALLOWED - HOMEBREW_GITHUB_PACKAGES_AUTH - ].freeze - PATH_LIKE_ENV_REGEX = /.+#{File::PATH_SEPARATOR}/ def self.run(*args, global: false, file: nil, subcommand: "", services: false) - # Cleanup Homebrew's global environment - HOMEBREW_ENV_CLEANUP.each { |key| ENV.delete(key) } - # Store the old environment so we can check if things were already set # before we start mutating it. old_env = ENV.to_h @@ -149,15 +111,36 @@ module Homebrew # For commands which aren't either absolute or relative raise "command was not found in your PATH: #{command}" if command.exclude?("/") && which(command).nil? + # Don't need to export Homebrew internal variables that won't be used by other tools. + # Those Homebrew needs have already been set to global constants and/or are exported again later. + # Setting these globally can interfere with nested Homebrew invocations/environments. + ENV.delete_if { |key, _| key.start_with?("HOMEBREW_", "PORTABLE_RUBY_") } + if subcommand == "env" ENV.sort.each do |key, value| # No need to export empty values. next if value.blank? - # Skip exporting non-Homebrew things that were already set in the old environment. - next if !key.start_with?("HOMEBREW_") && old_env.key?(key) && old_env[key] == value + # Skip exporting things that were the same in the old environment. + old_value = old_env[key] + next if old_value == value - puts "export #{key}=\"#{Utils::Shell.sh_quote(value)}\"" + # Look for PATH-like environment variables + if key.include?("PATH") && value.match?(PATH_LIKE_ENV_REGEX) + old_values = old_value.to_s.split(File::PATH_SEPARATOR) + path = PATH.new(value) + .reject do |path_value| + # Exclude Homebrew shims from the PATH as they don't work + # without all Homebrew environment variables. + # Exclude existing/old values as they've already been exported. + path_value.include?("/Homebrew/shims/") || old_values.include?(path_value) + end + next if path.blank? + + puts "export #{key}=\"#{Utils::Shell.sh_quote(path.to_s)}:${#{key}:-}\"" + else + puts "export #{key}=\"#{Utils::Shell.sh_quote(value)}\"" + end end return end diff --git a/Library/Homebrew/test/bundle/commands/exec_spec.rb b/Library/Homebrew/test/bundle/commands/exec_spec.rb index a6cc0114de..101ab72f05 100644 --- a/Library/Homebrew/test/bundle/commands/exec_spec.rb +++ b/Library/Homebrew/test/bundle/commands/exec_spec.rb @@ -65,12 +65,10 @@ RSpec.describe Homebrew::Bundle::Commands::Exec do context "with env command" do it "outputs the environment variables" do - ENV["HOMEBREW_PREFIX"] = "/opt/homebrew" - ENV["HOMEBREW_PATH"] = "/usr/bin" allow(OS).to receive(:linux?).and_return(true) expect { described_class.run("env", subcommand: "env") }.to \ - output(/HOMEBREW_PREFIX="#{ENV.fetch("HOMEBREW_PREFIX")}"/).to_stdout + output(/export PATH=".+:\${PATH:-}"/).to_stdout end end