diff options
Diffstat (limited to 'lib/bundler/spec_set.rb')
-rw-r--r-- | lib/bundler/spec_set.rb | 133 |
1 files changed, 107 insertions, 26 deletions
diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index 21630e3a3e..8e1130e40e 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -37,7 +37,7 @@ module Bundler specs_for_dep.first.dependencies.each do |d| next if d.type == :development - incomplete = true if d.name != "bundler" && lookup[d.name].empty? + incomplete = true if d.name != "bundler" && lookup[d.name].nil? deps << [d, dep[1]] end else @@ -45,28 +45,64 @@ module Bundler end if incomplete && check - @incomplete_specs += lookup[name].any? ? lookup[name] : [LazySpecification.new(name, nil, nil)] + @incomplete_specs += lookup[name] || [LazySpecification.new(name, nil, nil)] end end specs.uniq end + def add_extra_platforms!(platforms) + return platforms.concat([Gem::Platform::RUBY]).uniq if @specs.empty? + + new_platforms = all_platforms.select do |platform| + next if platforms.include?(platform) + next unless GemHelpers.generic(platform) == Gem::Platform::RUBY + + complete_platform(platform) + end + return platforms if new_platforms.empty? + + platforms.concat(new_platforms) + + less_specific_platform = new_platforms.find {|platform| platform != Gem::Platform::RUBY && Bundler.local_platform === platform && platform === Bundler.local_platform } + platforms.delete(Bundler.local_platform) if less_specific_platform + + platforms + end + + def complete_platforms!(platforms) + platforms.each do |platform| + complete_platform(platform) + end + end + + def validate_deps(s) + s.runtime_dependencies.each do |dep| + next if dep.name == "bundler" + + return :missing unless names.include?(dep.name) + return :invalid if none? {|spec| dep.matches_spec?(spec) } + end + + :valid + end + def [](key) key = key.name if key.respond_to?(:name) - lookup[key].reverse + lookup[key]&.reverse || [] end def []=(key, value) @specs << value - @lookup = nil - @sorted = nil + + reset! end def delete(specs) specs.each {|spec| @specs.delete(spec) } - @lookup = nil - @sorted = nil + + reset! end def sort! @@ -93,6 +129,7 @@ module Bundler def materialized_for_all_platforms @specs.map do |s| next s unless s.is_a?(LazySpecification) + s.source.cached! s.source.remote! spec = s.materialize_for_installation raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec @@ -100,12 +137,12 @@ module Bundler end end - def incomplete_ruby_specs?(deps) + def incomplete_for_platform?(deps, platform) return false if @specs.empty? @incomplete_specs = [] - self.for(deps, true, [Gem::Platform::RUBY]) + self.for(deps, true, [platform]) @incomplete_specs.any? end @@ -114,16 +151,6 @@ module Bundler @specs.select {|s| s.is_a?(LazySpecification) } end - def merge(set) - arr = sorted.dup - set.each do |set_spec| - full_name = set_spec.full_name - next if arr.any? {|spec| spec.full_name == full_name } - arr << set_spec - end - SpecSet.new(arr) - end - def -(other) SpecSet.new(to_a - other.to_a) end @@ -134,12 +161,12 @@ module Bundler def delete_by_name(name) @specs.reject! {|spec| spec.name == name } - @lookup = nil - @sorted = nil + + reset! end def what_required(spec) - unless req = find {|s| s.dependencies.any? {|d| d.type == :runtime && d.name == spec.name } } + unless req = find {|s| s.runtime_dependencies.any? {|d| d.name == spec.name } } return [spec] end what_required(req) << spec @@ -165,8 +192,52 @@ module Bundler sorted.each(&b) end + def names + lookup.keys + end + private + def reset! + @sorted = nil + @lookup = nil + end + + def complete_platform(platform) + new_specs = [] + + valid_platform = lookup.all? do |_, specs| + spec = specs.first + matching_specs = spec.source.specs.search([spec.name, spec.version]) + platform_spec = GemHelpers.select_best_platform_match(matching_specs, platform).find do |s| + s.matches_current_metadata? && valid_dependencies?(s) + end + + if platform_spec + new_specs << LazySpecification.from_spec(platform_spec) unless specs.include?(platform_spec) + true + else + false + end + end + + if valid_platform && new_specs.any? + @specs.concat(new_specs) + + reset! + end + + valid_platform + end + + def all_platforms + @specs.flat_map {|spec| spec.source.specs.search([spec.name, spec.version]).map(&:platform) }.uniq + end + + def valid_dependencies?(s) + validate_deps(s) == :valid + end + def sorted rake = @specs.find {|s| s.name == "rake" } begin @@ -185,8 +256,9 @@ module Bundler def lookup @lookup ||= begin - lookup = Hash.new {|h, k| h[k] = [] } + lookup = {} @specs.each do |s| + lookup[s.name] ||= [] lookup[s.name] << s end lookup @@ -200,8 +272,13 @@ module Bundler def specs_for_dependency(dep, platform) specs_for_name = lookup[dep.name] - target_platform = dep.force_ruby_platform ? Gem::Platform::RUBY : (platform || Bundler.local_platform) - matching_specs = GemHelpers.select_best_platform_match(specs_for_name, target_platform) + return [] unless specs_for_name + + matching_specs = if dep.force_ruby_platform + GemHelpers.force_ruby_platform(specs_for_name) + else + GemHelpers.select_best_platform_match(specs_for_name, platform || Bundler.local_platform) + end matching_specs.map!(&:materialize_for_installation).compact! if platform.nil? matching_specs end @@ -209,7 +286,11 @@ module Bundler def tsort_each_child(s) s.dependencies.sort_by(&:name).each do |d| next if d.type == :development - lookup[d.name].each {|s2| yield s2 } + + specs_for_name = lookup[d.name] + next unless specs_for_name + + specs_for_name.each {|s2| yield s2 } end end end |