From c83f8ad8671afbd8e9ae70c2c4e69a80c6a96d67 Mon Sep 17 00:00:00 2001 From: Ellen Marie Dash Date: Fri, 29 Sep 2023 23:50:30 -0400 Subject: [PATCH] [rubygems/rubygems] Simplify logic for Gem::PathSupport#home, and make GEM_HOME always overide it. https://github.com/rubygems/rubygems/commit/64273fd7e3 --- lib/rubygems/path_support.rb | 31 ++++++++++--------- spec/bundler/commands/doctor_spec.rb | 5 +-- .../test_gem_install_update_options.rb | 6 +++- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/lib/rubygems/path_support.rb b/lib/rubygems/path_support.rb index b7900f67eb..6ce66494ca 100644 --- a/lib/rubygems/path_support.rb +++ b/lib/rubygems/path_support.rb @@ -24,19 +24,24 @@ class Gem::PathSupport # hashtable, or defaults to ENV, the system environment. # def initialize(env) - @home = default_home_dir(env) + # Current implementation of @home, which is exposed as `Gem.paths.home`: + # 1. If `env["GEM_HOME"]` is defined in the environment: `env["GEM_HOME"]`. + # 2. If `Gem.default_dir` is writable OR it does not exist and it's parent + # directory is writable: `Gem.default_dir`. + # 3. Otherwise: `Gem.user_dir`. - # If @home (aka Gem.paths.home) exists, but we can't write to it, - # fall back to Gem.user_dir (the directory used for user installs). - if File.exist?(@home) && !File.writable?(@home) - warn "The default GEM_HOME (#{@home}) is not" \ - " writable, so rubygems is falling back to installing" \ - " under your home folder. To get rid of this warning" \ - " permanently either fix your GEM_HOME folder permissions" \ - " or add the following to your ~/.gemrc file:\n" \ - " gem: --install-dir #{Gem.user_dir}" + if env.key?("GEM_HOME") + @home = normalize_home_dir(env["GEM_HOME"]) + elsif File.writable?(Gem.default_dir) || \ + (!File.exist?(Gem.default_dir) && File.writable?(File.expand_path("..", Gem.default_dir))) - @home = Gem.user_dir + @home = normalize_home_dir(Gem.default_dir) + else + # If `GEM_HOME` is not set AND we can't use `Gem.default_dir`, + # default to a user installation and print a message about this. + puts "Defaulting to user installation because default GEM_HOME (#{Gem.default_dir}) is not writable." + + @home = normalize_home_dir(Gem.user_dir) end @path = split_gem_path env["GEM_PATH"], @home @@ -52,9 +57,7 @@ class Gem::PathSupport # The default home directory. # This function was broken out to accommodate tests in `bundler/spec/commands/doctor_spec.rb`. - def default_home_dir(env) - home = env["GEM_HOME"] || Gem.default_dir - + def normalize_home_dir(home) if File::ALT_SEPARATOR home = home.gsub(File::ALT_SEPARATOR, File::SEPARATOR) end diff --git a/spec/bundler/commands/doctor_spec.rb b/spec/bundler/commands/doctor_spec.rb index 4a8d0d6f46..9eb496b0b2 100644 --- a/spec/bundler/commands/doctor_spec.rb +++ b/spec/bundler/commands/doctor_spec.rb @@ -40,8 +40,9 @@ RSpec.describe "bundle doctor" do allow(File).to receive(:readable?).with(unwritable_file) { true } # The following 2 lines are for `Gem::PathSupport#initialize`. - allow(File).to receive(:exist?).with(Gem.paths.send(:default_home_dir)) - allow(File).to receive(:writable?).with(Gem.paths.send(:default_home_dir)) + allow(File).to receive(:exist?).with(Gem.default_dir) + allow(File).to receive(:writable?).with(Gem.default_dir) + allow(File).to receive(:writable?).with(File.expand_path("..", Gem.default_dir)) end it "exits with no message if the installed gem has no C extensions" do diff --git a/test/rubygems/test_gem_install_update_options.rb b/test/rubygems/test_gem_install_update_options.rb index 8c58520577..6ed40d226a 100644 --- a/test/rubygems/test_gem_install_update_options.rb +++ b/test/rubygems/test_gem_install_update_options.rb @@ -165,6 +165,9 @@ class TestGemInstallUpdateOptions < Gem::InstallerTestCase return end + orig_gem_home = ENV["GEM_HOME"] + ENV.delete("GEM_HOME") + @spec = quick_gem "a" do |spec| util_make_exec spec end @@ -179,11 +182,12 @@ class TestGemInstallUpdateOptions < Gem::InstallerTestCase FileUtils.chmod 0o755, @userhome FileUtils.chmod 0o000, @gemhome - Gem.use_paths @gemhome, @userhome + Gem.use_paths nil, @userhome assert_equal Gem.paths.home, Gem.user_dir ensure FileUtils.chmod 0o755, @gemhome + ENV["GEM_HOME"] = orig_gem_home if orig_gem_home end def test_vendor