diff --git a/bundler/lib/bundler/definition.rb b/bundler/lib/bundler/definition.rb index 486f469bf8ee..b585b06df102 100644 --- a/bundler/lib/bundler/definition.rb +++ b/bundler/lib/bundler/definition.rb @@ -190,25 +190,15 @@ def resolve_remotely! # # @return [Bundler::SpecSet] def specs - @specs ||= begin - begin - specs = resolve.materialize(requested_dependencies) - rescue GemNotFound => e # Handle yanked gem - gem_name, gem_version = extract_gem_info(e) - locked_gem = @locked_specs[gem_name].last - raise if locked_gem.nil? || locked_gem.version.to_s != gem_version || !@remote - raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \ - "no longer be found in that source. That means the author of #{locked_gem} has removed it. " \ - "You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \ - "removed in order to install." - end - unless specs["bundler"].any? - bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last - specs["bundler"] = bundler - end - - specs - end + @specs ||= add_bundler_to(resolve.materialize(requested_dependencies)) + rescue GemNotFound => e # Handle yanked gem + gem_name, gem_version = extract_gem_info(e) + locked_gem = @locked_specs[gem_name].last + raise if locked_gem.nil? || locked_gem.version.to_s != gem_version || !@remote + raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \ + "no longer be found in that source. That means the author of #{locked_gem} has removed it. " \ + "You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \ + "removed in order to install." end def new_specs @@ -240,17 +230,11 @@ def missing_specs? end def requested_specs - @requested_specs ||= begin - groups = requested_groups - groups.map!(&:to_sym) - specs_for(groups) - end + specs_for(requested_groups) end def requested_dependencies - groups = requested_groups - groups.map!(&:to_sym) - dependencies_for(groups) + dependencies_for(requested_groups) end def current_dependencies @@ -260,11 +244,13 @@ def current_dependencies end def specs_for(groups) + groups = requested_groups if groups.empty? deps = dependencies_for(groups) - SpecSet.new(specs.for(expand_dependencies(deps))) + add_bundler_to(resolve.materialize(expand_dependencies(deps))) end def dependencies_for(groups) + groups.map!(&:to_sym) current_dependencies.reject do |d| (d.groups & groups).empty? end @@ -514,6 +500,15 @@ def unlocking? private + def add_bundler_to(specs) + unless specs["bundler"].any? + bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last + specs["bundler"] = bundler + end + + specs + end + def precompute_source_requirements_for_indirect_dependencies? sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source? end diff --git a/bundler/lib/bundler/installer/standalone.rb b/bundler/lib/bundler/installer/standalone.rb index 2a3f5cfe3585..f16135cb481d 100644 --- a/bundler/lib/bundler/installer/standalone.rb +++ b/bundler/lib/bundler/installer/standalone.rb @@ -3,7 +3,7 @@ module Bundler class Standalone def initialize(groups, definition) - @specs = groups.empty? ? definition.requested_specs : definition.specs_for(groups.map(&:to_sym)) + @specs = definition.specs_for(groups) end def generate diff --git a/bundler/lib/bundler/runtime.rb b/bundler/lib/bundler/runtime.rb index e259b590bfc7..287fa1cfe94b 100644 --- a/bundler/lib/bundler/runtime.rb +++ b/bundler/lib/bundler/runtime.rb @@ -12,12 +12,10 @@ def initialize(root, definition) def setup(*groups) @definition.ensure_equivalent_gemfile_and_lockfile if Bundler.frozen_bundle? - groups.map!(&:to_sym) - # Has to happen first clean_load_path - specs = groups.any? ? @definition.specs_for(groups) : requested_specs + specs = @definition.specs_for(groups) SharedHelpers.set_bundle_environment Bundler.rubygems.replace_entrypoints(specs) diff --git a/bundler/lib/bundler/spec_set.rb b/bundler/lib/bundler/spec_set.rb index 13cee734c3e5..1a8906c47ee4 100644 --- a/bundler/lib/bundler/spec_set.rb +++ b/bundler/lib/bundler/spec_set.rb @@ -18,13 +18,13 @@ def for(dependencies, check = false, match_current_platform = false, raise_on_mi loop do break unless dep = deps.shift - next if handled.include?(dep) + next if handled.any?{|d| d.name == dep.name && (match_current_platform || d.__platform == dep.__platform) } || dep.name == "bundler" handled << dep specs_for_dep = spec_for_dependency(dep, match_current_platform) if specs_for_dep.any? - specs |= specs_for_dep + specs += specs_for_dep specs_for_dep.first.dependencies.each do |d| next if d.type == :development @@ -42,7 +42,7 @@ def for(dependencies, check = false, match_current_platform = false, raise_on_mi end if spec = lookup["bundler"].first - specs |= [spec] + specs << spec end check ? true : specs diff --git a/bundler/spec/runtime/setup_spec.rb b/bundler/spec/runtime/setup_spec.rb index d8ba569f0abb..380db991364d 100644 --- a/bundler/spec/runtime/setup_spec.rb +++ b/bundler/spec/runtime/setup_spec.rb @@ -644,6 +644,25 @@ def clean_load_path(lp) expect(err).to be_empty end + it "doesn't re-resolve when a pre-release bundler is used and a dependency includes a dependency on bundler" do + system_gems "bundler-9.99.9.beta1" + + build_repo4 do + build_gem "depends_on_bundler", "1.0" do |s| + s.add_dependency "bundler", ">= 1.5.0" + end + end + + install_gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + gem "depends_on_bundler" + G + + ruby "require '#{system_gem_path("gems/bundler-9.99.9.beta1/lib/bundler.rb")}'; Bundler.setup", :env => { "DEBUG" => "1" } + expect(out).to include("Found no changes, using resolution from the lockfile") + expect(err).to be_empty + end + it "remembers --without and does not include groups passed to Bundler.setup" do bundle "config set --local without rails" install_gemfile <<-G