diff --git a/bundler/lib/bundler.rb b/bundler/lib/bundler.rb index 51ea3beeb0f7..11966f8ca850 100644 --- a/bundler/lib/bundler.rb +++ b/bundler/lib/bundler.rb @@ -452,13 +452,13 @@ def default_bundle_dir SharedHelpers.default_bundle_dir end - def system_bindir + def system_bindir(install_dir = nil) # Gem.bindir doesn't always return the location that RubyGems will install # system binaries. If you put '-n foo' in your .gemrc, RubyGems will # install binstubs there instead. Unfortunately, RubyGems doesn't expose # that directory at all, so rather than parse .gemrc ourselves, we allow # the directory to be set as well, via `bundle config set --local bindir foo`. - Bundler.settings[:system_bindir] || Bundler.rubygems.gem_bindir + Bundler.settings[:system_bindir] || Bundler.rubygems.gem_bindir(install_dir) end def preferred_gemfile_name diff --git a/bundler/lib/bundler/plugin/installer/rubygems.rb b/bundler/lib/bundler/plugin/installer/rubygems.rb index cb5db9c30eb2..4bd0358f74b0 100644 --- a/bundler/lib/bundler/plugin/installer/rubygems.rb +++ b/bundler/lib/bundler/plugin/installer/rubygems.rb @@ -6,7 +6,7 @@ class Installer class Rubygems < Bundler::Source::Rubygems private - def rubygems_dir + def rubygems_dir(_) Plugin.root end diff --git a/bundler/lib/bundler/rubygems_integration.rb b/bundler/lib/bundler/rubygems_integration.rb index e04ef232592a..b5863b96ccd4 100644 --- a/bundler/lib/bundler/rubygems_integration.rb +++ b/bundler/lib/bundler/rubygems_integration.rb @@ -81,8 +81,8 @@ def gem_dir Gem.dir end - def gem_bindir - Gem.bindir + def gem_bindir(install_dir = nil) + Gem.bindir(install_dir || gem_dir) end def user_home diff --git a/bundler/lib/bundler/self_manager.rb b/bundler/lib/bundler/self_manager.rb index 1db77fd46b3f..10eec03151f6 100644 --- a/bundler/lib/bundler/self_manager.rb +++ b/bundler/lib/bundler/self_manager.rb @@ -67,11 +67,6 @@ def install(spec) end def restart_with(version) - configured_gem_home = ENV["GEM_HOME"] - configured_orig_gem_home = ENV["BUNDLER_ORIG_GEM_HOME"] - configured_gem_path = ENV["GEM_PATH"] - configured_orig_gem_path = ENV["BUNDLER_ORIG_GEM_PATH"] - argv0 = File.exist?($PROGRAM_NAME) ? $PROGRAM_NAME : Process.argv0 cmd = [argv0, *ARGV] cmd.unshift(Gem.ruby) unless File.executable?(argv0) @@ -79,10 +74,6 @@ def restart_with(version) Bundler.with_original_env do Kernel.exec( { - "GEM_HOME" => configured_gem_home, - "BUNDLER_ORIG_GEM_HOME" => configured_orig_gem_home, - "GEM_PATH" => configured_gem_path, - "BUNDLER_ORIG_GEM_PATH" => configured_orig_gem_path, "BUNDLER_VERSION" => version.to_s, }, *cmd @@ -132,7 +123,6 @@ def remote_specs end def find_latest_matching_spec(requirement) - Bundler.configure local_result = find_latest_matching_spec_from_collection(local_specs, requirement) return local_result if local_result && requirement.specific? @@ -163,8 +153,6 @@ def ruby_can_restart_with_same_arguments? end def installed?(restart_version) - Bundler.configure - Bundler.rubygems.find_bundler(restart_version.to_s) end diff --git a/bundler/lib/bundler/source/rubygems.rb b/bundler/lib/bundler/source/rubygems.rb index e1e030ffc899..1802aae96de1 100644 --- a/bundler/lib/bundler/source/rubygems.rb +++ b/bundler/lib/bundler/source/rubygems.rb @@ -173,8 +173,8 @@ def install(spec, options = {}) return if Bundler.settings[:no_install] - install_path = rubygems_dir - bin_path = Bundler.system_bindir + install_path = rubygems_dir(spec) + bin_path = Bundler.system_bindir(install_path) require_relative "../rubygems_gem_installer" @@ -432,7 +432,7 @@ def fetch_gem_if_possible(spec, previous_spec = nil) def fetch_gem(spec, previous_spec = nil) spec.fetch_platform - cache_path = download_cache_path(spec) || default_cache_path_for(rubygems_dir) + cache_path = download_cache_path(spec) || default_cache_path_for(rubygems_dir(spec)) gem_path = package_path(cache_path, spec) return gem_path if File.exist?(gem_path) @@ -448,8 +448,10 @@ def installed?(spec) installed_specs[spec].any? && !spec.installation_missing? end - def rubygems_dir - Bundler.bundle_path + def rubygems_dir(spec) + dir = Pathname(ENV["BUNDLER_ORIG_GEM_HOME"]) if spec.name == "bundler" + + dir ||= Bundler.bundle_path end def default_cache_path_for(dir) diff --git a/bundler/spec/commands/install_spec.rb b/bundler/spec/commands/install_spec.rb index ae651bf981c7..26ffa5b3c618 100644 --- a/bundler/spec/commands/install_spec.rb +++ b/bundler/spec/commands/install_spec.rb @@ -801,6 +801,39 @@ end end + describe "Bundler version in Gemfile.lock" do + it "always download the bundler gem to system path" do + gemfile <<~G + source "https://gem.repo4" + G + + lockfile <<~L + GEM + remote: https://gem.repo4/ + specs: + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + + BUNDLED WITH + 2.7.99 + L + + build_repo4 do + build_gem "bundler", "2.7.99" + end + + bundle :install, env: { "BUNDLE_PATH" => "vendor/bundle" } + + expect(system_gem_path("gems/bundler-2.7.99")).to exist + expect(system_gem_path("bin/bundler")).to exist + expect(vendored_gems("gems/bundler-2.7.99")).to_not exist + expect(vendored_gems("bin/bundler")).to_not exist + end + end + describe "Ruby version in Gemfile.lock" do context "and using an unsupported Ruby version" do it "prints an error" do diff --git a/bundler/spec/commands/update_spec.rb b/bundler/spec/commands/update_spec.rb index cdaeb75c4a33..f1e5b4bf715a 100644 --- a/bundler/spec/commands/update_spec.rb +++ b/bundler/spec/commands/update_spec.rb @@ -1700,7 +1700,7 @@ gem "myrack" G - system_gems "bundler-9.0.0.dev", path: local_gem_path + system_gems "bundler-9.0.0.dev" bundle :update, bundler: "9.0.0.dev", verbose: "true" checksums = checksums_section_when_enabled do |c| @@ -1737,7 +1737,7 @@ source "https://gem.repo4" gem "myrack" G - system_gems "bundler-9.0.0", path: local_gem_path + system_gems "bundler-9.0.0" bundle :update, bundler: "9.0.0", verbose: true expect(out).not_to include("Fetching gem metadata from https://rubygems.org/") @@ -1787,7 +1787,7 @@ 9.0.0 L - system_gems "bundler-9.9.9", path: local_gem_path + system_gems "bundler-9.9.9" bundle "update --bundler=9.9.9", env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false expect(err).to include("An update to the version of Bundler itself was requested, but the lockfile can't be updated because frozen mode is set") diff --git a/bundler/spec/runtime/self_management_spec.rb b/bundler/spec/runtime/self_management_spec.rb index fbffd2dca2df..2ed67b2572be 100644 --- a/bundler/spec/runtime/self_management_spec.rb +++ b/bundler/spec/runtime/self_management_spec.rb @@ -70,7 +70,7 @@ bundle "config set --local path vendor/bundle" bundle "install" expect(out).to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") - expect(vendored_gems("gems/bundler-#{previous_minor}")).to exist + expect(system_gem_path("gems/bundler-#{previous_minor}")).to exist # It does not uninstall the locked bundler bundle "clean" @@ -111,7 +111,7 @@ bundle "config set --local deployment true" bundle "install" expect(out).to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") - expect(vendored_gems("gems/bundler-#{previous_minor}")).to exist + expect(system_gem_path("gems/bundler-#{previous_minor}")).to exist # It does not uninstall the locked bundler bundle "clean" diff --git a/bundler/spec/runtime/setup_spec.rb b/bundler/spec/runtime/setup_spec.rb index 1ffaffef0ed2..09f49058bc9d 100644 --- a/bundler/spec/runtime/setup_spec.rb +++ b/bundler/spec/runtime/setup_spec.rb @@ -1218,6 +1218,42 @@ def lock_with(bundler_version = nil) end end + context "auto switch" do + it "picks the right bundler version without re-exec" do + bundle "config unset path.system" + bundle "config set --local path #{bundled_app(".bundle")}" + + build_repo4 do + build_bundler "4.4.99" + build_gem "myrack", "1.0.0" + end + + lockfile(lock_with("4.4.99")) + + install_gemfile <<-G + source "https://gem.repo4" + gem "myrack" + G + + # ruby-core test setup has always "lib" in $LOAD_PATH so `require "bundler/setup"` always activate the local version rather than using RubyGems gem activation stuff + unless ruby_core? + file = bundled_app("bin/bundle_version.rb") + create_file file, <<~RUBY + #!#{Gem.ruby} + p 'executed once' + require 'bundler/setup' + p Bundler::VERSION + RUBY + + file.chmod(0o777) + cmd = Gem.win_platform? ? "#{Gem.ruby} bin/bundle_version.rb" : "bin/bundle_version.rb" + in_bundled_app cmd + + expect(out).to eq(%("executed once"\n"4.4.99")) + end + end + end + context "is newer" do it "does not change the lock or warn" do lockfile lock_with(Bundler::VERSION.succ)