Skip to content
Merged
3 changes: 2 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ They are still available on rubygems.org and can be installed with
* typeprof 0.33.1
* mutex_m 0.3.0
* bigdecimal 4.1.3
* 4.0.1 to [v4.1.0][bigdecimal-v4.1.0], [v4.1.1][bigdecimal-v4.1.1], [v4.1.2][bigdecimal-v4.1.2]
* 4.0.1 to [v4.1.0][bigdecimal-v4.1.0], [v4.1.1][bigdecimal-v4.1.1], [v4.1.2][bigdecimal-v4.1.2], [v4.1.3][bigdecimal-v4.1.3]
* resolv-replace 0.2.0
* 0.1.1 to [v0.2.0][resolv-replace-v0.2.0]
* nkf 0.3.0
Expand Down Expand Up @@ -607,6 +607,7 @@ A lot of work has gone into making Ractors more stable, performant, and usable.
[bigdecimal-v4.1.0]: https://github.com/ruby/bigdecimal/releases/tag/v4.1.0
[bigdecimal-v4.1.1]: https://github.com/ruby/bigdecimal/releases/tag/v4.1.1
[bigdecimal-v4.1.2]: https://github.com/ruby/bigdecimal/releases/tag/v4.1.2
[bigdecimal-v4.1.3]: https://github.com/ruby/bigdecimal/releases/tag/v4.1.3
[resolv-replace-v0.2.0]: https://github.com/ruby/resolv-replace/releases/tag/v0.2.0
[nkf-v0.3.0]: https://github.com/ruby/nkf/releases/tag/v0.3.0
[syslog-v0.4.0]: https://github.com/ruby/syslog/releases/tag/v0.4.0
Expand Down
14 changes: 12 additions & 2 deletions lib/bundler/definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def setup_domain!(options = {})

sources.cached!

if options[:add_checksums] || (!options[:local] && (install_needed? || refetch_needed?(options)))
if options[:add_checksums] || (!options[:local] && (install_needed? || refetch_needed?(options) || @locked_spec_with_empty_checksums))
sources.remote!
true
else
Expand Down Expand Up @@ -650,7 +650,7 @@ def something_changed?
@missing_lockfile_dep ||
@unlocking_bundler ||
@locked_spec_with_missing_checksums ||
@locked_spec_with_empty_checksums ||
empty_checksums_actionable? ||
@locked_spec_with_missing_deps ||
@locked_spec_with_invalid_deps
end
Expand All @@ -659,6 +659,16 @@ def resolve_needed?
unlocking? || something_changed?
end

# Only a remote fetch can fill an empty CHECKSUMS entry, so it justifies a
# resolution only when one is coming. Resolving locally for it would repeat
# on every `Bundler.setup` without changing the lockfile. Frozen mode still
# has to refuse the entry.
def empty_checksums_actionable?
return false unless @locked_spec_with_empty_checksums

Bundler.frozen_bundle? || !sources.local_mode?
end

def should_add_extra_platforms?
!lockfile_exists? && Bundler::MatchPlatform.generic_local_platform_is_ruby? && !Bundler.settings[:force_ruby_platform]
end
Expand Down
4 changes: 2 additions & 2 deletions lib/rubygems/commands/update_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ def highest_installed_gems # :nodoc:
hig = {} # highest installed gems

# Get only gem specifications installed as --user-install
Gem::Specification.dirs = Gem.user_dir if options[:user_install]
specification_record = options[:user_install] ? Gem::SpecificationRecord.from_path(Gem.user_dir) : Gem::Specification.specification_record

Gem::Specification.each do |spec|
specification_record.each do |spec|
if hig[spec.name].nil? || hig[spec.name].version < spec.version
hig[spec.name] = spec
end
Expand Down
2 changes: 2 additions & 0 deletions lib/rubygems/specification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1255,6 +1255,8 @@ def self.reset
end

unresolved_deps.clear
# find_all_by_name above memoized the record, which would outlive dirs= and ignore its new dirs
@specification_record = nil
end
Gem.post_reset_hooks.each(&:call)
end
Expand Down
30 changes: 30 additions & 0 deletions spec/bundler/lock/lockfile_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1682,6 +1682,36 @@
expect(the_bundle).not_to include_gems "myrack 0.9.1"
end

it "fills empty CHECKSUMS entries when not frozen, even if every gem is already installed" do
system_gems "myrack-0.9.1", gem_repo: gem_repo2

lockfile <<-L
GEM
remote: https://gem.repo2/
specs:
myrack (0.9.1)

PLATFORMS
#{lockfile_platforms}

DEPENDENCIES
myrack

CHECKSUMS
myrack (0.9.1)

BUNDLED WITH
#{Bundler::VERSION}
L

install_gemfile <<-G
source "https://gem.repo2"
gem "myrack"
G

expect(lockfile).to include(" #{checksum_to_lock(gem_repo2, "myrack", "0.9.1")}\n")
end

it "automatically fixes the lockfile when it's missing deps, they conflict with other locked deps, but conflicts are fixable" do
build_repo4 do
build_gem "other_dep", "0.9"
Expand Down
18 changes: 18 additions & 0 deletions spec/bundler/runtime/setup_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,24 @@ def clean_load_path(lp)
expect(bundled_app_lock).to exist
end

it "does not resolve again for the empty CHECKSUMS entries it locked itself" do
system_gems "myrack-1.0.0"

gemfile <<-G
source "https://gem.repo1"
gem "myrack"
G

ruby "require 'bundler'; Bundler.setup"
expect(out).to include("Resolving dependencies...")
lockfile = File.read(bundled_app_lock)
expect(lockfile).to match(/^CHECKSUMS\n(?: .+\n)* myrack \(1\.0\.0\)\n/)

ruby "require 'bundler'; Bundler.setup"
expect(out).not_to include("Resolving dependencies...")
expect(File.read(bundled_app_lock)).to eq(lockfile)
end

describe "$BUNDLE_GEMFILE" do
context "user provides an absolute path" do
it "uses BUNDLE_GEMFILE to locate the gemfile if present" do
Expand Down
45 changes: 45 additions & 0 deletions test/rubygems/test_gem_commands_update_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,51 @@ def test_execute_user_install
assert_empty out
end

def test_execute_user_install_with_dependency_in_system_dir
spec_fetcher do |fetcher|
fetcher.download "b", 1
fetcher.download "a", 2 do |s|
s.add_dependency "b", ">= 1"
end
end

b = util_spec "b", 1
a = util_spec("a", 1) {|s| s.add_dependency "b", ">= 1" }
install_gem b
install_gem_user a

@cmd.handle_options %w[--user-install]

use_ui @ui do
@cmd.execute
end

out = @ui.output.split "\n"
assert_equal "Updating installed gems", out.shift
assert_equal "Updating a", out.shift
assert_equal "Gems updated: a", out.shift
assert_empty out

assert_path_not_exist File.join(Gem.user_dir, "specifications", "b-1.gemspec")
end

def test_highest_installed_gems_user_install_with_unresolved_deps
a = util_spec "a", 1
b = util_spec "b", 1
install_gem_user a
install_gem b

Gem::Specification.unresolved_deps["b"] = Gem::Dependency.new("b", ">= 0")
@cmd.handle_options %w[--user-install]

hig = nil
capture_output do
hig = @cmd.highest_installed_gems
end

assert_equal %w[a], hig.keys
end

def test_fetch_remote_gems
specs = spec_fetcher do |fetcher|
fetcher.gem "a", 1
Expand Down
34 changes: 34 additions & 0 deletions test/rubygems/test_gem_specification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,40 @@ def test_self_attribute_names
assert_equal expected_value, actual_value
end

def test_self_dirs_equals_with_unresolved_deps
pend_for_ruby_box_stdio_capture
a = util_spec "a", 1
b = util_spec "b", 1
install_gem_user a
install_gem b

Gem::Specification.unresolved_deps["b"] = Gem::Dependency.new("b", ">= 0")

_, err = capture_output do
Gem::Specification.dirs = Gem.user_dir
end

assert_match(/b \(>= 0\)\n.*\n - 1\n/, err)
# JRuby replaces dirs= in rubygems/defaults/jruby.rb without the ABI scoped spec dir
assert_equal Gem::SpecificationRecord.dirs_from([Gem.user_dir]), Gem::Specification.dirs unless Gem.java_platform?
assert_equal %w[a-1], Gem::Specification.map(&:full_name)
end

def test_self_dirs_equals_keeps_specs_set_by_post_reset_hooks
b = util_spec "b", 1
install_gem b
stub = util_spec "stub", 1

Gem.post_reset { Gem::Specification.all = [stub] }
Gem::Specification.unresolved_deps["b"] = Gem::Dependency.new("b", ">= 0")

capture_output do
Gem::Specification.dirs = Gem.user_dir
end

assert_equal %w[stub-1], Gem::Specification.map(&:full_name)
end

def test_self__load_future
spec = Gem::Specification.new
spec.name = "a"
Expand Down