From e58c0f2f6508a3a15fd505d97f7991a4265a8019 Mon Sep 17 00:00:00 2001 From: Lukas Oberhuber Date: Mon, 21 Dec 2020 11:30:40 +0000 Subject: [PATCH 1/4] Port of `force_version` POC Link to POC https://github.com/rubygems/bundler/pull/5670 Co-authored-by: Samuel Giddins --- bundler/lib/bundler/dependency.rb | 5 ++ bundler/lib/bundler/dsl.rb | 6 ++- bundler/lib/bundler/resolver.rb | 9 +++- bundler/lib/bundler/rubygems_ext.rb | 4 ++ bundler/spec/install/gemfile/force_spec.rb | 55 ++++++++++++++++++++++ 5 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 bundler/spec/install/gemfile/force_spec.rb diff --git a/bundler/lib/bundler/dependency.rb b/bundler/lib/bundler/dependency.rb index af07e8bc363c..c35a40e5319d 100644 --- a/bundler/lib/bundler/dependency.rb +++ b/bundler/lib/bundler/dependency.rb @@ -89,6 +89,7 @@ def initialize(name, version, options = {}, &blk) @gemfile = options["gemfile"] @autorequire = Array(options["require"] || []) if options.key?("require") + @force_version = options.fetch("force_version", false) end # Returns the platforms this dependency is valid for, in the same order as @@ -111,6 +112,10 @@ def should_include? @should_include && current_env? && current_platform? end + def force_version? + @force_version + end + def current_env? return true unless @env if @env.is_a?(Hash) diff --git a/bundler/lib/bundler/dsl.rb b/bundler/lib/bundler/dsl.rb index 1cc7908b8a88..9cf23eb278f1 100644 --- a/bundler/lib/bundler/dsl.rb +++ b/bundler/lib/bundler/dsl.rb @@ -16,7 +16,7 @@ def self.evaluate(gemfile, lockfile, unlock) VALID_PLATFORMS = Bundler::Dependency::PLATFORM_MAP.keys.freeze VALID_KEYS = %w[group groups git path glob name branch ref tag require submodules - platform platforms type source install_if gemfile].freeze + platform platforms type source install_if gemfile force_version].freeze attr_reader :gemspecs attr_accessor :dependencies @@ -371,6 +371,10 @@ def normalize_options(name, version, opts) opts["source"] = @sources.add_rubygems_source("remotes" => source) end + if opts.key?("force_version") && (r = Gem::Requirement.new(version)) && !r.exact? + raise GemfileError, "Cannot use force_version for inexact version requirement `#{r}`" + end + git_name = (git_names & opts.keys).last if @git_sources[git_name] opts["git"] = @git_sources[git_name].call(opts[git_name]) diff --git a/bundler/lib/bundler/resolver.rb b/bundler/lib/bundler/resolver.rb index 636dc8af4621..adaf960c6d8b 100644 --- a/bundler/lib/bundler/resolver.rb +++ b/bundler/lib/bundler/resolver.rb @@ -203,7 +203,7 @@ def name_for_locking_dependency_source end def requirement_satisfied_by?(requirement, activated, spec) - requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec) + requirement.matches_spec?(spec) || allows_conflicts?(requirement, activated, spec) end def relevant_sources_for_vertex(vertex) @@ -436,5 +436,12 @@ def validate_resolved_specs!(resolved_specs) Bundler.ui.warn "Warning: #{msg}" end end + + def allows_conflicts?(requirement, activated, spec) + return true if spec.source.is_a?(Source::Gemspec) + return false if requirement.force_version? + return true if activated.vertex_named(spec.name).requirements.any?(&:force_version?) + false + end end end diff --git a/bundler/lib/bundler/rubygems_ext.rb b/bundler/lib/bundler/rubygems_ext.rb index 0322b06d0787..824b873c3b54 100644 --- a/bundler/lib/bundler/rubygems_ext.rb +++ b/bundler/lib/bundler/rubygems_ext.rb @@ -127,6 +127,10 @@ def to_lock end out end + + def force_version? + false + end end # comparison is done order independently since rubygems 3.2.0.rc.2 diff --git a/bundler/spec/install/gemfile/force_spec.rb b/bundler/spec/install/gemfile/force_spec.rb new file mode 100644 index 000000000000..9393e5e97088 --- /dev/null +++ b/bundler/spec/install/gemfile/force_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true +require "spec_helper" + +RSpec.describe "bundle install with a gemfile that forces a gem version" do + context "with a simple conflict" do + it "works" do + install_gemfile <<-G + source "file:#{gem_repo1}" + gem "rack_middleware" + gem "rack", "1.0.0", :force_version => true + G + + expect(the_bundle).to include_gems("rack 1.0.0", "rack_middleware 1.0") + end + + it "raises when forcing to an inexact version" do + install_gemfile <<-G + gem "rack", "> 1.0.0", :force_version => true + G + + bundle :install, :env => { "DEBUG" => "1" } + + expect(out).to include("Cannot use force_version for inexact version requirement `> 1.0.0`.") + end + + it "raises when forcing without specifying a version" do + install_gemfile <<-G + gem "rack", :force_version => true + G + + expect(out).to include("Cannot use force_version for inexact version requirement `>= 0`.") + end + + it "works when there's no conflict" do + install_gemfile <<-G + source "file:#{gem_repo1}" + gem "rack", "1.0.0", :force_version => true + G + + expect(the_bundle).to include_gems("rack 1.0.0") + end + end + + context "with a complex conflict" do + it "works" do + install_gemfile <<-G + source "file:#{gem_repo1}" + gem "rails", "2.3.2" + gem "activesupport", "2.3.5", :force_version => true + G + + expect(the_bundle).to include_gems("rails 2.3.2", "activesupport 2.3.5", "actionpack 2.3.2", "activerecord 2.3.2", "actionmailer 2.3.2", "activeresource 2.3.2") + end + end +end From 4fb53e85eba565e4ac8c6387728feb9b3b076e29 Mon Sep 17 00:00:00 2001 From: Lukas Oberhuber Date: Mon, 21 Dec 2020 11:31:22 +0000 Subject: [PATCH 2/4] Implement `force_version: true` logic for gems --- bundler/lib/bundler.rb | 8 +- bundler/lib/bundler/resolver.rb | 30 ++++- bundler/lib/bundler/source.rb | 4 + .../delegates/specification_provider.rb | 7 + .../molinillo/lib/molinillo/resolution.rb | 12 +- bundler/spec/install/gemfile/force_spec.rb | 122 ++++++++++++++++-- 6 files changed, 164 insertions(+), 19 deletions(-) diff --git a/bundler/lib/bundler.rb b/bundler/lib/bundler.rb index c72ad27c401b..cf4ca80eb30a 100644 --- a/bundler/lib/bundler.rb +++ b/bundler/lib/bundler.rb @@ -196,6 +196,10 @@ def definition(unlock = nil) end end + def definition? + defined?(@definition) && @definition + end + def frozen_bundle? frozen = settings[:deployment] frozen ||= settings[:frozen] unless feature_flag.deployment_means_frozen? @@ -204,7 +208,7 @@ def frozen_bundle? def locked_gems @locked_gems ||= - if defined?(@definition) && @definition + if definition? definition.locked_gems elsif Bundler.default_lockfile.file? lock = Bundler.read_file(Bundler.default_lockfile) @@ -213,7 +217,7 @@ def locked_gems end def most_specific_locked_platform?(platform) - return false unless defined?(@definition) && @definition + return false unless definition? definition.most_specific_locked_platform == platform end diff --git a/bundler/lib/bundler/resolver.rb b/bundler/lib/bundler/resolver.rb index adaf960c6d8b..ce8b2c7cf9cf 100644 --- a/bundler/lib/bundler/resolver.rb +++ b/bundler/lib/bundler/resolver.rb @@ -203,7 +203,21 @@ def name_for_locking_dependency_source end def requirement_satisfied_by?(requirement, activated, spec) - requirement.matches_spec?(spec) || allows_conflicts?(requirement, activated, spec) + return true if spec.source.is_a?(Source::Gemspec) + return true if requirement.matches_spec?(spec) && + forced_or_no_forced_alternative_spec(requirement, activated, spec) + return true if !requirement.matches_spec?(spec) && is_forced_spec(activated, spec) + false + end + + # Forced version overrides all other requirements + def requirements_satisfied_by?(requirements, activated, possibility) + forced_req = requirements.find(&:force_version?) + if forced_req + requirement_satisfied_by?(forced_req, activated, possibility) + else + requirements.all? {|req| requirement_satisfied_by?(req, activated, possibility) } + end end def relevant_sources_for_vertex(vertex) @@ -225,6 +239,7 @@ def sort_dependencies(dependencies, activated, conflicts) @base_dg.vertex_named(name) ? 0 : 1, vertex.payload ? 0 : 1, vertex.root? ? 0 : 1, + dependency.force_version? ? 0 : 1, amount_constrained(dependency), conflicts[name] ? 0 : 1, vertex.payload ? 0 : search_for(dependency).count, @@ -437,11 +452,14 @@ def validate_resolved_specs!(resolved_specs) end end - def allows_conflicts?(requirement, activated, spec) - return true if spec.source.is_a?(Source::Gemspec) - return false if requirement.force_version? - return true if activated.vertex_named(spec.name).requirements.any?(&:force_version?) - false + def forced_or_no_forced_alternative_spec(requirement, activated, spec) + requirement.force_version? || !activated.vertex_named(spec.name)&.requirements&.any?(&:force_version?) + end + + def is_forced_spec(activated, spec) + activated.vertex_named(spec.name)&. + requirements&.select(&:force_version?)&. + any? {|r| r.matches_spec?(spec) } end end end diff --git a/bundler/lib/bundler/source.rb b/bundler/lib/bundler/source.rb index be00143f5a40..98868c9e53ad 100644 --- a/bundler/lib/bundler/source.rb +++ b/bundler/lib/bundler/source.rb @@ -18,6 +18,10 @@ def version_message(spec) message = "#{spec.name} #{spec.version}" message += " (#{spec.platform})" if spec.platform != Gem::Platform::RUBY && !spec.platform.nil? + if Bundler.definition? && Bundler.definition.dependencies.select {|d| d.name == spec.name }.any?(&:force_version?) + message += " [version forced]" + end + if Bundler.locked_gems locked_spec = Bundler.locked_gems.specs.find {|s| s.name == spec.name } locked_spec_version = locked_spec.version if locked_spec diff --git a/bundler/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb b/bundler/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb index ec9c770a2889..84b0a940a23e 100644 --- a/bundler/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +++ b/bundler/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb @@ -26,6 +26,13 @@ def requirement_satisfied_by?(requirement, activated, spec) end end + # (see Bundler::Molinillo::SpecificationProvider#requirements_satisfied_by?) + def requirements_satisfied_by?(requirements, activated, spec) + with_no_such_dependency_error_handling do + specification_provider.requirements_satisfied_by?(requirements, activated, spec) + end + end + # (see Bundler::Molinillo::SpecificationProvider#name_for) def name_for(dependency) with_no_such_dependency_error_handling do diff --git a/bundler/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb b/bundler/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb index 26b8bc745c40..7c22f08750dd 100644 --- a/bundler/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +++ b/bundler/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb @@ -218,7 +218,7 @@ def resolve_activated_specs next unless vertex.payload latest_version = vertex.payload.possibilities.reverse_each.find do |possibility| - vertex.requirements.all? { |req| requirement_satisfied_by?(req, activated, possibility) } + requirements_satisfied_by?(vertex.requirements, activated, possibility) end activated.set_payload(vertex.name, latest_version) @@ -473,7 +473,7 @@ def possibility_satisfies_requirements?(possibility, requirements) activated.tag(:swap) activated.set_payload(name, possibility) if activated.vertex_named(name) - satisfied = requirements.all? { |r| requirement_satisfied_by?(r, activated, possibility) } + satisfied = requirements_satisfied_by?(requirements, activated, possibility) activated.rewind_to(:swap) satisfied @@ -702,7 +702,13 @@ def attempt_to_filter_existing_spec(vertex) # @param [Object] vertex existing vertex # @return [PossibilitySet] filtered possibility set def filtered_possibility_set(vertex) - PossibilitySet.new(vertex.payload.dependencies, vertex.payload.possibilities & possibility.possibilities) + filtered = if vertex.requirements.any?(&:force_version?) + debug(depth) { "Forced version from existing spec (#{vertex.payload})" } + vertex.payload.possibilities + else + vertex.payload.possibilities & possibility.possibilities + end + PossibilitySet.new(vertex.payload.dependencies, filtered) end # @param [String] requirement_name the spec name to search for diff --git a/bundler/spec/install/gemfile/force_spec.rb b/bundler/spec/install/gemfile/force_spec.rb index 9393e5e97088..eb73b2dd96f5 100644 --- a/bundler/spec/install/gemfile/force_spec.rb +++ b/bundler/spec/install/gemfile/force_spec.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true + require "spec_helper" RSpec.describe "bundle install with a gemfile that forces a gem version" do context "with a simple conflict" do it "works" do install_gemfile <<-G - source "file:#{gem_repo1}" + source "#{file_uri_for(gem_repo1)}" gem "rack_middleware" gem "rack", "1.0.0", :force_version => true G @@ -14,42 +15,147 @@ end it "raises when forcing to an inexact version" do - install_gemfile <<-G + gemfile <<-G gem "rack", "> 1.0.0", :force_version => true G - bundle :install, :env => { "DEBUG" => "1" } + bundle :install, :quiet => true, :raise_on_error => false - expect(out).to include("Cannot use force_version for inexact version requirement `> 1.0.0`.") + expect(exitstatus).to_not eq(0) + expect(err).to include("Cannot use force_version for inexact version requirement `> 1.0.0`.") end it "raises when forcing without specifying a version" do - install_gemfile <<-G + gemfile <<-G gem "rack", :force_version => true G - expect(out).to include("Cannot use force_version for inexact version requirement `>= 0`.") + bundle :install, :quiet => true, :raise_on_error => false + + expect(exitstatus).to_not eq(0) + expect(err).to include("Cannot use force_version for inexact version requirement `>= 0`.") end it "works when there's no conflict" do install_gemfile <<-G - source "file:#{gem_repo1}" + source "#{file_uri_for(gem_repo1)}" gem "rack", "1.0.0", :force_version => true G expect(the_bundle).to include_gems("rack 1.0.0") end + + it "raises when gem doesn't exist" do + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "rack_middleware" + gem "rack", "2.0.0", :force_version => true + G + + bundle :install, :quiet => true, :raise_on_error => false + + expect(exitstatus).to_not eq(0) + expect(err).to include("Could not find gem 'rack (= 2.0.0)") + end end context "with a complex conflict" do it "works" do install_gemfile <<-G - source "file:#{gem_repo1}" + source "#{file_uri_for(gem_repo1)}" gem "rails", "2.3.2" gem "activesupport", "2.3.5", :force_version => true G expect(the_bundle).to include_gems("rails 2.3.2", "activesupport 2.3.5", "actionpack 2.3.2", "activerecord 2.3.2", "actionmailer 2.3.2", "activeresource 2.3.2") end + + it "resolves even with clashing requirements" do + build_repo4 do + build_gem "first_parent", %w[1.0.0] do |s| + s.add_dependency "wasabi", "~> 3.6" + end + build_gem "second_parent", %w[1.0.0] do |s| + s.add_dependency "wasabi", "~> 3.1.0" + end + build_gem "wasabi", %w[3.1.0 3.6.1] + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "first_parent" + gem "second_parent" + gem "wasabi", "3.6.1", :force_version => true + G + + expect(the_bundle).to include_gems("first_parent 1.0.0", "second_parent 1.0.0", "wasabi 3.6.1") + end + + it "resolves even with complex multi-source" do + build_repo2 do + build_gem "sfmc-fuelsdk-ruby", %w[1.3.2] do |s| + s.add_dependency "wasabi", "3.6.1" + s.add_dependency "jwt", "~> 2.2" + end + build_gem "cognito-rack", %w[0.16.6] do |s| + s.add_dependency "jwt", "~> 2.2" + end + end + + build_repo4 do + build_gem "skynet", %w[2.0.2] do |s| + s.add_dependency "sfmc-fuelsdk-ruby", "1.3.2" + end + build_gem "sfmc-fuelsdk-ruby", %w[1.3.0] do |s| + s.add_dependency "wasabi", "3.1.0" + s.add_dependency "jwt", [">= 1.0.0", "~> 1.0"] + end + build_gem "wasabi", %w[3.1.0 3.6.1] + build_gem "jwt", %w[1.0.0 2.2] + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "skynet" + source "#{file_uri_for(gem_repo2)}" do + gem "sfmc-fuelsdk-ruby" + gem "cognito-rack" + end + G + + gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "sfmc-fuelsdk-ruby", "1.3.0", :force_version => true + gem "jwt", "2.2", :force_version => true + gem "skynet" + source "#{file_uri_for(gem_repo2)}" do + gem "cognito-rack" + end + G + + bundle "update sfmc-fuelsdk-ruby" + + expect(the_bundle).to include_gems("skynet 2.0.2", "sfmc-fuelsdk-ruby 1.3.0", "wasabi 3.1.0") + end + end + + context "shows indicator that force_version was active" do + it "works" do + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "rack_middleware" + gem "rack", "1.0.0", :force_version => true + G + + bundle :install + + expect(out).to include("Installing rack 1.0.0 [version forced]") + + if Gem::Version.create(Bundler::VERSION).segments.first < 3 + bundle :install + + expect(out).to include("Using rack 1.0.0 [version forced]") + end + end end end From 1d04c7ff95a2dffcb133965717b1b72dc2e3dd24 Mon Sep 17 00:00:00 2001 From: Lukas Oberhuber Date: Sun, 27 Dec 2020 16:11:03 +0000 Subject: [PATCH 3/4] Remove all changes to vendored Molinillo --- bundler/lib/bundler/resolver.rb | 42 +++++++++---------- .../delegates/specification_provider.rb | 7 ---- .../molinillo/lib/molinillo/resolution.rb | 12 ++---- 3 files changed, 22 insertions(+), 39 deletions(-) diff --git a/bundler/lib/bundler/resolver.rb b/bundler/lib/bundler/resolver.rb index ce8b2c7cf9cf..97c98741195e 100644 --- a/bundler/lib/bundler/resolver.rb +++ b/bundler/lib/bundler/resolver.rb @@ -46,6 +46,8 @@ def start(requirements) @gem_version_promoter.prerelease_specified = @prerelease_specified = {} requirements.each {|dep| @prerelease_specified[dep.name] ||= dep.prerelease? } + @forced_requirements = requirements.select {|dep| dep.force_version? } + verify_gemfile_dependencies_are_found!(requirements) dg = @resolver.resolve(requirements, @base_dg) dg. @@ -103,7 +105,14 @@ def indicate_progress include Molinillo::SpecificationProvider def dependencies_for(specification) - specification.dependencies_for_activated_platforms + deps = specification.dependencies_for_activated_platforms + deps.map do |dep| + if @forced_requirements.map(&:name).include?(dep.name) + @forced_requirements.find {|r| r.name == dep.name } + else + dep + end + end end def search_for(dependency_proxy) @@ -204,23 +213,20 @@ def name_for_locking_dependency_source def requirement_satisfied_by?(requirement, activated, spec) return true if spec.source.is_a?(Source::Gemspec) - return true if requirement.matches_spec?(spec) && - forced_or_no_forced_alternative_spec(requirement, activated, spec) - return true if !requirement.matches_spec?(spec) && is_forced_spec(activated, spec) - false - end - # Forced version overrides all other requirements - def requirements_satisfied_by?(requirements, activated, possibility) - forced_req = requirements.find(&:force_version?) - if forced_req - requirement_satisfied_by?(forced_req, activated, possibility) + requirements = activated.vertex_named(spec.name)&.requirements + if requirements&.any?(&:force_version?) + # true if spec matches the forced requirement + return true if requirements&.select(&:force_version?)&. + any? {|r| r.matches_spec?(spec) } else - requirements.all? {|req| requirement_satisfied_by?(req, activated, possibility) } + return true if requirement.matches_spec?(spec) end + + false end - def relevant_sources_for_vertex(vertex) + def relevant_sources_for_vertex(vertex) if vertex.root? [@source_requirements[vertex.name]] elsif @lockfile_uses_separate_rubygems_sources @@ -451,15 +457,5 @@ def validate_resolved_specs!(resolved_specs) Bundler.ui.warn "Warning: #{msg}" end end - - def forced_or_no_forced_alternative_spec(requirement, activated, spec) - requirement.force_version? || !activated.vertex_named(spec.name)&.requirements&.any?(&:force_version?) - end - - def is_forced_spec(activated, spec) - activated.vertex_named(spec.name)&. - requirements&.select(&:force_version?)&. - any? {|r| r.matches_spec?(spec) } - end end end diff --git a/bundler/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb b/bundler/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb index 84b0a940a23e..ec9c770a2889 100644 --- a/bundler/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +++ b/bundler/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb @@ -26,13 +26,6 @@ def requirement_satisfied_by?(requirement, activated, spec) end end - # (see Bundler::Molinillo::SpecificationProvider#requirements_satisfied_by?) - def requirements_satisfied_by?(requirements, activated, spec) - with_no_such_dependency_error_handling do - specification_provider.requirements_satisfied_by?(requirements, activated, spec) - end - end - # (see Bundler::Molinillo::SpecificationProvider#name_for) def name_for(dependency) with_no_such_dependency_error_handling do diff --git a/bundler/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb b/bundler/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb index 7c22f08750dd..26b8bc745c40 100644 --- a/bundler/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +++ b/bundler/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb @@ -218,7 +218,7 @@ def resolve_activated_specs next unless vertex.payload latest_version = vertex.payload.possibilities.reverse_each.find do |possibility| - requirements_satisfied_by?(vertex.requirements, activated, possibility) + vertex.requirements.all? { |req| requirement_satisfied_by?(req, activated, possibility) } end activated.set_payload(vertex.name, latest_version) @@ -473,7 +473,7 @@ def possibility_satisfies_requirements?(possibility, requirements) activated.tag(:swap) activated.set_payload(name, possibility) if activated.vertex_named(name) - satisfied = requirements_satisfied_by?(requirements, activated, possibility) + satisfied = requirements.all? { |r| requirement_satisfied_by?(r, activated, possibility) } activated.rewind_to(:swap) satisfied @@ -702,13 +702,7 @@ def attempt_to_filter_existing_spec(vertex) # @param [Object] vertex existing vertex # @return [PossibilitySet] filtered possibility set def filtered_possibility_set(vertex) - filtered = if vertex.requirements.any?(&:force_version?) - debug(depth) { "Forced version from existing spec (#{vertex.payload})" } - vertex.payload.possibilities - else - vertex.payload.possibilities & possibility.possibilities - end - PossibilitySet.new(vertex.payload.dependencies, filtered) + PossibilitySet.new(vertex.payload.dependencies, vertex.payload.possibilities & possibility.possibilities) end # @param [String] requirement_name the spec name to search for From 01e23ef041fe2f9ae731b1b4e68705e7763b7599 Mon Sep 17 00:00:00 2001 From: Lukas Oberhuber Date: Mon, 28 Dec 2020 00:32:34 +0000 Subject: [PATCH 4/4] Simplify code --- bundler/lib/bundler/resolver.rb | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/bundler/lib/bundler/resolver.rb b/bundler/lib/bundler/resolver.rb index 97c98741195e..e463586984bd 100644 --- a/bundler/lib/bundler/resolver.rb +++ b/bundler/lib/bundler/resolver.rb @@ -46,7 +46,7 @@ def start(requirements) @gem_version_promoter.prerelease_specified = @prerelease_specified = {} requirements.each {|dep| @prerelease_specified[dep.name] ||= dep.prerelease? } - @forced_requirements = requirements.select {|dep| dep.force_version? } + @forced_requirements = requirements.select(&:force_version?).map {|dep| [dep.name, dep] }.to_h verify_gemfile_dependencies_are_found!(requirements) dg = @resolver.resolve(requirements, @base_dg) @@ -106,13 +106,7 @@ def indicate_progress def dependencies_for(specification) deps = specification.dependencies_for_activated_platforms - deps.map do |dep| - if @forced_requirements.map(&:name).include?(dep.name) - @forced_requirements.find {|r| r.name == dep.name } - else - dep - end - end + deps.map {|dep| @forced_requirements[dep.name] || dep } end def search_for(dependency_proxy) @@ -212,21 +206,10 @@ def name_for_locking_dependency_source end def requirement_satisfied_by?(requirement, activated, spec) - return true if spec.source.is_a?(Source::Gemspec) - - requirements = activated.vertex_named(spec.name)&.requirements - if requirements&.any?(&:force_version?) - # true if spec matches the forced requirement - return true if requirements&.select(&:force_version?)&. - any? {|r| r.matches_spec?(spec) } - else - return true if requirement.matches_spec?(spec) - end - - false + requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec) end - def relevant_sources_for_vertex(vertex) + def relevant_sources_for_vertex(vertex) if vertex.root? [@source_requirements[vertex.name]] elsif @lockfile_uses_separate_rubygems_sources @@ -238,14 +221,13 @@ def relevant_sources_for_vertex(vertex) def sort_dependencies(dependencies, activated, conflicts) dependencies.sort_by do |dependency| - dependency.all_sources = relevant_sources_for_vertex(activated.vertex_named(dependency.name)) name = name_for(dependency) + dependency.all_sources = relevant_sources_for_vertex(activated.vertex_named(name)) vertex = activated.vertex_named(name) [ @base_dg.vertex_named(name) ? 0 : 1, vertex.payload ? 0 : 1, vertex.root? ? 0 : 1, - dependency.force_version? ? 0 : 1, amount_constrained(dependency), conflicts[name] ? 0 : 1, vertex.payload ? 0 : search_for(dependency).count,