[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.

1c282d98d5
This commit is contained in:
David Rodríguez 2025-06-12 19:48:36 +02:00 committed by Hiroshi SHIBATA
parent 0c2f0ffa60
commit 0a62e82ac4
No known key found for this signature in database
GPG key ID: F9CF13417264FAC2
2 changed files with 55 additions and 6 deletions

View file

@ -181,14 +181,11 @@ 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
end
spec =
begin

View file

@ -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