class Bundler::Explain::Source
Public Class Methods
new(requirements:, platform:, resolver:)
click to toggle source
# File lib/bundler/explain/source.rb, line 6 def initialize(requirements:, platform:, resolver:) @definition = Bundler.definition(true) @requirements = requirements @resolver = resolver @specs_by_name = Hash.new do |h, name| @resolver.search_for(Bundler::DepProxy.new(Gem::Dependency.new(name), platform)).reverse end @sorted_specs_by_name = Hash.new do |h, name| h[name] = @specs_by_name[name].sort_by(&:version) end @package_by_name = Hash.new do |h, name| h[name] = PubGrub::Package.new(name) end @deps_by_spec = Hash.new do |h, s| h[s] = s.dependencies_for_activated_platforms.map do |dep| [dep.name, dep.requirement] end.to_h end end
Public Instance Methods
incompatibilities_for(package, version) { |incompatibility([source_term, target_term], cause: :dependency)| ... }
click to toggle source
# File lib/bundler/explain/source.rb, line 44 def incompatibilities_for(package, version) return enum_for(__method__, package, version) unless block_given? if package == root_package source_constraint = PubGrub::VersionConstraint.exact(package, version) source_term = PubGrub::Term.new(source_constraint, true) @requirements.each do |dependency| target_constraint = constraint_for_dep(dependency.name, dependency.dep.requirement) target_term = PubGrub::Term.new(target_constraint, false) yield PubGrub::Incompatibility.new([source_term, target_term], cause: :dependency) end else specs = @specs_by_name[package.name] spec = specs.detect { |s| s.version == version } raise "can't find spec" unless spec @deps_by_spec[spec].each do |dep_name, dep_requirement| # Default case target_constraint = constraint_for_dep(dep_name, dep_requirement) source_constraint = range_constraint(spec) do |near_spec| @deps_by_spec[near_spec][dep_name] == dep_requirement end yield dependency_incompatiblity(source_constraint, target_constraint) # Special case: exact dependencies (like rails 5.0.7 requires) # We want to add an extra loosened (semver-like) dependency in # addition to the exact dependency above. if dep_requirement.exact? dep_version = dep_requirement.requirements[0][1] if dep_version == spec.version derived_requirements(dep_version).each do |new_requirement| next unless new_requirement === dep_version target_constraint = constraint_for_dep(dep_name, new_requirement) source_constraint = range_constraint(spec) do |near_spec| near_dep = @deps_by_spec[near_spec][dep_name] near_dep && near_dep.exact? && new_requirement === near_dep.requirements[0][1] end yield dependency_incompatiblity(source_constraint, target_constraint) end end end end end end
root_package()
click to toggle source
# File lib/bundler/explain/source.rb, line 30 def root_package PubGrub::Package.root end
versions_for(package, range)
click to toggle source
# File lib/bundler/explain/source.rb, line 34 def versions_for(package, range) return [PubGrub::Package.root_version] if package == root_package @specs_by_name[package.name].map do |spec_group| spec_group.version end.select do |version| range.include?(version) end end
Private Instance Methods
constraint_between_specs(package, low_spec, high_spec)
click to toggle source
# File lib/bundler/explain/source.rb, line 124 def constraint_between_specs(package, low_spec, high_spec) low_version = low_spec && low_spec.version high_version = high_spec && high_spec.version if !low_spec && !high_spec PubGrub::VersionConstraint.any(package) elsif low_spec == high_spec PubGrub::VersionConstraint.exact(package, low_version) else range = PubGrub::VersionRange.new(min: low_version, max: high_version, include_min: true) PubGrub::VersionConstraint.new(package, range: range) end end
constraint_for_dep(name, requirement)
click to toggle source
# File lib/bundler/explain/source.rb, line 164 def constraint_for_dep(name, requirement) package = @package_by_name[name] PubGrub::RubyGems.requirement_to_constraint(package, requirement) end
dependency_incompatiblity(source_constraint, target_constraint)
click to toggle source
# File lib/bundler/explain/source.rb, line 110 def dependency_incompatiblity(source_constraint, target_constraint) source_term = PubGrub::Term.new(source_constraint, true) target_term = PubGrub::Term.new(target_constraint, false) PubGrub::Incompatibility.new([source_term, target_term], cause: :dependency) end
derived_requirements(original_version) { |requirement(">= #{s}.#{s}.a", "< #{release}")| ... }
click to toggle source
# File lib/bundler/explain/source.rb, line 96 def derived_requirements(original_version) return enum_for(__method__, original_version) unless block_given? v = original_version s = original_version.segments return [] unless s.length >= 3 yield Gem::Requirement.new(">= #{s[0]}.#{s[1]}.a", "< #{v.release}") yield Gem::Requirement.new(["~> #{s[0]}.#{s[1]}.0"]) yield Gem::Requirement.new(["~> #{s[0]}.#{s[1]}.0.a"]) yield Gem::Requirement.new(["~> #{s[0]}.0.a"]) end
range_constraint(spec, &block)
click to toggle source
# File lib/bundler/explain/source.rb, line 116 def range_constraint(spec, &block) sorted_specs = @sorted_specs_by_name[spec.name] package = @package_by_name[spec.name] low, high = range_matching(sorted_specs, sorted_specs.index(spec), &block) constraint_between_specs(package, low && sorted_specs[low], high && sorted_specs[high]) end
range_matching(sorted_list, index) { |sorted_list| ... }
click to toggle source
# File lib/bundler/explain/source.rb, line 138 def range_matching(sorted_list, index) low = high = index raise "range_matching started at non-matching index" unless yield(sorted_list[index]) loop do high += 1 if high >= sorted_list.length high = nil break end break unless yield(sorted_list[high]) end loop do low -= 1 if low < 0 low = nil break end break unless yield(sorted_list[low]) end [low && low + 1, high] end