summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Rodríguez <[email protected]>2024-10-08 20:01:25 +0200
committergit <[email protected]>2024-10-10 14:54:04 +0000
commitd12c8cbf14084c35209a9cb07bccc8b4bee7760a (patch)
tree6c24650c75e41c1c528d32111ed5030ee3ed5451
parent36e9a6bb41621793f6719c6e269ffebb422636fe (diff)
[rubygems/rubygems] Fix `gem pristine etc` resetting gem twice sometimes
If a default version and a regular version of etc are present at the same time, RubyGems will end up duplicating work and running pristine twice. The `etc` gem is special because it's loaded by RubyGems by default. When doing this, RubyGems will activate the regularly installed version. The when `gem pristine` runs, it will find to installed specifications but materialize both to the already activated specification. Before: ``` $ gem pristine etc --version 1.4.3 Restoring gems to pristine condition... Building native extensions. This could take a while... Restored etc-1.4.3 Building native extensions. This could take a while... Restored etc-1.4.3 ``` After: ``` $ gem pristine etc --version 1.4.3 Restoring gems to pristine condition... Skipped etc-1.4.3, it is a default gem Building native extensions. This could take a while... Restored etc-1.4.3 ``` https://github.com/rubygems/rubygems/commit/5c279ac56b
-rw-r--r--lib/rubygems/basic_specification.rb2
-rw-r--r--lib/rubygems/stub_specification.rb21
-rw-r--r--test/rubygems/test_gem_stub_specification.rb29
3 files changed, 41 insertions, 11 deletions
diff --git a/lib/rubygems/basic_specification.rb b/lib/rubygems/basic_specification.rb
index ccd3e49cea..8c75fd41d4 100644
--- a/lib/rubygems/basic_specification.rb
+++ b/lib/rubygems/basic_specification.rb
@@ -100,7 +100,7 @@ class Gem::BasicSpecification
end
def default_gem?
- loaded_from &&
+ !loaded_from.nil? &&
File.dirname(loaded_from) == Gem.default_specifications_dir
end
diff --git a/lib/rubygems/stub_specification.rb b/lib/rubygems/stub_specification.rb
index ea66fbc3f6..4f6a70ba4b 100644
--- a/lib/rubygems/stub_specification.rb
+++ b/lib/rubygems/stub_specification.rb
@@ -83,11 +83,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
# True when this gem has been activated
def activated?
- @activated ||=
- begin
- loaded = Gem.loaded_specs[name]
- loaded && loaded.version == version
- end
+ @activated ||= !loaded_spec.nil?
end
def default_gem?
@@ -187,11 +183,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
# The full Gem::Specification for this gem, loaded from evalling its gemspec
def spec
- @spec ||= if @data
- loaded = Gem.loaded_specs[name]
- loaded if loaded && loaded.version == version
- end
-
+ @spec ||= loaded_spec if @data
@spec ||= Gem::Specification.load(loaded_from)
end
alias_method :to_spec, :spec
@@ -231,4 +223,13 @@ class Gem::StubSpecification < Gem::BasicSpecification
def sort_obj # :nodoc:
[name, version, Gem::Platform.sort_priority(platform)]
end
+
+ private
+
+ def loaded_spec
+ spec = Gem.loaded_specs[name]
+ return unless spec && spec.version == version && spec.default_gem? == default_gem?
+
+ spec
+ end
end
diff --git a/test/rubygems/test_gem_stub_specification.rb b/test/rubygems/test_gem_stub_specification.rb
index 471fb6bbb2..4b2d4c570a 100644
--- a/test/rubygems/test_gem_stub_specification.rb
+++ b/test/rubygems/test_gem_stub_specification.rb
@@ -171,6 +171,35 @@ class TestStubSpecification < Gem::TestCase
assert_same real_foo, @foo.to_spec
end
+ def test_to_spec_default
+ bar_default_spec = File.join(@gemhome, "specifications", "default", "bar-0.0.2.gemspec")
+ File.open bar_default_spec, "w" do |io|
+ io.write <<~STUB
+ # -*- encoding: utf-8 -*-
+ # stub: bar 0.0.2 ruby lib
+
+ Gem::Specification.new do |s|
+ s.name = "bar"
+ s.version = "0.0.2"
+ s.platform = "ruby"
+ s.require_paths = ["lib"]
+ s.summary = "A very bar gem"
+ end
+ STUB
+ end
+
+ bar = Gem::StubSpecification.gemspec_stub BAR, @base_dir, @gems_dir
+ bar_default = Gem::StubSpecification.default_gemspec_stub bar_default_spec, @base_dir, @gems_dir
+
+ real_bar = util_spec bar_default.name, bar_default.version
+ real_bar.activate
+
+ assert_equal bar.version, Gem.loaded_specs[bar.name].version,
+ "sanity check"
+
+ refute_same real_bar, bar_default.to_spec
+ end
+
def test_to_spec_with_other_specs_loaded_does_not_warn
real_foo = util_spec @foo.name, @foo.version
real_foo.activate