Skip to content

Commit

Permalink
Merge pull request rubygems#8459 from rubygems/deivid-rodriguez/avoid…
Browse files Browse the repository at this point in the history
…-race-condition

Fix `bundle install` output sometimes getting interleaved
  • Loading branch information
deivid-rodriguez authored Feb 13, 2025
2 parents 126cfe2 + a33aeb3 commit 0027440
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 28 deletions.
5 changes: 2 additions & 3 deletions bundler/lib/bundler/rubygems_integration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def reverse_rubygems_kernel_mixin
end
end

def replace_gem(specs, specs_by_name)
def replace_gem(specs_by_name)
executables = nil

[::Kernel.singleton_class, ::Kernel].each do |kernel_class|
Expand Down Expand Up @@ -274,7 +274,7 @@ def replace_entrypoints(specs)
else
Gem::BUNDLED_GEMS.replace_require(specs) if Gem::BUNDLED_GEMS.respond_to?(:replace_require)
end
replace_gem(specs, specs_by_name)
replace_gem(specs_by_name)
stub_rubygems(specs_by_name.values)
replace_bin_path(specs_by_name)

Expand All @@ -293,7 +293,6 @@ def add_default_gems_to(specs)
default_spec_name = default_spec.name
next if specs_by_name.key?(default_spec_name)

specs << default_spec
specs_by_name[default_spec_name] = default_spec
end

Expand Down
70 changes: 45 additions & 25 deletions bundler/lib/bundler/spec_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,13 @@ def [](key)
end

def []=(key, value)
@specs << value
delete_by_name(key)

reset!
add_spec(value)
end

def delete(specs)
Array(specs).each {|spec| @specs.delete(spec) }

reset!
Array(specs).each {|spec| remove_spec(spec) }
end

def sort!
Expand Down Expand Up @@ -168,8 +166,10 @@ def specs_with_additional_variants_from(other)

def delete_by_name(name)
@specs.reject! {|spec| spec.name == name }
@sorted&.reject! {|spec| spec.name == name }
return if @lookup.nil?

reset!
@lookup[name] = nil
end

def version_for(name)
Expand Down Expand Up @@ -248,11 +248,6 @@ def materialized_specs
@materializations.filter_map(&:materialized_spec)
end

def reset!
@sorted = nil
@lookup = nil
end

def complete_platform(platform)
new_specs = []

Expand All @@ -272,9 +267,7 @@ def complete_platform(platform)
end

if valid_platform && new_specs.any?
@specs.concat(new_specs)

reset!
new_specs.each {|spec| add_spec(spec) }
end

valid_platform
Expand All @@ -295,15 +288,12 @@ def valid_dependencies?(s)
end

def sorted
rake = @specs.find {|s| s.name == "rake" }
begin
@sorted ||= ([rake] + tsort).compact.uniq
rescue TSort::Cyclic => error
cgems = extract_circular_gems(error)
raise CyclicDependencyError, "Your bundle requires gems that depend" \
" on each other, creating an infinite loop. Please remove either" \
" gem '#{cgems[0]}' or gem '#{cgems[1]}' and try again."
end
@sorted ||= ([@specs.find {|s| s.name == "rake" }] + tsort).compact.uniq
rescue TSort::Cyclic => error
cgems = extract_circular_gems(error)
raise CyclicDependencyError, "Your bundle requires gems that depend" \
" on each other, creating an infinite loop. Please remove either" \
" gem '#{cgems[0]}' or gem '#{cgems[1]}' and try again."
end

def extract_circular_gems(error)
Expand All @@ -314,8 +304,7 @@ def lookup
@lookup ||= begin
lookup = {}
@specs.each do |s|
lookup[s.name] ||= []
lookup[s.name] << s
index_spec(lookup, s.name, s)
end
lookup
end
Expand All @@ -336,5 +325,36 @@ def tsort_each_child(s)
specs_for_name.each {|s2| yield s2 }
end
end

def add_spec(spec)
@specs << spec

name = spec.name

@sorted&.insert(@sorted.bsearch_index {|s| s.name >= name } || @sorted.size, spec)
return if @lookup.nil?

index_spec(@lookup, name, spec)
end

def remove_spec(spec)
@specs.delete(spec)
@sorted&.delete(spec)
return if @lookup.nil?

indexed_specs = @lookup[spec.name]
return unless indexed_specs

if indexed_specs.size > 1
@lookup[spec.name].delete(spec)
else
@lookup[spec.name] = nil
end
end

def index_spec(hash, key, value)
hash[key] ||= []
hash[key] << value
end
end
end

0 comments on commit 0027440

Please sign in to comment.