Skip to content
This repository was archived by the owner on Apr 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions lib/bundle/commands/exec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require "exceptions"
require "extend/ENV"
require "utils"
require "PATH"

module Bundle
module Commands
Expand Down Expand Up @@ -45,6 +46,8 @@ module Exec
HOMEBREW_GITHUB_PACKAGES_AUTH
].freeze

PATH_LIKE_ENV_REGEX = /.+#{File::PATH_SEPARATOR}/

def run(*args, global: false, file: nil, subcommand: "")
# Cleanup Homebrew's global environment
HOMEBREW_ENV_CLEANUP.each { |key| ENV.delete(key) }
Expand Down Expand Up @@ -99,8 +102,10 @@ def run(*args, global: false, file: nil, subcommand: "")
end

# Setup pkg-config, if present, to help locate packages
pkgconfig = Formulary.factory("pkg-config")
ENV.prepend_path "PATH", pkgconfig.opt_bin.to_s if pkgconfig.any_version_installed?
# Only need this on Linux as Homebrew provides a shim on macOS
if OS.linux? && (pkgconf = Formulary.factory("pkgconf")) && pkgconf.any_version_installed?
ENV.prepend_path "PATH", pkgconf.opt_bin.to_s
end

# Ensure the Ruby path we saved goes before anything else, if the command was in the PATH
ENV.prepend_path "PATH", command_path if command_path.present?
Expand All @@ -122,7 +127,22 @@ def run(*args, global: false, file: nil, subcommand: "")
opt = %r{/opt/#{formula_name}([/:$])}
next unless value.match(opt)

ENV[key] = value.gsub(opt, "/Cellar/#{formula_name}/#{formula_version}\\1")
cellar = "/Cellar/#{formula_name}/#{formula_version}\\1"

# Look for PATH-like environment variables
if key.include?("PATH") && value.match?(PATH_LIKE_ENV_REGEX)
rejected_opts = []
path = PATH.new(ENV.fetch("PATH"))
.reject do |value|
rejected_opts << value if value.match?(opt)
end
rejected_opts.each do |value|
path.prepend(value.gsub(opt, cellar))
end
ENV["PATH"] = path.to_s
else
ENV[key] = value.gsub(opt, cellar)
end
end
end

Expand Down
4 changes: 3 additions & 1 deletion spec/bundle/commands/exec_command_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@

it "uses the formula version from the environment variable" do
openssl_version = "1.1.1"
ENV["PATH"] = "/opt/homebrew/opt/openssl/bin"
ENV["PATH"] = "/opt/homebrew/opt/openssl/bin:/usr/bin:/bin"
ENV["MANPATH"] = "/opt/homebrew/opt/openssl/man"
ENV["HOMEBREW_BUNDLE_EXEC_FORMULA_VERSION_OPENSSL"] = openssl_version
described_class.run("bundle", "install")
expect(ENV.fetch("PATH")).to include("/Cellar/openssl/1.1.1/bin")
Expand All @@ -53,6 +54,7 @@
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
Expand Down
28 changes: 28 additions & 0 deletions spec/stub/PATH.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

class PATH
def initialize(*paths)
@paths = parse(paths)
end

def prepend(*paths)
@paths = parse(paths + @paths)
end

def reject(&block)
self.class.new(@paths.reject(&block))
end

def to_s
@paths.join(File::PATH_SEPARATOR)
end

private

def parse(paths)
paths.flatten
.compact
.flat_map { |p| Pathname(p).to_path.split(File::PATH_SEPARATOR) }
.uniq
end
end