From 358736a1716f2b87879c11858b2672af538ed82d Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Thu, 15 Jun 2017 14:21:13 -0500 Subject: Implement source pinning for 2.0 --- lib/bundler/definition.rb | 65 ++++++++++++++++++++++++---- lib/bundler/dsl.rb | 19 +++++++-- lib/bundler/index.rb | 13 ++++++ lib/bundler/lockfile_parser.rb | 14 +++++-- lib/bundler/plugin/source_list.rb | 15 ++++--- lib/bundler/resolver.rb | 79 ++++++++++++++++++++++++++++------- lib/bundler/rubygems_ext.rb | 4 +- lib/bundler/settings.rb | 2 +- lib/bundler/source.rb | 6 +++ lib/bundler/source/metadata.rb | 31 ++++++++++++++ lib/bundler/source/rubygems.rb | 23 +++++++++- lib/bundler/source_list.rb | 46 +++++++++++++++----- spec/bundler/plugin/installer_spec.rb | 4 ++ spec/bundler/source_list_spec.rb | 2 + spec/install/bundler_spec.rb | 2 +- spec/install/gemfile/git_spec.rb | 6 +-- spec/install/gemfile/sources_spec.rb | 16 +++++-- spec/install/gems/resolving_spec.rb | 3 +- 18 files changed, 286 insertions(+), 64 deletions(-) create mode 100644 lib/bundler/source/metadata.rb diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 01df860d6e..9a7c8ba04d 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -255,10 +255,38 @@ module Bundler dependency_names -= pinned_spec_names(source.specs) dependency_names.concat(source.unmet_deps).uniq! end - idx << Gem::Specification.new("ruby\0", RubyVersion.system.to_gem_version_with_patchlevel) - idx << Gem::Specification.new("rubygems\0", Gem::VERSION) + + double_check_for_index(idx, dependency_names) + end + end + + # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both + # sources A and B. At this point, the API request will have found all the versions of Bar in source A, + # but will not have found any versions of Bar from source B, which is a problem if the requested version + # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for + # each spec we found, we add all possible versions from all sources to the index. + def double_check_for_index(idx, dependency_names) + return unless Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? + + loop do + idxcount = idx.size + sources.all_sources.each do |source| + names = :names # do this so we only have to traverse to get dependency_names from the index once + unmet_dependency_names = proc do + break names unless names == :names + names = if idx.size > Source::Rubygems::API_REQUEST_LIMIT + new_names = idx.dependency_names_if_available + new_names && dependency_names.+(new_names).uniq + else + dependency_names.+(idx.dependency_names).uniq + end + end + source.double_check_for(unmet_dependency_names, :override_dupes) + end + break if idxcount == idx.size end end + private :double_check_for_index # used when frozen is enabled so we can find the bundler # spec, even if (say) a git gem is not checked out. @@ -640,7 +668,9 @@ module Bundler end end - def converge_sources + def converge_rubygems_sources + return false if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? + changes = false # Get the RubyGems sources from the Gemfile.lock @@ -656,6 +686,14 @@ module Bundler end end + changes + end + + def converge_sources + changes = false + + changes |= converge_rubygems_sources + # Replace the sources from the Gemfile with the sources from the Gemfile.lock, # if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent # source in the Gemfile.lock, use the one from the Gemfile. @@ -829,17 +867,21 @@ module Bundler # the metadata dependencies here def expanded_dependencies @expanded_dependencies ||= begin + expand_dependencies(dependencies + metadata_dependencies, @remote) + end + end + + def metadata_dependencies + @metadata_dependencies ||= begin ruby_versions = concat_ruby_version_requirements(@ruby_version) if ruby_versions.empty? || !@ruby_version.exact? concat_ruby_version_requirements(RubyVersion.system) concat_ruby_version_requirements(locked_ruby_version_object) unless @unlock[:ruby] end - - metadata_dependencies = [ + [ Dependency.new("ruby\0", ruby_versions), Dependency.new("rubygems\0", Gem::VERSION), ] - expand_dependencies(dependencies + metadata_dependencies, @remote) end end @@ -894,10 +936,15 @@ module Bundler # Record the specs available in each gem's source, so that those # specs will be available later when the resolver knows where to # look for that gemspec (or its dependencies) - source_requirements = {} + default = sources.default_source + source_requirements = { :default => default } + default = nil unless Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? dependencies.each do |dep| - next unless dep.source - source_requirements[dep.name] = dep.source.specs + next unless source = dep.source || default + source_requirements[dep.name] = source + end + metadata_dependencies.each do |dep| + source_requirements[dep.name] = sources.metadata_source end source_requirements end diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb index 72e2f761bb..097e83298c 100644 --- a/lib/bundler/dsl.rb +++ b/lib/bundler/dsl.rb @@ -147,7 +147,7 @@ module Bundler with_source(@sources.add_rubygems_source("remotes" => source), &blk) else check_primary_source_safety(@sources) - @sources.add_rubygems_remote(source) + @sources.global_rubygems_source = source end end @@ -165,6 +165,19 @@ module Bundler end def path(path, options = {}, &blk) + unless block_given? + msg = "You can no longer specify a path source by itself. Instead, \n" \ + "either use the :path option on a gem, or specify the gems that \n" \ + "bundler should find in the path source by passing a block to \n" \ + "the path method, like: \n\n" \ + " path 'dir/containing/rails' do\n" \ + " gem 'rails'\n" \ + " end" + + raise DeprecatedError, msg if Bundler.feature_flag.disable_multisource? + SharedHelpers.major_deprecation(msg) + end + source_options = normalize_hash(options).merge( "path" => Pathname.new(path), "root_path" => gemfile_root, @@ -429,8 +442,8 @@ repo_name ||= user_name end end - def check_primary_source_safety(source) - return unless source.rubygems_primary_remotes.any? + def check_primary_source_safety(source_list) + return if source_list.rubygems_primary_remotes.empty? && source_list.global_rubygems_source.nil? if Bundler.feature_flag.disable_multisource? raise GemfileError, "Warning: this Gemfile contains multiple primary sources. " \ diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb index 5f54796fa2..fd4dea32e7 100644 --- a/lib/bundler/index.rb +++ b/lib/bundler/index.rb @@ -131,6 +131,19 @@ module Bundler names.uniq end + def dependency_names_if_available + reduce([]) do |names, spec| + case spec + when EndpointSpecification, Gem::Specification, LazySpecification, StubSpecification + names.concat(spec.dependencies) + when RemoteSpecification # from the full index + return nil + else + raise "unhandled spec type in #dependency_names_if_available (#{spec.inspect})" + end + end.tap {|n| n && n.map!(&:name) } + end + def use(other, override_dupes = false) return unless other other.each do |s| diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb index dbf8926690..ff706fca1d 100644 --- a/lib/bundler/lockfile_parser.rb +++ b/lib/bundler/lockfile_parser.rb @@ -90,7 +90,7 @@ module Bundler send("parse_#{@state}", line) end end - @sources << @rubygems_aggregate + @sources << @rubygems_aggregate unless Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? @specs = @specs.values.sort_by(&:identifier) warn_for_outdated_bundler_version rescue ArgumentError => e @@ -141,10 +141,16 @@ module Bundler @sources << @current_source end when GEM - Array(@opts["remote"]).each do |url| - @rubygems_aggregate.add_remote(url) + if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? + @opts["remotes"] = @opts.delete("remote") + @current_source = TYPES[@type].from_lock(@opts) + @sources << @current_source + else + Array(@opts["remote"]).each do |url| + @rubygems_aggregate.add_remote(url) + end + @current_source = @rubygems_aggregate end - @current_source = @rubygems_aggregate when PLUGIN @current_source = Plugin.source_from_lock(@opts) @sources << @current_source diff --git a/lib/bundler/plugin/source_list.rb b/lib/bundler/plugin/source_list.rb index 33f5e5afbd..f0e212205f 100644 --- a/lib/bundler/plugin/source_list.rb +++ b/lib/bundler/plugin/source_list.rb @@ -5,13 +5,6 @@ module Bundler # approptiate options to be used with Source classes for plugin installation module Plugin class SourceList < Bundler::SourceList - def initialize - @path_sources = [] - @git_sources = [] - @rubygems_aggregate = Plugin::Installer::Rubygems.new - @rubygems_sources = [] - end - def add_git_source(options = {}) add_source_to_list Plugin::Installer::Git.new(options), git_sources end @@ -21,7 +14,13 @@ module Bundler end def all_sources - path_sources + git_sources + rubygems_sources + path_sources + git_sources + rubygems_sources + [metadata_source] + end + + private + + def rubygems_aggregate_class + Plugin::Installer::Rubygems end end end diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 93c9d669c4..637c0b1313 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -59,12 +59,31 @@ module Bundler o << %(the gems in your Gemfile, which may resolve the conflict.\n) elsif !conflict.existing o << "\n" + + relevant_sources = if conflict.requirement.source + [conflict.requirement.source] + elsif conflict.requirement.all_sources + conflict.requirement.all_sources + elsif Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? + # every conflict should have an explicit group of sources when we + # enforce strict pinning + raise "no source set for #{conflict}" + else + [] + end.compact.map(&:to_s).uniq.sort + if conflict.requirement_trees.first.size > 1 - o << "Could not find gem '#{conflict.requirement}', which is required by " - o << "gem '#{conflict.requirement_trees.first[-2]}', in any of the sources." + o << "Could not find gem '#{printable_dep(conflict.requirement)}', which is required by " + o << "gem '#{printable_dep(conflict.requirement_trees.first[-2])}', " else - o << "Could not find gem '#{conflict.requirement}' in any of the sources\n" + o << "Could not find gem '#{printable_dep(conflict.requirement)}' " end + + o << if relevant_sources.empty? + "in any of the sources.\n" + else + "in any of the relevant sources:\n #{relevant_sources * "\n "}\n" + end end o end.strip @@ -300,7 +319,22 @@ module Bundler end def index_for(dependency) - @source_requirements[dependency.name] || @index + source = @source_requirements[dependency.name] + if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? + Index.build do |idx| + if source + idx.add_source source.specs + elsif dependency.all_sources + dependency.all_sources.each {|s| idx.add_source(s.specs) if s } + else + idx.add_source @source_requirements[:default].specs + end + end + elsif source + source.specs + else + @index + end end def name_for(dependency) @@ -325,8 +359,19 @@ module Bundler true end + def relevant_sources_for_vertex(vertex) + if vertex.root? + [@source_requirements[vertex.name]] + elsif Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? + vertex.recursive_predecessors.map do |v| + @source_requirements[v.name] + end << @source_requirements[:default] + end + end + 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) [ @base_dg.vertex_named(name) ? 0 : 1, @@ -366,25 +411,26 @@ module Bundler def verify_gemfile_dependencies_are_found!(requirements) requirements.each do |requirement| - next if requirement.name == "bundler" + name = requirement.name + next if name == "bundler" next unless search_for(requirement).empty? - if (base = @base[requirement.name]) && !base.empty? + + if (base = @base[name]) && !base.empty? version = base.first.version message = "You have requested:\n" \ - " #{requirement.name} #{requirement.requirement}\n\n" \ - "The bundle currently has #{requirement.name} locked at #{version}.\n" \ - "Try running `bundle update #{requirement.name}`\n\n" \ + " #{name} #{requirement.requirement}\n\n" \ + "The bundle currently has #{name} locked at #{version}.\n" \ + "Try running `bundle update #{name}`\n\n" \ "If you are updating multiple gems in your Gemfile at once,\n" \ "try passing them all to `bundle update`" - elsif requirement.source - name = requirement.name - specs = @source_requirements[name][name] + elsif source = @source_requirements[name] + specs = source.specs[name] versions_with_platforms = specs.map {|s| [s.version, s.platform] } - message = String.new("Could not find gem '#{requirement}' in #{requirement.source}.\n") + message = String.new("Could not find gem '#{requirement}' in #{source}.\n") message << if versions_with_platforms.any? - "Source contains '#{name}' at: #{formatted_versions_with_platforms(versions_with_platforms)}" + "The source contains '#{name}' at: #{formatted_versions_with_platforms(versions_with_platforms)}" else - "Source does not contain any versions of '#{requirement}'" + "The source does not contain any versions of '#{requirement}'" end else cache_message = begin @@ -404,7 +450,8 @@ module Bundler version = vwp.first platform = vwp.last version_platform_str = String.new(version.to_s) - version_platform_str << " #{platform}" unless platform.nil? + version_platform_str << " #{platform}" unless platform.nil? || platform == Gem::Platform::RUBY + version_platform_str end version_platform_strs.join(", ") end diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb index 74a80c923b..0d282a8fcc 100644 --- a/lib/bundler/rubygems_ext.rb +++ b/lib/bundler/rubygems_ext.rb @@ -135,7 +135,7 @@ module Gem end class Dependency - attr_accessor :source, :groups + attr_accessor :source, :groups, :all_sources alias_method :eql?, :== @@ -146,7 +146,7 @@ module Gem end def to_yaml_properties - instance_variables.reject {|p| ["@source", "@groups"].include?(p.to_s) } + instance_variables.reject {|p| ["@source", "@groups", "@all_sources"].include?(p.to_s) } end def to_lock diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index 66cb785137..e0381421e5 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -114,7 +114,7 @@ module Bundler end def all - env_keys = ENV.keys.select {|k| k =~ /BUNDLE_.*/ } + env_keys = ENV.keys.grep(/\ABUNDLE_.+/) keys = @global_config.keys | @local_config.keys | env_keys diff --git a/lib/bundler/source.rb b/lib/bundler/source.rb index cf56ed1cc1..cb5f2da83e 100644 --- a/lib/bundler/source.rb +++ b/lib/bundler/source.rb @@ -3,6 +3,7 @@ module Bundler class Source autoload :Gemspec, "bundler/source/gemspec" autoload :Git, "bundler/source/git" + autoload :Metadata, "bundler/source/metadata" autoload :Path, "bundler/source/path" autoload :Rubygems, "bundler/source/rubygems" @@ -31,6 +32,11 @@ module Bundler spec.source == self end + # it's possible that gems from one source depend on gems from some + # other source, so now we download gemspecs and iterate over those + # dependencies, looking for gems we don't have info on yet. + def double_check_for(*); end + def include?(other) other == self end diff --git a/lib/bundler/source/metadata.rb b/lib/bundler/source/metadata.rb new file mode 100644 index 0000000000..173c897998 --- /dev/null +++ b/lib/bundler/source/metadata.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Bundler + class Source + class Metadata < Source + def specs + @specs ||= Index.build do |idx| + idx << Gem::Specification.new("ruby\0", RubyVersion.system.to_gem_version_with_patchlevel) + idx << Gem::Specification.new("rubygems\0", Gem::VERSION) + end + end + + def cached!; end + + def remote!; end + + def to_s + "the local ruby installation" + end + + def ==(other) + self.class == other.class + end + alias_method :eql?, :== + + def hash + self.class.hash + end + end + end +end diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index a1d4266960..8644c05d64 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -50,6 +50,7 @@ module Bundler end def can_lock?(spec) + return super if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? spec.source.is_a?(Rubygems) end @@ -70,8 +71,12 @@ module Bundler end def to_s - remote_names = remotes.map(&:to_s).join(", ") - "rubygems repository #{remote_names}" + if remotes.empty? + "locally installed gems" + else + remote_names = remotes.map(&:to_s).join(", ") + "rubygems repository #{remote_names} or installed locally" + end end alias_method :name, :to_s @@ -237,6 +242,20 @@ module Bundler end end + def double_check_for(unmet_dependency_names, override_dupes = false, index = specs) + return unless @allow_remote + raise ArgumentError, "missing index" unless index + + return unless api_fetchers.any? + + unmet_dependency_names = unmet_dependency_names.call + Bundler.ui.debug "#{self}: 2x check for #{unmet_dependency_names}" + + return if unmet_dependency_names && unmet_dependency_names.empty? + + fetch_names(api_fetchers, unmet_dependency_names, index, override_dupes) + end + protected def credless_remotes diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb index b6ce6029c8..ed9a4cd0d7 100644 --- a/lib/bundler/source_list.rb +++ b/lib/bundler/source_list.rb @@ -3,14 +3,18 @@ module Bundler class SourceList attr_reader :path_sources, :git_sources, - :plugin_sources + :plugin_sources, + :global_rubygems_source, + :metadata_source def initialize - @path_sources = [] - @git_sources = [] - @plugin_sources = [] - @rubygems_aggregate = Source::Rubygems.new - @rubygems_sources = [] + @path_sources = [] + @git_sources = [] + @plugin_sources = [] + @global_rubygems_source = nil + @rubygems_aggregate = rubygems_aggregate_class.new + @rubygems_sources = [] + @metadata_source = Source::Metadata.new end def add_path_source(options = {}) @@ -35,13 +39,25 @@ module Bundler add_source_to_list Plugin.source(source).new(options), @plugin_sources end + def global_rubygems_source=(uri) + if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? + @global_rubygems_source ||= Source::Rubygems.new("remotes" => uri) + end + add_rubygems_remote(uri) + end + def add_rubygems_remote(uri) + return if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? @rubygems_aggregate.add_remote(uri) @rubygems_aggregate end + def default_source + global_rubygems_source || @rubygems_aggregate + end + def rubygems_sources - @rubygems_sources + [@rubygems_aggregate] + @rubygems_sources + [default_source] end def rubygems_remotes @@ -49,7 +65,7 @@ module Bundler end def all_sources - path_sources + git_sources + plugin_sources + rubygems_sources + path_sources + git_sources + plugin_sources + rubygems_sources + [metadata_source] end def get(source) @@ -57,8 +73,14 @@ module Bundler end def lock_sources - lock_sources = (path_sources + git_sources + plugin_sources).sort_by(&:to_s) - lock_sources << combine_rubygems_sources + if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? + [rubygems_sources, git_sources, path_sources, plugin_sources].map do |sources| + sources.sort_by(&:to_s) + end.flatten(1) + else + lock_sources = (path_sources + git_sources + plugin_sources).sort_by(&:to_s) + lock_sources << combine_rubygems_sources + end end def replace_sources!(replacement_sources) @@ -93,6 +115,10 @@ module Bundler private + def rubygems_aggregate_class + Source::Rubygems + end + def add_source_to_list(source, list) list.unshift(source).uniq! source diff --git a/spec/bundler/plugin/installer_spec.rb b/spec/bundler/plugin/installer_spec.rb index ece34a784c..8ede96ffea 100644 --- a/spec/bundler/plugin/installer_spec.rb +++ b/spec/bundler/plugin/installer_spec.rb @@ -3,6 +3,10 @@ RSpec.describe Bundler::Plugin::Installer do subject(:installer) { Bundler::Plugin::Installer.new } + before do + # allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(Pathname.new("/Gemfile")) + end + describe "cli install" do it "uses Gem.sources when non of the source is provided" do sources = double(:sources) diff --git a/spec/bundler/source_list_spec.rb b/spec/bundler/source_list_spec.rb index fb703806e1..5489b367ec 100644 --- a/spec/bundler/source_list_spec.rb +++ b/spec/bundler/source_list_spec.rb @@ -12,6 +12,7 @@ RSpec.describe Bundler::SourceList do subject(:source_list) { Bundler::SourceList.new } let(:rubygems_aggregate) { Bundler::Source::Rubygems.new } + let(:metadata_source) { Bundler::Source::Metadata.new } describe "adding sources" do before do @@ -203,6 +204,7 @@ RSpec.describe Bundler::SourceList do Bundler::Source::Rubygems.new("remotes" => ["https://fourth-rubygems.org"]), Bundler::Source::Rubygems.new("remotes" => ["https://fifth-rubygems.org"]), rubygems_aggregate, + metadata_source, ] end end diff --git a/spec/install/bundler_spec.rb b/spec/install/bundler_spec.rb index 69f85f4964..d0ce331f7d 100644 --- a/spec/install/bundler_spec.rb +++ b/spec/install/bundler_spec.rb @@ -46,7 +46,7 @@ RSpec.describe "bundle install" do This Gemfile requires a different version of Bundler. Perhaps you need to update Bundler by running `gem install bundler`? - Could not find gem 'bundler (= 0.9.2)' in any of the sources + Could not find gem 'bundler (= 0.9.2)' in any of the sources. E expect(last_command.bundler_err).to include(nice_error) end diff --git a/spec/install/gemfile/git_spec.rb b/spec/install/gemfile/git_spec.rb index ab66337ffa..c160170a7a 100644 --- a/spec/install/gemfile/git_spec.rb +++ b/spec/install/gemfile/git_spec.rb @@ -80,7 +80,7 @@ RSpec.describe "bundle install with git sources" do gem "foo", "1.1", :git => "#{lib_path("foo-1.0")}" G - expect(out).to include("Source contains 'foo' at: 1.0 ruby") + expect(out).to include("The source contains 'foo' at: 1.0") end it "complains with version and platform if pinned specs don't exist in the git repo" do @@ -96,7 +96,7 @@ RSpec.describe "bundle install with git sources" do end G - expect(out).to include("Source contains 'only_java' at: 1.0 java") + expect(out).to include("The source contains 'only_java' at: 1.0 java") end it "complains with multiple versions and platforms if pinned specs don't exist in the git repo" do @@ -117,7 +117,7 @@ RSpec.describe "bundle install with git sources" do end G - expect(out).to include("Source contains 'only_java' at: 1.0 java, 1.1 java") + expect(out).to include("The source contains 'only_java' at: 1.0 java, 1.1 java") end it "still works after moving the application directory" do diff --git a/spec/install/gemfile/sources_spec.rb b/spec/install/gemfile/sources_spec.rb index 810d1862ef..ee772023c6 100644 --- a/spec/install/gemfile/sources_spec.rb +++ b/spec/install/gemfile/sources_spec.rb @@ -78,6 +78,10 @@ RSpec.describe "bundle install with gems on multiple sources" do build_gem "rack", "1.0.0" do |s| s.write "lib/rack.rb", "RACK = 'FAIL'" end + + build_gem "rack-obama" do |s| + s.add_dependency "rack" + end end gemfile <<-G @@ -91,19 +95,19 @@ RSpec.describe "bundle install with gems on multiple sources" do end it "installs the gems without any warning" do - bundle :install + bundle! :install expect(out).not_to include("Warning") expect(the_bundle).to include_gems("rack-obama 1.0.0") expect(the_bundle).to include_gems("rack 1.0.0", :source => "remote1") end it "can cache and deploy" do - bundle :package + bundle! :package expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist expect(bundled_app("vendor/cache/rack-obama-1.0.gem")).to exist - bundle "install --deployment" + bundle! "install --deployment" expect(exitstatus).to eq(0) if exitstatus expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0") @@ -118,6 +122,10 @@ RSpec.describe "bundle install with gems on multiple sources" do build_gem "rack", "1.0.0" do |s| s.write "lib/rack.rb", "RACK = 'FAIL'" end + + build_gem "rack-obama" do |s| + s.add_dependency "rack" + end end gemfile <<-G @@ -335,7 +343,7 @@ RSpec.describe "bundle install with gems on multiple sources" do it "does not find the dependency" do bundle :install - expect(out).to include("Could not find gem 'rack (>= 0) ruby'") + expect(out).to include("Could not find gem 'rack', which is required by gem 'depends_on_rack', in any of the relevant sources") end end diff --git a/spec/install/gems/resolving_spec.rb b/spec/install/gems/resolving_spec.rb index 261286f7e4..f6f2bb41cc 100644 --- a/spec/install/gems/resolving_spec.rb +++ b/spec/install/gems/resolving_spec.rb @@ -147,7 +147,8 @@ RSpec.describe "bundle install with install-time dependencies" do require_ruby was resolved to 1.0, which depends on ruby\0 (> 9000) - Could not find gem 'ruby\0 (> 9000)', which is required by gem 'require_ruby', in any of the sources. + Could not find gem 'ruby\0 (> 9000)', which is required by gem 'require_ruby', in any of the relevant sources: + the local ruby installation E expect(last_command.bundler_err).to end_with(nice_error) end -- cgit v1.2.1