summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Rodríguez <deivid.rodriguez@riseup.net>2025-06-12 19:48:36 +0200
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2025-06-17 15:09:34 +0900
commit0a62e82ac4ea75f5dd435c922500cb87af40612c (patch)
tree5ef8cf1cb0a4cc517e248c5e6463161842ca954a
parent0c2f0ffa60930308cf07201527489475cf98781f (diff)
[rubygems/rubygems] Fix `gem install` sometimes compiling the wrong source files
If a previous copy of a gem is already installed, RubyGems will not reinstall the gem but only recompile its extensions. This seems like a good idea, but only if the gem is being installed from the registry. If we are installing a locally built package, then the package should be completely reinstalled and extensions compiled from the sources in the locally built package, not from the sources in the previous installation. https://github.com/rubygems/rubygems/commit/1c282d98d5
-rw-r--r--lib/rubygems/request_set.rb9
-rw-r--r--test/rubygems/test_gem_dependency_installer.rb52
2 files changed, 55 insertions, 6 deletions
diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb
index 875df7e019..5a855fdb10 100644
--- a/lib/rubygems/request_set.rb
+++ b/lib/rubygems/request_set.rb
@@ -181,13 +181,10 @@ class Gem::RequestSet
# Install requested gems after they have been downloaded
sorted_requests.each do |req|
- if req.installed?
+ if req.installed? && @always_install.none? {|spec| spec == req.spec.spec }
req.spec.spec.build_extensions
-
- if @always_install.none? {|spec| spec == req.spec.spec }
- yield req, nil if block_given?
- next
- end
+ yield req, nil if block_given?
+ next
end
spec =
diff --git a/test/rubygems/test_gem_dependency_installer.rb b/test/rubygems/test_gem_dependency_installer.rb
index 330009e9bd..f84881579a 100644
--- a/test/rubygems/test_gem_dependency_installer.rb
+++ b/test/rubygems/test_gem_dependency_installer.rb
@@ -519,6 +519,58 @@ class TestGemDependencyInstaller < Gem::TestCase
assert_equal %w[a-1], inst.installed_gems.map(&:full_name)
end
+ def test_install_local_with_extensions_already_installed
+ pend "needs investigation" if Gem.java_platform?
+ pend "ruby.h is not provided by ruby repo" if ruby_repo?
+
+ @spec = quick_gem "a" do |s|
+ s.extensions << "extconf.rb"
+ s.files += %w[extconf.rb a.c]
+ end
+
+ write_dummy_extconf "a"
+
+ c_source_path = File.join(@tempdir, "a.c")
+
+ write_file c_source_path do |io|
+ io.write <<-C
+ #include <ruby.h>
+ void Init_a() { }
+ C
+ end
+
+ package_path = Gem::Package.build @spec
+ installer = Gem::Installer.at(package_path)
+
+ # Make sure the gem is installed and backup the correct package
+
+ installer.install
+
+ package_bkp_path = "#{package_path}.bkp"
+ FileUtils.cp package_path, package_bkp_path
+
+ # Break the extension, rebuild it, and try to install it
+
+ write_file c_source_path do |io|
+ io.write "typo"
+ end
+
+ Gem::Package.build @spec
+
+ assert_raise Gem::Ext::BuildError do
+ installer.install
+ end
+
+ # Make sure installing the good package again still works
+
+ FileUtils.cp "#{package_path}.bkp", package_path
+
+ Dir.chdir @tempdir do
+ inst = Gem::DependencyInstaller.new domain: :local
+ inst.install package_path
+ end
+ end
+
def test_install_minimal_deps
util_setup_gems