diff options
-rw-r--r-- | lib/bundler/definition.rb | 71 | ||||
-rw-r--r-- | lib/bundler/inline.rb | 1 | ||||
-rw-r--r-- | lib/bundler/installer.rb | 10 | ||||
-rw-r--r-- | lib/bundler/lazy_specification.rb | 11 | ||||
-rw-r--r-- | lib/bundler/resolver.rb | 104 | ||||
-rw-r--r-- | lib/bundler/resolver/base.rb | 45 | ||||
-rw-r--r-- | lib/bundler/resolver/candidate.rb | 7 | ||||
-rw-r--r-- | lib/bundler/resolver/package.rb | 13 | ||||
-rw-r--r-- | lib/bundler/shared_helpers.rb | 2 | ||||
-rw-r--r-- | lib/bundler/source/rubygems.rb | 2 | ||||
-rw-r--r-- | spec/bundler/bundler/gem_version_promoter_spec.rb | 24 | ||||
-rw-r--r-- | spec/bundler/bundler/shared_helpers_spec.rb | 2 | ||||
-rw-r--r-- | spec/bundler/commands/lock_spec.rb | 283 | ||||
-rw-r--r-- | spec/bundler/install/gemfile/specific_platform_spec.rb | 177 | ||||
-rw-r--r-- | spec/bundler/realworld/edgecases_spec.rb | 2 | ||||
-rw-r--r-- | spec/bundler/realworld/slow_perf_spec.rb | 2 | ||||
-rw-r--r-- | spec/bundler/runtime/inline_spec.rb | 26 | ||||
-rw-r--r-- | spec/bundler/support/indexes.rb | 21 |
18 files changed, 521 insertions, 282 deletions
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 09a756abc7..9763298504 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -159,13 +159,6 @@ module Bundler resolve end - def resolve_prefering_local! - @prefer_local = true - @remote = true - sources.remote! - resolve - end - def resolve_with_cache! sources.cached! resolve @@ -177,6 +170,23 @@ module Bundler resolve end + def resolution_mode=(options) + if options["local"] + @remote = false + else + @remote = true + @prefer_local = options["prefer-local"] + end + end + + def setup_sources_for_resolve + if @remote == false + sources.cached! + else + sources.remote! + end + end + # For given dependency list returns a SpecSet with Gemspec of all the required # dependencies. # 1. The method first resolves the dependencies specified in Gemfile @@ -473,31 +483,19 @@ module Bundler private def resolver - @resolver ||= begin - last_resolve = converge_locked_specs - remove_ruby_from_platforms_if_necessary!(current_dependencies) - Resolver.new(source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve(last_resolve)) - end + @resolver ||= Resolver.new(resolution_packages, gem_version_promoter) end def expanded_dependencies - @expanded_dependencies ||= dependencies + metadata_dependencies + dependencies + metadata_dependencies end def resolution_packages @resolution_packages ||= begin - packages = Hash.new do |h, k| - h[k] = Resolver::Package.new(k, @platforms, @originally_locked_specs, @unlock[:gems]) - end - - expanded_dependencies.each do |dep| - name = dep.name - platforms = dep.gem_platforms(@platforms) - - packages[name] = Resolver::Package.new(name, platforms, @originally_locked_specs, @unlock[:gems], :dependency => dep) - end - - packages + last_resolve = converge_locked_specs + remove_ruby_from_platforms_if_necessary!(current_dependencies) + packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, :locked_specs => @originally_locked_specs, :unlock => @unlock[:gems], :prerelease => gem_version_promoter.pre?) + additional_base_requirements_for_resolve(packages, last_resolve) end end @@ -531,13 +529,15 @@ module Bundler break if incomplete_specs.empty? Bundler.ui.debug("The lockfile does not have all gems needed for the current platform though, Bundler will still re-resolve dependencies") - @resolve = start_resolution(:exclude_specs => incomplete_specs) + setup_sources_for_resolve + resolution_packages.delete(incomplete_specs) + @resolve = start_resolution specs = resolve.materialize(dependencies) still_incomplete_specs = specs.incomplete_specs if still_incomplete_specs == incomplete_specs - package = resolution_packages[incomplete_specs.first.name] + package = resolution_packages.get_package(incomplete_specs.first.name) resolver.raise_not_found! package end @@ -550,14 +550,14 @@ module Bundler specs end - def start_resolution(exclude_specs: []) - result = resolver.start(expanded_dependencies, resolution_packages, :exclude_specs => exclude_specs) + def start_resolution + result = resolver.start SpecSet.new(SpecSet.new(result).for(dependencies, false, @platforms)) end def precompute_source_requirements_for_indirect_dependencies? - @remote && sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source? + sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source? end def pin_locally_available_names(source_requirements) @@ -885,11 +885,12 @@ module Bundler current == proposed end - def additional_base_requirements_for_resolve(last_resolve) - return [] unless @locked_gems && unlocking? && !sources.expired_sources?(@locked_gems.sources) - converge_specs(@originally_locked_specs - last_resolve).map do |locked_spec| - Dependency.new(locked_spec.name, ">= #{locked_spec.version}") - end.uniq + def additional_base_requirements_for_resolve(resolution_packages, last_resolve) + return resolution_packages unless @locked_gems && unlocking? && !sources.expired_sources?(@locked_gems.sources) + converge_specs(@originally_locked_specs - last_resolve).each do |locked_spec| + resolution_packages.base_requirements[locked_spec.name] = Gem::Requirement.new(">= #{locked_spec.version}") + end + resolution_packages end def remove_ruby_from_platforms_if_necessary!(dependencies) diff --git a/lib/bundler/inline.rb b/lib/bundler/inline.rb index 855ae5526a..5c184f67a1 100644 --- a/lib/bundler/inline.rb +++ b/lib/bundler/inline.rb @@ -31,6 +31,7 @@ # def gemfile(install = false, options = {}, &gemfile) require_relative "../bundler" + Bundler.reset! opts = options.dup ui = opts.delete(:ui) { Bundler::UI::Shell.new } diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb index 04d7dc6f23..680e812ac8 100644 --- a/lib/bundler/installer.rb +++ b/lib/bundler/installer.rb @@ -249,17 +249,13 @@ module Bundler # returns whether or not a re-resolve was needed def resolve_if_needed(options) + @definition.resolution_mode = options + if !@definition.unlocking? && !options["force"] && !Bundler.settings[:inline] && Bundler.default_lockfile.file? return false if @definition.nothing_changed? && !@definition.missing_specs? end - if options["local"] - @definition.resolve_with_cache! - elsif options["prefer-local"] - @definition.resolve_prefering_local! - else - @definition.resolve_remotely! - end + @definition.setup_sources_for_resolve true end diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb index dccfe48bba..6749892930 100644 --- a/lib/bundler/lazy_specification.rb +++ b/lib/bundler/lazy_specification.rb @@ -89,7 +89,7 @@ module Bundler installable_candidates = GemHelpers.select_best_platform_match(matching_specs, target_platform) - specification = __materialize__(installable_candidates) + specification = __materialize__(installable_candidates, :fallback_to_non_installable => false) return specification unless specification.nil? if target_platform != platform @@ -102,13 +102,18 @@ module Bundler __materialize__(candidates) end - def __materialize__(candidates) + # If in frozen mode, we fallback to a non-installable candidate because by + # doing this we avoid re-resolving and potentially end up changing the + # lock file, which is not allowed. In that case, we will give a proper error + # about the mismatch higher up the stack, right before trying to install the + # bad gem. + def __materialize__(candidates, fallback_to_non_installable: Bundler.frozen_bundle?) search = candidates.reverse.find do |spec| spec.is_a?(StubSpecification) || (spec.matches_current_ruby? && spec.matches_current_rubygems?) end - if search.nil? && Bundler.frozen_bundle? + if search.nil? && fallback_to_non_installable search = candidates.last else search.dependencies = dependencies if search && search.full_name == full_name && (search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification)) diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index df9ce2ff3f..8237ff53fe 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -9,26 +9,21 @@ module Bundler class Resolver require_relative "vendored_pub_grub" require_relative "resolver/base" - require_relative "resolver/package" require_relative "resolver/candidate" require_relative "resolver/incompatibility" require_relative "resolver/root" include GemHelpers - def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements) - @source_requirements = source_requirements - @base = Resolver::Base.new(base, additional_base_requirements) + def initialize(base, gem_version_promoter) + @source_requirements = base.source_requirements + @base = base @gem_version_promoter = gem_version_promoter end - def start(requirements, packages, exclude_specs: []) - exclude_specs.each do |spec| - remove_from_candidates(spec) - end - - @requirements = requirements - @packages = packages + def start + @requirements = @base.requirements + @packages = @base.packages root, logger = setup_solver @@ -78,33 +73,26 @@ module Bundler rescue PubGrub::SolveFailure => e incompatibility = e.incompatibility - names_to_unlock = [] - extended_explanation = nil + names_to_unlock, names_to_allow_prereleases_for, extended_explanation = find_names_to_relax(incompatibility) - while incompatibility.conflict? - cause = incompatibility.cause - incompatibility = cause.incompatibility - - incompatibility.terms.each do |term| - name = term.package.name - names_to_unlock << name if base_requirements[name] + names_to_relax = names_to_unlock + names_to_allow_prereleases_for - no_versions_incompat = [cause.incompatibility, cause.satisfier].find {|incompat| incompat.cause.is_a?(PubGrub::Incompatibility::NoVersions) } - next unless no_versions_incompat + if names_to_relax.any? + if names_to_unlock.any? + Bundler.ui.debug "Found conflicts with locked dependencies. Will retry with #{names_to_unlock.join(", ")} unlocked...", true - extended_explanation = no_versions_incompat.extended_explanation + @base.unlock_names(names_to_unlock) end - end - - names_to_unlock.uniq! - if names_to_unlock.any? - Bundler.ui.debug "Found conflicts with locked dependencies. Retrying with #{names_to_unlock.join(", ")} unlocked...", true + if names_to_allow_prereleases_for.any? + Bundler.ui.debug "Found conflicts with dependencies with prereleases. Will retrying considering prereleases for #{names_to_allow_prereleases_for.join(", ")}...", true - @base.unlock_names(names_to_unlock) + @base.include_prereleases(names_to_allow_prereleases_for) + end root, logger = setup_solver + Bundler.ui.debug "Retrying resolution...", true retry end @@ -118,6 +106,35 @@ module Bundler raise SolveFailure.new(explanation) end + def find_names_to_relax(incompatibility) + names_to_unlock = [] + names_to_allow_prereleases_for = [] + extended_explanation = nil + + while incompatibility.conflict? + cause = incompatibility.cause + incompatibility = cause.incompatibility + + incompatibility.terms.each do |term| + package = term.package + name = package.name + + if base_requirements[name] + names_to_unlock << name + elsif package.ignores_prereleases? + names_to_allow_prereleases_for << name + end + + no_versions_incompat = [cause.incompatibility, cause.satisfier].find {|incompat| incompat.cause.is_a?(PubGrub::Incompatibility::NoVersions) } + next unless no_versions_incompat + + extended_explanation = no_versions_incompat.extended_explanation + end + end + + [names_to_unlock.uniq, names_to_allow_prereleases_for.uniq, extended_explanation] + end + def parse_dependency(package, dependency) range = if repository_for(package).is_a?(Source::Gemspec) PubGrub::VersionRange.any @@ -215,7 +232,7 @@ module Bundler def all_versions_for(package) name = package.name - results = (@base[name] + @all_specs[name]).uniq {|spec| [spec.version.hash, spec.platform] } + results = (@base[name] + filter_prereleases(@all_specs[name], package)).uniq {|spec| [spec.version.hash, spec.platform] } locked_requirement = base_requirements[name] results = filter_matching_specs(results, locked_requirement) if locked_requirement @@ -284,6 +301,12 @@ module Bundler end end + def filter_prereleases(specs, package) + return specs unless package.ignores_prereleases? + + specs.reject {|s| s.version.prerelease? } + end + def requirement_satisfied_by?(requirement, spec) requirement.satisfied_by?(spec.version) || spec.source.is_a?(Source::Gemspec) end @@ -304,25 +327,20 @@ module Bundler @base.base_requirements end - def remove_from_candidates(spec) - @base.delete(spec) - end - def prepare_dependencies(requirements, packages) to_dependency_hash(requirements, packages).map do |dep_package, dep_constraint| name = dep_package.name - # If a dependency is scoped to a platform different from the current - # one, we ignore it. However, it may reappear during resolution as a - # transitive dependency of another package, so we need to reset the - # package so the proper versions are considered if reintroduced later. - if dep_package.platforms.empty? - @packages.delete(name) - next + next [dep_package, dep_constraint] if name == "bundler" + + versions = versions_for(dep_package, dep_constraint.range) + if versions.empty? && dep_package.ignores_prereleases? + @sorted_versions.delete(dep_package) + dep_package.consider_prereleases! + versions = versions_for(dep_package, dep_constraint.range) end + next [dep_package, dep_constraint] unless versions.empty? - next [dep_package, dep_constraint] if name == "bundler" - next [dep_package, dep_constraint] unless versions_for(dep_package, dep_constraint.range).empty? next unless dep_package.current_platform? raise_not_found!(dep_package) diff --git a/lib/bundler/resolver/base.rb b/lib/bundler/resolver/base.rb index 78b798f4ec..6921c047a7 100644 --- a/lib/bundler/resolver/base.rb +++ b/lib/bundler/resolver/base.rb @@ -1,19 +1,47 @@ # frozen_string_literal: true +require_relative "package" + module Bundler class Resolver class Base - def initialize(base, additional_base_requirements) + attr_reader :packages, :requirements, :source_requirements + + def initialize(source_requirements, dependencies, base, platforms, options) + @source_requirements = source_requirements + @base = base - @additional_base_requirements = additional_base_requirements + + @packages = Hash.new do |hash, name| + hash[name] = Package.new(name, platforms, **options) + end + + @requirements = dependencies.map do |dep| + dep_platforms = dep.gem_platforms(platforms) + + # Dependencies scoped to external platforms are ignored + next if dep_platforms.empty? + + name = dep.name + + @packages[name] = Package.new(name, dep_platforms, **options.merge(:dependency => dep)) + + dep + end.compact end def [](name) @base[name] end - def delete(spec) - @base.delete(spec) + def delete(specs) + specs.each do |spec| + @base.delete(spec) + end + end + + def get_package(name) + @packages[name] end def base_requirements @@ -24,10 +52,14 @@ module Bundler names.each do |name| @base.delete_by_name(name) - @additional_base_requirements.reject! {|dep| dep.name == name } + @base_requirements.delete(name) end + end - @base_requirements = nil + def include_prereleases(names) + names.each do |name| + get_package(name).consider_prereleases! + end end private @@ -38,7 +70,6 @@ module Bundler req = Gem::Requirement.new(ls.version) base_requirements[ls.name] = req end - @additional_base_requirements.each {|d| base_requirements[d.name] = d.requirement } base_requirements end end diff --git a/lib/bundler/resolver/candidate.rb b/lib/bundler/resolver/candidate.rb index 681f9aca73..e695ef08ee 100644 --- a/lib/bundler/resolver/candidate.rb +++ b/lib/bundler/resolver/candidate.rb @@ -26,9 +26,8 @@ module Bundler def initialize(version, specs: []) @spec_group = Resolver::SpecGroup.new(specs) - @platforms = specs.map(&:platform).sort_by(&:to_s).uniq @version = Gem::Version.new(version) - @ruby_only = @platforms == [Gem::Platform::RUBY] + @ruby_only = specs.map(&:platform).uniq == [Gem::Platform::RUBY] end def dependencies @@ -88,9 +87,7 @@ module Bundler end def to_s - return @version.to_s if @platforms.empty? || @ruby_only - - "#{@version} (#{@platforms.join(", ")})" + @version.to_s end end end diff --git a/lib/bundler/resolver/package.rb b/lib/bundler/resolver/package.rb index 7d64632860..7499a75006 100644 --- a/lib/bundler/resolver/package.rb +++ b/lib/bundler/resolver/package.rb @@ -15,12 +15,13 @@ module Bundler class Package attr_reader :name, :platforms, :dependency, :locked_version - def initialize(name, platforms, locked_specs, unlock, dependency: nil) + def initialize(name, platforms, locked_specs:, unlock:, prerelease: false, dependency: nil) @name = name @platforms = platforms @locked_version = locked_specs[name].first&.version @unlock = unlock @dependency = dependency || Dependency.new(name, @locked_version) + @prerelease = @dependency.prerelease? || @locked_version&.prerelease? || prerelease ? :consider_first : :ignore end def to_s @@ -47,8 +48,16 @@ module Bundler @unlock.empty? || @unlock.include?(name) end + def ignores_prereleases? + @prerelease == :ignore + end + def prerelease_specified? - @dependency.prerelease? + @prerelease == :consider_first + end + + def consider_prereleases! + @prerelease = :consider_last end def force_ruby_platform? diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb index 0a6afe0e5a..794a03e62d 100644 --- a/lib/bundler/shared_helpers.rb +++ b/lib/bundler/shared_helpers.rb @@ -284,7 +284,7 @@ module Bundler Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", exe_file Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", find_gemfile.to_s Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION - Bundler::SharedHelpers.set_env "BUNDLER_SETUP", File.expand_path("setup", __dir__) + Bundler::SharedHelpers.set_env "BUNDLER_SETUP", File.expand_path("setup", __dir__) unless RUBY_VERSION < "2.7" end def set_path diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 7eefd291a2..c39071705a 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -292,7 +292,7 @@ module Bundler end def dependency_api_available? - api_fetchers.any? + @allow_remote && api_fetchers.any? end protected diff --git a/spec/bundler/bundler/gem_version_promoter_spec.rb b/spec/bundler/bundler/gem_version_promoter_spec.rb index e944f387d3..b5c0f69795 100644 --- a/spec/bundler/bundler/gem_version_promoter_spec.rb +++ b/spec/bundler/bundler/gem_version_promoter_spec.rb @@ -16,6 +16,10 @@ RSpec.describe Bundler::GemVersionPromoter do Bundler::SpecSet.new(build_spec(name, v)) end + def build_package(name, platforms, locked_specs, unlock) + Bundler::Resolver::Package.new(name, platforms, :locked_specs => locked_specs, :unlock => unlock) + end + # Rightmost (highest array index) in result is most preferred. # Leftmost (lowest array index) in result is least preferred. # `build_candidates` has all versions of gem in index. @@ -35,7 +39,7 @@ RSpec.describe Bundler::GemVersionPromoter do it "when keeping build_spec, keep current, next release" do res = gvp.sort_versions( - Bundler::Resolver::Package.new("foo", [], build_spec_set("foo", "1.7.8"), []), + build_package("foo", [], build_spec_set("foo", "1.7.8"), []), build_candidates(%w[1.7.8 1.7.9 1.8.0]) ) expect(versions(res)).to eq %w[1.7.8 1.7.9] @@ -43,7 +47,7 @@ RSpec.describe Bundler::GemVersionPromoter do it "when unlocking prefer next release first" do res = gvp.sort_versions( - Bundler::Resolver::Package.new("foo", [], build_spec_set("foo", "1.7.8"), []), + build_package("foo", [], build_spec_set("foo", "1.7.8"), []), build_candidates(%w[1.7.8 1.7.9 1.8.0]) ) expect(versions(res)).to eq %w[1.7.8 1.7.9] @@ -51,7 +55,7 @@ RSpec.describe Bundler::GemVersionPromoter do it "when unlocking keep current when already at latest release" do res = gvp.sort_versions( - Bundler::Resolver::Package.new("foo", [], build_spec_set("foo", "1.7.9"), []), + build_package("foo", [], build_spec_set("foo", "1.7.9"), []), build_candidates(%w[1.7.9 1.8.0 2.0.0]) ) expect(versions(res)).to eq %w[1.7.9] @@ -68,7 +72,7 @@ RSpec.describe Bundler::GemVersionPromoter do it "when unlocking favor next releases, remove minor and major increases" do res = gvp.sort_versions( - Bundler::Resolver::Package.new("foo", [], build_spec_set("foo", "0.2.0"), []), + build_package("foo", [], build_spec_set("foo", "0.2.0"), []), build_candidates(%w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.0 2.0.1]) ) expect(versions(res)).to eq %w[0.2.0 0.3.0 0.3.1 0.9.0] @@ -76,7 +80,7 @@ RSpec.describe Bundler::GemVersionPromoter do it "when keep locked, keep current, then favor next release, remove minor and major increases" do res = gvp.sort_versions( - Bundler::Resolver::Package.new("foo", [], build_spec_set("foo", "0.2.0"), ["bar"]), + build_package("foo", [], build_spec_set("foo", "0.2.0"), ["bar"]), build_candidates(%w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.0 2.0.1]) ) expect(versions(res)).to eq %w[0.3.0 0.3.1 0.9.0 0.2.0] @@ -93,7 +97,7 @@ RSpec.describe Bundler::GemVersionPromoter do it "when not unlocking, same order but make sure build_spec version is most preferred to stay put" do res = gvp.sort_versions( - Bundler::Resolver::Package.new("foo", [], build_spec_set("foo", "1.7.7"), ["bar"]), + build_package("foo", [], build_spec_set("foo", "1.7.7"), ["bar"]), build_candidates(%w[1.5.4 1.6.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 2.0.0 2.0.1]) ) expect(versions(res)).to eq %w[1.5.4 1.6.5 1.7.6 2.0.0 2.0.1 1.8.0 1.8.1 1.7.8 1.7.9 1.7.7] @@ -101,7 +105,7 @@ RSpec.describe Bundler::GemVersionPromoter do it "when unlocking favor next release, then current over minor increase" do res = gvp.sort_versions( - Bundler::Resolver::Package.new("foo", [], build_spec_set("foo", "1.7.8"), []), + build_package("foo", [], build_spec_set("foo", "1.7.8"), []), build_candidates(%w[1.7.7 1.7.8 1.7.9 1.8.0]) ) expect(versions(res)).to eq %w[1.7.7 1.8.0 1.7.8 1.7.9] @@ -109,7 +113,7 @@ RSpec.describe Bundler::GemVersionPromoter do it "when unlocking do proper integer comparison, not string" do res = gvp.sort_versions( - Bundler::Resolver::Package.new("foo", [], build_spec_set("foo", "1.7.8"), []), + build_package("foo", [], build_spec_set("foo", "1.7.8"), []), build_candidates(%w[1.7.7 1.7.8 1.7.9 1.7.15 1.8.0]) ) expect(versions(res)).to eq %w[1.7.7 1.8.0 1.7.8 1.7.9 1.7.15] @@ -117,7 +121,7 @@ RSpec.describe Bundler::GemVersionPromoter do it "leave current when unlocking but already at latest release" do res = gvp.sort_versions( - Bundler::Resolver::Package.new("foo", [], build_spec_set("foo", "1.7.9"), []), + build_package("foo", [], build_spec_set("foo", "1.7.9"), []), build_candidates(%w[1.7.9 1.8.0 2.0.0]) ) expect(versions(res)).to eq %w[2.0.0 1.8.0 1.7.9] @@ -134,7 +138,7 @@ RSpec.describe Bundler::GemVersionPromoter do it "when unlocking favor next release, then minor increase over current" do res = gvp.sort_versions( - Bundler::Resolver::Package.new("foo", [], build_spec_set("foo", "0.2.0"), []), + build_package("foo", [], build_spec_set("foo", "0.2.0"), []), build_candidates(%w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.0 2.0.1]) ) expect(versions(res)).to eq %w[2.0.0 2.0.1 1.0.0 0.2.0 0.3.0 0.3.1 0.9.0] diff --git a/spec/bundler/bundler/shared_helpers_spec.rb b/spec/bundler/bundler/shared_helpers_spec.rb index 3d8014b665..3c6536c4eb 100644 --- a/spec/bundler/bundler/shared_helpers_spec.rb +++ b/spec/bundler/bundler/shared_helpers_spec.rb @@ -248,6 +248,8 @@ RSpec.describe Bundler::SharedHelpers do shared_examples_for "ENV['BUNDLER_SETUP'] gets set correctly" do it "ensures bundler/setup is set in ENV['BUNDLER_SETUP']" do + skip "Does not play well with DidYouMean being a bundled gem instead of a default gem in Ruby 2.6" if RUBY_VERSION < "2.7" + subject.set_bundle_environment expect(ENV["BUNDLER_SETUP"]).to eq("#{source_lib_dir}/bundler/setup") end diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb index 38bef77eaf..08ac333664 100644 --- a/spec/bundler/commands/lock_spec.rb +++ b/spec/bundler/commands/lock_spec.rb @@ -768,133 +768,212 @@ RSpec.describe "bundle lock" do #{Bundler::VERSION} L end + end - it "properly shows resolution errors including OR requirements" do - build_repo4 do - build_gem "activeadmin", "2.13.1" do |s| - s.add_dependency "railties", ">= 6.1", "< 7.1" - end - build_gem "actionpack", "6.1.4" - build_gem "actionpack", "7.0.3.1" - build_gem "actionpack", "7.0.4" - build_gem "railties", "6.1.4" do |s| - s.add_dependency "actionpack", "6.1.4" - end - build_gem "rails", "7.0.3.1" do |s| - s.add_dependency "railties", "7.0.3.1" - end - build_gem "rails", "7.0.4" do |s| - s.add_dependency "railties", "7.0.4" - end + it "properly shows resolution errors including OR requirements" do + build_repo4 do + build_gem "activeadmin", "2.13.1" do |s| + s.add_dependency "railties", ">= 6.1", "< 7.1" + end + build_gem "actionpack", "6.1.4" + build_gem "actionpack", "7.0.3.1" + build_gem "actionpack", "7.0.4" + build_gem "railties", "6.1.4" do |s| + s.add_dependency "actionpack", "6.1.4" + end + build_gem "rails", "7.0.3.1" do |s| + s.add_dependency "railties", "7.0.3.1" end + build_gem "rails", "7.0.4" do |s| + s.add_dependency "railties", "7.0.4" + end + end - gemfile <<~G - source "#{file_uri_for(gem_repo4)}" + gemfile <<~G + source "#{file_uri_for(gem_repo4)}" - gem "rails", ">= 7.0.3.1" - gem "activeadmin", "2.13.1" - G + gem "rails", ">= 7.0.3.1" + gem "activeadmin", "2.13.1" + G - bundle "lock", :raise_on_error => false + bundle "lock", :raise_on_error => false - expect(err).to eq <<~ERR.strip - Could not find compatible versions + expect(err).to eq <<~ERR.strip + Could not find compatible versions - Because rails >= 7.0.4 depends on railties = 7.0.4 - and rails < 7.0.4 depends on railties = 7.0.3.1, - railties = 7.0.3.1 OR = 7.0.4 is required. - So, because railties = 7.0.3.1 OR = 7.0.4 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally, - version solving has failed. - ERR - end + Because rails >= 7.0.4 depends on railties = 7.0.4 + and rails < 7.0.4 depends on railties = 7.0.3.1, + railties = 7.0.3.1 OR = 7.0.4 is required. + So, because railties = 7.0.3.1 OR = 7.0.4 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally, + version solving has failed. + ERR + end - it "is able to display some explanation on crazy irresolvable cases" do - build_repo4 do - build_gem "activeadmin", "2.13.1" do |s| - s.add_dependency "ransack", "= 3.1.0" - end + it "is able to display some explanation on crazy irresolvable cases" do + build_repo4 do + build_gem "activeadmin", "2.13.1" do |s| + s.add_dependency "ransack", "= 3.1.0" + end - # Activemodel is missing as a dependency in lockfile - build_gem "ransack", "3.1.0" do |s| - s.add_dependency "activemodel", ">= 6.0.4" - s.add_dependency "activesupport", ">= 6.0.4" - end + # Activemodel is missing as a dependency in lockfile + build_gem "ransack", "3.1.0" do |s| + s.add_dependency "activemodel", ">= 6.0.4" + s.add_dependency "activesupport", ">= 6.0.4" + end - %w[6.0.4 7.0.2.3 7.0.3.1 7.0.4].each do |version| - build_gem "activesupport", version + %w[6.0.4 7.0.2.3 7.0.3.1 7.0.4].each do |version| + build_gem "activesupport", version - # Activemodel is only available on 6.0.4 - if version == "6.0.4" - build_gem "activemodel", version do |s| - s.add_dependency "activesupport", version - end + # Activemodel is only available on 6.0.4 + if version == "6.0.4" + build_gem "activemodel", version do |s| + s.add_dependency "activesupport", version end + end - build_gem "rails", version do |s| - # Depednencies of Rails 7.0.2.3 are in reverse order - if version == "7.0.2.3" - s.add_dependency "activesupport", version - s.add_dependency "activemodel", version - else - s.add_dependency "activemodel", version - s.add_dependency "activesupport", version - end + build_gem "rails", version do |s| + # Depednencies of Rails 7.0.2.3 are in reverse order + if version == "7.0.2.3" + s.add_dependency "activesupport", version + s.add_dependency "activemodel", version + else + s.add_dependency "activemodel", version + s.add_dependency "activesupport", version end end end + end - gemfile <<~G - source "#{file_uri_for(gem_repo4)}" + gemfile <<~G + source "#{file_uri_for(gem_repo4)}" - gem "rails", ">= 7.0.2.3" - gem "activeadmin", "= 2.13.1" - G + gem "rails", ">= 7.0.2.3" + gem "activeadmin", "= 2.13.1" + G - lockfile <<~L - GEM - remote: #{file_uri_for(gem_repo4)}/ - specs: - activeadmin (2.13.1) - ransack (= 3.1.0) - ransack (3.1.0) - activemodel (>= 6.0.4) + lockfile <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + activeadmin (2.13.1) + ransack (= 3.1.0) + ransack (3.1.0) + activemodel (>= 6.0.4) - PLATFORMS - #{lockfile_platforms} + PLATFORMS + #{lockfile_platforms} - DEPENDENCIES - activeadmin (= 2.13.1) - ransack (= 3.1.0) + DEPENDENCIES + activeadmin (= 2.13.1) + ransack (= 3.1.0) - BUNDLED WITH - #{Bundler::VERSION} - L + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "lock", :raise_on_error => false + + expect(err).to eq <<~ERR.strip + Could not find compatible versions + + Because every version of activemodel depends on activesupport = 6.0.4 + and rails >= 7.0.2.3, < 7.0.3.1 depends on activesupport = 7.0.2.3, + every version of activemodel is incompatible with rails >= 7.0.2.3, < 7.0.3.1. + And because rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3, + rails >= 7.0.2.3, < 7.0.3.1 is forbidden. + (1) So, because rails >= 7.0.3.1, < 7.0.4 depends on activemodel = 7.0.3.1 + and rails >= 7.0.4 depends on activemodel = 7.0.4, + rails >= 7.0.2.3 requires activemodel = 7.0.3.1 OR = 7.0.4. + + Because rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3 + and rails >= 7.0.3.1, < 7.0.4 depends on activesupport = 7.0.3.1, + rails >= 7.0.2.3, < 7.0.4 requires activemodel = 7.0.2.3 or activesupport = 7.0.3.1. + And because rails >= 7.0.4 depends on activesupport = 7.0.4 + and every version of activemodel depends on activesupport = 6.0.4, + activemodel != 7.0.2.3 is incompatible with rails >= 7.0.2.3. + And because rails >= 7.0.2.3 requires activemodel = 7.0.3.1 OR = 7.0.4 (1), + rails >= 7.0.2.3 is forbidden. + So, because Gemfile depends on rails >= 7.0.2.3, + version solving has failed. + ERR + end + + it "does not accidentally resolves to prereleases" do + build_repo4 do + build_gem "autoproj", "2.0.3" do |s| + s.add_dependency "autobuild", ">= 1.10.0.a" + s.add_dependency "tty-prompt" + end + + build_gem "tty-prompt", "0.6.0" + build_gem "tty-prompt", "0.7.0" + build_gem "autobuild", "1.10.0.b3" + build_gem "autobuild", "1.10.1" do |s| + s.add_dependency "tty-prompt", "~> 0.6.0" + end + end + + gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + gem "autoproj", ">= 2.0.0" + G + + bundle "lock" + expect(lockfile).to_not include("autobuild (1.10.0.b3)") + expect(lockfile).to include("autobuild (1.10.1)") + end + + it "deals with platform specific incompatibilities" do + build_repo4 do + build_gem "activerecord", "6.0.6" + build_gem "activerecord-jdbc-adapter", "60.4" do |s| + s.platform = "java" + s.add_dependency "activerecord", "~> 6.0.0" + end + build_gem "activerecord-jdbc-adapter", "61.0" do |s| + s.platform = "java" + s.add_dependency "activerecord", "~> 6.1.0" + end + end + + gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + gem "activerecord", "6.0.6" + gem "activerecord-jdbc-adapter", "61.0" + G + + simulate_platform "universal-java-19" do bundle "lock", :raise_on_error => false + end + + expect(err).to include("Could not find compatible versions") + expect(err).not_to include("ERROR REPORT TEMPLATE") + end + + context "when re-resolving to include prereleases" do + before do + build_repo4 do + build_gem "tzinfo-data", "1.2022.7" + build_gem "rails", "7.1.0.alpha" do |s| + s.add_dependency "activesupport" + end + build_gem "activesupport", "7.1.0.alpha" + end + end + + it "does not end up including gems scoped to other platforms in the lockfile" do + gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "rails" + gem "tzinfo-data", platform: :windows + G + + simulate_platform "x86_64-darwin-22" do + bundle "lock" + end - expect(err).to eq <<~ERR.strip - Could not find compatible versions - - Because every version of activemodel depends on activesupport = 6.0.4 - and rails >= 7.0.2.3, < 7.0.3.1 depends on activesupport = 7.0.2.3, - every version of activemodel is incompatible with rails >= 7.0.2.3, < 7.0.3.1. - And because rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3, - rails >= 7.0.2.3, < 7.0.3.1 is forbidden. - (1) So, because rails >= 7.0.3.1, < 7.0.4 depends on activemodel = 7.0.3.1 - and rails >= 7.0.4 depends on activemodel = 7.0.4, - rails >= 7.0.2.3 requires activemodel = 7.0.3.1 OR = 7.0.4. - - Because rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3 - and rails >= 7.0.3.1, < 7.0.4 depends on activesupport = 7.0.3.1, - rails >= 7.0.2.3, < 7.0.4 requires activemodel = 7.0.2.3 or activesupport = 7.0.3.1. - And because rails >= 7.0.4 depends on activesupport = 7.0.4 - and every version of activemodel depends on activesupport = 6.0.4, - activemodel != 7.0.2.3 is incompatible with rails >= 7.0.2.3. - And because rails >= 7.0.2.3 requires activemodel = 7.0.3.1 OR = 7.0.4 (1), - rails >= 7.0.2.3 is forbidden. - So, because Gemfile depends on rails >= 7.0.2.3, - version solving has failed. - ERR + expect(lockfile).not_to include("tzinfo-data (1.2022.7)") end end end diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb index 8f23b509bd..2f82a9f9f3 100644 --- a/spec/bundler/install/gemfile/specific_platform_spec.rb +++ b/spec/bundler/install/gemfile/specific_platform_spec.rb @@ -6,10 +6,8 @@ RSpec.describe "bundle install with specific platforms" do gem "google-protobuf" G - context "when on a darwin machine" do - before { simulate_platform "x86_64-darwin-15" } - - it "locks to the specific darwin platform" do + it "locks to the specific darwin platform" do + simulate_platform "x86_64-darwin-15" do setup_multiplatform_gem install_gemfile(google_protobuf) allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) @@ -19,8 +17,10 @@ RSpec.describe "bundle install with specific platforms" do google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin ]) end + end - it "understands that a non-platform specific gem in a old lockfile doesn't necessarily mean installing the non-specific variant" do + it "understands that a non-platform specific gem in a old lockfile doesn't necessarily mean installing the non-specific variant" do + simulate_platform "x86_64-darwin-15" do setup_multiplatform_gem system_gems "bundler-2.1.4" @@ -53,8 +53,10 @@ RSpec.describe "bundle install with specific platforms" do # make sure the platform that got actually installed with the old bundler is used expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin") end + end - it "understands that a non-platform specific gem in a new lockfile locked only to RUBY doesn't necessarily mean installing the non-specific variant" do + it "understands that a non-platform specific gem in a new lockfile locked only to RUBY doesn't necessarily mean installing the non-specific variant" do + simulate_platform "x86_64-darwin-15" do setup_multiplatform_gem system_gems "bundler-2.1.4" @@ -103,8 +105,10 @@ RSpec.describe "bundle install with specific platforms" do #{Bundler::VERSION} L end + end - it "still installs the generic RUBY variant if necessary even when running on a legacy lockfile locked only to RUBY" do + context "when running on a legacy lockfile locked only to RUBY" do + around do |example| build_repo4 do build_gem "nokogiri", "1.3.10" build_gem "nokogiri", "1.3.10" do |s| @@ -140,12 +144,20 @@ RSpec.describe "bundle install with specific platforms" do 2.1.4 L - simulate_platform "arm64-darwin-22" do - bundle "update --bundler", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } - end + simulate_platform "arm64-darwin-22", &example end - it "doesn't discard previously installed platform specific gem and fall back to ruby on subsequent bundles" do + it "still installs the generic RUBY variant if necessary" do + bundle "update --bundler", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + end + + it "still installs the generic RUBY variant if necessary, even in frozen mode" do + bundle "update --bundler", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s, "BUNDLE_FROZEN" => "true" } + end + end + + it "doesn't discard previously installed platform specific gem and fall back to ruby on subsequent bundles" do + simulate_platform "x86_64-darwin-15" do build_repo2 do build_gem("libv8", "8.4.255.0") build_gem("libv8", "8.4.255.0") {|s| s.platform = "universal-darwin" } @@ -188,8 +200,10 @@ RSpec.describe "bundle install with specific platforms" do bundle "add mini_racer --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } expect(out).to include("Using libv8 8.4.255.0 (universal-darwin)") end + end - it "chooses platform specific gems even when resolving upon materialization and the API returns more specific platforms first" do + it "chooses platform specific gems even when resolving upon materialization and the API returns more specific platforms first" do + simulate_platform "x86_64-darwin-15" do build_repo4 do build_gem("grpc", "1.50.0") build_gem("grpc", "1.50.0") {|s| s.platform = "universal-darwin" } @@ -220,8 +234,10 @@ RSpec.describe "bundle install with specific platforms" do bundle "install --verbose", :artifice => "compact_index_precompiled_before", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } expect(out).to include("Installing grpc 1.50.0 (universal-darwin)") end + end - it "caches the universal-darwin gem when --all-platforms is passed and properly picks it up on further bundler invocations" do + it "caches the universal-darwin gem when --all-platforms is passed and properly picks it up on further bundler invocations" do + simulate_platform "x86_64-darwin-15" do setup_multiplatform_gem gemfile(google_protobuf) bundle "cache --all-platforms" @@ -230,8 +246,10 @@ RSpec.describe "bundle install with specific platforms" do bundle "install --verbose" expect(err).to be_empty end + end - it "caches the universal-darwin gem when cache_all_platforms is configured and properly picks it up on further bundler invocations" do + it "caches the universal-darwin gem when cache_all_platforms is configured and properly picks it up on further bundler invocations" do + simulate_platform "x86_64-darwin-15" do setup_multiplatform_gem gemfile(google_protobuf) bundle "config set --local cache_all_platforms true" @@ -241,44 +259,46 @@ RSpec.describe "bundle install with specific platforms" do bundle "install --verbose" expect(err).to be_empty end + end - it "caches multiplatform git gems with a single gemspec when --all-platforms is passed" do - git = build_git "pg_array_parser", "1.0" + it "caches multiplatform git gems with a single gemspec when --all-platforms is passed" do + git = build_git "pg_array_parser", "1.0" - gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "pg_array_parser", :git => "#{lib_path("pg_array_parser-1.0")}" - G + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "pg_array_parser", :git => "#{lib_path("pg_array_parser-1.0")}" + G - lockfile <<-L - GIT - remote: #{lib_path("pg_array_parser-1.0")} - revision: #{git.ref_for("main")} - specs: - pg_array_parser (1.0-java) - pg_array_parser (1.0) + lockfile <<-L + GIT + remote: #{lib_path("pg_array_parser-1.0")} + revision: #{git.ref_for("main")} + specs: + pg_array_parser (1.0-java) + pg_array_parser (1.0) - GEM - specs: + GEM + specs: - PLATFORMS - java - #{lockfile_platforms} + PLATFORMS + java + #{lockfile_platforms} - DEPENDENCIES - pg_array_parser! + DEPENDENCIES + pg_array_parser! - BUNDLED WITH - #{Bundler::VERSION} - L + BUNDLED WITH + #{Bundler::VERSION} + L - bundle "config set --local cache_all true" - bundle "cache --all-platforms" + bundle "config set --local cache_all true" + bundle "cache --all-platforms" - expect(err).to be_empty - end + expect(err).to be_empty + end - it "uses the platform-specific gem with extra dependencies" do + it "uses the platform-specific gem with extra dependencies" do + simulate_platform "x86_64-darwin-15" do setup_multiplatform_gem_with_different_dependencies_per_platform install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" @@ -291,13 +311,15 @@ RSpec.describe "bundle install with specific platforms" do expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(["CFPropertyList-1.0", "facter-2.4.6-universal-darwin"]) end + end - context "when adding a platform via lock --add_platform" do - before do - allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) - end + context "when adding a platform via lock --add_platform" do + before do + allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) + end - it "adds the foreign platform" do + it "adds the foreign platform" do + simulate_platform "x86_64-darwin-15" do setup_multiplatform_gem install_gemfile(google_protobuf) bundle "lock --add-platform=#{x64_mingw32}" @@ -308,8 +330,10 @@ RSpec.describe "bundle install with specific platforms" do google-protobuf-3.0.0.alpha.5.0.5.1-x64-mingw32 ]) end + end - it "falls back on plain ruby when that version doesn't have a platform-specific gem" do + it "falls back on plain ruby when that version doesn't have a platform-specific gem" do + simulate_platform "x86_64-darwin-15" do setup_multiplatform_gem install_gemfile(google_protobuf) bundle "lock --add-platform=#{java}" @@ -664,6 +688,63 @@ RSpec.describe "bundle install with specific platforms" do L end + it "automatically fixes the lockfile without removing other variants if it's missing platform gems, but they are installed locally" do + simulate_platform "x86_64-darwin-21" do + build_repo4 do + build_gem("sorbet-static", "0.5.10549") do |s| + s.platform = "universal-darwin-20" + end + + build_gem("sorbet-static", "0.5.10549") do |s| + s.platform = "universal-darwin-21" + end + end + + # Make sure sorbet-static-0.5.10549-universal-darwin-21 is installed + install_gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + + gem "sorbet-static", "= 0.5.10549" + G + + # Make sure the lockfile is missing sorbet-static-0.5.10549-universal-darwin-21 + lockfile <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + sorbet-static (0.5.10549-universal-darwin-20) + + PLATFORMS + x86_64-darwin + + DEPENDENCIES + sorbet-static (= 0.5.10549) + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "install" + + expect(lockfile).to eq <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + sorbet-static (0.5.10549-universal-darwin-20) + sorbet-static (0.5.10549-universal-darwin-21) + + PLATFORMS + x86_64-darwin + + DEPENDENCIES + sorbet-static (= 0.5.10549) + + BUNDLED WITH + #{Bundler::VERSION} + L + end + end + it "does not remove ruby if gems for other platforms, and not present in the lockfile, exist in the Gemfile" do build_repo4 do build_gem "nokogiri", "1.13.8" diff --git a/spec/bundler/realworld/edgecases_spec.rb b/spec/bundler/realworld/edgecases_spec.rb index d04da0c334..2f465b7b25 100644 --- a/spec/bundler/realworld/edgecases_spec.rb +++ b/spec/bundler/realworld/edgecases_spec.rb @@ -323,7 +323,7 @@ RSpec.describe "real world edgecases", :realworld => true do if Bundler.feature_flag.bundler_3_mode? # Conflicts on bundler version, so we count attempts differently bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }, :raise_on_error => false - expect(out.split("\n").grep(/backtracking to/).count).to eq(8) + expect(out.split("\n").grep(/backtracking to/).count).to eq(16) else bundle :lock, :env => { "DEBUG_RESOLVER" => "1" } expect(out).to include("Solution found after 7 attempts") diff --git a/spec/bundler/realworld/slow_perf_spec.rb b/spec/bundler/realworld/slow_perf_spec.rb index 3ef537be0a..aa8a48fcc7 100644 --- a/spec/bundler/realworld/slow_perf_spec.rb +++ b/spec/bundler/realworld/slow_perf_spec.rb @@ -28,6 +28,6 @@ RSpec.describe "bundle install with complex dependencies", :realworld => true do gem 'rspec-rails' G - expect { bundle "lock" }.to take_less_than(18) # seconds + expect { bundle "lock" }.to take_less_than(30) # seconds end end diff --git a/spec/bundler/runtime/inline_spec.rb b/spec/bundler/runtime/inline_spec.rb index 8f347dfa68..9567d2a3c3 100644 --- a/spec/bundler/runtime/inline_spec.rb +++ b/spec/bundler/runtime/inline_spec.rb @@ -168,6 +168,29 @@ RSpec.describe "bundler/inline#gemfile" do expect(err).to be_empty end + it "installs subdependencies quietly if necessary when the install option is not set" do + build_repo4 do + build_gem "rack" do |s| + s.add_dependency "rackdep" + end + + build_gem "rackdep", "1.0.0" + end + + script <<-RUBY + gemfile do + source "#{file_uri_for(gem_repo4)}" + gem "rack" + end + + require "rackdep" + puts RACKDEP + RUBY + + expect(out).to eq("1.0.0") + expect(err).to be_empty + end + it "installs quietly from git if necessary when the install option is not set" do build_git "foo", "1.0.0" baz_ref = build_git("baz", "2.0.0").ref_for("HEAD") @@ -207,8 +230,6 @@ RSpec.describe "bundler/inline#gemfile" do expect(err).to be_empty end -<<<<<<< HEAD:spec/bundler/runtime/inline_spec.rb -======= it "doesn't reinstall already installed gems" do system_gems "rack-1.0.0" @@ -316,7 +337,6 @@ RSpec.describe "bundler/inline#gemfile" do expect(err).to be_empty end ->>>>>>> fa6e6ea95c2 (Fix issue with extensions not compiling properly using inline gemfile):bundler/spec/runtime/inline_spec.rb it "installs inline gems when a Gemfile.lock is present" do gemfile <<-G source "https://notaserver.com" diff --git a/spec/bundler/support/indexes.rb b/spec/bundler/support/indexes.rb index 670f3b0230..78372302f1 100644 --- a/spec/bundler/support/indexes.rb +++ b/spec/bundler/support/indexes.rb @@ -18,22 +18,17 @@ module Spec @platforms ||= ["ruby"] default_source = instance_double("Bundler::Source::Rubygems", :specs => @index, :to_s => "locally install gems") source_requirements = { :default => default_source } - args[0] ||= Bundler::SpecSet.new([]) # base - args[0].each {|ls| ls.source = default_source } - args[1] ||= Bundler::GemVersionPromoter.new # gem_version_promoter - args[2] ||= [] # additional_base_requirements - originally_locked = args[3] || Bundler::SpecSet.new([]) - unlock = args[4] || [] - packages = Hash.new do |h, k| - h[k] = Bundler::Resolver::Package.new(k, @platforms, originally_locked, unlock) - end + base = args[0] || Bundler::SpecSet.new([]) + base.each {|ls| ls.source = default_source } + gem_version_promoter = args[1] || Bundler::GemVersionPromoter.new + originally_locked = args[2] || Bundler::SpecSet.new([]) + unlock = args[3] || [] @deps.each do |d| name = d.name - platforms = d.gem_platforms(@platforms) source_requirements[name] = d.source = default_source - packages[name] = Bundler::Resolver::Package.new(name, platforms, originally_locked, unlock, :dependency => d) end - Bundler::Resolver.new(source_requirements, *args[0..2]).start(@deps, packages) + packages = Bundler::Resolver::Base.new(source_requirements, @deps, base, @platforms, :locked_specs => originally_locked, :unlock => unlock) + Bundler::Resolver.new(packages, gem_version_promoter).start end def should_not_resolve @@ -71,7 +66,7 @@ module Spec s.level = opts.first s.strict = opts.include?(:strict) end - should_resolve_and_include specs, [@base, search, [], @locked, unlock] + should_resolve_and_include specs, [@base, search, @locked, unlock] end def an_awesome_index |