From 93fd9826f1b0a428175f6c76d8e33d6afc900497 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Wed, 14 Jun 2017 12:47:28 -0500 Subject: Add a feature flag for the lockfile using separate RubyGems sources --- lib/bundler/feature_flag.rb | 1 + lib/bundler/settings.rb | 1 + spec/quality_spec.rb | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb index ee93773c2f..423e98ba65 100644 --- a/lib/bundler/feature_flag.rb +++ b/lib/bundler/feature_flag.rb @@ -30,6 +30,7 @@ module Bundler settings_flag(:allow_offline_install) { bundler_2_mode? } settings_flag(:error_on_stderr) { bundler_2_mode? } settings_flag(:init_gems_rb) { bundler_2_mode? } + settings_flag(:lockfile_uses_separate_rubygems_sources) { bundler_2_mode? } settings_flag(:only_update_to_newer_versions) { bundler_2_mode? } settings_flag(:plugins) { @bundler_version >= Gem::Version.new("1.14") } settings_flag(:prefer_gems_rb) { bundler_2_mode? } diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index 078c517919..f4dd28d376 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -24,6 +24,7 @@ module Bundler gem.mit ignore_messages init_gems_rb + lockfile_uses_separate_rubygems_sources major_deprecations no_install no_prune diff --git a/spec/quality_spec.rb b/spec/quality_spec.rb index 0c1ab942b5..4561ce0461 100644 --- a/spec/quality_spec.rb +++ b/spec/quality_spec.rb @@ -172,6 +172,7 @@ RSpec.describe "The library itself" do default_cli_command gem.coc gem.mit + lockfile_uses_separate_rubygems_sources warned_version ] -- cgit v1.2.1 From 049e700d467e36778f4f799fdb4bede3bc871f5e Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 29 May 2015 09:14:52 +1000 Subject: Failing spec for #3671. --- spec/install/gemfile/sources_spec.rb | 75 +++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/spec/install/gemfile/sources_spec.rb b/spec/install/gemfile/sources_spec.rb index b7f8b3d99e..d596331276 100644 --- a/spec/install/gemfile/sources_spec.rb +++ b/spec/install/gemfile/sources_spec.rb @@ -134,7 +134,7 @@ RSpec.describe "bundle install with gems on multiple sources" do end end - context "with an indirect dependency" do + context "when a pinned gem has an indirect dependency" do before do build_repo gem_repo3 do build_gem "depends_on_rack", "1.0.1" do |s| @@ -270,6 +270,79 @@ RSpec.describe "bundle install with gems on multiple sources" do end end + context "when a top-level gem has an indirect dependency" do + before do + build_repo gem_repo2 do + build_gem "depends_on_rack", "1.0.1" do |s| + s.add_dependency "rack" + end + end + + build_repo gem_repo3 do + build_gem "unrelated_gem", "1.0.0" + end + + gemfile <<-G + source "file://#{gem_repo2}" + + gem "depends_on_rack" + + source "file://#{gem_repo3}" do + gem "unrelated_gem" + end + G + end + + context "and the dependency is only in the top-level source" do + before do + update_repo gem_repo2 do + build_gem "rack", "1.0.0" + end + end + + it "installs all gems without warning" do + bundle :install + expect(out).not_to include("Warning") + should_be_installed("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0") + end + end + + context "and the dependency is only in a pinned source" do + before do + update_repo gem_repo3 do + build_gem "rack", "1.0.0" do |s| + s.write "lib/rack.rb", "RACK = 'FAIL'" + end + end + end + + it "does not find the dependency" do + bundle :install + expect(out).to include("Could not find gem 'rack (>= 0) ruby'") + end + end + + context "and the dependency is in both the top-level and a pinned source" do + before do + update_repo gem_repo2 do + build_gem "rack", "1.0.0" + end + + update_repo gem_repo3 do + build_gem "rack", "1.0.0" do |s| + s.write "lib/rack.rb", "RACK = 'FAIL'" + end + end + end + + it "installs the dependency from the top-level source without warning" do + bundle :install + expect(out).not_to include("Warning") + should_be_installed("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0") + end + end + end + context "with a gem that is only found in the wrong source" do before do build_repo gem_repo3 do -- cgit v1.2.1 From fe7ed25f319f4bec6ad4856fd45093e4404c0c8e Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Wed, 14 Jun 2017 12:53:46 -0500 Subject: Put new source pinning specs behind a feature flag Also update them to modern bundler test syntax --- spec/install/gemfile/sources_spec.rb | 102 ++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 49 deletions(-) diff --git a/spec/install/gemfile/sources_spec.rb b/spec/install/gemfile/sources_spec.rb index d596331276..9d727118de 100644 --- a/spec/install/gemfile/sources_spec.rb +++ b/spec/install/gemfile/sources_spec.rb @@ -271,74 +271,78 @@ RSpec.describe "bundle install with gems on multiple sources" do end context "when a top-level gem has an indirect dependency" do - before do - build_repo gem_repo2 do - build_gem "depends_on_rack", "1.0.1" do |s| - s.add_dependency "rack" + context "when lockfile_uses_separate_rubygems_sources is set" do + before { bundle! "config lockfile_uses_separate_rubygems_sources true" } + + before do + build_repo gem_repo2 do + build_gem "depends_on_rack", "1.0.1" do |s| + s.add_dependency "rack" + end end - end - build_repo gem_repo3 do - build_gem "unrelated_gem", "1.0.0" - end + build_repo gem_repo3 do + build_gem "unrelated_gem", "1.0.0" + end - gemfile <<-G - source "file://#{gem_repo2}" + gemfile <<-G + source "file://#{gem_repo2}" - gem "depends_on_rack" + gem "depends_on_rack" - source "file://#{gem_repo3}" do - gem "unrelated_gem" - end - G - end + source "file://#{gem_repo3}" do + gem "unrelated_gem" + end + G + end - context "and the dependency is only in the top-level source" do - before do - update_repo gem_repo2 do - build_gem "rack", "1.0.0" + context "and the dependency is only in the top-level source" do + before do + update_repo gem_repo2 do + build_gem "rack", "1.0.0" + end end - end - it "installs all gems without warning" do - bundle :install - expect(out).not_to include("Warning") - should_be_installed("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0") + it "installs all gems without warning" do + bundle :install + expect(out).not_to include("Warning") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0") + end end - end - context "and the dependency is only in a pinned source" do - before do - update_repo gem_repo3 do - build_gem "rack", "1.0.0" do |s| - s.write "lib/rack.rb", "RACK = 'FAIL'" + context "and the dependency is only in a pinned source" do + before do + update_repo gem_repo3 do + build_gem "rack", "1.0.0" do |s| + s.write "lib/rack.rb", "RACK = 'FAIL'" + end end end - end - it "does not find the dependency" do - bundle :install - expect(out).to include("Could not find gem 'rack (>= 0) ruby'") + it "does not find the dependency" do + bundle :install + expect(out).to include("Could not find gem 'rack (>= 0) ruby'") + end end - end - context "and the dependency is in both the top-level and a pinned source" do - before do - update_repo gem_repo2 do - build_gem "rack", "1.0.0" - end + context "and the dependency is in both the top-level and a pinned source" do + before do + update_repo gem_repo2 do + build_gem "rack", "1.0.0" + end - update_repo gem_repo3 do - build_gem "rack", "1.0.0" do |s| - s.write "lib/rack.rb", "RACK = 'FAIL'" + update_repo gem_repo3 do + build_gem "rack", "1.0.0" do |s| + s.write "lib/rack.rb", "RACK = 'FAIL'" + end end end - end - it "installs the dependency from the top-level source without warning" do - bundle :install - expect(out).not_to include("Warning") - should_be_installed("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0") + it "installs the dependency from the top-level source without warning" do + bundle :install + expect(out).not_to include("Warning") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0") + end end end end -- cgit v1.2.1 From 9c8dab3c0e9078637edd50049bdc2351d6d27458 Mon Sep 17 00:00:00 2001 From: Juan Barreneche Date: Thu, 15 Oct 2015 18:50:39 -0300 Subject: Add failing test for invalid warning # Conflicts: # spec/install/gemfile/sources_spec.rb --- spec/install/gemfile/sources_spec.rb | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/spec/install/gemfile/sources_spec.rb b/spec/install/gemfile/sources_spec.rb index 9d727118de..810d1862ef 100644 --- a/spec/install/gemfile/sources_spec.rb +++ b/spec/install/gemfile/sources_spec.rb @@ -180,10 +180,24 @@ RSpec.describe "bundle install with gems on multiple sources" do end end - it "installs from the same source without any warning" do - bundle :install - expect(out).not_to include("Warning") - expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") + context "when lockfile_uses_separate_rubygems_sources is set" do + before { bundle! "config lockfile_uses_separate_rubygems_sources true" } + + it "installs from the same source without any warning" do + bundle! :install + + expect(out).not_to include("Warning: the gem 'rack' was found in multiple sources.") + expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") + + # when there is already a lock file, and the gems are missing, so try again + system_gems [] + bundle! :install + + expect(out).not_to include("Warning: the gem 'rack' was found in multiple sources.") + expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") + end end end end -- cgit v1.2.1 From 1e23246902f950a3fa4132d2effaea47c723d51c Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Wed, 14 Jun 2017 13:11:22 -0500 Subject: Disable mutisource gemfiles by default on 2.0 --- lib/bundler/dsl.rb | 3 +-- lib/bundler/feature_flag.rb | 1 + lib/bundler/settings.rb | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb index 665724f54d..72e2f761bb 100644 --- a/lib/bundler/dsl.rb +++ b/lib/bundler/dsl.rb @@ -432,8 +432,7 @@ repo_name ||= user_name def check_primary_source_safety(source) return unless source.rubygems_primary_remotes.any? - # TODO: 2.0 upgrade from setting to default - if Bundler.settings[:disable_multisource] + if Bundler.feature_flag.disable_multisource? raise GemfileError, "Warning: this Gemfile contains multiple primary sources. " \ "Each source after the first must include a block to indicate which gems " \ "should come from that source. To downgrade this error to a warning, run " \ diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb index 423e98ba65..fe0c1c9770 100644 --- a/lib/bundler/feature_flag.rb +++ b/lib/bundler/feature_flag.rb @@ -28,6 +28,7 @@ module Bundler settings_flag(:allow_bundler_dependency_conflicts) { bundler_2_mode? } settings_flag(:allow_offline_install) { bundler_2_mode? } + settings_flag(:disable_multisource) { bundler_2_mode? } settings_flag(:error_on_stderr) { bundler_2_mode? } settings_flag(:init_gems_rb) { bundler_2_mode? } settings_flag(:lockfile_uses_separate_rubygems_sources) { bundler_2_mode? } diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index f4dd28d376..66cb785137 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -15,6 +15,7 @@ module Bundler disable_checksum_validation disable_exec_load disable_local_branch_check + disable_multisource disable_shared_gems disable_version_check error_on_stderr -- cgit v1.2.1 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 From 1867eafe120a97f31c5a8a4976dadf4089b13e1f Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Thu, 15 Jun 2017 16:53:02 -0500 Subject: Avoid fetching the full index to get all dependency names --- lib/bundler/source/rubygems.rb | 4 ++-- spec/install/gems/compact_index_spec.rb | 24 ++++++++++++++++++++++ .../artifice/compact_index_extra_api_missing.rb | 16 +++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 spec/support/artifice/compact_index_extra_api_missing.rb diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 8644c05d64..465aec6136 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -249,9 +249,9 @@ module Bundler 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.nil? && unmet_dependency_names.empty? - return if unmet_dependency_names && unmet_dependency_names.empty? + Bundler.ui.debug "Double checking for #{unmet_dependency_names || "all specs (due to the size of the request)"} in #{self}" fetch_names(api_fetchers, unmet_dependency_names, index, override_dupes) end diff --git a/spec/install/gems/compact_index_spec.rb b/spec/install/gems/compact_index_spec.rb index 9fc5b1f90a..ad1abe2e89 100644 --- a/spec/install/gems/compact_index_spec.rb +++ b/spec/install/gems/compact_index_spec.rb @@ -363,6 +363,30 @@ The checksum of /versions does not match the checksum provided by the server! So expect(the_bundle).to include_gems "back_deps 1.0" end + it "does not fetch every spec if the index of gems is large when doing back deps & everything is the compact index" do + build_repo4 do + build_gem "back_deps" do |s| + s.add_dependency "foo" + end + build_gem "missing" + # need to hit the limit + 1.upto(Bundler::Source::Rubygems::API_REQUEST_LIMIT) do |i| + build_gem "gem#{i}" + end + + FileUtils.rm_rf Dir[gem_repo4("gems/foo-*.gem")] + end + + install_gemfile! <<-G, :artifice => "compact_index_extra_api_missing" + source "#{source_uri}" + source "#{source_uri}/extra" do + gem "back_deps" + end + G + + expect(the_bundle).to include_gem "back_deps 1.0" + end + it "uses the endpoint if all sources support it" do gemfile <<-G source "#{source_uri}" diff --git a/spec/support/artifice/compact_index_extra_api_missing.rb b/spec/support/artifice/compact_index_extra_api_missing.rb new file mode 100644 index 0000000000..d11793fc2b --- /dev/null +++ b/spec/support/artifice/compact_index_extra_api_missing.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +require File.expand_path("../compact_index_extra_api", __FILE__) + +Artifice.deactivate + +class CompactIndexExtraAPIMissing < CompactIndexExtraApi + get "/extra/fetch/actual/gem/:id" do + if params[:id] == "missing-1.0.gemspec.rz" + halt 404 + else + File.read("#{gem_repo2}/quick/Marshal.4.8/#{params[:id]}") + end + end +end + +Artifice.activate_with(CompactIndexExtraAPIMissing) -- cgit v1.2.1 From ebd40b60d8a267c2f3ec1ca1c8ad3be5e307ce11 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Thu, 15 Jun 2017 17:10:09 -0500 Subject: Consolidate the double-checking logic --- lib/bundler/definition.rb | 2 -- lib/bundler/source/rubygems.rb | 62 ++++++++++-------------------------------- 2 files changed, 14 insertions(+), 50 deletions(-) diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 9a7c8ba04d..bcae470569 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -266,8 +266,6 @@ module Bundler # 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| diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 465aec6136..4d87ca7249 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -368,62 +368,28 @@ module Bundler index_fetchers = fetchers - api_fetchers # gather lists from non-api sites - index_fetchers.each do |f| - Bundler.ui.info "Fetching source index from #{f.uri}" - idx.use f.specs_with_retry(nil, self) - end + fetch_names(index_fetchers, nil, idx, false) # because ensuring we have all the gems we need involves downloading # the gemspecs of those gems, if the non-api sites contain more than - # about 100 gems, we treat all sites as non-api for speed. + # about 500 gems, we treat all sites as non-api for speed. allow_api = idx.size < API_REQUEST_LIMIT && dependency_names.size < API_REQUEST_LIMIT Bundler.ui.debug "Need to query more than #{API_REQUEST_LIMIT} gems." \ " Downloading full index instead..." unless allow_api - if allow_api - api_fetchers.each do |f| - Bundler.ui.info "Fetching gem metadata from #{f.uri}", Bundler.ui.debug? - idx.use f.specs_with_retry(dependency_names, self) - Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over - 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. - loop do - idxcount = idx.size - api_fetchers.each do |f| - Bundler.ui.info "Fetching version metadata from #{f.uri}", Bundler.ui.debug? - idx.use f.specs_with_retry(idx.dependency_names, self), true - Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over - end - break if idxcount == idx.size - end - - if api_fetchers.any? - # 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. - unmet = idx.unmet_dependency_names - - # if there are any cross-site gems we missed, get them now - api_fetchers.each do |f| - Bundler.ui.info "Fetching dependency metadata from #{f.uri}", Bundler.ui.debug? - idx.use f.specs_with_retry(unmet, self) - Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over - end if unmet.any? - else - allow_api = false - end - end + fetch_names(api_fetchers, allow_api && dependency_names, idx, false) + end + end - unless allow_api - api_fetchers.each do |f| - Bundler.ui.info "Fetching source index from #{f.uri}" - idx.use f.specs_with_retry(nil, self) - end + def fetch_names(fetchers, dependency_names, index, override_dupes) + fetchers.each do |f| + if dependency_names + Bundler.ui.info "Fetching gem metadata from #{f.uri}", Bundler.ui.debug? + index.use f.specs_with_retry(dependency_names, self), override_dupes + Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over + else + Bundler.ui.info "Fetching source index from #{f.uri}" + index.use f.specs_with_retry(nil, self), override_dupes end end end -- cgit v1.2.1 From 14b8eb6a1d3203a42c345142590dac30e3716d9c Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Thu, 15 Jun 2017 17:37:43 -0500 Subject: Error if lockfile_uses_separate_rubygems_sources is set without disable_multisource --- lib/bundler/source_list.rb | 5 ++++- spec/install/gemfile/sources_spec.rb | 10 ++++++++-- spec/install/gems/flex_spec.rb | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb index ed9a4cd0d7..c68eb51d59 100644 --- a/lib/bundler/source_list.rb +++ b/lib/bundler/source_list.rb @@ -47,7 +47,10 @@ module Bundler end def add_rubygems_remote(uri) - return if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? + if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? + return if Bundler.feature_flag.disable_multisource? + raise InvalidOption, "`lockfile_uses_separate_rubygems_sources` cannot be set without `disable_multisource` being set" + end @rubygems_aggregate.add_remote(uri) @rubygems_aggregate end diff --git a/spec/install/gemfile/sources_spec.rb b/spec/install/gemfile/sources_spec.rb index ee772023c6..285082438f 100644 --- a/spec/install/gemfile/sources_spec.rb +++ b/spec/install/gemfile/sources_spec.rb @@ -189,7 +189,10 @@ RSpec.describe "bundle install with gems on multiple sources" do end context "when lockfile_uses_separate_rubygems_sources is set" do - before { bundle! "config lockfile_uses_separate_rubygems_sources true" } + before do + bundle! "config lockfile_uses_separate_rubygems_sources true" + bundle! "config disable_multisource true" + end it "installs from the same source without any warning" do bundle! :install @@ -294,7 +297,10 @@ RSpec.describe "bundle install with gems on multiple sources" do context "when a top-level gem has an indirect dependency" do context "when lockfile_uses_separate_rubygems_sources is set" do - before { bundle! "config lockfile_uses_separate_rubygems_sources true" } + before do + bundle! "config lockfile_uses_separate_rubygems_sources true" + bundle! "config disable_multisource true" + end before do build_repo gem_repo2 do diff --git a/spec/install/gems/flex_spec.rb b/spec/install/gems/flex_spec.rb index b7cef0b53e..30e1019cfa 100644 --- a/spec/install/gems/flex_spec.rb +++ b/spec/install/gems/flex_spec.rb @@ -246,11 +246,11 @@ RSpec.describe "bundle flex_install" do describe "when adding a new source" do it "updates the lockfile" do build_repo2 - install_gemfile <<-G + install_gemfile! <<-G source "file://#{gem_repo1}" gem "rack" G - install_gemfile <<-G + install_gemfile! <<-G source "file://#{gem_repo1}" source "file://#{gem_repo2}" gem "rack" -- cgit v1.2.1 From f1ffdf65a07f5764c42dfd6bbb044d6afeda0b86 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Tue, 20 Jun 2017 09:37:48 -0500 Subject: Fix plugin sources --- lib/bundler/plugin/api/source.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/bundler/plugin/api/source.rb b/lib/bundler/plugin/api/source.rb index 5d3f58df92..820f9ee874 100644 --- a/lib/bundler/plugin/api/source.rb +++ b/lib/bundler/plugin/api/source.rb @@ -293,6 +293,13 @@ module Bundler def bundler_plugin_api_source? true end + + # @private + # This API on source might not be stable, and for now we expect plugins + # to download all specs in `#specs`, so we implement the method for + # compatibility purposes and leave it undocumented (and don't support) + # overriding it) + def double_check_for(*); end end end end -- cgit v1.2.1 From 6b40a8a22bfb3f04e677a3de4d5b9329c689d2c2 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Fri, 23 Jun 2017 17:13:11 -0500 Subject: Get the Bundler 2 specs passing with transitive source pinning --- .rubocop_todo.yml | 1 + lib/bundler/dsl.rb | 14 +- lib/bundler/plugin/installer.rb | 13 +- lib/bundler/source_list.rb | 14 +- spec/bundler/definition_spec.rb | 40 +- spec/bundler/plugin/installer_spec.rb | 1 + spec/bundler/source_list_spec.rb | 39 +- spec/commands/add_spec.rb | 2 +- spec/commands/exec_spec.rb | 20 +- spec/commands/install_spec.rb | 8 +- spec/commands/lock_spec.rb | 2 +- spec/install/bundler_spec.rb | 2 +- spec/install/deploy_spec.rb | 5 +- spec/install/gemfile/gemspec_spec.rb | 103 ++- spec/install/gemfile/path_spec.rb | 14 +- spec/install/gems/compact_index_spec.rb | 2 +- spec/lock/lockfile_bundler_1_spec.rb | 1382 +++++++++++++++++++++++++++++++ spec/lock/lockfile_spec.rb | 122 +-- spec/plugins/source/example_spec.rb | 29 +- spec/quality_spec.rb | 2 +- spec/resolver/basic_spec.rb | 2 +- spec/runtime/inline_spec.rb | 15 +- spec/runtime/require_spec.rb | 79 +- spec/runtime/setup_spec.rb | 5 +- spec/support/indexes.rb | 8 +- spec/update/git_spec.rb | 38 +- 26 files changed, 1818 insertions(+), 144 deletions(-) create mode 100644 spec/lock/lockfile_bundler_1_spec.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 74a89bab6f..2eaf40e8de 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -73,6 +73,7 @@ Lint/AmbiguousBlockAssociation: - 'spec/commands/install_spec.rb' - 'spec/install/gems/flex_spec.rb' - 'spec/lock/lockfile_spec.rb' + - 'spec/lock/lockfile_bundler_1_spec.rb' - 'spec/other/major_deprecation_spec.rb' - 'spec/runtime/setup_spec.rb' - 'spec/support/helpers.rb' diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb index 097e83298c..5435512810 100644 --- a/lib/bundler/dsl.rb +++ b/lib/bundler/dsl.rb @@ -172,10 +172,10 @@ module Bundler "the path method, like: \n\n" \ " path 'dir/containing/rails' do\n" \ " gem 'rails'\n" \ - " end" + " end\n\n" raise DeprecatedError, msg if Bundler.feature_flag.disable_multisource? - SharedHelpers.major_deprecation(msg) + SharedHelpers.major_deprecation(msg.strip) end source_options = normalize_hash(options).merge( @@ -446,10 +446,14 @@ repo_name ||= user_name 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. " \ + msg = "This Gemfile contains multiple primary sources. " \ "Each source after the first must include a block to indicate which gems " \ - "should come from that source. To downgrade this error to a warning, run " \ - "`bundle config --delete disable_multisource`" + "should come from that source" + unless Bundler.feature_flag.bundler_2_mode? + msg += ". To downgrade this error to a warning, run " \ + "`bundle config --delete disable_multisource`" + end + raise GemfileEvalError, msg else Bundler::SharedHelpers.major_deprecation "Your Gemfile contains multiple primary sources. " \ "Using `source` more than once without a block is a security risk, and " \ diff --git a/lib/bundler/plugin/installer.rb b/lib/bundler/plugin/installer.rb index a50d0ceedd..5379c38979 100644 --- a/lib/bundler/plugin/installer.rb +++ b/lib/bundler/plugin/installer.rb @@ -13,12 +13,13 @@ module Bundler def install(names, options) version = options[:version] || [">= 0"] - - if options[:git] - install_git(names, version, options) - else - sources = options[:source] || Bundler.rubygems.sources - install_rubygems(names, version, sources) + Bundler.settings.temporary(:lockfile_uses_separate_rubygems_sources => false, :disable_multisource => false) do + if options[:git] + install_git(names, version, options) + else + sources = options[:source] || Bundler.rubygems.sources + install_rubygems(names, version, sources) + end end end diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb index c68eb51d59..136650e436 100644 --- a/lib/bundler/source_list.rb +++ b/lib/bundler/source_list.rb @@ -41,7 +41,7 @@ module Bundler def global_rubygems_source=(uri) if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? - @global_rubygems_source ||= Source::Rubygems.new("remotes" => uri) + @global_rubygems_source ||= rubygems_aggregate_class.new("remotes" => uri) end add_rubygems_remote(uri) end @@ -77,7 +77,7 @@ module Bundler def lock_sources if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? - [rubygems_sources, git_sources, path_sources, plugin_sources].map do |sources| + [[default_source], @rubygems_sources, git_sources, path_sources, plugin_sources].map do |sources| sources.sort_by(&:to_s) end.flatten(1) else @@ -86,6 +86,7 @@ module Bundler end end + # Returns true if there are changes def replace_sources!(replacement_sources) return true if replacement_sources.empty? @@ -95,13 +96,14 @@ module Bundler end end - replacement_rubygems = + replacement_rubygems = !Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? && replacement_sources.detect {|s| s.is_a?(Source::Rubygems) } @rubygems_aggregate = replacement_rubygems if replacement_rubygems - # Return true if there were changes - lock_sources.to_set != replacement_sources.to_set || - rubygems_remotes.to_set != replacement_rubygems.remotes.to_set + return true if lock_sources.to_set != replacement_sources.to_set + return true if replacement_rubygems && rubygems_remotes.to_set != replacement_rubygems.remotes.to_set + + false end def cached! diff --git a/spec/bundler/definition_spec.rb b/spec/bundler/definition_spec.rb index cb642da9f7..ca280c70a1 100644 --- a/spec/bundler/definition_spec.rb +++ b/spec/bundler/definition_spec.rb @@ -31,7 +31,7 @@ RSpec.describe Bundler::Definition do end describe "detects changes" do - it "for a path gem with changes" do + it "for a path gem with changes", :bundler => "< 2" do build_lib "foo", "1.0", :path => lib_path("foo") install_gemfile <<-G @@ -69,6 +69,44 @@ RSpec.describe Bundler::Definition do G end + it "for a path gem with changes", :bundler => "2" do + build_lib "foo", "1.0", :path => lib_path("foo") + + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "foo", :path => "#{lib_path("foo")}" + G + + build_lib "foo", "1.0", :path => lib_path("foo") do |s| + s.add_dependency "rack", "1.0" + end + + bundle :install, :env => { "DEBUG" => 1 } + + expect(out).to match(/re-resolving dependencies/) + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PATH + remote: #{lib_path("foo")} + specs: + foo (1.0) + rack (= 1.0) + + PLATFORMS + ruby + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + it "for a path gem with deps and no changes" do build_lib "foo", "1.0", :path => lib_path("foo") do |s| s.add_dependency "rack", "1.0" diff --git a/spec/bundler/plugin/installer_spec.rb b/spec/bundler/plugin/installer_spec.rb index 8ede96ffea..f8bf8450c9 100644 --- a/spec/bundler/plugin/installer_spec.rb +++ b/spec/bundler/plugin/installer_spec.rb @@ -10,6 +10,7 @@ RSpec.describe Bundler::Plugin::Installer do describe "cli install" do it "uses Gem.sources when non of the source is provided" do sources = double(:sources) + Bundler.settings # initialize it before we have to touch rubygems.ext_lock allow(Bundler).to receive_message_chain("rubygems.sources") { sources } allow(installer).to receive(:install_rubygems). diff --git a/spec/bundler/source_list_spec.rb b/spec/bundler/source_list_spec.rb index 5489b367ec..915b638a46 100644 --- a/spec/bundler/source_list_spec.rb +++ b/spec/bundler/source_list_spec.rb @@ -115,18 +115,19 @@ RSpec.describe Bundler::SourceList do end end - describe "#add_rubygems_remote" do - before do - @returned_source = source_list.add_rubygems_remote("https://rubygems.org/") - end + describe "#add_rubygems_remote", :bundler => "< 2" do + let!(:returned_source) { source_list.add_rubygems_remote("https://rubygems.org/") } it "returns the aggregate rubygems source" do - expect(@returned_source).to be_instance_of(Bundler::Source::Rubygems) + expect(returned_source).to be_instance_of(Bundler::Source::Rubygems) end it "adds the provided remote to the beginning of the aggregate source" do source_list.add_rubygems_remote("https://othersource.org") - expect(@returned_source.remotes.first).to eq(URI("https://othersource.org/")) + expect(returned_source.remotes).to eq [ + URI("https://othersource.org/"), + URI("https://rubygems.org/"), + ] end end @@ -355,7 +356,7 @@ RSpec.describe Bundler::SourceList do end describe "#lock_sources" do - it "combines the rubygems sources into a single instance, removing duplicate remotes from the end" do + before do source_list.add_git_source("uri" => "git://third-git.org/path.git") source_list.add_rubygems_source("remotes" => ["https://duplicate-rubygems.org"]) source_list.add_plugin_source("new_source", "uri" => "https://third-bar.org/foo") @@ -369,7 +370,9 @@ RSpec.describe Bundler::SourceList do source_list.add_path_source("path" => "/first/path/to/gem") source_list.add_rubygems_source("remotes" => ["https://duplicate-rubygems.org"]) source_list.add_git_source("uri" => "git://first-git.org/path.git") + end + it "combines the rubygems sources into a single instance, removing duplicate remotes from the end", :bundler => "< 2" do expect(source_list.lock_sources).to eq [ Bundler::Source::Git.new("uri" => "git://first-git.org/path.git"), Bundler::Source::Git.new("uri" => "git://second-git.org/path.git"), @@ -387,6 +390,24 @@ RSpec.describe Bundler::SourceList do ]), ] end + + it "returns all sources, without combining rubygems sources", :bundler => "2" do + expect(source_list.lock_sources).to eq [ + Bundler::Source::Rubygems.new, + Bundler::Source::Rubygems.new("remotes" => ["https://duplicate-rubygems.org"]), + Bundler::Source::Rubygems.new("remotes" => ["https://first-rubygems.org"]), + Bundler::Source::Rubygems.new("remotes" => ["https://second-rubygems.org"]), + Bundler::Source::Rubygems.new("remotes" => ["https://third-rubygems.org"]), + Bundler::Source::Git.new("uri" => "git://first-git.org/path.git"), + Bundler::Source::Git.new("uri" => "git://second-git.org/path.git"), + Bundler::Source::Git.new("uri" => "git://third-git.org/path.git"), + Bundler::Source::Path.new("path" => "/first/path/to/gem"), + Bundler::Source::Path.new("path" => "/second/path/to/gem"), + Bundler::Source::Path.new("path" => "/third/path/to/gem"), + ASourcePlugin.new("uri" => "https://second-plugin.org/random"), + ASourcePlugin.new("uri" => "https://third-bar.org/foo"), + ] + end end describe "replace_sources!" do @@ -415,7 +436,7 @@ RSpec.describe Bundler::SourceList do end describe "#cached!" do - let(:rubygems_source) { source_list.add_rubygems_remote("https://rubygems.org") } + let(:rubygems_source) { source_list.add_rubygems_source("remotes" => ["https://rubygems.org"]) } let(:git_source) { source_list.add_git_source("uri" => "git://host/path.git") } let(:path_source) { source_list.add_path_source("path" => "/path/to/gem") } @@ -428,7 +449,7 @@ RSpec.describe Bundler::SourceList do end describe "#remote!" do - let(:rubygems_source) { source_list.add_rubygems_remote("https://rubygems.org") } + let(:rubygems_source) { source_list.add_rubygems_source("remotes" => ["https://rubygems.org"]) } let(:git_source) { source_list.add_git_source("uri" => "git://host/path.git") } let(:path_source) { source_list.add_path_source("path" => "/path/to/gem") } diff --git a/spec/commands/add_spec.rb b/spec/commands/add_spec.rb index 36e696da0b..aebe8442d1 100644 --- a/spec/commands/add_spec.rb +++ b/spec/commands/add_spec.rb @@ -92,7 +92,7 @@ RSpec.describe "bundle add" do it "shows error message when gem cannot be found" do bundle "add 'werk_it'" - expect(out).to match("Could not find gem 'werk_it' in any of the gem sources listed in your Gemfile.") + expect(out).to match("Could not find gem 'werk_it' in") bundle "add 'werk_it' -s='file://#{gem_repo2}'" expect(out).to match("Could not find gem 'werk_it' in rubygems repository") diff --git a/spec/commands/exec_spec.rb b/spec/commands/exec_spec.rb index cc5989790e..c2e3b88fdd 100644 --- a/spec/commands/exec_spec.rb +++ b/spec/commands/exec_spec.rb @@ -589,7 +589,7 @@ RSpec.describe "bundle exec" do it_behaves_like "it runs" end - context "when Bundler.setup fails" do + context "when Bundler.setup fails", :bundler => "< 2" do before do gemfile <<-G gem 'rack', '2' @@ -606,6 +606,24 @@ RSpec.describe "bundle exec" do it_behaves_like "it runs" end + context "when Bundler.setup fails", :bundler => "2" do + before do + gemfile <<-G + gem 'rack', '2' + G + ENV["BUNDLER_FORCE_TTY"] = "true" + end + + let(:exit_code) { Bundler::GemNotFound.new.status_code } + let(:expected) { <<-EOS.strip } +\e[31mCould not find gem 'rack (= 2)' in locally installed gems. +The source contains 'rack' at: 0.9.1, 1.0.0\e[0m +\e[33mRun `bundle install` to install missing gems.\e[0m + EOS + + it_behaves_like "it runs" + end + context "when the executable exits non-zero via at_exit" do let(:executable) { super() + "\n\nat_exit { $! ? raise($!) : exit(1) }" } let(:exit_code) { 1 } diff --git a/spec/commands/install_spec.rb b/spec/commands/install_spec.rb index 5be6c40a44..23dcdd1806 100644 --- a/spec/commands/install_spec.rb +++ b/spec/commands/install_spec.rb @@ -280,7 +280,7 @@ RSpec.describe "bundle install with gem sources" do end end - it "finds gems in multiple sources" do + it "finds gems in multiple sources", :bundler => "< 2" do build_repo2 update_repo2 @@ -314,9 +314,9 @@ RSpec.describe "bundle install with gem sources" do it "gracefully handles error when rubygems server is unavailable" do install_gemfile <<-G, :artifice => nil source "file://#{gem_repo1}" - source "http://localhost:9384" - - gem 'foo' + source "http://localhost:9384" do + gem 'foo' + end G bundle :install, :artifice => nil diff --git a/spec/commands/lock_spec.rb b/spec/commands/lock_spec.rb index 11742dede6..83bd233d6d 100644 --- a/spec/commands/lock_spec.rb +++ b/spec/commands/lock_spec.rb @@ -86,7 +86,7 @@ RSpec.describe "bundle lock" do it "does not fetch remote specs when using the --local option" do bundle "lock --update --local" - expect(out).to include("sources listed in your Gemfile") + expect(out).to match(/sources listed in your Gemfile|installed locally/) end it "writes to a custom location using --lockfile" do diff --git a/spec/install/bundler_spec.rb b/spec/install/bundler_spec.rb index d0ce331f7d..ecddff616a 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 E expect(last_command.bundler_err).to include(nice_error) end diff --git a/spec/install/deploy_spec.rb b/spec/install/deploy_spec.rb index 032ff01b66..8ef948de77 100644 --- a/spec/install/deploy_spec.rb +++ b/spec/install/deploy_spec.rb @@ -93,15 +93,14 @@ RSpec.describe "install with --deployment or --frozen" do end it "works with sources given by a block" do - install_gemfile <<-G + install_gemfile! <<-G source "file://#{gem_repo1}" do gem "rack" end G - bundle "install --deployment" + bundle! "install --deployment" - expect(exitstatus).to eq(0) if exitstatus expect(the_bundle).to include_gems "rack 1.0" end diff --git a/spec/install/gemfile/gemspec_spec.rb b/spec/install/gemfile/gemspec_spec.rb index 4f1a69688c..e04dafb2fa 100644 --- a/spec/install/gemfile/gemspec_spec.rb +++ b/spec/install/gemfile/gemspec_spec.rb @@ -424,7 +424,7 @@ RSpec.describe "bundle install from an existing gemspec" do end end - context "on ruby" do + context "on ruby", :bundler => "< 2" do before do simulate_platform("ruby") bundle :install @@ -524,6 +524,107 @@ RSpec.describe "bundle install from an existing gemspec" do end end end + + context "on ruby", :bundler => "2" do + before do + simulate_platform("ruby") + bundle :install + end + + context "as a runtime dependency" do + it "keeps java dependencies in the lockfile" do + expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY" + expect(lockfile).to eq strip_whitespace(<<-L) + GEM + remote: file:#{gem_repo2}/ + specs: + platform_specific (1.0) + platform_specific (1.0-java) + + PATH + remote: . + specs: + foo (1.0) + platform_specific + + PLATFORMS + java + ruby + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + end + + context "as a development dependency" do + let(:platform_specific_type) { :development } + + it "keeps java dependencies in the lockfile" do + expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY" + expect(lockfile).to eq strip_whitespace(<<-L) + GEM + remote: file:#{gem_repo2}/ + specs: + platform_specific (1.0) + platform_specific (1.0-java) + + PATH + remote: . + specs: + foo (1.0) + + PLATFORMS + java + ruby + + DEPENDENCIES + foo! + platform_specific + + BUNDLED WITH + #{Bundler::VERSION} + L + end + end + + context "with an indirect platform-specific development dependency" do + let(:platform_specific_type) { :development } + let(:dependency) { "indirect_platform_specific" } + + it "keeps java dependencies in the lockfile" do + expect(the_bundle).to include_gems "foo 1.0", "indirect_platform_specific 1.0", "platform_specific 1.0 RUBY" + expect(lockfile).to eq strip_whitespace(<<-L) + GEM + remote: file:#{gem_repo2}/ + specs: + indirect_platform_specific (1.0) + platform_specific + platform_specific (1.0) + platform_specific (1.0-java) + + PATH + remote: . + specs: + foo (1.0) + + PLATFORMS + java + ruby + + DEPENDENCIES + foo! + indirect_platform_specific + + BUNDLED WITH + #{Bundler::VERSION} + L + end + end + end end end diff --git a/spec/install/gemfile/path_spec.rb b/spec/install/gemfile/path_spec.rb index e76d5c486e..5f5e82074b 100644 --- a/spec/install/gemfile/path_spec.rb +++ b/spec/install/gemfile/path_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe "bundle install with explicit source paths" do - it "fetches gems" do + it "fetches gems with a global path source", :bundler => "< 2" do build_lib "foo" install_gemfile <<-G @@ -12,6 +12,18 @@ RSpec.describe "bundle install with explicit source paths" do expect(the_bundle).to include_gems("foo 1.0") end + it "fetches gems" do + build_lib "foo" + + install_gemfile <<-G + path "#{lib_path("foo-1.0")}" do + gem 'foo' + end + G + + expect(the_bundle).to include_gems("foo 1.0") + end + it "supports pinned paths" do build_lib "foo" diff --git a/spec/install/gems/compact_index_spec.rb b/spec/install/gems/compact_index_spec.rb index ad1abe2e89..c9eae35016 100644 --- a/spec/install/gems/compact_index_spec.rb +++ b/spec/install/gems/compact_index_spec.rb @@ -539,7 +539,7 @@ The checksum of /versions does not match the checksum provided by the server! So expect(out).not_to include("#{user}:#{password}") end - it "strips http basic auth creds when warning about ambiguous sources" do + it "strips http basic auth creds when warning about ambiguous sources", :bundler => "< 2" do gemfile <<-G source "#{basic_auth_source_uri}" source "file://#{gem_repo1}" diff --git a/spec/lock/lockfile_bundler_1_spec.rb b/spec/lock/lockfile_bundler_1_spec.rb new file mode 100644 index 0000000000..209c70be78 --- /dev/null +++ b/spec/lock/lockfile_bundler_1_spec.rb @@ -0,0 +1,1382 @@ +# frozen_string_literal: true + +RSpec.describe "the lockfile format", :bundler => "< 2" do + include Bundler::GemHelpers + + it "generates a simple lockfile for a single source, gem" do + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "updates the lockfile's bundler version if current ver. is newer" do + lockfile <<-L + GIT + remote: git://github.com/nex3/haml.git + revision: 8a2271f + specs: + + GEM + remote: file://#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + omg! + rack + + BUNDLED WITH + 1.8.2 + L + + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "does not update the lockfile's bundler version if nothing changed during bundle install" do + version = "#{Bundler::VERSION.split(".").first}.0.0.0.a" + + lockfile <<-L + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack + + BUNDLED WITH + #{version} + L + + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack + + BUNDLED WITH + #{version} + G + end + + it "updates the lockfile's bundler version if not present" do + lockfile <<-L + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack + L + + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack", "> 0" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack (> 0) + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "outputs a warning if the current is older than lockfile's bundler version" do + lockfile <<-L + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack + + BUNDLED WITH + 9999999.1.0 + L + + simulate_bundler_version "9999999.0.0" do + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack" + G + end + + warning_message = "the running version of Bundler (9999999.0.0) is older " \ + "than the version that created the lockfile (9999999.1.0)" + expect(out.scan(warning_message).size).to eq(1) + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack + + BUNDLED WITH + 9999999.1.0 + G + end + + it "errors if the current is a major version older than lockfile's bundler version" do + lockfile <<-L + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack + + BUNDLED WITH + 9999999.0.0 + L + + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack" + G + + expect(exitstatus > 0) if exitstatus + expect(out).to include("You must use Bundler 9999999 or greater with this lockfile.") + end + + it "shows a friendly error when running with a new bundler 2 lockfile" do + lockfile <<-L + GEM + remote: https://rails-assets.org/ + specs: + rails-assets-bootstrap (3.3.4) + rails-assets-jquery (>= 1.9.1) + rails-assets-jquery (2.1.4) + + GEM + remote: https://rubygems.org/ + specs: + rake (10.4.2) + + PLATFORMS + ruby + + DEPENDENCIES + rails-assets-bootstrap! + rake + + BUNDLED WITH + 9999999.0.0 + L + + install_gemfile <<-G + source 'https://rubygems.org' + gem 'rake' + + source 'https://rails-assets.org' do + gem 'rails-assets-bootstrap' + end + G + + expect(exitstatus > 0) if exitstatus + expect(out).to include("You must use Bundler 9999999 or greater with this lockfile.") + end + + it "warns when updating bundler major version" do + lockfile <<-L + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack + + BUNDLED WITH + 1.10.0 + L + + simulate_bundler_version "9999999.0.0" do + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack" + G + end + + expect(out).to include("Warning: the lockfile is being updated to Bundler " \ + "9999999, after which you will be unable to return to Bundler 1.") + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack + + BUNDLED WITH + 9999999.0.0 + G + end + + it "generates a simple lockfile for a single source, gem with dependencies" do + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack-obama" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + rack-obama (1.0) + rack + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack-obama + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "generates a simple lockfile for a single source, gem with a version requirement" do + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack-obama", ">= 1.0" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + rack-obama (1.0) + rack + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack-obama (>= 1.0) + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "generates a lockfile wihout credentials for a configured source" do + bundle "config http://localgemserver.test/ user:pass" + + install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true) + source "http://localgemserver.test/" + source "http://user:pass@othergemserver.test/" + + gem "rack-obama", ">= 1.0" + G + + lockfile_should_be <<-G + GEM + remote: http://localgemserver.test/ + remote: http://user:pass@othergemserver.test/ + specs: + rack (1.0.0) + rack-obama (1.0) + rack + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack-obama (>= 1.0) + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "generates lockfiles with multiple requirements" do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "net-sftp" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + net-sftp (1.1.1) + net-ssh (>= 1.0.0, < 1.99.0) + net-ssh (1.0) + + PLATFORMS + ruby + + DEPENDENCIES + net-sftp + + BUNDLED WITH + #{Bundler::VERSION} + G + + expect(the_bundle).to include_gems "net-sftp 1.1.1", "net-ssh 1.0.0" + end + + it "generates a simple lockfile for a single pinned source, gem with a version requirement" do + git = build_git "foo" + + install_gemfile <<-G + gem "foo", :git => "#{lib_path("foo-1.0")}" + G + + lockfile_should_be <<-G + GIT + remote: #{lib_path("foo-1.0")} + revision: #{git.ref_for("master")} + specs: + foo (1.0) + + GEM + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "does not asplode when a platform specific dependency is present and the Gemfile has not been resolved on that platform" do + build_lib "omg", :path => lib_path("omg") + + gemfile <<-G + source "file://#{gem_repo1}" + + platforms :#{not_local_tag} do + gem "omg", :path => "#{lib_path("omg")}" + end + + gem "rack" + G + + lockfile <<-L + GIT + remote: git://github.com/nex3/haml.git + revision: 8a2271f + specs: + + GEM + remote: file://#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{not_local} + + DEPENDENCIES + omg! + rack + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "install" + expect(the_bundle).to include_gems "rack 1.0.0" + end + + it "serializes global git sources" do + git = build_git "foo" + + install_gemfile <<-G + git "#{lib_path("foo-1.0")}" do + gem "foo" + end + G + + lockfile_should_be <<-G + GIT + remote: #{lib_path("foo-1.0")} + revision: #{git.ref_for("master")} + specs: + foo (1.0) + + GEM + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "generates a lockfile with a ref for a single pinned source, git gem with a branch requirement" do + git = build_git "foo" + update_git "foo", :branch => "omg" + + install_gemfile <<-G + gem "foo", :git => "#{lib_path("foo-1.0")}", :branch => "omg" + G + + lockfile_should_be <<-G + GIT + remote: #{lib_path("foo-1.0")} + revision: #{git.ref_for("omg")} + branch: omg + specs: + foo (1.0) + + GEM + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "generates a lockfile with a ref for a single pinned source, git gem with a tag requirement" do + git = build_git "foo" + update_git "foo", :tag => "omg" + + install_gemfile <<-G + gem "foo", :git => "#{lib_path("foo-1.0")}", :tag => "omg" + G + + lockfile_should_be <<-G + GIT + remote: #{lib_path("foo-1.0")} + revision: #{git.ref_for("omg")} + tag: omg + specs: + foo (1.0) + + GEM + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "serializes pinned path sources to the lockfile" do + build_lib "foo" + + install_gemfile <<-G + gem "foo", :path => "#{lib_path("foo-1.0")}" + G + + lockfile_should_be <<-G + PATH + remote: #{lib_path("foo-1.0")} + specs: + foo (1.0) + + GEM + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "serializes pinned path sources to the lockfile even when packaging" do + build_lib "foo" + + install_gemfile! <<-G + gem "foo", :path => "#{lib_path("foo-1.0")}" + G + + bundle! "package --all" + bundle! "install --local" + + lockfile_should_be <<-G + PATH + remote: #{lib_path("foo-1.0")} + specs: + foo (1.0) + + GEM + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "sorts serialized sources by type" do + build_lib "foo" + bar = build_git "bar" + + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack" + gem "foo", :path => "#{lib_path("foo-1.0")}" + gem "bar", :git => "#{lib_path("bar-1.0")}" + G + + lockfile_should_be <<-G + GIT + remote: #{lib_path("bar-1.0")} + revision: #{bar.ref_for("master")} + specs: + bar (1.0) + + PATH + remote: #{lib_path("foo-1.0")} + specs: + foo (1.0) + + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + bar! + foo! + rack + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "lists gems alphabetically" do + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "thin" + gem "actionpack" + gem "rack-obama" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + actionpack (2.3.2) + activesupport (= 2.3.2) + activesupport (2.3.2) + rack (1.0.0) + rack-obama (1.0) + rack + thin (1.0) + rack + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + actionpack + rack-obama + thin + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "orders dependencies' dependencies in alphabetical order" do + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "rails" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + actionmailer (2.3.2) + activesupport (= 2.3.2) + actionpack (2.3.2) + activesupport (= 2.3.2) + activerecord (2.3.2) + activesupport (= 2.3.2) + activeresource (2.3.2) + activesupport (= 2.3.2) + activesupport (2.3.2) + rails (2.3.2) + actionmailer (= 2.3.2) + actionpack (= 2.3.2) + activerecord (= 2.3.2) + activeresource (= 2.3.2) + rake (= 10.0.2) + rake (10.0.2) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rails + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "orders dependencies by version" do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem 'double_deps' + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + double_deps (1.0) + net-ssh + net-ssh (>= 1.0.0) + net-ssh (1.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + double_deps + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "does not add the :require option to the lockfile" do + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack-obama", ">= 1.0", :require => "rack/obama" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + rack-obama (1.0) + rack + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack-obama (>= 1.0) + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "does not add the :group option to the lockfile" do + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack-obama", ">= 1.0", :group => :test + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + rack-obama (1.0) + rack + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + rack-obama (>= 1.0) + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "stores relative paths when the path is provided in a relative fashion and in Gemfile dir" do + build_lib "foo", :path => bundled_app("foo") + + install_gemfile <<-G + path "foo" + gem "foo" + G + + lockfile_should_be <<-G + PATH + remote: foo + specs: + foo (1.0) + + GEM + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + foo + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "stores relative paths when the path is provided in a relative fashion and is above Gemfile dir" do + build_lib "foo", :path => bundled_app(File.join("..", "foo")) + + install_gemfile <<-G + path "../foo" + gem "foo" + G + + lockfile_should_be <<-G + PATH + remote: ../foo + specs: + foo (1.0) + + GEM + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + foo + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "stores relative paths when the path is provided in an absolute fashion but is relative" do + build_lib "foo", :path => bundled_app("foo") + + install_gemfile <<-G + path File.expand_path("../foo", __FILE__) + gem "foo" + G + + lockfile_should_be <<-G + PATH + remote: foo + specs: + foo (1.0) + + GEM + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + foo + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "stores relative paths when the path is provided for gemspec" do + build_lib("foo", :path => tmp.join("foo")) + + install_gemfile <<-G + gemspec :path => "../foo" + G + + lockfile_should_be <<-G + PATH + remote: ../foo + specs: + foo (1.0) + + GEM + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "keeps existing platforms in the lockfile" do + lockfile <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + java + + DEPENDENCIES + rack + + BUNDLED WITH + #{Bundler::VERSION} + G + + install_gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack" + G + + platforms = ["java", generic_local_platform.to_s].sort + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + #{platforms[0]} + #{platforms[1]} + + DEPENDENCIES + rack + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "persists the spec's platform to the lockfile" do + build_gem "platform_specific", "1.0.0", :to_system => true do |s| + s.platform = Gem::Platform.new("universal-java-16") + end + + simulate_platform "universal-java-16" + + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "platform_specific" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + platform_specific (1.0-java) + + PLATFORMS + java + + DEPENDENCIES + platform_specific + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "does not add duplicate gems" do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack" + G + + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack" + gem "activesupport" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + activesupport (2.3.5) + rack (1.0.0) + + PLATFORMS + ruby + + DEPENDENCIES + activesupport + rack + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "does not add duplicate dependencies" do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack" + gem "rack" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + ruby + + DEPENDENCIES + rack + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "does not add duplicate dependencies with versions" do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack", "1.0" + gem "rack", "1.0" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + ruby + + DEPENDENCIES + rack (= 1.0) + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "does not add duplicate dependencies in different groups" do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack", "1.0", :group => :one + gem "rack", "1.0", :group => :two + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PLATFORMS + ruby + + DEPENDENCIES + rack (= 1.0) + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "raises if two different versions are used" do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack", "1.0" + gem "rack", "1.1" + G + + expect(bundled_app("Gemfile.lock")).not_to exist + expect(out).to include "rack (= 1.0) and rack (= 1.1)" + end + + it "raises if two different sources are used" do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack" + gem "rack", :git => "git://hubz.com" + G + + expect(bundled_app("Gemfile.lock")).not_to exist + expect(out).to include "rack (>= 0) should come from an unspecified source and git://hubz.com (at master)" + end + + it "works correctly with multiple version dependencies" do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack", "> 0.9", "< 1.0" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (0.9.1) + + PLATFORMS + ruby + + DEPENDENCIES + rack (> 0.9, < 1.0) + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "captures the Ruby version in the lockfile" do + install_gemfile <<-G + source "file://#{gem_repo1}" + ruby '#{RUBY_VERSION}' + gem "rack", "> 0.9", "< 1.0" + G + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (0.9.1) + + PLATFORMS + ruby + + DEPENDENCIES + rack (> 0.9, < 1.0) + + RUBY VERSION + ruby #{RUBY_VERSION}p#{RUBY_PATCHLEVEL} + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + # Some versions of the Bundler 1.1 RC series introduced corrupted + # lockfiles. There were two major problems: + # + # * multiple copies of the same GIT section appeared in the lockfile + # * when this happened, those sections got multiple copies of gems + # in those sections. + it "fixes corrupted lockfiles" do + build_git "omg", :path => lib_path("omg") + revision = revision_for(lib_path("omg")) + + gemfile <<-G + source "file://#{gem_repo1}" + gem "omg", :git => "#{lib_path("omg")}", :branch => 'master' + G + + bundle "install --path vendor" + expect(the_bundle).to include_gems "omg 1.0" + + # Create a Gemfile.lock that has duplicate GIT sections + lockfile <<-L + GIT + remote: #{lib_path("omg")} + revision: #{revision} + branch: master + specs: + omg (1.0) + + GIT + remote: #{lib_path("omg")} + revision: #{revision} + branch: master + specs: + omg (1.0) + + GEM + remote: file:#{gem_repo1}/ + specs: + + PLATFORMS + #{local} + + DEPENDENCIES + omg! + + BUNDLED WITH + #{Bundler::VERSION} + L + + FileUtils.rm_rf(bundled_app("vendor")) + bundle "install" + expect(the_bundle).to include_gems "omg 1.0" + + # Confirm that duplicate specs do not appear + expect(File.read(bundled_app("Gemfile.lock"))).to eq(strip_whitespace(<<-L)) + GIT + remote: #{lib_path("omg")} + revision: #{revision} + branch: master + specs: + omg (1.0) + + GEM + remote: file:#{gem_repo1}/ + specs: + + PLATFORMS + #{local} + + DEPENDENCIES + omg! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "raises a helpful error message when the lockfile is missing deps" do + lockfile <<-L + GEM + remote: file:#{gem_repo1}/ + specs: + rack_middleware (1.0) + + PLATFORMS + #{local} + + DEPENDENCIES + rack_middleware + L + + install_gemfile <<-G + source "file:#{gem_repo1}" + gem "rack_middleware" + G + + expect(out).to include("Downloading rack_middleware-1.0 revealed dependencies not in the API or the lockfile (#{Gem::Dependency.new("rack", "= 0.9.1")})."). + and include("Either installing with `--full-index` or running `bundle update rack_middleware` should fix the problem.") + end + + describe "a line ending" do + def set_lockfile_mtime_to_known_value + time = Time.local(2000, 1, 1, 0, 0, 0) + File.utime(time, time, bundled_app("Gemfile.lock")) + end + before(:each) do + build_repo2 + + install_gemfile <<-G + source "file://#{gem_repo2}" + gem "rack" + G + set_lockfile_mtime_to_known_value + end + + it "generates Gemfile.lock with \\n line endings" do + expect(File.read(bundled_app("Gemfile.lock"))).not_to match("\r\n") + expect(the_bundle).to include_gems "rack 1.0" + end + + context "during updates" do + it "preserves Gemfile.lock \\n line endings" do + update_repo2 + + expect { bundle "update", :all => true }.to change { File.mtime(bundled_app("Gemfile.lock")) } + expect(File.read(bundled_app("Gemfile.lock"))).not_to match("\r\n") + expect(the_bundle).to include_gems "rack 1.2" + end + + it "preserves Gemfile.lock \\n\\r line endings" do + update_repo2 + win_lock = File.read(bundled_app("Gemfile.lock")).gsub(/\n/, "\r\n") + File.open(bundled_app("Gemfile.lock"), "wb") {|f| f.puts(win_lock) } + set_lockfile_mtime_to_known_value + + expect { bundle "update", :all => true }.to change { File.mtime(bundled_app("Gemfile.lock")) } + expect(File.read(bundled_app("Gemfile.lock"))).to match("\r\n") + expect(the_bundle).to include_gems "rack 1.2" + end + end + + context "when nothing changes" do + it "preserves Gemfile.lock \\n line endings" do + expect do + ruby <<-RUBY + require 'rubygems' + require 'bundler' + Bundler.setup + RUBY + end.not_to change { File.mtime(bundled_app("Gemfile.lock")) } + end + + it "preserves Gemfile.lock \\n\\r line endings" do + win_lock = File.read(bundled_app("Gemfile.lock")).gsub(/\n/, "\r\n") + File.open(bundled_app("Gemfile.lock"), "wb") {|f| f.puts(win_lock) } + set_lockfile_mtime_to_known_value + + expect do + ruby <<-RUBY + require 'rubygems' + require 'bundler' + Bundler.setup + RUBY + end.not_to change { File.mtime(bundled_app("Gemfile.lock")) } + end + end + end + + it "refuses to install if Gemfile.lock contains conflict markers" do + lockfile <<-L + GEM + remote: file://#{gem_repo1}/ + specs: + <<<<<<< + rack (1.0.0) + ======= + rack (1.0.1) + >>>>>>> + + PLATFORMS + ruby + + DEPENDENCIES + rack + + BUNDLED WITH + #{Bundler::VERSION} + L + + install_gemfile(<<-G) + source "file://#{gem_repo1}" + gem "rack" + G + + expect(last_command.bundler_err).to match(/your Gemfile.lock contains merge conflicts/i) + expect(last_command.bundler_err).to match(/git checkout HEAD -- Gemfile.lock/i) + end +end diff --git a/spec/lock/lockfile_spec.rb b/spec/lock/lockfile_spec.rb index 149372472d..2c4f2a6679 100644 --- a/spec/lock/lockfile_spec.rb +++ b/spec/lock/lockfile_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.describe "the lockfile format" do +RSpec.describe "the lockfile format", :bundler => "2" do include Bundler::GemHelpers it "generates a simple lockfile for a single source, gem" do @@ -360,19 +360,28 @@ RSpec.describe "the lockfile format" do G end - it "generates a lockfile wihout credentials for a configured source" do + it "generates a lockfile without credentials for a configured source" do bundle "config http://localgemserver.test/ user:pass" install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true) - source "http://localgemserver.test/" - source "http://user:pass@othergemserver.test/" + source "http://localgemserver.test/" do - gem "rack-obama", ">= 1.0" + end + + source "http://user:pass@othergemserver.test/" do + gem "rack-obama", ">= 1.0" + end G lockfile_should_be <<-G + GEM + specs: + GEM remote: http://localgemserver.test/ + specs: + + GEM remote: http://user:pass@othergemserver.test/ specs: rack (1.0.0) @@ -383,7 +392,7 @@ RSpec.describe "the lockfile format" do #{generic_local_platform} DEPENDENCIES - rack-obama (>= 1.0) + rack-obama (>= 1.0)! BUNDLED WITH #{Bundler::VERSION} @@ -494,15 +503,15 @@ RSpec.describe "the lockfile format" do G lockfile_should_be <<-G + GEM + specs: + GIT remote: #{lib_path("foo-1.0")} revision: #{git.ref_for("master")} specs: foo (1.0) - GEM - specs: - PLATFORMS #{generic_local_platform} @@ -523,6 +532,9 @@ RSpec.describe "the lockfile format" do G lockfile_should_be <<-G + GEM + specs: + GIT remote: #{lib_path("foo-1.0")} revision: #{git.ref_for("omg")} @@ -530,9 +542,6 @@ RSpec.describe "the lockfile format" do specs: foo (1.0) - GEM - specs: - PLATFORMS #{generic_local_platform} @@ -553,6 +562,9 @@ RSpec.describe "the lockfile format" do G lockfile_should_be <<-G + GEM + specs: + GIT remote: #{lib_path("foo-1.0")} revision: #{git.ref_for("omg")} @@ -560,9 +572,6 @@ RSpec.describe "the lockfile format" do specs: foo (1.0) - GEM - specs: - PLATFORMS #{generic_local_platform} @@ -582,14 +591,14 @@ RSpec.describe "the lockfile format" do G lockfile_should_be <<-G + GEM + specs: + PATH remote: #{lib_path("foo-1.0")} specs: foo (1.0) - GEM - specs: - PLATFORMS #{generic_local_platform} @@ -612,14 +621,14 @@ RSpec.describe "the lockfile format" do bundle! "install --local" lockfile_should_be <<-G + GEM + specs: + PATH remote: #{lib_path("foo-1.0")} specs: foo (1.0) - GEM - specs: - PLATFORMS #{generic_local_platform} @@ -644,6 +653,11 @@ RSpec.describe "the lockfile format" do G lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + GIT remote: #{lib_path("bar-1.0")} revision: #{bar.ref_for("master")} @@ -655,11 +669,6 @@ RSpec.describe "the lockfile format" do specs: foo (1.0) - GEM - remote: file:#{gem_repo1}/ - specs: - rack (1.0.0) - PLATFORMS #{generic_local_platform} @@ -829,24 +838,25 @@ RSpec.describe "the lockfile format" do build_lib "foo", :path => bundled_app("foo") install_gemfile <<-G - path "foo" - gem "foo" + path "foo" do + gem "foo" + end G lockfile_should_be <<-G + GEM + specs: + PATH remote: foo specs: foo (1.0) - GEM - specs: - PLATFORMS #{generic_local_platform} DEPENDENCIES - foo + foo! BUNDLED WITH #{Bundler::VERSION} @@ -857,24 +867,25 @@ RSpec.describe "the lockfile format" do build_lib "foo", :path => bundled_app(File.join("..", "foo")) install_gemfile <<-G - path "../foo" - gem "foo" + path "../foo" do + gem "foo" + end G lockfile_should_be <<-G + GEM + specs: + PATH remote: ../foo specs: foo (1.0) - GEM - specs: - PLATFORMS #{generic_local_platform} DEPENDENCIES - foo + foo! BUNDLED WITH #{Bundler::VERSION} @@ -885,24 +896,25 @@ RSpec.describe "the lockfile format" do build_lib "foo", :path => bundled_app("foo") install_gemfile <<-G - path File.expand_path("../foo", __FILE__) - gem "foo" + path File.expand_path("../foo", __FILE__) do + gem "foo" + end G lockfile_should_be <<-G + GEM + specs: + PATH remote: foo specs: foo (1.0) - GEM - specs: - PLATFORMS #{generic_local_platform} DEPENDENCIES - foo + foo! BUNDLED WITH #{Bundler::VERSION} @@ -917,14 +929,14 @@ RSpec.describe "the lockfile format" do G lockfile_should_be <<-G + GEM + specs: + PATH remote: ../foo specs: foo (1.0) - GEM - specs: - PLATFORMS #{generic_local_platform} @@ -1203,6 +1215,10 @@ RSpec.describe "the lockfile format" do # Create a Gemfile.lock that has duplicate GIT sections lockfile <<-L + GEM + remote: file:#{gem_repo1}/ + specs: + GIT remote: #{lib_path("omg")} revision: #{revision} @@ -1217,10 +1233,6 @@ RSpec.describe "the lockfile format" do specs: omg (1.0) - GEM - remote: file:#{gem_repo1}/ - specs: - PLATFORMS #{local} @@ -1237,6 +1249,10 @@ RSpec.describe "the lockfile format" do # Confirm that duplicate specs do not appear expect(File.read(bundled_app("Gemfile.lock"))).to eq(strip_whitespace(<<-L)) + GEM + remote: file:#{gem_repo1}/ + specs: + GIT remote: #{lib_path("omg")} revision: #{revision} @@ -1244,10 +1260,6 @@ RSpec.describe "the lockfile format" do specs: omg (1.0) - GEM - remote: file:#{gem_repo1}/ - specs: - PLATFORMS #{local} diff --git a/spec/plugins/source/example_spec.rb b/spec/plugins/source/example_spec.rb index d898c1f95c..69e33e4077 100644 --- a/spec/plugins/source/example_spec.rb +++ b/spec/plugins/source/example_spec.rb @@ -326,7 +326,7 @@ RSpec.describe "real source plugins" do expect(the_bundle).to include_gems("ma-gitp-gem 1.0") end - it "writes to lock file" do + it "writes to lock file", :bundler => "< 2" do revision = revision_for(lib_path("ma-gitp-gem-1.0")) bundle "install" @@ -353,6 +353,33 @@ RSpec.describe "real source plugins" do G end + it "writes to lock file", :bundler => "2" do + revision = revision_for(lib_path("ma-gitp-gem-1.0")) + bundle "install" + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo2}/ + specs: + + PLUGIN SOURCE + remote: file://#{lib_path("ma-gitp-gem-1.0")} + type: gitp + revision: #{revision} + specs: + ma-gitp-gem (1.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + ma-gitp-gem! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + context "with lockfile" do before do revision = revision_for(lib_path("ma-gitp-gem-1.0")) diff --git a/spec/quality_spec.rb b/spec/quality_spec.rb index 4561ce0461..bbdaa8b30d 100644 --- a/spec/quality_spec.rb +++ b/spec/quality_spec.rb @@ -131,7 +131,7 @@ RSpec.describe "The library itself" do it "does not include any unresolved merge conflicts" do error_messages = [] - exempt = %r{lock/lockfile_spec|quality_spec|vcr_cassettes|\.ronn|lockfile_parser\.rb} + exempt = %r{lock/lockfile_(bundler_1_)?spec|quality_spec|vcr_cassettes|\.ronn|lockfile_parser\.rb} Dir.chdir(root) do `git ls-files -z`.split("\x0").each do |filename| next if filename =~ exempt diff --git a/spec/resolver/basic_spec.rb b/spec/resolver/basic_spec.rb index 8d9aef2891..a34b905806 100644 --- a/spec/resolver/basic_spec.rb +++ b/spec/resolver/basic_spec.rb @@ -124,7 +124,7 @@ Bundler could not find compatible versions for gem "a": deps << Bundler::DepProxy.new(d, "ruby") end - should_resolve_and_include %w[foo-1.0.0 bar-1.0.0], [{}, []] + should_resolve_and_include %w[foo-1.0.0 bar-1.0.0], [[]] end context "conservative" do diff --git a/spec/runtime/inline_spec.rb b/spec/runtime/inline_spec.rb index 3ebcfd8852..2893920e44 100644 --- a/spec/runtime/inline_spec.rb +++ b/spec/runtime/inline_spec.rb @@ -52,8 +52,9 @@ RSpec.describe "bundler/inline#gemfile" do it "requires the gems" do script <<-RUBY gemfile do - path "#{lib_path}" - gem "two" + path "#{lib_path}" do + gem "two" + end end RUBY @@ -62,8 +63,9 @@ RSpec.describe "bundler/inline#gemfile" do script <<-RUBY gemfile do - path "#{lib_path}" - gem "eleven" + path "#{lib_path}" do + gem "eleven" + end end puts "success" @@ -132,8 +134,9 @@ RSpec.describe "bundler/inline#gemfile" do require 'bundler' options = { :ui => Bundler::UI::Shell.new } gemfile(false, options) do - path "#{lib_path}" - gem "two" + path "#{lib_path}" do + gem "two" + end end puts "OKAY" if options.key?(:ui) RUBY diff --git a/spec/runtime/require_spec.rb b/spec/runtime/require_spec.rb index 749f2a4e33..5dcbba5d06 100644 --- a/spec/runtime/require_spec.rb +++ b/spec/runtime/require_spec.rb @@ -46,19 +46,20 @@ RSpec.describe "Bundler.require" do end gemfile <<-G - path "#{lib_path}" - gem "one", :group => :bar, :require => %w[baz qux] - gem "two" - gem "three", :group => :not - gem "four", :require => false - gem "five" - gem "six", :group => "string" - gem "seven", :group => :not - gem "eight", :require => true, :group => :require_true - env "BUNDLER_TEST" => "nine" do - gem "nine", :require => true + path "#{lib_path}" do + gem "one", :group => :bar, :require => %w[baz qux] + gem "two" + gem "three", :group => :not + gem "four", :require => false + gem "five" + gem "six", :group => "string" + gem "seven", :group => :not + gem "eight", :require => true, :group => :require_true + env "BUNDLER_TEST" => "nine" do + gem "nine", :require => true + end + gem "ten", :install_if => lambda { ENV["BUNDLER_TEST"] == "ten" } end - gem "ten", :install_if => lambda { ENV["BUNDLER_TEST"] == "ten" } G end @@ -111,8 +112,9 @@ RSpec.describe "Bundler.require" do it "raises an exception if a require is specified but the file does not exist" do gemfile <<-G - path "#{lib_path}" - gem "two", :require => 'fail' + path "#{lib_path}" do + gem "two", :require => 'fail' + end G load_error_run <<-R, "fail" @@ -128,8 +130,9 @@ RSpec.describe "Bundler.require" do end gemfile <<-G - path "#{lib_path}" - gem "faulty" + path "#{lib_path}" do + gem "faulty" + end G run "Bundler.require" @@ -143,8 +146,9 @@ RSpec.describe "Bundler.require" do end gemfile <<-G - path "#{lib_path}" - gem "loadfuuu" + path "#{lib_path}" do + gem "loadfuuu" + end G cmd = <<-RUBY @@ -169,8 +173,9 @@ RSpec.describe "Bundler.require" do it "requires gem names that are namespaced" do gemfile <<-G - path '#{lib_path}' - gem 'jquery-rails' + path '#{lib_path}' do + gem 'jquery-rails' + end G run "Bundler.require" @@ -182,8 +187,9 @@ RSpec.describe "Bundler.require" do s.write "lib/brcrypt.rb", "BCrypt = '1.0.0'" end gemfile <<-G - path "#{lib_path}" - gem "bcrypt-ruby" + path "#{lib_path}" do + gem "bcrypt-ruby" + end G cmd = <<-RUBY @@ -197,8 +203,9 @@ RSpec.describe "Bundler.require" do it "does not mangle explicitly given requires" do gemfile <<-G - path "#{lib_path}" - gem 'jquery-rails', :require => 'jquery-rails' + path "#{lib_path}" do + gem 'jquery-rails', :require => 'jquery-rails' + end G load_error_run <<-R, "jquery-rails" @@ -213,8 +220,9 @@ RSpec.describe "Bundler.require" do end gemfile <<-G - path "#{lib_path}" - gem "load-fuuu" + path "#{lib_path}" do + gem "load-fuuu" + end G cmd = <<-RUBY @@ -236,8 +244,9 @@ RSpec.describe "Bundler.require" do lib_path("load-fuuu-1.0.0/lib/load-fuuu.rb").rmtree gemfile <<-G - path "#{lib_path}" - gem "load-fuuu" + path "#{lib_path}" do + gem "load-fuuu" + end G cmd = <<-RUBY @@ -293,9 +302,10 @@ RSpec.describe "Bundler.require" do it "works when the gems are in the Gemfile in the correct order" do gemfile <<-G - path "#{lib_path}" - gem "two" - gem "one" + path "#{lib_path}" do + gem "two" + gem "one" + end G run "Bundler.require" @@ -333,9 +343,10 @@ RSpec.describe "Bundler.require" do it "fails when the gems are in the Gemfile in the wrong order" do gemfile <<-G - path "#{lib_path}" - gem "one" - gem "two" + path "#{lib_path}" do + gem "one" + gem "two" + end G run "Bundler.require" diff --git a/spec/runtime/setup_spec.rb b/spec/runtime/setup_spec.rb index 909378ab02..ef02ce0630 100644 --- a/spec/runtime/setup_spec.rb +++ b/spec/runtime/setup_spec.rb @@ -395,9 +395,10 @@ RSpec.describe "Bundler.setup" do end gemfile <<-G - path "#{lib_path("rack-1.0.0")}" source "file://#{gem_repo1}" - gem "rack" + path "#{lib_path("rack-1.0.0")}" do + gem "rack" + end G run "require 'rack'" diff --git a/spec/support/indexes.rb b/spec/support/indexes.rb index bb941e66ab..1feff7d816 100644 --- a/spec/support/indexes.rb +++ b/spec/support/indexes.rb @@ -16,12 +16,16 @@ module Spec def resolve(args = []) @platforms ||= ["ruby"] deps = [] + default_source = instance_double("Bundler::Source::Rubygems", :specs => @index) + source_requirements = { :default => default_source } @deps.each do |d| @platforms.each do |p| + source_requirements[d.name] = d.source = default_source deps << Bundler::DepProxy.new(d, p) end end - Bundler::Resolver.resolve(deps, @index, *args) + source_requirements ||= {} + Bundler::Resolver.resolve(deps, @index, source_requirements, *args) end def should_resolve_as(specs) @@ -62,7 +66,7 @@ module Spec s.level = opts.first s.strict = opts.include?(:strict) end - should_resolve_and_include specs, [{}, @base, search] + should_resolve_and_include specs, [@base, search] end def an_awesome_index diff --git a/spec/update/git_spec.rb b/spec/update/git_spec.rb index c04e3c68b0..f7e10de666 100644 --- a/spec/update/git_spec.rb +++ b/spec/update/git_spec.rb @@ -294,7 +294,7 @@ RSpec.describe "bundle update" do G end - it "the --source flag updates version of gems that were originally pulled in by the source" do + it "the --source flag updates version of gems that were originally pulled in by the source", :bundler => "< 2" do spec_lines = lib_path("bar/foo.gemspec").read.split("\n") spec_lines[5] = "s.version = '2.0'" @@ -329,5 +329,41 @@ RSpec.describe "bundle update" do #{Bundler::VERSION} G end + + it "the --source flag updates version of gems that were originally pulled in by the source", :bundler => "2" do + spec_lines = lib_path("bar/foo.gemspec").read.split("\n") + spec_lines[5] = "s.version = '2.0'" + + update_git "foo", "2.0", :path => @git.path do |s| + s.write "foo.gemspec", spec_lines.join("\n") + end + + ref = @git.ref_for "master" + + bundle "update --source bar" + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo2}/ + specs: + rack (1.0.0) + + GIT + remote: #{@git.path} + revision: #{ref} + specs: + foo (2.0) + + PLATFORMS + ruby + + DEPENDENCIES + foo! + rack + + BUNDLED WITH + #{Bundler::VERSION} + G + end end end -- cgit v1.2.1 From 0f336c7d311f2471e7191db05ddc0f9c278829a5 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Fri, 23 Jun 2017 17:32:09 -0500 Subject: Always serve the Bundler gemspec from the metadata source --- lib/bundler/definition.rb | 16 +++------------- lib/bundler/source/metadata.rb | 24 ++++++++++++++++++++++++ lib/bundler/source/rubygems.rb | 32 +++++--------------------------- 3 files changed, 32 insertions(+), 40 deletions(-) diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index bcae470569..dc8bdc7bad 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -167,8 +167,8 @@ module Bundler "to a different version of #{locked_gem} that hasn't been removed in order to install." end unless specs["bundler"].any? - bundler = rubygems_index.search(Gem::Dependency.new("bundler", VERSION)).last - specs["bundler"] = bundler if bundler + bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last + specs["bundler"] = bundler end specs @@ -286,16 +286,6 @@ module Bundler 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. - def rubygems_index - @rubygems_index ||= Index.build do |idx| - sources.rubygems_sources.each do |rubygems| - idx.add_source rubygems.specs - end - end - end - def has_rubygems_remotes? sources.rubygems_sources.any? {|s| s.remotes.any? } end @@ -935,7 +925,7 @@ module Bundler # specs will be available later when the resolver knows where to # look for that gemspec (or its dependencies) default = sources.default_source - source_requirements = { :default => default } + source_requirements = { :default => default, "bundler" => sources.metadata_source } default = nil unless Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? dependencies.each do |dep| next unless source = dep.source || default diff --git a/lib/bundler/source/metadata.rb b/lib/bundler/source/metadata.rb index 173c897998..63d16365c5 100644 --- a/lib/bundler/source/metadata.rb +++ b/lib/bundler/source/metadata.rb @@ -7,6 +7,21 @@ module Bundler @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) + + idx << Gem::Specification.new do |s| + s.name = "bundler" + s.version = VERSION + s.platform = Gem::Platform::RUBY + s.source = self + s.authors = ["bundler team"] + # can't point to the actual gemspec or else the require paths will be wrong + s.loaded_from = File.expand_path("..", __FILE__) + end + if loaded_spec = nil && Bundler.rubygems.loaded_specs("bundler") + idx << loaded_spec # this has to come after the fake gemspec, to override it + elsif local_spec = Bundler.rubygems.find_name("bundler").find {|s| s.version.to_s == VERSION } + idx << local_spec + end end end @@ -14,6 +29,15 @@ module Bundler def remote!; end + def options + {} + end + + def install(spec, opts) + Bundler.ui.info "Using #{version_message(spec)}" + nil + end + def to_s "the local ruby installation" end diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 4d87ca7249..98c8fdad3b 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -105,7 +105,7 @@ module Bundler end end - if installed?(spec) && (!force || spec.name.eql?("bundler")) + if installed?(spec) && !force Bundler.ui.info "Using #{version_message(spec)}" return nil # no post-install message end @@ -305,14 +305,9 @@ module Bundler end def installed_specs - @installed_specs ||= begin - idx = Index.new - have_bundler = false + @installed_specs ||= Index.build do |idx| Bundler.rubygems.all_specs.reverse_each do |spec| - if spec.name == "bundler" - next unless spec.version.to_s == VERSION - have_bundler = true - end + next if spec.name == "bundler" spec.source = self if Bundler.rubygems.spec_missing_extensions?(spec, false) Bundler.ui.debug "Source #{self} is ignoring #{spec} because it is missing extensions" @@ -320,23 +315,6 @@ module Bundler end idx << spec end - - # Always have bundler locally - unless have_bundler - # We're running bundler directly from the source - # so, let's create a fake gemspec for it (it's a path) - # gemspec - bundler = Gem::Specification.new do |s| - s.name = "bundler" - s.version = VERSION - s.platform = Gem::Platform::RUBY - s.source = self - s.authors = ["bundler team"] - s.loaded_from = File.expand_path("..", __FILE__) - end - idx << bundler - end - idx end end @@ -354,9 +332,9 @@ module Bundler end idx << s end - end - idx + idx + end end def api_fetchers -- cgit v1.2.1 From a415012239b05bef85e2cb1dc04606e9ced58360 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Fri, 23 Jun 2017 19:39:49 -0500 Subject: Fix plugin installation when the plugin depends upon Bundler --- lib/bundler/dsl.rb | 2 +- lib/bundler/source/metadata.rb | 6 +++++- spec/plugins/source/example_spec.rb | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb index 5435512810..b91e4034a7 100644 --- a/lib/bundler/dsl.rb +++ b/lib/bundler/dsl.rb @@ -134,7 +134,7 @@ module Bundler if options.key?("type") options["type"] = options["type"].to_s unless Plugin.source?(options["type"]) - raise "No sources available for #{options["type"]}" + raise InvalidOption, "No plugin sources available for #{options["type"]}" end unless block_given? diff --git a/lib/bundler/source/metadata.rb b/lib/bundler/source/metadata.rb index 63d16365c5..e35a52e597 100644 --- a/lib/bundler/source/metadata.rb +++ b/lib/bundler/source/metadata.rb @@ -33,7 +33,7 @@ module Bundler {} end - def install(spec, opts) + def install(spec, _opts = {}) Bundler.ui.info "Using #{version_message(spec)}" nil end @@ -50,6 +50,10 @@ module Bundler def hash self.class.hash end + + def version_message(spec) + "#{spec.name} #{spec.version}" + end end end end diff --git a/spec/plugins/source/example_spec.rb b/spec/plugins/source/example_spec.rb index 69e33e4077..28fdd6c03f 100644 --- a/spec/plugins/source/example_spec.rb +++ b/spec/plugins/source/example_spec.rb @@ -172,7 +172,7 @@ RSpec.describe "real source plugins" do end it "installs" do - bundle "install" + bundle! "install" expect(the_bundle).to include_gems("a-path-gem 1.0") end -- cgit v1.2.1 From 3497223754ed1928befd93f3be2ea998e2c5ae85 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Fri, 23 Jun 2017 23:27:15 -0500 Subject: Only limit to 25 failures on CI --- spec/spec_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index fd9ab14b77..ee7777a4bd 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -73,7 +73,7 @@ RSpec.configure do |config| # once we have a large number of failures (indicative of core pieces of # bundler being broken) so that running the full test suite doesn't take # forever due to memory constraints - config.fail_fast ||= 25 + config.fail_fast ||= 25 if ENV["CI"] if ENV["BUNDLER_SUDO_TESTS"] && Spec::Sudo.present? config.filter_run :sudo => true -- cgit v1.2.1 From 4dcd33379bdf203493f4ecbd28c04e519a8eab3d Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Fri, 23 Jun 2017 23:27:46 -0500 Subject: More bundler 2 spec fixes --- lib/bundler/definition.rb | 3 +- lib/bundler/resolver.rb | 13 ++-- lib/bundler/source/metadata.rb | 2 + spec/bundler/definition_spec.rb | 51 +++++++++++++-- spec/commands/newgem_spec.rb | 6 +- spec/install/bundler_spec.rb | 2 +- spec/install/gemfile/path_spec.rb | 5 +- spec/install/gemfile/sources_spec.rb | 8 +-- spec/install/gems/compact_index_spec.rb | 83 +++++++++++++++++++++--- spec/install/gems/dependency_api_spec.rb | 107 ++++++++++++++++++++++++++++--- spec/install/gems/flex_spec.rb | 37 ++++++++++- spec/install/post_bundle_message_spec.rb | 17 ++++- spec/install/yanked_spec.rb | 2 +- spec/lock/lockfile_spec.rb | 30 ++++++++- spec/plugins/source/example_spec.rb | 27 +++++++- 15 files changed, 349 insertions(+), 44 deletions(-) diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index dc8bdc7bad..68bc40844e 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -925,7 +925,7 @@ module Bundler # specs will be available later when the resolver knows where to # look for that gemspec (or its dependencies) default = sources.default_source - source_requirements = { :default => default, "bundler" => sources.metadata_source } + source_requirements = { :default => default } default = nil unless Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? dependencies.each do |dep| next unless source = dep.source || default @@ -934,6 +934,7 @@ module Bundler metadata_dependencies.each do |dep| source_requirements[dep.name] = sources.metadata_source end + source_requirements["bundler"] = sources.metadata_source # needs to come last to override source_requirements end diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 637c0b1313..8bdeae275f 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -415,6 +415,12 @@ module Bundler next if name == "bundler" next unless search_for(requirement).empty? + cache_message = begin + " or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist? + rescue GemfileNotFound + nil + end + if (base = @base[name]) && !base.empty? version = base.first.version message = "You have requested:\n" \ @@ -426,18 +432,13 @@ module Bundler 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 #{source}.\n") + message = String.new("Could not find gem '#{requirement}' in #{source}#{cache_message}.\n") message << if versions_with_platforms.any? "The source contains '#{name}' at: #{formatted_versions_with_platforms(versions_with_platforms)}" else "The source does not contain any versions of '#{requirement}'" end else - cache_message = begin - " or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist? - rescue GemfileNotFound - nil - end message = "Could not find gem '#{requirement}' in any of the gem sources " \ "listed in your Gemfile#{cache_message}." end diff --git a/lib/bundler/source/metadata.rb b/lib/bundler/source/metadata.rb index e35a52e597..f6d2f0729d 100644 --- a/lib/bundler/source/metadata.rb +++ b/lib/bundler/source/metadata.rb @@ -22,6 +22,8 @@ module Bundler elsif local_spec = Bundler.rubygems.find_name("bundler").find {|s| s.version.to_s == VERSION } idx << local_spec end + + idx.each {|s| s.source = self } end end diff --git a/spec/bundler/definition_spec.rb b/spec/bundler/definition_spec.rb index ca280c70a1..4bc6b23106 100644 --- a/spec/bundler/definition_spec.rb +++ b/spec/bundler/definition_spec.rb @@ -107,7 +107,7 @@ RSpec.describe Bundler::Definition do G end - it "for a path gem with deps and no changes" do + it "for a path gem with deps and no changes", :bundler => "< 2" do build_lib "foo", "1.0", :path => lib_path("foo") do |s| s.add_dependency "rack", "1.0" s.add_development_dependency "net-ssh", "1.0" @@ -144,6 +144,43 @@ RSpec.describe Bundler::Definition do G end + it "for a path gem with deps and no changes", :bundler => "2" do + build_lib "foo", "1.0", :path => lib_path("foo") do |s| + s.add_dependency "rack", "1.0" + s.add_development_dependency "net-ssh", "1.0" + end + + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "foo", :path => "#{lib_path("foo")}" + G + + bundle :check, :env => { "DEBUG" => 1 } + + expect(out).to match(/using resolution from the lockfile/) + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + PATH + remote: #{lib_path("foo")} + specs: + foo (1.0) + rack (= 1.0) + + PLATFORMS + ruby + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + it "for a rubygems gem" do install_gemfile <<-G source "file://#{gem_repo1}" @@ -197,6 +234,12 @@ RSpec.describe Bundler::Definition do end context "eager unlock" do + let(:source_list) do + Bundler::SourceList.new.tap do |source_list| + source_list.global_rubygems_source = "file://#{gem_repo4}" + end + end + before do gemfile <<-G source "file://#{gem_repo4}" @@ -240,11 +283,11 @@ RSpec.describe Bundler::Definition do definition = Bundler::Definition.new( bundled_app("Gemfile.lock"), updated_deps_in_gemfile, - Bundler::SourceList.new, + source_list, unlock_hash_for_bundle_install ) locked = definition.send(:converge_locked_specs).map(&:name) - expect(locked.include?("shared_dep")).to be_truthy + expect(locked).to include "shared_dep" end it "should not eagerly unlock shared dependency with bundle update conservative updating behavior" do @@ -254,7 +297,7 @@ RSpec.describe Bundler::Definition do definition = Bundler::Definition.new( bundled_app("Gemfile.lock"), updated_deps_in_gemfile, - Bundler::SourceList.new, + source_list, :gems => ["shared_owner_a"], :lock_shared_dependencies => true ) locked = definition.send(:converge_locked_specs).map(&:name) diff --git a/spec/commands/newgem_spec.rb b/spec/commands/newgem_spec.rb index ebca2a2ddd..d08a0c0c6b 100644 --- a/spec/commands/newgem_spec.rb +++ b/spec/commands/newgem_spec.rb @@ -214,12 +214,10 @@ RSpec.describe "bundle gem" do end Dir.chdir(bundled_app("newgem")) do - bundle "exec rake build" + bundle! "exec rake build" end - expect(exitstatus).to be_zero if exitstatus - expect(out).not_to include("ERROR") - expect(err).not_to include("ERROR") + expect(last_command.stdboth).not_to include("ERROR") end context "gem naming with relative paths" do diff --git a/spec/install/bundler_spec.rb b/spec/install/bundler_spec.rb index ecddff616a..b59096e1ea 100644 --- a/spec/install/bundler_spec.rb +++ b/spec/install/bundler_spec.rb @@ -131,7 +131,7 @@ RSpec.describe "bundle install" do gem "rails", "3.0" G - simulate_bundler_version "10.0.0" + simulate_bundler_version "99999999.99.1" bundle "check" expect(out).to include("The Gemfile's dependencies are satisfied") diff --git a/spec/install/gemfile/path_spec.rb b/spec/install/gemfile/path_spec.rb index 5f5e82074b..283c66dbfa 100644 --- a/spec/install/gemfile/path_spec.rb +++ b/spec/install/gemfile/path_spec.rb @@ -281,8 +281,9 @@ RSpec.describe "bundle install with explicit source paths" do end install_gemfile <<-G - path "#{lib_path("foo-1.0")}" - gem 'foo' + path "#{lib_path("foo-1.0")}" do + gem 'foo' + end G expect(the_bundle).to include_gems "foo 1.0" diff --git a/spec/install/gemfile/sources_spec.rb b/spec/install/gemfile/sources_spec.rb index 285082438f..7641a14254 100644 --- a/spec/install/gemfile/sources_spec.rb +++ b/spec/install/gemfile/sources_spec.rb @@ -28,7 +28,7 @@ RSpec.describe "bundle install with gems on multiple sources" do bundle "config major_deprecations true" end - it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first" do + it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first", :bundler => "< 2" do bundle :install expect(out).to have_major_deprecation a_string_including("Your Gemfile contains multiple primary sources.") @@ -58,7 +58,7 @@ RSpec.describe "bundle install with gems on multiple sources" do bundle "config major_deprecations true" end - it "warns about ambiguous gems, but installs anyway" do + it "warns about ambiguous gems, but installs anyway", :bundler => "< 2" do bundle :install expect(out).to have_major_deprecation a_string_including("Your Gemfile contains multiple primary sources.") @@ -249,7 +249,7 @@ RSpec.describe "bundle install with gems on multiple sources" do G end - it "installs from the other source and warns about ambiguous gems" do + it "installs from the other source and warns about ambiguous gems", :bundler => "< 2" do bundle "config major_deprecations true" bundle :install expect(out).to have_major_deprecation a_string_including("Your Gemfile contains multiple primary sources.") @@ -277,7 +277,7 @@ RSpec.describe "bundle install with gems on multiple sources" do G end - it "installs the dependency from the pinned source without warning" do + it "installs the dependency from the pinned source without warning", :bundler => "< 2" do bundle :install expect(out).not_to include("Warning: the gem 'rack' was found in multiple sources.") diff --git a/spec/install/gems/compact_index_spec.rb b/spec/install/gems/compact_index_spec.rb index c9eae35016..fb5d97ce57 100644 --- a/spec/install/gems/compact_index_spec.rb +++ b/spec/install/gems/compact_index_spec.rb @@ -254,7 +254,7 @@ The checksum of /versions does not match the checksum provided by the server! So end end - it "fetches again when more dependencies are found in subsequent sources" do + it "fetches again when more dependencies are found in subsequent sources", :bundler => "< 2" do build_repo2 do build_gem "back_deps" do |s| s.add_dependency "foo" @@ -269,7 +269,26 @@ The checksum of /versions does not match the checksum provided by the server! So G bundle! :install, :artifice => "compact_index_extra" - expect(the_bundle).to include_gems "back_deps 1.0" + expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0" + end + + it "fetches again when more dependencies are found in subsequent sources with source blocks" do + build_repo2 do + build_gem "back_deps" do |s| + s.add_dependency "foo" + end + FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + end + + gemfile <<-G + source "#{source_uri}" + source "#{source_uri}/extra" do + gem "back_deps" + end + G + + bundle! :install, :artifice => "compact_index_extra" + expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0" end it "fetches gem versions even when those gems are already installed" do @@ -295,7 +314,7 @@ The checksum of /versions does not match the checksum provided by the server! So expect(the_bundle).to include_gems "rack 1.2" end - it "considers all possible versions of dependencies from all api gem sources" do + it "considers all possible versions of dependencies from all api gem sources", :bundler => "< 2" do # In this scenario, the gem "somegem" only exists in repo4. It depends on specific version of activesupport that # exists only in repo1. There happens also be a version of activesupport in repo4, but not the one that version 1.0.0 # of somegem wants. This test makes sure that bundler actually finds version 1.2.3 of active support in the other @@ -319,6 +338,31 @@ The checksum of /versions does not match the checksum provided by the server! So expect(the_bundle).to include_gems "activesupport 1.2.3" end + it "considers all possible versions of dependencies from all api gem sources when using blocks", :bundler => "< 2" do + # In this scenario, the gem "somegem" only exists in repo4. It depends on specific version of activesupport that + # exists only in repo1. There happens also be a version of activesupport in repo4, but not the one that version 1.0.0 + # of somegem wants. This test makes sure that bundler actually finds version 1.2.3 of active support in the other + # repo and installs it. + build_repo4 do + build_gem "activesupport", "1.2.0" + build_gem "somegem", "1.0.0" do |s| + s.add_dependency "activesupport", "1.2.3" # This version exists only in repo1 + end + end + + gemfile <<-G + source "#{source_uri}" + source "#{source_uri}/extra" do + gem 'somegem', '1.0.0' + end + G + + bundle! :install, :artifice => "compact_index_extra_api" + + expect(the_bundle).to include_gems "somegem 1.0.0" + expect(the_bundle).to include_gems "activesupport 1.2.3" + end + it "prints API output properly with back deps" do build_repo2 do build_gem "back_deps" do |s| @@ -329,8 +373,9 @@ The checksum of /versions does not match the checksum provided by the server! So gemfile <<-G source "#{source_uri}" - source "#{source_uri}/extra" - gem "back_deps" + source "#{source_uri}/extra" do + gem "back_deps" + end G bundle! :install, :artifice => "compact_index_extra" @@ -355,8 +400,9 @@ The checksum of /versions does not match the checksum provided by the server! So gemfile <<-G source "#{source_uri}" - source "#{source_uri}/extra" - gem "back_deps" + source "#{source_uri}/extra" do + gem "back_deps" + end G bundle! :install, :artifice => "compact_index_extra_missing" @@ -398,7 +444,7 @@ The checksum of /versions does not match the checksum provided by the server! So expect(the_bundle).to include_gems "foo 1.0" end - it "fetches again when more dependencies are found in subsequent sources using --deployment" do + it "fetches again when more dependencies are found in subsequent sources using --deployment", :bundler => "< 2" do build_repo2 do build_gem "back_deps" do |s| s.add_dependency "foo" @@ -418,6 +464,27 @@ The checksum of /versions does not match the checksum provided by the server! So expect(the_bundle).to include_gems "back_deps 1.0" end + it "fetches again when more dependencies are found in subsequent sources using --deployment with blocks" do + build_repo2 do + build_gem "back_deps" do |s| + s.add_dependency "foo" + end + FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + end + + gemfile <<-G + source "#{source_uri}" + source "#{source_uri}/extra" do + gem "back_deps" + end + G + + bundle! :install, :artifice => "compact_index_extra" + + bundle "install --deployment", :artifice => "compact_index_extra" + expect(the_bundle).to include_gems "back_deps 1.0" + end + it "does not refetch if the only unmet dependency is bundler" do gemfile <<-G source "#{source_uri}" diff --git a/spec/install/gems/dependency_api_spec.rb b/spec/install/gems/dependency_api_spec.rb index 60202d1658..14440652d6 100644 --- a/spec/install/gems/dependency_api_spec.rb +++ b/spec/install/gems/dependency_api_spec.rb @@ -244,7 +244,7 @@ RSpec.describe "gemcutter's dependency API" do end end - it "fetches again when more dependencies are found in subsequent sources" do + it "fetches again when more dependencies are found in subsequent sources", :bundler => "< 2" do build_repo2 do build_gem "back_deps" do |s| s.add_dependency "foo" @@ -259,7 +259,26 @@ RSpec.describe "gemcutter's dependency API" do G bundle :install, :artifice => "endpoint_extra" - expect(the_bundle).to include_gems "back_deps 1.0" + expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0" + end + + it "fetches again when more dependencies are found in subsequent sources using blocks" do + build_repo2 do + build_gem "back_deps" do |s| + s.add_dependency "foo" + end + FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + end + + gemfile <<-G + source "#{source_uri}" + source "#{source_uri}/extra" do + gem "back_deps" + end + G + + bundle :install, :artifice => "endpoint_extra" + expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0" end it "fetches gem versions even when those gems are already installed" do @@ -284,7 +303,7 @@ RSpec.describe "gemcutter's dependency API" do expect(the_bundle).to include_gems "rack 1.2" end - it "considers all possible versions of dependencies from all api gem sources" do + it "considers all possible versions of dependencies from all api gem sources", :bundler => "< 2" do # In this scenario, the gem "somegem" only exists in repo4. It depends on specific version of activesupport that # exists only in repo1. There happens also be a version of activesupport in repo4, but not the one that version 1.0.0 # of somegem wants. This test makes sure that bundler actually finds version 1.2.3 of active support in the other @@ -308,6 +327,31 @@ RSpec.describe "gemcutter's dependency API" do expect(the_bundle).to include_gems "activesupport 1.2.3" end + it "considers all possible versions of dependencies from all api gem sources using blocks" do + # In this scenario, the gem "somegem" only exists in repo4. It depends on specific version of activesupport that + # exists only in repo1. There happens also be a version of activesupport in repo4, but not the one that version 1.0.0 + # of somegem wants. This test makes sure that bundler actually finds version 1.2.3 of active support in the other + # repo and installs it. + build_repo4 do + build_gem "activesupport", "1.2.0" + build_gem "somegem", "1.0.0" do |s| + s.add_dependency "activesupport", "1.2.3" # This version exists only in repo1 + end + end + + gemfile <<-G + source "#{source_uri}" + source "#{source_uri}/extra" do + gem 'somegem', '1.0.0' + end + G + + bundle :install, :artifice => "endpoint_extra_api" + + expect(the_bundle).to include_gems "somegem 1.0.0" + expect(the_bundle).to include_gems "activesupport 1.2.3" + end + it "prints API output properly with back deps" do build_repo2 do build_gem "back_deps" do |s| @@ -318,8 +362,9 @@ RSpec.describe "gemcutter's dependency API" do gemfile <<-G source "#{source_uri}" - source "#{source_uri}/extra" - gem "back_deps" + source "#{source_uri}/extra" do + gem "back_deps" + end G bundle :install, :artifice => "endpoint_extra" @@ -328,7 +373,7 @@ RSpec.describe "gemcutter's dependency API" do expect(out).to include("Fetching source index from http://localgemserver.test/extra") end - it "does not fetch every spec if the index of gems is large when doing back deps" do + it "does not fetch every spec if the index of gems is large when doing back deps", :bundler => "< 2" do build_repo2 do build_gem "back_deps" do |s| s.add_dependency "foo" @@ -352,6 +397,31 @@ RSpec.describe "gemcutter's dependency API" do expect(the_bundle).to include_gems "back_deps 1.0" end + it "does not fetch every spec if the index of gems is large when doing back deps using blocks" do + build_repo2 do + build_gem "back_deps" do |s| + s.add_dependency "foo" + end + build_gem "missing" + # need to hit the limit + 1.upto(Bundler::Source::Rubygems::API_REQUEST_LIMIT) do |i| + build_gem "gem#{i}" + end + + FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + end + + gemfile <<-G + source "#{source_uri}" + source "#{source_uri}/extra" do + gem "back_deps" + end + G + + bundle :install, :artifice => "endpoint_extra_missing" + expect(the_bundle).to include_gems "back_deps 1.0" + end + it "uses the endpoint if all sources support it" do gemfile <<-G source "#{source_uri}" @@ -363,7 +433,7 @@ RSpec.describe "gemcutter's dependency API" do expect(the_bundle).to include_gems "foo 1.0" end - it "fetches again when more dependencies are found in subsequent sources using --deployment" do + it "fetches again when more dependencies are found in subsequent sources using --deployment", :bundler => "< 2" do build_repo2 do build_gem "back_deps" do |s| s.add_dependency "foo" @@ -383,6 +453,27 @@ RSpec.describe "gemcutter's dependency API" do expect(the_bundle).to include_gems "back_deps 1.0" end + it "fetches again when more dependencies are found in subsequent sources using --deployment with blocks" do + build_repo2 do + build_gem "back_deps" do |s| + s.add_dependency "foo" + end + FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + end + + gemfile <<-G + source "#{source_uri}" + source "#{source_uri}/extra" do + gem "back_deps" + end + G + + bundle :install, :artifice => "endpoint_extra" + + bundle "install --deployment", :artifice => "endpoint_extra" + expect(the_bundle).to include_gems "back_deps 1.0" + end + it "does not refetch if the only unmet dependency is bundler" do gemfile <<-G source "#{source_uri}" @@ -504,7 +595,7 @@ RSpec.describe "gemcutter's dependency API" do expect(out).not_to include("#{user}:#{password}") end - it "strips http basic auth creds when warning about ambiguous sources" do + it "strips http basic auth creds when warning about ambiguous sources", :bundler => "< 2" do gemfile <<-G source "#{basic_auth_source_uri}" source "file://#{gem_repo1}" diff --git a/spec/install/gems/flex_spec.rb b/spec/install/gems/flex_spec.rb index 30e1019cfa..d0f7c0af79 100644 --- a/spec/install/gems/flex_spec.rb +++ b/spec/install/gems/flex_spec.rb @@ -244,7 +244,7 @@ RSpec.describe "bundle flex_install" do end describe "when adding a new source" do - it "updates the lockfile" do + it "updates the lockfile", :bundler => "< 2" do build_repo2 install_gemfile! <<-G source "file://#{gem_repo1}" @@ -273,6 +273,41 @@ RSpec.describe "bundle flex_install" do #{Bundler::VERSION} L end + + it "updates the lockfile", :bundler => "2" do + build_repo2 + install_gemfile! <<-G + source "file://#{gem_repo1}" + gem "rack" + G + + install_gemfile! <<-G + source "file://#{gem_repo1}" + source "file://#{gem_repo2}" do + end + gem "rack" + G + + lockfile_should_be <<-L + GEM + remote: file:#{gem_repo1}/ + specs: + rack (1.0.0) + + GEM + remote: file:#{gem_repo2}/ + specs: + + PLATFORMS + ruby + + DEPENDENCIES + rack + + BUNDLED WITH + #{Bundler::VERSION} + L + end end # This was written to test github issue #636 diff --git a/spec/install/post_bundle_message_spec.rb b/spec/install/post_bundle_message_spec.rb index 77311a527f..bc700b5c4b 100644 --- a/spec/install/post_bundle_message_spec.rb +++ b/spec/install/post_bundle_message_spec.rb @@ -97,7 +97,7 @@ RSpec.describe "post bundle message" do end describe "with misspelled or non-existent gem name" do - it "should report a helpful error message" do + it "should report a helpful error message", :bundler => "< 2" do install_gemfile <<-G source "file://#{gem_repo1}" gem "rack" @@ -106,6 +106,18 @@ RSpec.describe "post bundle message" do expect(out).to include("Could not find gem 'not-a-gem' in any of the gem sources listed in your Gemfile.") end + it "should report a helpful error message", :bundler => "2" do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack" + gem "not-a-gem", :group => :development + G + expect(out).to include <<-EOS.strip +Could not find gem 'not-a-gem' in rubygems repository file:#{gem_repo1}/ or installed locally. +The source does not contain any versions of 'not-a-gem' + EOS + end + it "should report a helpful error message with reference to cache if available" do install_gemfile <<-G source "file://#{gem_repo1}" @@ -118,7 +130,8 @@ RSpec.describe "post bundle message" do gem "rack" gem "not-a-gem", :group => :development G - expect(out).to include("Could not find gem 'not-a-gem' in any of the gem sources listed in your Gemfile or in gems cached in vendor/cache.") + expect(out).to include("Could not find gem 'not-a-gem' in"). + and include("or in gems cached in vendor/cache.") end end end diff --git a/spec/install/yanked_spec.rb b/spec/install/yanked_spec.rb index 65783e294b..7c4b98bfdf 100644 --- a/spec/install/yanked_spec.rb +++ b/spec/install/yanked_spec.rb @@ -37,7 +37,7 @@ RSpec.context "when installing a bundle that includes yanked gems" do G expect(out).not_to include("Your bundle is locked to foo (10.0.0)") - expect(out).to include("Could not find gem 'foo (= 10.0.0)' in any of the gem sources") + expect(out).to include("Could not find gem 'foo (= 10.0.0)' in") end end diff --git a/spec/lock/lockfile_spec.rb b/spec/lock/lockfile_spec.rb index 2c4f2a6679..a502e4a282 100644 --- a/spec/lock/lockfile_spec.rb +++ b/spec/lock/lockfile_spec.rb @@ -426,7 +426,7 @@ RSpec.describe "the lockfile format", :bundler => "2" do expect(the_bundle).to include_gems "net-sftp 1.1.1", "net-ssh 1.0.0" end - it "generates a simple lockfile for a single pinned source, gem with a version requirement" do + it "generates a simple lockfile for a single pinned source, gem with a version requirement", :bundler => "< 2" do git = build_git "foo" install_gemfile <<-G @@ -454,6 +454,34 @@ RSpec.describe "the lockfile format", :bundler => "2" do G end + it "generates a simple lockfile for a single pinned source, gem with a version requirement" do + git = build_git "foo" + + install_gemfile <<-G + gem "foo", :git => "#{lib_path("foo-1.0")}" + G + + lockfile_should_be <<-G + GEM + specs: + + GIT + remote: #{lib_path("foo-1.0")} + revision: #{git.ref_for("master")} + specs: + foo (1.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + it "does not asplode when a platform specific dependency is present and the Gemfile has not been resolved on that platform" do build_lib "omg", :path => lib_path("omg") diff --git a/spec/plugins/source/example_spec.rb b/spec/plugins/source/example_spec.rb index 28fdd6c03f..748f083456 100644 --- a/spec/plugins/source/example_spec.rb +++ b/spec/plugins/source/example_spec.rb @@ -63,7 +63,7 @@ RSpec.describe "real source plugins" do expect(the_bundle).to include_gems("a-path-gem 1.0") end - it "writes to lock file" do + it "writes to lock file", :bundler => "< 2" do bundle "install" lockfile_should_be <<-G @@ -88,6 +88,31 @@ RSpec.describe "real source plugins" do G end + it "writes to lock file", :bundler => "2" do + bundle "install" + + lockfile_should_be <<-G + GEM + remote: file:#{gem_repo2}/ + specs: + + PLUGIN SOURCE + remote: #{lib_path("a-path-gem-1.0")} + type: mpath + specs: + a-path-gem (1.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + a-path-gem! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + it "provides correct #full_gem_path" do bundle "install" run <<-RUBY -- cgit v1.2.1