diff options
Diffstat (limited to 'spec/bundler/install/gems')
-rw-r--r-- | spec/bundler/install/gems/compact_index_spec.rb | 412 | ||||
-rw-r--r-- | spec/bundler/install/gems/dependency_api_spec.rb | 170 | ||||
-rw-r--r-- | spec/bundler/install/gems/flex_spec.rb | 90 | ||||
-rw-r--r-- | spec/bundler/install/gems/fund_spec.rb | 43 | ||||
-rw-r--r-- | spec/bundler/install/gems/native_extensions_spec.rb | 6 | ||||
-rw-r--r-- | spec/bundler/install/gems/resolving_spec.rb | 410 | ||||
-rw-r--r-- | spec/bundler/install/gems/standalone_spec.rb | 171 | ||||
-rw-r--r-- | spec/bundler/install/gems/sudo_spec.rb | 205 |
8 files changed, 955 insertions, 552 deletions
diff --git a/spec/bundler/install/gems/compact_index_spec.rb b/spec/bundler/install/gems/compact_index_spec.rb index 66f755c18f..50add8743b 100644 --- a/spec/bundler/install/gems/compact_index_spec.rb +++ b/spec/bundler/install/gems/compact_index_spec.rb @@ -10,7 +10,7 @@ RSpec.describe "compact index api" do gem "rack" G - bundle :install, :artifice => "compact_index" + bundle :install, artifice: "compact_index" expect(out).to include("Fetching gem metadata from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -21,7 +21,7 @@ RSpec.describe "compact index api" do gem " sinatra" G - bundle :install, :artifice => "compact_index", :raise_on_error => false + bundle :install, artifice: "compact_index", raise_on_error: false expect(err).to include("' sinatra' is not a valid gem name because it contains whitespace.") end @@ -31,7 +31,7 @@ RSpec.describe "compact index api" do gem "rails" G - bundle :install, :artifice => "compact_index" + bundle :install, artifice: "compact_index" expect(out).to include("Fetching gem metadata from #{source_uri}") expect(the_bundle).to include_gems( "rails 2.3.2", @@ -44,14 +44,14 @@ RSpec.describe "compact index api" do end it "should handle case sensitivity conflicts" do - build_repo4 do + build_repo4(build_compact_index: false) do build_gem "rack", "1.0" do |s| s.add_runtime_dependency("Rack", "0.1") end build_gem "Rack", "0.1" end - install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } source "#{source_uri}" gem "rack", "1.0" gem "Rack", "0.1" @@ -69,7 +69,7 @@ RSpec.describe "compact index api" do gem "net-sftp" G - bundle :install, :artifice => "compact_index" + bundle :install, artifice: "compact_index" expect(the_bundle).to include_gems "net-sftp 1.1.1" end @@ -78,11 +78,11 @@ RSpec.describe "compact index api" do source "#{source_uri}" gem "rack" G - bundle :install, :artifice => "compact_index" + bundle :install, artifice: "compact_index" bundle "config set --local deployment true" bundle "config set --local path vendor/bundle" - bundle :install, :artifice => "compact_index" + bundle :install, artifice: "compact_index" expect(out).to include("Fetching gem metadata from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -100,7 +100,7 @@ RSpec.describe "compact index api" do end G - bundle :install, :artifice => "compact_index" + bundle :install, artifice: "compact_index" expect(the_bundle).to include_gems("rails 2.3.2") end @@ -116,10 +116,10 @@ RSpec.describe "compact index api" do gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}" G - bundle :install, :artifice => "compact_index" + bundle :install, artifice: "compact_index" bundle "config set --local deployment true" - bundle :install, :artifice => "compact_index" + bundle :install, artifice: "compact_index" expect(the_bundle).to include_gems("rails 2.3.2") end @@ -131,9 +131,9 @@ RSpec.describe "compact index api" do gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}" G - bundle "install", :artifice => "compact_index" + bundle "install", artifice: "compact_index" bundle "config set --local deployment true" - bundle :install, :artifice => "compact_index" + bundle :install, artifice: "compact_index" expect(the_bundle).to include_gems("foo 1.0") end @@ -144,7 +144,7 @@ RSpec.describe "compact index api" do gem "rack" G - bundle :install, :verbose => true, :artifice => "compact_index_forbidden" + bundle :install, verbose: true, artifice: "compact_index_forbidden" expect(out).to include("Fetching gem metadata from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -155,14 +155,34 @@ RSpec.describe "compact index api" do gem "rack" G - bundle :install, :verbose => true, :artifice => "compact_index_checksum_mismatch" + bundle :install, verbose: true, artifice: "compact_index_checksum_mismatch" expect(out).to include("Fetching gem metadata from #{source_uri}") - expect(out).to include <<-'WARN' -The checksum of /versions does not match the checksum provided by the server! Something is wrong (local checksum is "\"d41d8cd98f00b204e9800998ecf8427e\"", was expecting "\"123\""). - WARN + expect(out).to include("The checksum of /versions does not match the checksum provided by the server!") + expect(out).to include('Calculated checksums {"sha-256"=>"8KfZiM/fszVkqhP/m5s9lvE6M9xKu4I1bU4Izddp5Ms="} did not match expected {"sha-256"=>"ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0="}') expect(the_bundle).to include_gems "rack 1.0.0" end + it "shows proper path when permission errors happen", :permissions do + gemfile <<-G + source "#{source_uri}" + gem "rack" + G + + versions = Pathname.new(Bundler.rubygems.user_home).join( + ".bundle", "cache", "compact_index", + "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions" + ) + versions.dirname.mkpath + versions.write("created_at") + FileUtils.chmod("-r", versions) + + bundle :install, artifice: "compact_index", raise_on_error: false + + expect(err).to include( + "There was an error while trying to read from `#{versions}`. It is likely that you need to grant read permissions for that path." + ) + end + it "falls back when the user's home directory does not exist or is not writable" do ENV["HOME"] = tmp("missing_home").to_s @@ -171,7 +191,7 @@ The checksum of /versions does not match the checksum provided by the server! So gem "rack" G - bundle :install, :artifice => "compact_index" + bundle :install, artifice: "compact_index" expect(out).to include("Fetching gem metadata from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -182,11 +202,11 @@ The checksum of /versions does not match the checksum provided by the server! So gem "rack" G - bundle :install, :artifice => "compact_index_host_redirect" + bundle :install, artifice: "compact_index_host_redirect" expect(the_bundle).to include_gems "rack 1.0.0" end - it "handles host redirects without Net::HTTP::Persistent" do + it "handles host redirects without Gem::Net::HTTP::Persistent" do gemfile <<-G source "#{source_uri}" gem "rack" @@ -205,7 +225,7 @@ The checksum of /versions does not match the checksum provided by the server! So H end - bundle :install, :artifice => "compact_index_host_redirect", :requires => [lib_path("disable_net_http_persistent.rb")] + bundle :install, artifice: "compact_index_host_redirect", requires: [lib_path("disable_net_http_persistent.rb")] expect(out).to_not match(/Too many redirects/) expect(the_bundle).to include_gems "rack 1.0.0" end @@ -216,7 +236,7 @@ The checksum of /versions does not match the checksum provided by the server! So gem "rack" G - bundle :install, :artifice => "compact_index_redirects", :raise_on_error => false + bundle :install, artifice: "compact_index_redirects", raise_on_error: false expect(err).to match(/Too many redirects/) end @@ -227,7 +247,7 @@ The checksum of /versions does not match the checksum provided by the server! So gem "rack" G - bundle "install --full-index", :artifice => "compact_index" + bundle "install --full-index", artifice: "compact_index" expect(out).to include("Fetching source index from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -238,7 +258,7 @@ The checksum of /versions does not match the checksum provided by the server! So gem "rack" G - bundle "update --full-index", :artifice => "compact_index", :all => true + bundle "update --full-index", artifice: "compact_index", all: true expect(out).to include("Fetching source index from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -258,7 +278,7 @@ The checksum of /versions does not match the checksum provided by the server! So s.extensions << "Rakefile" s.write "Rakefile", <<-RUBY task :default do - path = File.expand_path("../lib", __FILE__) + path = File.expand_path("lib", __dir__) FileUtils.mkdir_p(path) File.open("\#{path}/net_build_extensions.rb", "w") do |f| f.puts "NET_BUILD_EXTENSIONS = 'YES'" @@ -268,14 +288,14 @@ The checksum of /versions does not match the checksum provided by the server! So end end - system_gems %w[rack-1.0.0 thin-1.0 net_a-1.0], :gem_repo => gem_repo2 + system_gems %w[rack-1.0.0 thin-1.0 net_a-1.0], gem_repo: gem_repo2 bundle "config set --local path.system true" - ENV["BUNDLER_SPEC_ALL_REQUESTS"] = strip_whitespace(<<-EOS).strip + ENV["BUNDLER_SPEC_ALL_REQUESTS"] = <<~EOS.strip #{source_uri}/versions #{source_uri}/info/rack EOS - install_gemfile <<-G, :artifice => "compact_index", :verbose => true, :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } + install_gemfile <<-G, artifice: "compact_index", verbose: true, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } source "#{source_uri}" gem "rack" G @@ -283,7 +303,7 @@ The checksum of /versions does not match the checksum provided by the server! So expect(last_command.stdboth).not_to include "Double checking" end - it "fetches again when more dependencies are found in subsequent sources", :bundler => "< 3" do + it "fetches again when more dependencies are found in subsequent sources", bundler: "< 3" do build_repo2 do build_gem "back_deps" do |s| s.add_dependency "foo" @@ -297,7 +317,7 @@ The checksum of /versions does not match the checksum provided by the server! So gem "back_deps" G - bundle :install, :artifice => "compact_index_extra" + bundle :install, artifice: "compact_index_extra" expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0" end @@ -309,7 +329,7 @@ The checksum of /versions does not match the checksum provided by the server! So FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] end - install_gemfile <<-G, :artifice => "compact_index_extra", :verbose => true + install_gemfile <<-G, artifice: "compact_index_extra", verbose: true source "#{source_uri}" source "#{source_uri}/extra" do gem "back_deps" @@ -324,7 +344,7 @@ The checksum of /versions does not match the checksum provided by the server! So source "#{source_uri}" gem "rack", "1.0.0" G - bundle :install, :artifice => "compact_index_extra_api" + bundle :install, artifice: "compact_index_extra_api" expect(the_bundle).to include_gems "rack 1.0.0" build_repo4 do @@ -338,11 +358,11 @@ The checksum of /versions does not match the checksum provided by the server! So source "#{source_uri}/extra" gem "rack", "1.2" G - bundle :install, :artifice => "compact_index_extra_api" + bundle :install, artifice: "compact_index_extra_api" expect(the_bundle).to include_gems "rack 1.2" end - it "considers all possible versions of dependencies from all api gem sources", :bundler => "< 3" do + it "considers all possible versions of dependencies from all api gem sources", bundler: "< 3" 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 @@ -360,7 +380,7 @@ The checksum of /versions does not match the checksum provided by the server! So gem 'somegem', '1.0.0' G - bundle :install, :artifice => "compact_index_extra_api" + 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" @@ -381,13 +401,13 @@ The checksum of /versions does not match the checksum provided by the server! So end G - bundle :install, :artifice => "compact_index_extra" + bundle :install, artifice: "compact_index_extra" expect(out).to include("Fetching gem metadata from http://localgemserver.test/") 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 when doing back deps" do build_repo2 do build_gem "back_deps" do |s| s.add_dependency "foo" @@ -397,9 +417,7 @@ The checksum of /versions does not match the checksum provided by the server! So FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] end - api_request_limit = low_api_request_limit_for(gem_repo2) - - install_gemfile <<-G, :artifice => "compact_index_extra_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation) + install_gemfile <<-G, artifice: "compact_index_extra_missing" source "#{source_uri}" source "#{source_uri}/extra" do gem "back_deps" @@ -409,7 +427,7 @@ 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 + it "does not fetch every spec when doing back deps & everything is the compact index" do build_repo4 do build_gem "back_deps" do |s| s.add_dependency "foo" @@ -419,9 +437,7 @@ The checksum of /versions does not match the checksum provided by the server! So FileUtils.rm_rf Dir[gem_repo4("gems/foo-*.gem")] end - api_request_limit = low_api_request_limit_for(gem_repo4) - - install_gemfile <<-G, :artifice => "compact_index_extra_api_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation) + install_gemfile <<-G, artifice: "compact_index_extra_api_missing" source "#{source_uri}" source "#{source_uri}/extra" do gem "back_deps" @@ -438,11 +454,11 @@ The checksum of /versions does not match the checksum provided by the server! So gem 'foo' G - bundle :install, :artifice => "compact_index_api_missing" + bundle :install, artifice: "compact_index_api_missing" expect(the_bundle).to include_gems "foo 1.0" end - it "fetches again when more dependencies are found in subsequent sources using deployment mode", :bundler => "< 3" do + it "fetches again when more dependencies are found in subsequent sources using deployment mode", bundler: "< 3" do build_repo2 do build_gem "back_deps" do |s| s.add_dependency "foo" @@ -456,9 +472,9 @@ The checksum of /versions does not match the checksum provided by the server! So gem "back_deps" G - bundle :install, :artifice => "compact_index_extra" + bundle :install, artifice: "compact_index_extra" bundle "config --set local deployment true" - bundle :install, :artifice => "compact_index_extra" + bundle :install, artifice: "compact_index_extra" expect(the_bundle).to include_gems "back_deps 1.0" end @@ -477,9 +493,9 @@ The checksum of /versions does not match the checksum provided by the server! So end G - bundle :install, :artifice => "compact_index_extra" + bundle :install, artifice: "compact_index_extra" bundle "config set --local deployment true" - bundle :install, :artifice => "compact_index_extra" + bundle :install, artifice: "compact_index_extra" expect(the_bundle).to include_gems "back_deps 1.0" end @@ -496,52 +512,40 @@ The checksum of /versions does not match the checksum provided by the server! So gem "bundler_dep" G - bundle :install, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } + bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } expect(out).to include("Fetching gem metadata from #{source_uri}") end - it "should install when EndpointSpecification has a bin dir owned by root", :sudo => true do - sudo "mkdir -p #{system_gem_path("bin")}" - sudo "chown -R root #{system_gem_path("bin")}" - - gemfile <<-G - source "#{source_uri}" - gem "rails" - G - bundle :install, :artifice => "compact_index" - expect(the_bundle).to include_gems "rails 2.3.2" - end - - it "installs the binstubs", :bundler => "< 3" do + it "installs the binstubs", bundler: "< 3" do gemfile <<-G source "#{source_uri}" gem "rack" G - bundle "install --binstubs", :artifice => "compact_index" + bundle "install --binstubs", artifice: "compact_index" gembin "rackup" expect(out).to eq("1.0.0") end - it "installs the bins when using --path and uses autoclean", :bundler => "< 3" do + it "installs the bins when using --path and uses autoclean", bundler: "< 3" do gemfile <<-G source "#{source_uri}" gem "rack" G - bundle "install --path vendor/bundle", :artifice => "compact_index" + bundle "install --path vendor/bundle", artifice: "compact_index" expect(vendored_gems("bin/rackup")).to exist end - it "installs the bins when using --path and uses bundle clean", :bundler => "< 3" do + it "installs the bins when using --path and uses bundle clean", bundler: "< 3" do gemfile <<-G source "#{source_uri}" gem "rack" G - bundle "install --path vendor/bundle --no-clean", :artifice => "compact_index" + bundle "install --path vendor/bundle --no-clean", artifice: "compact_index" expect(vendored_gems("bin/rackup")).to exist end @@ -552,7 +556,7 @@ The checksum of /versions does not match the checksum provided by the server! So gem 'rack-obama' G - bundle :install, :artifice => "compact_index" + bundle :install, artifice: "compact_index" expect(out).to include("Post-install message from rack:") end @@ -562,7 +566,7 @@ The checksum of /versions does not match the checksum provided by the server! So gem 'rack_middleware' G - bundle :install, :artifice => "compact_index" + bundle :install, artifice: "compact_index" expect(out).to include("Post-install message from rack:") expect(out).to include("Rack's post install message") end @@ -571,7 +575,7 @@ The checksum of /versions does not match the checksum provided by the server! So let(:user) { "user" } let(:password) { "pass" } let(:basic_auth_source_uri) do - uri = Bundler::URI.parse(source_uri) + uri = Gem::URI.parse(source_uri) uri.user = user uri.password = password @@ -584,7 +588,7 @@ The checksum of /versions does not match the checksum provided by the server! So gem "rack" G - bundle :install, :artifice => "compact_index_basic_authentication" + bundle :install, artifice: "compact_index_basic_authentication" expect(out).not_to include("#{user}:#{password}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -595,19 +599,19 @@ The checksum of /versions does not match the checksum provided by the server! So gem "rack" G - bundle :install, :verbose => true, :artifice => "compact_index_basic_authentication" + bundle :install, verbose: true, artifice: "compact_index_basic_authentication" expect(out).not_to include("#{user}:#{password}") expect(the_bundle).to include_gems "rack 1.0.0" end - it "strips http basic auth creds when warning about ambiguous sources", :bundler => "< 3" do + it "strips http basic auth creds when warning about ambiguous sources", bundler: "< 3" do gemfile <<-G source "#{basic_auth_source_uri}" source "#{file_uri_for(gem_repo1)}" gem "rack" G - bundle :install, :artifice => "compact_index_basic_authentication" + bundle :install, artifice: "compact_index_basic_authentication" expect(err).to include("Warning: the gem 'rack' was found in multiple sources.") expect(err).not_to include("#{user}:#{password}") expect(the_bundle).to include_gems "rack 1.0.0" @@ -619,7 +623,7 @@ The checksum of /versions does not match the checksum provided by the server! So gem "rack" G - bundle :install, :artifice => "compact_index_creds_diff_host" + bundle :install, artifice: "compact_index_creds_diff_host" expect(the_bundle).to include_gems "rack 1.0.0" end @@ -634,7 +638,7 @@ The checksum of /versions does not match the checksum provided by the server! So it "reads authentication details by host name from bundle config" do bundle "config set #{source_hostname} #{user}:#{password}" - bundle :install, :artifice => "compact_index_strict_basic_authentication" + bundle :install, artifice: "compact_index_strict_basic_authentication" expect(out).to include("Fetching gem metadata from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" @@ -644,7 +648,7 @@ The checksum of /versions does not match the checksum provided by the server! So # The trailing slash is necessary here; Fetcher canonicalizes the URI. bundle "config set #{source_uri}/ #{user}:#{password}" - bundle :install, :artifice => "compact_index_strict_basic_authentication" + bundle :install, artifice: "compact_index_strict_basic_authentication" expect(out).to include("Fetching gem metadata from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" @@ -652,7 +656,7 @@ The checksum of /versions does not match the checksum provided by the server! So it "should use the API" do bundle "config set #{source_hostname} #{user}:#{password}" - bundle :install, :artifice => "compact_index_strict_basic_authentication" + bundle :install, artifice: "compact_index_strict_basic_authentication" expect(out).to include("Fetching gem metadata from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -665,20 +669,29 @@ The checksum of /versions does not match the checksum provided by the server! So bundle "config set #{source_hostname} otheruser:wrong" - bundle :install, :artifice => "compact_index_strict_basic_authentication" + bundle :install, artifice: "compact_index_strict_basic_authentication" expect(the_bundle).to include_gems "rack 1.0.0" end it "shows instructions if auth is not provided for the source" do - bundle :install, :artifice => "compact_index_strict_basic_authentication", :raise_on_error => false + bundle :install, artifice: "compact_index_strict_basic_authentication", raise_on_error: false expect(err).to include("bundle config set --global #{source_hostname} username:password") end it "fails if authentication has already been provided, but failed" do bundle "config set #{source_hostname} #{user}:wrong" - bundle :install, :artifice => "compact_index_strict_basic_authentication", :raise_on_error => false + bundle :install, artifice: "compact_index_strict_basic_authentication", raise_on_error: false + expect(err).to include("Bad username or password") + end + + it "does not fallback to old dependency API if bad authentication is provided" do + bundle "config set #{source_hostname} #{user}:wrong" + + bundle :install, artifice: "compact_index_strict_basic_authentication", raise_on_error: false, verbose: true expect(err).to include("Bad username or password") + expect(out).to include("HTTP 401 Unauthorized http://user@localgemserver.test/versions") + expect(out).not_to include("HTTP 401 Unauthorized http://user@localgemserver.test/api/v1/dependencies") end end @@ -691,7 +704,7 @@ The checksum of /versions does not match the checksum provided by the server! So gem "rack" G - bundle :install, :artifice => "compact_index_basic_authentication" + bundle :install, artifice: "compact_index_basic_authentication" expect(the_bundle).to include_gems "rack 1.0.0" end end @@ -716,7 +729,7 @@ The checksum of /versions does not match the checksum provided by the server! So gem "rack" G - bundle :install, :env => { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, :raise_on_error => false + bundle :install, env: { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, raise_on_error: false expect(err).to include("OpenSSL") end end @@ -726,7 +739,7 @@ The checksum of /versions does not match the checksum provided by the server! So # Install a monkeypatch that reproduces the effects of openssl raising # a certificate validation error when RubyGems tries to connect. gemfile <<-G - class Net::HTTP + class Gem::Net::HTTP def start raise OpenSSL::SSL::SSLError, "certificate verify failed" end @@ -736,7 +749,7 @@ The checksum of /versions does not match the checksum provided by the server! So gem "rack" G - bundle :install, :raise_on_error => false + bundle :install, raise_on_error: false expect(err).to match(/could not verify the SSL certificate/i) end end @@ -744,7 +757,7 @@ The checksum of /versions does not match the checksum provided by the server! So context ".gemrc with sources is present" do it "uses other sources declared in the Gemfile" do File.open(home(".gemrc"), "w") do |file| - file.puts({ :sources => ["https://rubygems.org"] }.to_yaml) + file.puts({ sources: ["https://rubygems.org"] }.to_yaml) end begin @@ -753,23 +766,30 @@ The checksum of /versions does not match the checksum provided by the server! So gem 'rack' G - bundle :install, :artifice => "compact_index_forbidden" + bundle :install, artifice: "compact_index_forbidden" ensure home(".gemrc").rmtree end end end - it "performs partial update with a non-empty range" do - skip "HTTP_RANGE not set" if Gem.win_platform? + it "performs update with etag not-modified" do + versions_etag = Pathname.new(Bundler.rubygems.user_home).join( + ".bundle", "cache", "compact_index", + "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions.etag" + ) + expect(versions_etag.file?).to eq(false) gemfile <<-G source "#{source_uri}" gem 'rack', '0.9.1' G - # Initial install creates the cached versions file - bundle :install, :artifice => "compact_index" + # Initial install creates the cached versions file and etag file + bundle :install, artifice: "compact_index" + + expect(versions_etag.file?).to eq(true) + previous_content = versions_etag.binread # Update the Gemfile so we can check subsequent install was successful gemfile <<-G @@ -777,8 +797,59 @@ The checksum of /versions does not match the checksum provided by the server! So gem 'rack', '1.0.0' G - # Second install should make only a partial request to /versions - bundle :install, :artifice => "compact_index_partial_update" + # Second install should match etag + bundle :install, artifice: "compact_index_etag_match" + + expect(versions_etag.binread).to eq(previous_content) + expect(the_bundle).to include_gems "rack 1.0.0" + end + + it "performs full update when range is ignored" do + gemfile <<-G + source "#{source_uri}" + gem 'rack', '0.9.1' + G + + # Initial install creates the cached versions file and etag file + bundle :install, artifice: "compact_index" + + gemfile <<-G + source "#{source_uri}" + gem 'rack', '1.0.0' + G + + versions = Pathname.new(Bundler.rubygems.user_home).join( + ".bundle", "cache", "compact_index", + "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions" + ) + # Modify the cached file. The ranged request will be based on this but, + # in this test, the range is ignored so this gets overwritten, allowing install. + versions.write "ruining this file" + + bundle :install, artifice: "compact_index_range_ignored" + + expect(the_bundle).to include_gems "rack 1.0.0" + end + + it "performs partial update with a non-empty range" do + build_repo4 do + build_gem "rack", "0.9.1" + end + + # Initial install creates the cached versions file + install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + source "#{source_uri}" + gem 'rack', '0.9.1' + G + + update_repo4 do + build_gem "rack", "1.0.0" + end + + install_gemfile <<-G, artifice: "compact_index_partial_update", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + source "#{source_uri}" + gem 'rack', '1.0.0' + G expect(the_bundle).to include_gems "rack 1.0.0" end @@ -789,24 +860,26 @@ The checksum of /versions does not match the checksum provided by the server! So gem 'rack' G - # Create an empty file to trigger a partial download - versions = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index", - "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions") - FileUtils.mkdir_p(File.dirname(versions)) - FileUtils.touch(versions) + # Create a partial cache versions file + versions = Pathname.new(Bundler.rubygems.user_home).join( + ".bundle", "cache", "compact_index", + "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions" + ) + versions.dirname.mkpath + versions.write("created_at") - bundle :install, :artifice => "compact_index_concurrent_download" + bundle :install, artifice: "compact_index_concurrent_download" - expect(File.read(versions)).to start_with("created_at") + expect(versions.read).to start_with("created_at") expect(the_bundle).to include_gems "rack 1.0.0" end - it "performs full update if server endpoints serve partial content responses but don't have incremental content and provide no Etag" do + it "performs a partial update that fails digest check, then a full update" do build_repo4 do build_gem "rack", "0.9.1" end - install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } source "#{source_uri}" gem 'rack', '0.9.1' G @@ -815,7 +888,29 @@ The checksum of /versions does not match the checksum provided by the server! So build_gem "rack", "1.0.0" end - install_gemfile <<-G, :artifice => "compact_index_partial_update_no_etag_not_incremental", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + install_gemfile <<-G, artifice: "compact_index_partial_update_bad_digest", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + source "#{source_uri}" + gem 'rack', '1.0.0' + G + + expect(the_bundle).to include_gems "rack 1.0.0" + end + + it "performs full update if server endpoints serve partial content responses but don't have incremental content and provide no digest" do + build_repo4 do + build_gem "rack", "0.9.1" + end + + install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + source "#{source_uri}" + gem 'rack', '0.9.1' + G + + update_repo4 do + build_gem "rack", "1.0.0" + end + + install_gemfile <<-G, artifice: "compact_index_partial_update_no_digest_not_incremental", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } source "#{source_uri}" gem 'rack', '1.0.0' G @@ -829,15 +924,19 @@ The checksum of /versions does not match the checksum provided by the server! So gem 'rack', '0.9.1' G - rake_info_path = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index", - "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "info", "rack") + bundle :install, artifice: "compact_index" - bundle :install, :artifice => "compact_index" + # We must remove the etag so that we don't ignore the range and get a 304 Not Modified. + rake_info_etag_path = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index", + "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "info-etags", "rack-11690b09f16021ff06a6857d784a1870") + File.unlink(rake_info_etag_path) if File.exist?(rake_info_etag_path) + rake_info_path = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index", + "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "info", "rack") expected_rack_info_content = File.read(rake_info_path) - # Modify the cache files. We expect them to be reset to the normal ones when we re-run :install - File.open(rake_info_path, "w") {|f| f << (expected_rack_info_content + "this is different") } + # Modify the cache files to make the range not satisfiable + File.open(rake_info_path, "a") {|f| f << "0.9.2 |checksum:c55b525b421fd833a93171ad3d7f04528ca8e87d99ac273f8933038942a5888c" } # Update the Gemfile so the next install does its normal things gemfile <<-G @@ -847,7 +946,7 @@ The checksum of /versions does not match the checksum provided by the server! So # The cache files now being longer means the requested range is going to be not satisfiable # Bundler must end up requesting the whole file to fix things up. - bundle :install, :artifice => "compact_index_range_not_satisfiable" + bundle :install, artifice: "compact_index_range_not_satisfiable" resulting_rack_info_content = File.read(rake_info_path) @@ -855,7 +954,7 @@ The checksum of /versions does not match the checksum provided by the server! So end it "fails gracefully when the source URI has an invalid scheme" do - install_gemfile <<-G, :raise_on_error => false + install_gemfile <<-G, raise_on_error: false source "htps://rubygems.org" gem "rack" G @@ -866,38 +965,76 @@ The checksum of /versions does not match the checksum provided by the server! So end describe "checksum validation" do + before do + lockfile <<-L + GEM + remote: #{source_uri} + specs: + rack (1.0.0) + + PLATFORMS + ruby + + DEPENDENCIES + #{checksums_section} + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "handles checksums from the server in base64" do + api_checksum = checksum_digest(gem_repo1, "rack", "1.0.0") + rack_checksum = [[api_checksum].pack("H*")].pack("m0") + install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_RACK_CHECKSUM" => rack_checksum } + source "#{source_uri}" + gem "rack" + G + + expect(out).to include("Fetching gem metadata from #{source_uri}") + expect(the_bundle).to include_gems("rack 1.0.0") + end + it "raises when the checksum does not match" do - install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum", :raise_on_error => false + install_gemfile <<-G, artifice: "compact_index_wrong_gem_checksum", raise_on_error: false source "#{source_uri}" gem "rack" G - expect(exitstatus).to eq(19) - expect(err). - to include("Bundler cannot continue installing rack (1.0.0)."). - and include("The checksum for the downloaded `rack-1.0.0.gem` does not match the checksum given by the server."). - and include("This means the contents of the downloaded gem is different from what was uploaded to the server, and could be a potential security issue."). - and include("To resolve this issue:"). - and include("1. delete the downloaded gem located at: `#{default_bundle_path}/gems/rack-1.0.0/rack-1.0.0.gem`"). - and include("2. run `bundle install`"). - and include("If you wish to continue installing the downloaded gem, and are certain it does not pose a security issue despite the mismatching checksum, do the following:"). - and include("1. run `bundle config set --local disable_checksum_validation true` to turn off checksum verification"). - and include("2. run `bundle install`"). - and match(/\(More info: The expected SHA256 checksum was "#{"ab" * 22}", but the checksum for the downloaded gem was ".+?"\.\)/) + gem_path = if Bundler.feature_flag.global_gem_cache? + default_cache_path.dirname.join("cache", "gems", "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "rack-1.0.0.gem") + else + default_cache_path.dirname.join("rack-1.0.0.gem") + end + + expect(exitstatus).to eq(37) + expect(err).to eq <<~E.strip + Bundler found mismatched checksums. This is a potential security risk. + rack (1.0.0) sha256=2222222222222222222222222222222222222222222222222222222222222222 + from the API at http://localgemserver.test/ + #{checksum_to_lock(gem_repo1, "rack", "1.0.0")} + from the gem at #{gem_path} + + If you trust the API at http://localgemserver.test/, to resolve this issue you can: + 1. remove the gem at #{gem_path} + 2. run `bundle install` + + To ignore checksum security warnings, disable checksum validation with + `bundle config set --local disable_checksum_validation true` + E end it "raises when the checksum is the wrong length" do - install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum", :env => { "BUNDLER_SPEC_RACK_CHECKSUM" => "checksum!", "DEBUG" => "1" }, :verbose => true, :raise_on_error => false + install_gemfile <<-G, artifice: "compact_index_wrong_gem_checksum", env: { "BUNDLER_SPEC_RACK_CHECKSUM" => "checksum!", "DEBUG" => "1" }, verbose: true, raise_on_error: false source "#{source_uri}" gem "rack" G - expect(exitstatus).to eq(5) - expect(err).to include("The given checksum for rack-1.0.0 (\"checksum!\") is not a valid SHA256 hexdigest nor base64digest") + expect(exitstatus).to eq(14) + expect(err).to include('Invalid checksum for rack-0.9.1: "checksum!" is not a valid SHA256 hex or base64 digest') end it "does not raise when disable_checksum_validation is set" do bundle "config set disable_checksum_validation true" - install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum" + install_gemfile <<-G, artifice: "compact_index_wrong_gem_checksum" source "#{source_uri}" gem "rack" G @@ -905,7 +1042,7 @@ The checksum of /versions does not match the checksum provided by the server! So end it "works when cache dir is world-writable" do - install_gemfile <<-G, :artifice => "compact_index" + install_gemfile <<-G, artifice: "compact_index" File.umask(0000) source "#{source_uri}" gem "rack" @@ -913,11 +1050,11 @@ The checksum of /versions does not match the checksum provided by the server! So end it "doesn't explode when the API dependencies are wrong" do - install_gemfile <<-G, :artifice => "compact_index_wrong_dependencies", :env => { "DEBUG" => "true" }, :raise_on_error => false + install_gemfile <<-G, artifice: "compact_index_wrong_dependencies", env: { "DEBUG" => "true" }, raise_on_error: false source "#{source_uri}" gem "rails" G - deps = [Gem::Dependency.new("rake", "= 13.0.1"), + deps = [Gem::Dependency.new("rake", "= #{rake_version}"), Gem::Dependency.new("actionpack", "= 2.3.2"), Gem::Dependency.new("activerecord", "= 2.3.2"), Gem::Dependency.new("actionmailer", "= 2.3.2"), @@ -925,12 +1062,12 @@ The checksum of /versions does not match the checksum provided by the server! So expect(out).to include("rails-2.3.2 from rubygems remote at #{source_uri}/ has either corrupted API or lockfile dependencies") expect(err).to include(<<-E.strip) Bundler::APIResponseMismatchError: Downloading rails-2.3.2 revealed dependencies not in the API or the lockfile (#{deps.map(&:to_s).join(", ")}). -Either installing with `--full-index` or running `bundle update rails` should fix the problem. +Running `bundle update rails` should fix the problem. E end it "does not duplicate specs in the lockfile when updating and a dependency is not installed" do - install_gemfile <<-G, :artifice => "compact_index" + install_gemfile <<-G, artifice: "compact_index" source "#{file_uri_for(gem_repo1)}" source "#{source_uri}" do gem "rails" @@ -938,7 +1075,8 @@ Either installing with `--full-index` or running `bundle update rails` should fi end G gem_command "uninstall activemerchant" - bundle "update rails", :artifice => "compact_index" - expect(lockfile.scan(/activemerchant \(/).size).to eq(1) + bundle "update rails", artifice: "compact_index" + count = lockfile.match?("CHECKSUMS") ? 2 : 1 # Once in the specs, and once in CHECKSUMS + expect(lockfile.scan(/activemerchant \(/).size).to eq(count) end end diff --git a/spec/bundler/install/gems/dependency_api_spec.rb b/spec/bundler/install/gems/dependency_api_spec.rb index 79317a7fad..35468b3a1c 100644 --- a/spec/bundler/install/gems/dependency_api_spec.rb +++ b/spec/bundler/install/gems/dependency_api_spec.rb @@ -10,7 +10,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle :install, :artifice => "endpoint" + bundle :install, artifice: "endpoint" expect(out).to include("Fetching gem metadata from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -21,7 +21,7 @@ RSpec.describe "gemcutter's dependency API" do gem " sinatra" G - bundle :install, :artifice => "endpoint", :raise_on_error => false + bundle :install, artifice: "endpoint", raise_on_error: false expect(err).to include("' sinatra' is not a valid gem name because it contains whitespace.") end @@ -31,7 +31,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rails" G - bundle :install, :artifice => "endpoint" + bundle :install, artifice: "endpoint" expect(out).to include("Fetching gem metadata from #{source_uri}/...") expect(the_bundle).to include_gems( "rails 2.3.2", @@ -49,7 +49,7 @@ RSpec.describe "gemcutter's dependency API" do gem "net-sftp" G - bundle :install, :artifice => "endpoint" + bundle :install, artifice: "endpoint" expect(the_bundle).to include_gems "net-sftp 1.1.1" end @@ -58,11 +58,11 @@ RSpec.describe "gemcutter's dependency API" do source "#{source_uri}" gem "rack" G - bundle :install, :artifice => "endpoint" + bundle :install, artifice: "endpoint" bundle "config set --local deployment true" bundle "config set --local path vendor/bundle" - bundle :install, :artifice => "endpoint" + bundle :install, artifice: "endpoint" expect(out).to include("Fetching gem metadata from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -80,7 +80,7 @@ RSpec.describe "gemcutter's dependency API" do end G - bundle :install, :artifice => "endpoint" + bundle :install, artifice: "endpoint" expect(the_bundle).to include_gems("rails 2.3.2") end @@ -96,10 +96,10 @@ RSpec.describe "gemcutter's dependency API" do gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}" G - bundle :install, :artifice => "endpoint" + bundle :install, artifice: "endpoint" bundle "config set --local deployment true" - bundle :install, :artifice => "endpoint" + bundle :install, artifice: "endpoint" expect(the_bundle).to include_gems("rails 2.3.2") end @@ -111,15 +111,15 @@ RSpec.describe "gemcutter's dependency API" do gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}" G - bundle "install", :artifice => "endpoint" + bundle "install", artifice: "endpoint" bundle "config set --local deployment true" - bundle :install, :artifice => "endpoint" + bundle :install, artifice: "endpoint" expect(the_bundle).to include_gems("foo 1.0") end it "falls back when the API errors out" do - simulate_platform mswin + simulate_platform x86_mswin32 build_repo2 do # The rcov gem is platform mswin32, but has no arch @@ -134,7 +134,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rcov" G - bundle :install, :artifice => "windows", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } + bundle :install, artifice: "windows", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } expect(out).to include("Fetching source index from #{source_uri}") expect(the_bundle).to include_gems "rcov 1.0.0" end @@ -150,7 +150,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" gem "rails" G - bundle :install, :artifice => "endpoint_fallback" + bundle :install, artifice: "endpoint_fallback" expect(out).to include("Fetching source index from #{source_uri}") expect(the_bundle).to include_gems( @@ -171,7 +171,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle :install, :verbose => true, :artifice => "endpoint_marshal_fail" + bundle :install, verbose: true, artifice: "endpoint_marshal_fail" expect(out).to include("could not fetch from the dependency API, trying the full index") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -182,7 +182,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle :install, :verbose => true, :artifice => "endpoint_api_forbidden" + bundle :install, verbose: true, artifice: "endpoint_api_forbidden" expect(out).to include("Fetching source index from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -193,11 +193,11 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle :install, :artifice => "endpoint_host_redirect" + bundle :install, artifice: "endpoint_host_redirect" expect(the_bundle).to include_gems "rack 1.0.0" end - it "handles host redirects without Net::HTTP::Persistent" do + it "handles host redirects without Gem::Net::HTTP::Persistent" do gemfile <<-G source "#{source_uri}" gem "rack" @@ -216,7 +216,7 @@ RSpec.describe "gemcutter's dependency API" do H end - bundle :install, :artifice => "endpoint_host_redirect", :requires => [lib_path("disable_net_http_persistent.rb")] + bundle :install, artifice: "endpoint_host_redirect", requires: [lib_path("disable_net_http_persistent.rb")] expect(out).to_not match(/Too many redirects/) expect(the_bundle).to include_gems "rack 1.0.0" end @@ -227,7 +227,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle :install, :artifice => "endpoint_redirect", :raise_on_error => false + bundle :install, artifice: "endpoint_redirect", raise_on_error: false expect(err).to match(/Too many redirects/) end @@ -238,7 +238,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle "install --full-index", :artifice => "endpoint" + bundle "install --full-index", artifice: "endpoint" expect(out).to include("Fetching source index from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -249,13 +249,13 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle "update --full-index", :artifice => "endpoint", :all => true + bundle "update --full-index", artifice: "endpoint", all: true expect(out).to include("Fetching source index from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" end end - it "fetches again when more dependencies are found in subsequent sources", :bundler => "< 3" do + it "fetches again when more dependencies are found in subsequent sources", bundler: "< 3" do build_repo2 do build_gem "back_deps" do |s| s.add_dependency "foo" @@ -269,7 +269,7 @@ RSpec.describe "gemcutter's dependency API" do gem "back_deps" G - bundle :install, :artifice => "endpoint_extra" + bundle :install, artifice: "endpoint_extra" expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0" end @@ -288,7 +288,7 @@ RSpec.describe "gemcutter's dependency API" do end G - bundle :install, :artifice => "endpoint_extra" + bundle :install, artifice: "endpoint_extra" expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0" end @@ -297,7 +297,7 @@ RSpec.describe "gemcutter's dependency API" do source "#{source_uri}" gem "rack", "1.0.0" G - bundle :install, :artifice => "endpoint_extra_api" + bundle :install, artifice: "endpoint_extra_api" build_repo4 do build_gem "rack", "1.2" do |s| @@ -310,11 +310,11 @@ RSpec.describe "gemcutter's dependency API" do source "#{source_uri}/extra" gem "rack", "1.2" G - bundle :install, :artifice => "endpoint_extra_api" + bundle :install, artifice: "endpoint_extra_api" expect(the_bundle).to include_gems "rack 1.2" end - it "considers all possible versions of dependencies from all api gem sources", :bundler => "< 3" do + it "considers all possible versions of dependencies from all api gem sources", bundler: "< 3" 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 @@ -332,7 +332,7 @@ RSpec.describe "gemcutter's dependency API" do gem 'somegem', '1.0.0' G - bundle :install, :artifice => "endpoint_extra_api" + 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" @@ -353,13 +353,13 @@ RSpec.describe "gemcutter's dependency API" do end G - bundle :install, :artifice => "endpoint_extra" + bundle :install, artifice: "endpoint_extra" expect(out).to include("Fetching gem metadata from http://localgemserver.test/.") 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", :bundler => "< 3" do + it "does not fetch every spec when doing back deps", bundler: "< 3" do build_repo2 do build_gem "back_deps" do |s| s.add_dependency "foo" @@ -369,9 +369,7 @@ RSpec.describe "gemcutter's dependency API" do FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] end - api_request_limit = low_api_request_limit_for(gem_repo2) - - install_gemfile <<-G, :artifice => "endpoint_extra_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation) + install_gemfile <<-G, artifice: "endpoint_extra_missing" source "#{source_uri}" source "#{source_uri}/extra" gem "back_deps" @@ -380,7 +378,7 @@ 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 + it "does not fetch every spec when doing back deps using blocks" do build_repo2 do build_gem "back_deps" do |s| s.add_dependency "foo" @@ -390,9 +388,7 @@ RSpec.describe "gemcutter's dependency API" do FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] end - api_request_limit = low_api_request_limit_for(gem_repo2) - - install_gemfile <<-G, :artifice => "endpoint_extra_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation) + install_gemfile <<-G, artifice: "endpoint_extra_missing" source "#{source_uri}" source "#{source_uri}/extra" do gem "back_deps" @@ -402,7 +398,7 @@ 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 mode", :bundler => "< 3" do + it "fetches again when more dependencies are found in subsequent sources using deployment mode", bundler: "< 3" do build_repo2 do build_gem "back_deps" do |s| s.add_dependency "foo" @@ -416,9 +412,9 @@ RSpec.describe "gemcutter's dependency API" do gem "back_deps" G - bundle :install, :artifice => "endpoint_extra" + bundle :install, artifice: "endpoint_extra" bundle "config set --local deployment true" - bundle :install, :artifice => "endpoint_extra" + bundle :install, artifice: "endpoint_extra" expect(the_bundle).to include_gems "back_deps 1.0" end @@ -437,12 +433,28 @@ RSpec.describe "gemcutter's dependency API" do end G - bundle :install, :artifice => "endpoint_extra" + bundle :install, artifice: "endpoint_extra" bundle "config set --local deployment true" - bundle "install", :artifice => "endpoint_extra" + bundle "install", artifice: "endpoint_extra" expect(the_bundle).to include_gems "back_deps 1.0" end + it "does not fetch all marshaled specs" do + build_repo2 do + build_gem "foo", "1.0" + build_gem "foo", "2.0" + end + + install_gemfile <<-G, artifice: "endpoint", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, verbose: true + source "#{source_uri}" + + gem "foo" + G + + expect(out).to include("foo-2.0.gemspec.rz") + expect(out).not_to include("foo-1.0.gemspec.rz") + end + it "does not refetch if the only unmet dependency is bundler" do build_repo2 do build_gem "bundler_dep" do |s| @@ -456,52 +468,40 @@ RSpec.describe "gemcutter's dependency API" do gem "bundler_dep" G - bundle :install, :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } + bundle :install, artifice: "endpoint", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } expect(out).to include("Fetching gem metadata from #{source_uri}") end - it "should install when EndpointSpecification has a bin dir owned by root", :sudo => true do - sudo "mkdir -p #{system_gem_path("bin")}" - sudo "chown -R root #{system_gem_path("bin")}" - - gemfile <<-G - source "#{source_uri}" - gem "rails" - G - bundle :install, :artifice => "endpoint" - expect(the_bundle).to include_gems "rails 2.3.2" - end - - it "installs the binstubs", :bundler => "< 3" do + it "installs the binstubs", bundler: "< 3" do gemfile <<-G source "#{source_uri}" gem "rack" G - bundle "install --binstubs", :artifice => "endpoint" + bundle "install --binstubs", artifice: "endpoint" gembin "rackup" expect(out).to eq("1.0.0") end - it "installs the bins when using --path and uses autoclean", :bundler => "< 3" do + it "installs the bins when using --path and uses autoclean", bundler: "< 3" do gemfile <<-G source "#{source_uri}" gem "rack" G - bundle "install --path vendor/bundle", :artifice => "endpoint" + bundle "install --path vendor/bundle", artifice: "endpoint" expect(vendored_gems("bin/rackup")).to exist end - it "installs the bins when using --path and uses bundle clean", :bundler => "< 3" do + it "installs the bins when using --path and uses bundle clean", bundler: "< 3" do gemfile <<-G source "#{source_uri}" gem "rack" G - bundle "install --path vendor/bundle --no-clean", :artifice => "endpoint" + bundle "install --path vendor/bundle --no-clean", artifice: "endpoint" expect(vendored_gems("bin/rackup")).to exist end @@ -512,7 +512,7 @@ RSpec.describe "gemcutter's dependency API" do gem 'rack-obama' G - bundle :install, :artifice => "endpoint" + bundle :install, artifice: "endpoint" expect(out).to include("Post-install message from rack:") end @@ -522,7 +522,7 @@ RSpec.describe "gemcutter's dependency API" do gem 'rack_middleware' G - bundle :install, :artifice => "endpoint" + bundle :install, artifice: "endpoint" expect(out).to include("Post-install message from rack:") expect(out).to include("Rack's post install message") end @@ -531,7 +531,7 @@ RSpec.describe "gemcutter's dependency API" do let(:user) { "user" } let(:password) { "pass" } let(:basic_auth_source_uri) do - uri = Bundler::URI.parse(source_uri) + uri = Gem::URI.parse(source_uri) uri.user = user uri.password = password @@ -544,7 +544,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle :install, :artifice => "endpoint_basic_authentication" + bundle :install, artifice: "endpoint_basic_authentication" expect(out).not_to include("#{user}:#{password}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -555,7 +555,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle :install, :verbose => true, :artifice => "endpoint_basic_authentication" + bundle :install, verbose: true, artifice: "endpoint_basic_authentication" expect(out).not_to include("#{user}:#{password}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -566,7 +566,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle :install, :artifice => "endpoint_marshal_fail_basic_authentication" + bundle :install, artifice: "endpoint_marshal_fail_basic_authentication" expect(out).not_to include("#{user}:#{password}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -577,18 +577,18 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle :install, :artifice => "endpoint_500", :raise_on_error => false + bundle :install, artifice: "endpoint_500", raise_on_error: false expect(out).not_to include("#{user}:#{password}") end - it "strips http basic auth creds when warning about ambiguous sources", :bundler => "< 3" do + it "strips http basic auth creds when warning about ambiguous sources", bundler: "< 3" do gemfile <<-G source "#{basic_auth_source_uri}" source "#{file_uri_for(gem_repo1)}" gem "rack" G - bundle :install, :artifice => "endpoint_basic_authentication" + bundle :install, artifice: "endpoint_basic_authentication" expect(err).to include("Warning: the gem 'rack' was found in multiple sources.") expect(err).not_to include("#{user}:#{password}") expect(the_bundle).to include_gems "rack 1.0.0" @@ -600,7 +600,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle :install, :artifice => "endpoint_creds_diff_host" + bundle :install, artifice: "endpoint_creds_diff_host" expect(the_bundle).to include_gems "rack 1.0.0" end @@ -613,7 +613,7 @@ RSpec.describe "gemcutter's dependency API" do end it "reads authentication details from a valid ENV variable" do - bundle :install, :artifice => "endpoint_strict_basic_authentication", :env => { "BUNDLE_LOCAL___GEMSERVER__TEST" => "#{user}:#{password}" } + bundle :install, artifice: "endpoint_strict_basic_authentication", env: { "BUNDLE_LOCAL___GEMSERVER__TEST" => "#{user}:#{password}" } expect(out).to include("Fetching gem metadata from http://local-gemserver.test") expect(the_bundle).to include_gems "rack 1.0.0" @@ -631,7 +631,7 @@ RSpec.describe "gemcutter's dependency API" do it "reads authentication details by host name from bundle config" do bundle "config set #{source_hostname} #{user}:#{password}" - bundle :install, :artifice => "endpoint_strict_basic_authentication" + bundle :install, artifice: "endpoint_strict_basic_authentication" expect(out).to include("Fetching gem metadata from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" @@ -641,7 +641,7 @@ RSpec.describe "gemcutter's dependency API" do # The trailing slash is necessary here; Fetcher canonicalizes the URI. bundle "config set #{source_uri}/ #{user}:#{password}" - bundle :install, :artifice => "endpoint_strict_basic_authentication" + bundle :install, artifice: "endpoint_strict_basic_authentication" expect(out).to include("Fetching gem metadata from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" @@ -649,7 +649,7 @@ RSpec.describe "gemcutter's dependency API" do it "should use the API" do bundle "config set #{source_hostname} #{user}:#{password}" - bundle :install, :artifice => "endpoint_strict_basic_authentication" + bundle :install, artifice: "endpoint_strict_basic_authentication" expect(out).to include("Fetching gem metadata from #{source_uri}") expect(the_bundle).to include_gems "rack 1.0.0" end @@ -662,19 +662,19 @@ RSpec.describe "gemcutter's dependency API" do bundle "config set #{source_hostname} otheruser:wrong" - bundle :install, :artifice => "endpoint_strict_basic_authentication" + bundle :install, artifice: "endpoint_strict_basic_authentication" expect(the_bundle).to include_gems "rack 1.0.0" end it "shows instructions if auth is not provided for the source" do - bundle :install, :artifice => "endpoint_strict_basic_authentication", :raise_on_error => false + bundle :install, artifice: "endpoint_strict_basic_authentication", raise_on_error: false expect(err).to include("bundle config set --global #{source_hostname} username:password") end it "fails if authentication has already been provided, but failed" do bundle "config set #{source_hostname} #{user}:wrong" - bundle :install, :artifice => "endpoint_strict_basic_authentication", :raise_on_error => false + bundle :install, artifice: "endpoint_strict_basic_authentication", raise_on_error: false expect(err).to include("Bad username or password") end end @@ -688,7 +688,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle :install, :artifice => "endpoint_basic_authentication" + bundle :install, artifice: "endpoint_basic_authentication" expect(the_bundle).to include_gems "rack 1.0.0" end end @@ -713,7 +713,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle :install, :env => { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, :raise_on_error => false + bundle :install, env: { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, raise_on_error: false expect(err).to include("OpenSSL") end end @@ -723,7 +723,7 @@ RSpec.describe "gemcutter's dependency API" do # Install a monkeypatch that reproduces the effects of openssl raising # a certificate validation error when RubyGems tries to connect. gemfile <<-G - class Net::HTTP + class Gem::Net::HTTP def start raise OpenSSL::SSL::SSLError, "certificate verify failed" end @@ -733,7 +733,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle :install, :raise_on_error => false + bundle :install, raise_on_error: false expect(err).to match(/could not verify the SSL certificate/i) end end @@ -741,7 +741,7 @@ RSpec.describe "gemcutter's dependency API" do context ".gemrc with sources is present" do it "uses other sources declared in the Gemfile" do File.open(home(".gemrc"), "w") do |file| - file.puts({ :sources => ["https://rubygems.org"] }.to_yaml) + file.puts({ sources: ["https://rubygems.org"] }.to_yaml) end begin @@ -750,7 +750,7 @@ RSpec.describe "gemcutter's dependency API" do gem 'rack' G - bundle "install", :artifice => "endpoint_marshal_fail" + bundle "install", artifice: "endpoint_marshal_fail" ensure home(".gemrc").rmtree end diff --git a/spec/bundler/install/gems/flex_spec.rb b/spec/bundler/install/gems/flex_spec.rb index f9b374cf01..8ef3984975 100644 --- a/spec/bundler/install/gems/flex_spec.rb +++ b/spec/bundler/install/gems/flex_spec.rb @@ -156,7 +156,7 @@ RSpec.describe "bundle flex_install" do end end - describe "when Gemfile conflicts with lockfile" do + describe "when running bundle install and Gemfile conflicts with lockfile" do before(:each) do build_repo2 install_gemfile <<-G @@ -183,34 +183,70 @@ RSpec.describe "bundle flex_install" do end it "does not install gems whose dependencies are not met" do - bundle :install, :raise_on_error => false - ruby <<-RUBY, :raise_on_error => false + bundle :install, raise_on_error: false + ruby <<-RUBY, raise_on_error: false require 'bundler/setup' RUBY expect(err).to match(/could not find gem 'rack-obama/i) end - it "suggests bundle update when the Gemfile requires different versions than the lock" do + it "discards the locked gems when the Gemfile requires different versions than the lock" do bundle "config set force_ruby_platform true" - nice_error = <<-E.strip.gsub(/^ {8}/, "") - Bundler could not find compatible versions for gem "rack": - In snapshot (Gemfile.lock): - rack (= 0.9.1) + nice_error = <<~E.strip + Could not find compatible versions - In Gemfile: - rack-obama (= 2.0) was resolved to 2.0, which depends on - rack (= 1.2) + Because rack-obama >= 2.0 depends on rack = 1.2 + and rack = 1.2 could not be found in rubygems repository #{file_uri_for(gem_repo2)}/, cached gems or installed locally, + rack-obama >= 2.0 cannot be used. + So, because Gemfile depends on rack-obama = 2.0, + version solving has failed. + E + + bundle :install, retry: 0, raise_on_error: false + expect(err).to end_with(nice_error) + end - rack_middleware was resolved to 1.0, which depends on - rack (= 0.9.1) + it "does not include conflicts with a single requirement tree, because that can't possibly be a conflict" do + bundle "config set force_ruby_platform true" - Running `bundle update` will rebuild your snapshot from scratch, using only - the gems in your Gemfile, which may resolve the conflict. + bad_error = <<~E.strip + Bundler could not find compatible versions for gem "rack-obama": + In Gemfile: + rack-obama (= 2.0) E - bundle :install, :retry => 0, :raise_on_error => false - expect(err).to end_with(nice_error) + bundle "update rack_middleware", retry: 0, raise_on_error: false + expect(err).not_to end_with(bad_error) + end + end + + describe "when running bundle update and Gemfile conflicts with lockfile" do + before(:each) do + build_repo4 do + build_gem "jekyll-feed", "0.16.0" + build_gem "jekyll-feed", "0.15.1" + + build_gem "github-pages", "226" do |s| + s.add_dependency "jekyll-feed", "0.15.1" + end + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "jekyll-feed", "~> 0.12" + G + + gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "github-pages", "~> 226" + gem "jekyll-feed", "~> 0.12" + G + end + + it "discards the conflicting lockfile information and resolves properly" do + bundle :update, raise_on_error: false, all: true + expect(err).to be_empty end end @@ -232,6 +268,11 @@ RSpec.describe "bundle flex_install" do it "should work when you install" do bundle "install" + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo1, "rack", "0.9.1" + c.checksum gem_repo1, "rack-obama", "1.0" + end + expect(lockfile).to eq <<~L GEM remote: #{file_uri_for(gem_repo1)}/ @@ -246,7 +287,7 @@ RSpec.describe "bundle flex_install" do DEPENDENCIES rack (= 0.9.1) rack-obama - + #{checksums} BUNDLED WITH #{Bundler::VERSION} L @@ -272,6 +313,10 @@ RSpec.describe "bundle flex_install" do gem "rack" G + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo1, "rack", "1.0.0" + end + expect(lockfile).to eq <<~L GEM remote: #{file_uri_for(gem_repo1)}/ @@ -287,7 +332,7 @@ RSpec.describe "bundle flex_install" do DEPENDENCIES rack - + #{checksums} BUNDLED WITH #{Bundler::VERSION} L @@ -314,7 +359,7 @@ RSpec.describe "bundle flex_install" do end end - it "prints the correct error message" do + it "resolves them" do # install Rails 3.0.0.rc install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" @@ -323,13 +368,12 @@ RSpec.describe "bundle flex_install" do G # upgrade Rails to 3.0.0 and then install again - install_gemfile <<-G, :raise_on_error => false + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" gem "rails", "3.0.0" gem "capybara", "0.3.9" G - - expect(err).to include("Gemfile.lock") + expect(err).to be_empty end end end diff --git a/spec/bundler/install/gems/fund_spec.rb b/spec/bundler/install/gems/fund_spec.rb index f521b0296f..9aadc9ed25 100644 --- a/spec/bundler/install/gems/fund_spec.rb +++ b/spec/bundler/install/gems/fund_spec.rb @@ -6,20 +6,20 @@ RSpec.describe "bundle install" do build_repo2 do build_gem "has_funding_and_other_metadata" do |s| s.metadata = { - "bug_tracker_uri" => "https://example.com/user/bestgemever/issues", - "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md", + "bug_tracker_uri" => "https://example.com/user/bestgemever/issues", + "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md", "documentation_uri" => "https://www.example.info/gems/bestgemever/0.0.1", - "homepage_uri" => "https://bestgemever.example.io", - "mailing_list_uri" => "https://groups.example.com/bestgemever", - "funding_uri" => "https://example.com/has_funding_and_other_metadata/funding", - "source_code_uri" => "https://example.com/user/bestgemever", - "wiki_uri" => "https://example.com/user/bestgemever/wiki", + "homepage_uri" => "https://bestgemever.example.io", + "mailing_list_uri" => "https://groups.example.com/bestgemever", + "funding_uri" => "https://example.com/has_funding_and_other_metadata/funding", + "source_code_uri" => "https://example.com/user/bestgemever", + "wiki_uri" => "https://example.com/user/bestgemever/wiki", } end build_gem "has_funding", "1.2.3" do |s| s.metadata = { - "funding_uri" => "https://example.com/has_funding/funding", + "funding_uri" => "https://example.com/has_funding/funding", } end @@ -52,6 +52,33 @@ RSpec.describe "bundle install" do end end + context "when gems include a fund URI but `ignore_funding_requests` is configured" do + before do + bundle "config set ignore_funding_requests true" + end + + it "does not display the plural fund message after installing" do + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem 'has_funding_and_other_metadata' + gem 'has_funding' + gem 'rack-obama' + G + + expect(out).not_to include("2 installed gems you directly depend on are looking for funding.") + end + + it "does not display the singular fund message after installing" do + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem 'has_funding' + gem 'rack-obama' + G + + expect(out).not_to include("1 installed gem you directly depend on is looking for funding.") + end + end + context "when gems do not include fund messages" do it "does not display any fund messages" do install_gemfile <<-G diff --git a/spec/bundler/install/gems/native_extensions_spec.rb b/spec/bundler/install/gems/native_extensions_spec.rb index d5cafcfc2c..907778a384 100644 --- a/spec/bundler/install/gems/native_extensions_spec.rb +++ b/spec/bundler/install/gems/native_extensions_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.describe "installing a gem with native extensions", :ruby_repo do +RSpec.describe "installing a gem with native extensions" do it "installs" do build_repo2 do build_gem "c_extension" do |s| @@ -91,7 +91,7 @@ RSpec.describe "installing a gem with native extensions", :ruby_repo do it "installs correctly from git when multiple gems with extensions share one repository" do build_repo2 do ["one", "two"].each do |n| - build_lib "c_extension_#{n}", "1.0", :path => lib_path("gems/c_extension_#{n}") do |s| + build_lib "c_extension_#{n}", "1.0", path: lib_path("gems/c_extension_#{n}") do |s| s.extensions = ["ext/extconf.rb"] s.write "ext/extconf.rb", <<-E require "mkmf" @@ -119,7 +119,7 @@ RSpec.describe "installing a gem with native extensions", :ruby_repo do C end end - build_git "gems", :path => lib_path("gems"), :gemspec => false + build_git "gems", path: lib_path("gems"), gemspec: false end bundle "config set build.c_extension_one --with-c_extension_one=one" diff --git a/spec/bundler/install/gems/resolving_spec.rb b/spec/bundler/install/gems/resolving_spec.rb index b0209489b9..c5f9c4a3d3 100644 --- a/spec/bundler/install/gems/resolving_spec.rb +++ b/spec/bundler/install/gems/resolving_spec.rb @@ -7,7 +7,7 @@ RSpec.describe "bundle install with install-time dependencies" do s.extensions << "Rakefile" s.write "Rakefile", <<-RUBY task :default do - path = File.expand_path("../lib", __FILE__) + path = File.expand_path("lib", __dir__) FileUtils.mkdir_p(path) File.open("\#{path}/implicit_rake_dep.rb", "w") do |f| f.puts "IMPLICIT_RAKE_DEP = 'YES'" @@ -20,7 +20,7 @@ RSpec.describe "bundle install with install-time dependencies" do s.extensions << "Rakefile" s.write "Rakefile", <<-RUBY task :default do - path = File.expand_path("../lib", __FILE__) + path = File.expand_path("lib", __dir__) FileUtils.mkdir_p(path) File.open("\#{path}/another_implicit_rake_dep.rb", "w") do |f| f.puts "ANOTHER_IMPLICIT_RAKE_DEP = 'YES'" @@ -42,7 +42,7 @@ RSpec.describe "bundle install with install-time dependencies" do s.extensions << "Rakefile" s.write "Rakefile", <<-RUBY task :default do - path = File.expand_path("../lib", __FILE__) + path = File.expand_path("lib", __dir__) FileUtils.mkdir_p(path) File.open("\#{path}/net_build_extensions.rb", "w") do |f| f.puts "NET_BUILD_EXTENSIONS = 'YES'" @@ -106,7 +106,7 @@ RSpec.describe "bundle install with install-time dependencies" do path = "#{gem_repo2}/#{Gem::MARSHAL_SPEC_DIR}/actionpack-2.3.2.gemspec.rz" spec = Marshal.load(Bundler.rubygems.inflate(File.binread(path))) spec.dependencies.each do |d| - d.instance_variable_set(:@type, :fail) + d.instance_variable_set(:@type, "fail") end File.open(path, "wb") do |f| f.write Gem.deflate(Marshal.dump(spec)) @@ -131,7 +131,7 @@ RSpec.describe "bundle install with install-time dependencies" do end it "installs plugins depended on by other plugins" do - install_gemfile <<-G, :env => { "DEBUG" => "1" } + install_gemfile <<-G, env: { "DEBUG" => "1" } source "#{file_uri_for(gem_repo2)}" gem "net_a" G @@ -140,7 +140,7 @@ RSpec.describe "bundle install with install-time dependencies" do end it "installs multiple levels of dependencies" do - install_gemfile <<-G, :env => { "DEBUG" => "1" } + install_gemfile <<-G, env: { "DEBUG" => "1" } source "#{file_uri_for(gem_repo2)}" gem "net_c" gem "net_e" @@ -157,9 +157,9 @@ RSpec.describe "bundle install with install-time dependencies" do gem "net_e" G - bundle :install, :env => { "BUNDLER_DEBUG_RESOLVER" => "1", "DEBUG" => "1" } + bundle :install, env: { "BUNDLER_DEBUG_RESOLVER" => "1", "DEBUG" => "1" } - expect(out).to include("BUNDLER: Starting resolution") + expect(out).to include("Resolving dependencies...") end end @@ -171,9 +171,9 @@ RSpec.describe "bundle install with install-time dependencies" do gem "net_e" G - bundle :install, :env => { "DEBUG_RESOLVER" => "1", "DEBUG" => "1" } + bundle :install, env: { "DEBUG_RESOLVER" => "1", "DEBUG" => "1" } - expect(out).to include("BUNDLER: Starting resolution") + expect(out).to include("Resolving dependencies...") end end @@ -185,18 +185,12 @@ RSpec.describe "bundle install with install-time dependencies" do gem "net_e" G - bundle :install, :env => { "DEBUG_RESOLVER_TREE" => "1", "DEBUG" => "1" } - - activated_groups = if local_platforms.any? - "net_b (1.0) (ruby), net_b (1.0) (#{local_platforms.join(", ")})" - else - "net_b (1.0) (ruby)" - end + bundle :install, env: { "DEBUG_RESOLVER_TREE" => "1", "DEBUG" => "1" } expect(out).to include(" net_b"). - and include("BUNDLER: Starting resolution"). - and include("BUNDLER: Finished resolution"). - and include("Attempting to activate [#{activated_groups}]") + and include("Resolving dependencies..."). + and include("Solution found after 1 attempts:"). + and include("selected net_b 1.0") end end end @@ -214,13 +208,13 @@ RSpec.describe "bundle install with install-time dependencies" do end end - install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } - ruby "#{RUBY_VERSION}" + install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } + ruby "#{Gem.ruby_version}" source "http://localgemserver.test/" gem 'rack' G - expect(out).to_not include("rack-9001.0.0 requires ruby version > 9000") + expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000") expect(the_bundle).to include_gems("rack 1.2") end @@ -235,16 +229,306 @@ RSpec.describe "bundle install with install-time dependencies" do end end - install_gemfile <<-G, :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } - ruby "#{RUBY_VERSION}" + install_gemfile <<-G, artifice: "endpoint", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } + ruby "#{Gem.ruby_version}" source "http://localgemserver.test/" gem 'rack' G - expect(out).to_not include("rack-9001.0.0 requires ruby version > 9000") + expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000") expect(the_bundle).to include_gems("rack 1.2") end + context "when there is a lockfile using the newer incompatible version" do + before do + build_repo2 do + build_gem "parallel_tests", "3.7.0" do |s| + s.required_ruby_version = ">= #{current_ruby_minor}" + end + + build_gem "parallel_tests", "3.8.0" do |s| + s.required_ruby_version = ">= #{next_ruby_minor}" + end + end + + gemfile <<-G + source "http://localgemserver.test/" + gem 'parallel_tests' + G + + checksums = checksums_section do |c| + c.checksum gem_repo2, "parallel_tests", "3.8.0" + end + + lockfile <<~L + GEM + remote: http://localgemserver.test/ + specs: + parallel_tests (3.8.0) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + parallel_tests + #{checksums} + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "automatically updates lockfile to use the older version" do + bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } + + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo2, "parallel_tests", "3.7.0" + end + + expect(lockfile).to eq <<~L + GEM + remote: http://localgemserver.test/ + specs: + parallel_tests (3.7.0) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + parallel_tests + #{checksums} + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "gives a meaningful error if we're in frozen mode" do + expect do + bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s, "BUNDLE_FROZEN" => "true" }, raise_on_error: false + end.not_to change { lockfile } + + expect(err).to include("parallel_tests-3.8.0 requires ruby version >= #{next_ruby_minor}") + expect(err).not_to include("That means the author of parallel_tests (3.8.0) has removed it.") + end + end + + context "with transitive dependencies in a lockfile" do + before do + build_repo2 do + build_gem "rubocop", "1.28.2" do |s| + s.required_ruby_version = ">= #{current_ruby_minor}" + + s.add_dependency "rubocop-ast", ">= 1.17.0", "< 2.0" + end + + build_gem "rubocop", "1.35.0" do |s| + s.required_ruby_version = ">= #{next_ruby_minor}" + + s.add_dependency "rubocop-ast", ">= 1.20.1", "< 2.0" + end + + build_gem "rubocop-ast", "1.17.0" do |s| + s.required_ruby_version = ">= #{current_ruby_minor}" + end + + build_gem "rubocop-ast", "1.21.0" do |s| + s.required_ruby_version = ">= #{next_ruby_minor}" + end + end + + gemfile <<-G + source "http://localgemserver.test/" + gem 'rubocop' + G + + checksums = checksums_section do |c| + c.checksum gem_repo2, "rubocop", "1.35.0" + c.checksum gem_repo2, "rubocop-ast", "1.21.0" + end + + lockfile <<~L + GEM + remote: http://localgemserver.test/ + specs: + rubocop (1.35.0) + rubocop-ast (>= 1.20.1, < 2.0) + rubocop-ast (1.21.0) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + parallel_tests + #{checksums} + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "automatically updates lockfile to use the older compatible versions" do + bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } + + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo2, "rubocop", "1.28.2" + c.checksum gem_repo2, "rubocop-ast", "1.17.0" + end + + expect(lockfile).to eq <<~L + GEM + remote: http://localgemserver.test/ + specs: + rubocop (1.28.2) + rubocop-ast (>= 1.17.0, < 2.0) + rubocop-ast (1.17.0) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + rubocop + #{checksums} + BUNDLED WITH + #{Bundler::VERSION} + L + end + end + + context "with a Gemfile and lock file that don't resolve under the current platform" do + before do + build_repo4 do + build_gem "sorbet", "0.5.10554" do |s| + s.add_dependency "sorbet-static", "0.5.10554" + end + + build_gem "sorbet-static", "0.5.10554" do |s| + s.platform = "universal-darwin-21" + end + end + + gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + gem 'sorbet', '= 0.5.10554' + G + + lockfile <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + sorbet (0.5.10554) + sorbet-static (= 0.5.10554) + sorbet-static (0.5.10554-universal-darwin-21) + + PLATFORMS + arm64-darwin-21 + + DEPENDENCIES + sorbet (= 0.5.10554) + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "raises a proper error" do + simulate_platform "aarch64-linux" do + bundle "install", raise_on_error: false + end + + nice_error = <<~E.strip + Could not find gems matching 'sorbet-static (= 0.5.10554)' valid for all resolution platforms (arm64-darwin-21, aarch64-linux) in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally. + + The source contains the following gems matching 'sorbet-static (= 0.5.10554)': + * sorbet-static-0.5.10554-universal-darwin-21 + E + expect(err).to end_with(nice_error) + end + end + + context "when adding a new gem that does not resolve under all locked platforms" do + before do + simulate_platform "x86_64-linux" do + build_repo4 do + build_gem "nokogiri", "1.14.0" do |s| + s.platform = "x86_64-linux" + end + build_gem "nokogiri", "1.14.0" do |s| + s.platform = "arm-linux" + end + + build_gem "sorbet-static", "0.5.10696" do |s| + s.platform = "x86_64-linux" + end + end + + lockfile <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + nokogiri (1.14.0-arm-linux) + nokogiri (1.14.0-x86_64-linux) + + PLATFORMS + arm-linux + x86_64-linux + + DEPENDENCIES + nokogiri + + BUNDLED WITH + #{Bundler::VERSION} + L + + gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + + gem "nokogiri" + gem "sorbet-static" + G + + bundle "lock", raise_on_error: false + end + end + + it "raises a proper error" do + nice_error = <<~E.strip + Could not find gems matching 'sorbet-static' valid for all resolution platforms (arm-linux, x86_64-linux) in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally. + + The source contains the following gems matching 'sorbet-static': + * sorbet-static-0.5.10696-x86_64-linux + E + expect(err).to end_with(nice_error) + end + end + + it "gives a meaningful error on ruby version mismatches between dependencies" do + build_repo4 do + build_gem "requires-old-ruby" do |s| + s.required_ruby_version = "< #{Gem.ruby_version}" + end + end + + build_lib("foo", path: bundled_app) do |s| + s.required_ruby_version = ">= #{Gem.ruby_version}" + + s.add_dependency "requires-old-ruby" + end + + install_gemfile <<-G, raise_on_error: false + source "#{file_uri_for(gem_repo4)}" + gemspec + G + + expect(err).to end_with <<~E.strip + Could not find compatible versions + + Because every version of foo depends on requires-old-ruby >= 0 + and every version of requires-old-ruby depends on Ruby < #{Gem.ruby_version}, + every version of foo requires Ruby < #{Gem.ruby_version}. + So, because Gemfile depends on foo >= 0 + and current Ruby version is = #{Gem.ruby_version}, + version solving has failed. + E + end + it "installs the older version under rate limiting conditions" do build_repo4 do build_gem "rack", "9001.0.0" do |s| @@ -254,14 +538,14 @@ RSpec.describe "bundle install with install-time dependencies" do build_gem "foo1", "1.0" end - install_gemfile <<-G, :artifice => "compact_index_rate_limited", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } - ruby "#{RUBY_VERSION}" + install_gemfile <<-G, artifice: "compact_index_rate_limited", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + ruby "#{Gem.ruby_version}" source "http://localgemserver.test/" gem 'rack' gem 'foo1' G - expect(out).to_not include("rack-9001.0.0 requires ruby version > 9000") + expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000") expect(the_bundle).to include_gems("rack 1.2") end @@ -271,22 +555,22 @@ RSpec.describe "bundle install with install-time dependencies" do s.required_ruby_version = "> 9000" end build_gem "rack", "1.2" do |s| - s.platform = mingw + s.platform = x86_mingw32 s.required_ruby_version = "> 9000" end build_gem "rack", "1.2" end - simulate_platform mingw do - install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } - ruby "#{RUBY_VERSION}" + simulate_platform x86_mingw32 do + install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + ruby "#{Gem.ruby_version}" source "http://localgemserver.test/" gem 'rack' G end - expect(out).to_not include("rack-9001.0.0 requires ruby version > 9000") - expect(out).to_not include("rack-1.2-#{Bundler.local_platform} requires ruby version > 9000") + expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000") + expect(err).to_not include("rack-1.2-#{Bundler.local_platform} requires ruby version > 9000") expect(the_bundle).to include_gems("rack 1.2") end end @@ -300,12 +584,32 @@ RSpec.describe "bundle install with install-time dependencies" do end end - let(:ruby_requirement) { %("#{RUBY_VERSION}") } - let(:error_message_requirement) { "~> #{RUBY_VERSION}.0" } + let(:ruby_requirement) { %("#{Gem.ruby_version}") } + let(:error_message_requirement) { "= #{Gem.ruby_version}" } + + it "raises a proper error that mentions the current Ruby version during resolution" do + install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, raise_on_error: false + source "http://localgemserver.test/" + gem 'require_ruby' + G + + expect(out).to_not include("Gem::InstallError: require_ruby requires Ruby version > 9000") + + nice_error = <<~E.strip + Could not find compatible versions + + Because every version of require_ruby depends on Ruby > 9000 + and Gemfile depends on require_ruby >= 0, + Ruby > 9000 is required. + So, because current Ruby version is #{error_message_requirement}, + version solving has failed. + E + expect(err).to end_with(nice_error) + end shared_examples_for "ruby version conflicts" do it "raises an error during resolution" do - install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, :raise_on_error => false + install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, raise_on_error: false source "http://localgemserver.test/" ruby #{ruby_requirement} gem 'require_ruby' @@ -313,13 +617,14 @@ RSpec.describe "bundle install with install-time dependencies" do expect(out).to_not include("Gem::InstallError: require_ruby requires Ruby version > 9000") - nice_error = strip_whitespace(<<-E).strip - Bundler found conflicting requirements for the Ruby\0 version: - In Gemfile: - Ruby\0 (#{error_message_requirement}) + nice_error = <<~E.strip + Could not find compatible versions - require_ruby was resolved to 1.0, which depends on - Ruby\0 (> 9000) + Because every version of require_ruby depends on Ruby > 9000 + and Gemfile depends on require_ruby >= 0, + Ruby > 9000 is required. + So, because current Ruby version is #{error_message_requirement}, + version solving has failed. E expect(err).to end_with(nice_error) end @@ -329,7 +634,6 @@ RSpec.describe "bundle install with install-time dependencies" do describe "with a < requirement" do let(:ruby_requirement) { %("< 5000") } - let(:error_message_requirement) { "< 5000" } it_behaves_like "ruby version conflicts" end @@ -337,7 +641,6 @@ RSpec.describe "bundle install with install-time dependencies" do describe "with a compound requirement" do let(:reqs) { ["> 0.1", "< 5000"] } let(:ruby_requirement) { reqs.map(&:dump).join(", ") } - let(:error_message_requirement) { Gem::Requirement.new(reqs).to_s } it_behaves_like "ruby version conflicts" end @@ -352,19 +655,18 @@ RSpec.describe "bundle install with install-time dependencies" do end end - install_gemfile <<-G, :raise_on_error => false + install_gemfile <<-G, raise_on_error: false source "#{file_uri_for(gem_repo2)}" gem 'require_rubygems' G expect(err).to_not include("Gem::InstallError: require_rubygems requires RubyGems version > 9000") - nice_error = strip_whitespace(<<-E).strip - Bundler found conflicting requirements for the RubyGems\0 version: - In Gemfile: - RubyGems\0 (= #{Gem::VERSION}) - - require_rubygems was resolved to 1.0, which depends on - RubyGems\0 (> 9000) + nice_error = <<~E.strip + Because every version of require_rubygems depends on RubyGems > 9000 + and Gemfile depends on require_rubygems >= 0, + RubyGems > 9000 is required. + So, because current RubyGems version is = #{Gem::VERSION}, + version solving has failed. E expect(err).to end_with(nice_error) end diff --git a/spec/bundler/install/gems/standalone_spec.rb b/spec/bundler/install/gems/standalone_spec.rb index 337d5f021c..46cab2dfeb 100644 --- a/spec/bundler/install/gems/standalone_spec.rb +++ b/spec/bundler/install/gems/standalone_spec.rb @@ -32,6 +32,21 @@ RSpec.shared_examples "bundle install --standalone" do expect(out).to eq(expected_gems.values.join("\n")) end + it "makes the gems available without bundler nor rubygems" do + testrb = String.new <<-RUBY + $:.unshift File.expand_path("bundle") + require "bundler/setup" + + RUBY + expected_gems.each do |k, _| + testrb << "\nrequire \"#{k}\"" + testrb << "\nputs #{k.upcase}" + end + sys_exec %(#{Gem.ruby} --disable-gems -w -e #{testrb.shellescape}) + + expect(out).to eq(expected_gems.values.join("\n")) + end + it "makes the gems available without bundler via Kernel.require" do testrb = String.new <<-RUBY $:.unshift File.expand_path("bundle") @@ -82,7 +97,23 @@ RSpec.shared_examples "bundle install --standalone" do testrb << "\nrequire \"#{k}\"" testrb << "\nputs #{k.upcase}" end - ruby testrb, :dir => "#{bundled_app}2" + ruby testrb, dir: "#{bundled_app}2" + + expect(out).to eq(expected_gems.values.join("\n")) + end + + it "skips activating gems" do + testrb = String.new <<-RUBY + $:.unshift File.expand_path("bundle") + require "bundler/setup" + + gem "do_not_activate_me" + RUBY + expected_gems.each do |k, _| + testrb << "\nrequire \"#{k}\"" + testrb << "\nputs #{k.upcase}" + end + sys_exec %(#{Gem.ruby} -w -e #{testrb.shellescape}) expect(out).to eq(expected_gems.values.join("\n")) end @@ -95,7 +126,7 @@ RSpec.shared_examples "bundle install --standalone" do gem "rails" G bundle "config set --local path #{bundled_app("bundle")}" - bundle :install, :standalone => true, :dir => cwd + bundle :install, standalone: true, dir: cwd end let(:expected_gems) do @@ -110,20 +141,18 @@ RSpec.shared_examples "bundle install --standalone" do describe "with default gems and a lockfile", :ruby_repo do before do - skip "does not work on rubygems versions where `--install_dir` doesn't respect --default" unless Gem::Installer.for_spec(loaded_gemspec, :install_dir => "/foo").default_spec_file == "/foo/specifications/default/bundler-#{Bundler::VERSION}.gemspec" # Since rubygems 3.2.0.rc.2 - skip "does not work on old rubies because the realworld gems that need to be installed don't support them" if RUBY_VERSION < "2.7.0" + realworld_system_gems "tsort --version 0.1.0" - realworld_system_gems "fiddle --version 1.0.8", "tsort --version 0.1.0" - - necessary_system_gems = ["optparse --version 0.1.1", "psych --version 3.3.2", "yaml --version 0.1.1", "logger --version 1.4.3", "etc --version 1.2.0", "stringio --version 3.0.0"] + necessary_system_gems = ["optparse --version 0.1.1", "psych --version 3.3.2", "logger --version 1.4.3", "etc --version 1.2.0", "stringio --version 3.1.0"] necessary_system_gems += ["shellwords --version 0.1.0", "base64 --version 0.1.0", "resolv --version 0.2.1"] if Gem.rubygems_version < Gem::Version.new("3.3.a") - realworld_system_gems(*necessary_system_gems, :path => scoped_gem_path(bundled_app("bundle"))) + necessary_system_gems += ["yaml --version 0.1.1"] if Gem.rubygems_version < Gem::Version.new("3.4.a") + realworld_system_gems(*necessary_system_gems, path: scoped_gem_path(bundled_app("bundle"))) - build_gem "foo", "1.0.0", :to_system => true, :default => true do |s| + build_gem "foo", "1.0.0", to_system: true, default: true do |s| s.add_dependency "bar" end - build_gem "bar", "1.0.0", :to_system => true, :default => true + build_gem "bar", "1.0.0", to_system: true, default: true build_repo4 do build_gem "foo", "1.0.0" do |s| @@ -138,18 +167,25 @@ RSpec.shared_examples "bundle install --standalone" do gem "foo" G - bundle "lock", :dir => cwd, :artifice => "compact_index" + bundle "lock", dir: cwd, artifice: "compact_index" end - it "works" do + it "works and points to the vendored copies, not to the default copies", :realworld do bundle "config set --local path #{bundled_app("bundle")}" - bundle :install, :standalone => true, :dir => cwd, :artifice => "compact_index", :env => { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s } + bundle :install, standalone: true, dir: cwd, artifice: "compact_index", env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s } + + load_path_lines = bundled_app("bundle/bundler/setup.rb").read.split("\n").select {|line| line.start_with?("$:.unshift") } + + expect(load_path_lines).to eq [ + '$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/bar-1.0.0/lib")', + '$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/foo-1.0.0/lib")', + ] end end - describe "with Gemfiles using path sources and resulting bundle moved to a folder hierarchy with different nesting" do + describe "with Gemfiles using absolute path sources and resulting bundle moved to a folder hierarchy with different nesting" do before do - build_lib "minitest", "1.0.0", :path => lib_path("minitest") + build_lib "minitest", "1.0.0", path: lib_path("minitest") Dir.mkdir bundled_app("app") @@ -158,14 +194,14 @@ RSpec.shared_examples "bundle install --standalone" do gem "minitest", :path => "#{lib_path("minitest")}" G - bundle "install", :standalone => true, :dir => bundled_app("app") + bundle "install", standalone: true, dir: bundled_app("app") Dir.mkdir tmp("one_more_level") FileUtils.mv bundled_app, tmp("one_more_level") end it "also works" do - ruby <<-RUBY, :dir => tmp("one_more_level/bundled_app/app") + ruby <<-RUBY, dir: tmp("one_more_level/bundled_app/app") require "./bundle/bundler/setup" require "minitest" @@ -177,10 +213,39 @@ RSpec.shared_examples "bundle install --standalone" do end end - describe "with gems with native extension", :ruby_repo do + describe "with Gemfiles using relative path sources and app moved to a different root" do + before do + FileUtils.mkdir_p bundled_app("app/vendor") + + build_lib "minitest", "1.0.0", path: bundled_app("app/vendor/minitest") + + gemfile bundled_app("app/Gemfile"), <<-G + source "#{file_uri_for(gem_repo1)}" + gem "minitest", :path => "vendor/minitest" + G + + bundle "install", standalone: true, dir: bundled_app("app") + + FileUtils.mv(bundled_app("app"), bundled_app2("app")) + end + + it "also works" do + ruby <<-RUBY, dir: bundled_app2("app") + require "./bundle/bundler/setup" + + require "minitest" + puts MINITEST + RUBY + + expect(out).to eq("1.0.0") + expect(err).to be_empty + end + end + + describe "with gems with native extension" do before do bundle "config set --local path #{bundled_app("bundle")}" - install_gemfile <<-G, :standalone => true, :dir => cwd + install_gemfile <<-G, standalone: true, dir: cwd source "#{file_uri_for(gem_repo1)}" gem "very_simple_binary" G @@ -188,18 +253,22 @@ RSpec.shared_examples "bundle install --standalone" do it "generates a bundle/bundler/setup.rb with the proper paths" do expected_path = bundled_app("bundle/bundler/setup.rb") - extension_line = File.read(expected_path).each_line.find {|line| line.include? "/extensions/" }.strip - expect(extension_line).to start_with '$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{RbConfig::CONFIG["ruby_version"]}/extensions/' - expect(extension_line).to end_with '/very_simple_binary-1.0")' + script_content = File.read(expected_path) + expect(script_content).to include("def self.ruby_api_version") + expect(script_content).to include("def self.extension_api_version") + extension_line = script_content.each_line.find {|line| line.include? "/extensions/" }.strip + platform = Gem::Platform.local + expect(extension_line).to start_with '$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/' + expect(extension_line).to end_with platform.to_s + '/#{Gem.extension_api_version}/very_simple_binary-1.0")' end end describe "with gem that has an invalid gemspec" do before do - build_git "bar", :gemspec => false do |s| + build_git "bar", gemspec: false do |s| s.write "lib/bar/version.rb", %(BAR_VERSION = '1.0') s.write "bar.gemspec", <<-G - lib = File.expand_path('../lib/', __FILE__) + lib = File.expand_path('lib/', __dir__) $:.unshift lib unless $:.include?(lib) require 'bar/version' @@ -214,7 +283,7 @@ RSpec.shared_examples "bundle install --standalone" do G end bundle "config set --local path #{bundled_app("bundle")}" - install_gemfile <<-G, :standalone => true, :dir => cwd, :raise_on_error => false + install_gemfile <<-G, standalone: true, dir: cwd, raise_on_error: false source "#{file_uri_for(gem_repo1)}" gem "bar", :git => "#{lib_path("bar-1.0")}" G @@ -236,7 +305,7 @@ RSpec.shared_examples "bundle install --standalone" do gem "devise", :git => "#{lib_path("devise-1.0")}" G bundle "config set --local path #{bundled_app("bundle")}" - bundle :install, :standalone => true, :dir => cwd + bundle :install, standalone: true, dir: cwd end let(:expected_gems) do @@ -264,7 +333,7 @@ RSpec.shared_examples "bundle install --standalone" do end G bundle "config set --local path #{bundled_app("bundle")}" - bundle :install, :standalone => true, :dir => cwd + bundle :install, standalone: true, dir: cwd end let(:expected_gems) do @@ -278,7 +347,7 @@ RSpec.shared_examples "bundle install --standalone" do it "allows creating a standalone file with limited groups" do bundle "config set --local path #{bundled_app("bundle")}" - bundle :install, :standalone => "default", :dir => cwd + bundle :install, standalone: "default", dir: cwd load_error_ruby <<-RUBY, "spec" $:.unshift File.expand_path("bundle") @@ -296,7 +365,7 @@ RSpec.shared_examples "bundle install --standalone" do it "allows `without` configuration to limit the groups used in a standalone" do bundle "config set --local path #{bundled_app("bundle")}" bundle "config set --local without test" - bundle :install, :standalone => true, :dir => cwd + bundle :install, standalone: true, dir: cwd load_error_ruby <<-RUBY, "spec" $:.unshift File.expand_path("bundle") @@ -313,7 +382,7 @@ RSpec.shared_examples "bundle install --standalone" do it "allows `path` configuration to change the location of the standalone bundle" do bundle "config set --local path path/to/bundle" - bundle "install", :standalone => true, :dir => cwd + bundle "install", standalone: true, dir: cwd ruby <<-RUBY $:.unshift File.expand_path("path/to/bundle") @@ -328,9 +397,9 @@ RSpec.shared_examples "bundle install --standalone" do it "allows `without` to limit the groups used in a standalone" do bundle "config set --local without test" - bundle :install, :dir => cwd + bundle :install, dir: cwd bundle "config set --local path #{bundled_app("bundle")}" - bundle :install, :standalone => true, :dir => cwd + bundle :install, standalone: true, dir: cwd load_error_ruby <<-RUBY, "spec" $:.unshift File.expand_path("bundle") @@ -356,7 +425,7 @@ RSpec.shared_examples "bundle install --standalone" do gem "rails" G bundle "config set --local path #{bundled_app("bundle")}" - bundle :install, :standalone => true, :artifice => "endpoint", :dir => cwd + bundle :install, standalone: true, artifice: "endpoint", dir: cwd end let(:expected_gems) do @@ -370,14 +439,14 @@ RSpec.shared_examples "bundle install --standalone" do end end - describe "with --binstubs", :bundler => "< 3" do + describe "with --binstubs", bundler: "< 3" do before do gemfile <<-G source "#{file_uri_for(gem_repo1)}" gem "rails" G bundle "config set --local path #{bundled_app("bundle")}" - bundle :install, :standalone => true, :binstubs => true, :dir => cwd + bundle :install, standalone: true, binstubs: true, dir: cwd end let(:expected_gems) do @@ -395,7 +464,7 @@ RSpec.shared_examples "bundle install --standalone" do it "creates stubs that can be executed from anywhere" do require "tmpdir" - sys_exec(%(#{bundled_app("bin/rails")} -v), :dir => Dir.tmpdir) + sys_exec(%(#{bundled_app("bin/rails")} -v), dir: Dir.tmpdir) expect(out).to eq("2.3.2") end @@ -413,7 +482,7 @@ RSpec.shared_examples "bundle install --standalone" do it "creates stubs with the correct load path" do extension_line = File.read(bundled_app("bin/rails")).each_line.find {|line| line.include? "$:.unshift" }.strip - expect(extension_line).to eq %($:.unshift File.expand_path "../../bundle", path.realpath) + expect(extension_line).to eq %($:.unshift File.expand_path "../bundle", __dir__) end end end @@ -429,3 +498,31 @@ RSpec.describe "bundle install --standalone run in a subdirectory" do include_examples("bundle install --standalone") end + +RSpec.describe "bundle install --standalone --local" do + before do + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "rack" + G + + system_gems "rack-1.0.0", path: default_bundle_path + end + + it "generates script pointing to system gems" do + bundle "install --standalone --local --verbose" + + expect(out).to include("Using rack 1.0.0") + + load_error_ruby <<-RUBY, "spec" + require "./bundler/setup" + + require "rack" + puts RACK + require "spec" + RUBY + + expect(out).to eq("1.0.0") + expect(err).to eq("ZOMG LOAD ERROR") + end +end diff --git a/spec/bundler/install/gems/sudo_spec.rb b/spec/bundler/install/gems/sudo_spec.rb deleted file mode 100644 index 3e5d38ea4c..0000000000 --- a/spec/bundler/install/gems/sudo_spec.rb +++ /dev/null @@ -1,205 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe "when using sudo", :sudo => true do - describe "and BUNDLE_PATH is writable" do - context "but BUNDLE_PATH/build_info is not writable" do - let(:subdir) do - system_gem_path("cache") - end - - before do - bundle "config set path.system true" - subdir.mkpath - sudo "chmod u-w #{subdir}" - end - - after do - sudo "chmod u+w #{subdir}" - end - - it "installs" do - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" - G - - expect(out).to_not match(/an error occurred/i) - expect(system_gem_path("cache/rack-1.0.0.gem")).to exist - expect(the_bundle).to include_gems "rack 1.0" - end - end - end - - describe "and GEM_HOME is owned by root" do - before :each do - bundle "config set path.system true" - chown_system_gems_to_root - end - - it "installs" do - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", '1.0' - gem "thin" - G - - expect(system_gem_path("gems/rack-1.0.0")).to exist - expect(system_gem_path("gems/rack-1.0.0").stat.uid).to eq(0) - expect(the_bundle).to include_gems "rack 1.0" - end - - it "installs rake and a gem dependent on rake in the same session" do - build_repo2 do - build_gem "another_implicit_rake_dep" do |s| - s.extensions << "Rakefile" - s.write "Rakefile", <<-RUBY - task :default do - path = File.expand_path("../lib", __FILE__) - FileUtils.mkdir_p(path) - File.open("\#{path}/another_implicit_rake_dep.rb", "w") do |f| - f.puts "ANOTHER_IMPLICIT_RAKE_DEP = 'YES'" - end - end - RUBY - end - end - - gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem "rake" - gem "another_implicit_rake_dep" - G - bundle "install" - expect(system_gem_path("gems/another_implicit_rake_dep-1.0")).to exist - end - - it "installs when BUNDLE_PATH is owned by root" do - bundle_path = tmp("owned_by_root") - FileUtils.mkdir_p bundle_path - sudo "chown -R root #{bundle_path}" - - ENV["BUNDLE_PATH"] = bundle_path.to_s - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", '1.0' - G - - expect(bundle_path.join(Bundler.ruby_scope, "gems/rack-1.0.0")).to exist - expect(bundle_path.join(Bundler.ruby_scope, "gems/rack-1.0.0").stat.uid).to eq(0) - expect(the_bundle).to include_gems "rack 1.0" - end - - it "installs when BUNDLE_PATH does not exist" do - root_path = tmp("owned_by_root") - FileUtils.mkdir_p root_path - sudo "chown -R root #{root_path}" - bundle_path = root_path.join("does_not_exist") - - ENV["BUNDLE_PATH"] = bundle_path.to_s - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", '1.0' - G - - expect(bundle_path.join(Bundler.ruby_scope, "gems/rack-1.0.0")).to exist - expect(bundle_path.join(Bundler.ruby_scope, "gems/rack-1.0.0").stat.uid).to eq(0) - expect(the_bundle).to include_gems "rack 1.0" - end - - it "installs extensions/" do - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "very_simple_binary" - G - - expect(system_gem_path("gems/very_simple_binary-1.0")).to exist - binary_glob = system_gem_path("extensions/*/*/very_simple_binary-1.0") - expect(Dir.glob(binary_glob).first).to be - end - end - - describe "and BUNDLE_PATH is not writable" do - before do - bundle "config set --local path .bundle" - sudo "chmod ugo-w .bundle" - end - - after do - sudo "chmod ugo+w .bundle" - end - - it "installs" do - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", '1.0' - G - - expect(local_gem_path("gems/rack-1.0.0")).to exist - expect(the_bundle).to include_gems "rack 1.0" - end - - it "cleans up the tmpdirs generated" do - require "tmpdir" - Dir.glob("#{Dir.tmpdir}/bundler*").each do |tmpdir| - FileUtils.remove_entry_secure(tmpdir) - end - - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" - G - tmpdirs = Dir.glob("#{Dir.tmpdir}/bundler*") - - expect(tmpdirs).to be_empty - end - end - - describe "and GEM_HOME is not writable" do - it "installs" do - bundle "config set path.system true" - gem_home = tmp("sudo_gem_home") - sudo "mkdir -p #{gem_home}" - sudo "chmod ugo-w #{gem_home}" - - system_gems :bundler, :path => gem_home - - gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", '1.0' - G - - bundle :install, :env => { "GEM_HOME" => gem_home.to_s, "GEM_PATH" => nil } - expect(gem_home.join("bin/rackup")).to exist - expect(the_bundle).to include_gems "rack 1.0", :env => { "GEM_HOME" => gem_home.to_s, "GEM_PATH" => nil } - - sudo "rm -rf #{tmp("sudo_gem_home")}" - end - end - - describe "and root runs install" do - let(:warning) { "Don't run Bundler as root." } - - before do - gemfile %(source "#{file_uri_for(gem_repo1)}") - end - - it "warns against that" do - bundle :install, :sudo => :preserve_env - expect(err).to include(warning) - end - - context "when ENV['BUNDLE_SILENCE_ROOT_WARNING'] is set" do - it "skips the warning" do - bundle :install, :sudo => :preserve_env, :env => { "BUNDLE_SILENCE_ROOT_WARNING" => "true" } - expect(err).to_not include(warning) - end - end - - context "when silence_root_warning = false" do - it "warns against that" do - bundle :install, :sudo => :preserve_env, :env => { "BUNDLE_SILENCE_ROOT_WARNING" => "false" } - expect(err).to include(warning) - end - end - end -end |