summaryrefslogtreecommitdiff
path: root/spec/bundler/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'spec/bundler/runtime')
-rw-r--r--spec/bundler/runtime/env_helpers_spec.rb236
-rw-r--r--spec/bundler/runtime/executable_spec.rb132
-rw-r--r--spec/bundler/runtime/gem_tasks_spec.rb134
-rw-r--r--spec/bundler/runtime/inline_spec.rb573
-rw-r--r--spec/bundler/runtime/load_spec.rb44
-rw-r--r--spec/bundler/runtime/platform_spec.rb383
-rw-r--r--spec/bundler/runtime/require_spec.rb152
-rw-r--r--spec/bundler/runtime/requiring_spec.rb15
-rw-r--r--spec/bundler/runtime/self_management_spec.rb279
-rw-r--r--spec/bundler/runtime/setup_spec.rb1132
-rw-r--r--spec/bundler/runtime/with_unbundled_env_spec.rb270
11 files changed, 2403 insertions, 947 deletions
diff --git a/spec/bundler/runtime/env_helpers_spec.rb b/spec/bundler/runtime/env_helpers_spec.rb
new file mode 100644
index 0000000000..c4ebdd1fd2
--- /dev/null
+++ b/spec/bundler/runtime/env_helpers_spec.rb
@@ -0,0 +1,236 @@
+# frozen_string_literal: true
+
+RSpec.describe "env helpers" do
+ def bundle_exec_ruby(args, options = {})
+ build_bundler_context options.dup
+ bundle "exec '#{Gem.ruby}' #{args}", options
+ end
+
+ def build_bundler_context(options = {})
+ bundle "config set path vendor/bundle", options.dup
+ gemfile "source 'https://gem.repo1'"
+ bundle "install", options
+ end
+
+ def run_bundler_script(env, script)
+ system(env, "ruby", "-I#{lib_dir}", "-rbundler", script.to_s)
+ end
+
+ describe "Bundler.original_env" do
+ it "should return the PATH present before bundle was activated" do
+ create_file("source.rb", <<-RUBY)
+ print Bundler.original_env["PATH"]
+ RUBY
+ path = `getconf PATH`.strip + "#{File::PATH_SEPARATOR}/foo"
+ with_path_as(path) do
+ bundle_exec_ruby(bundled_app("source.rb").to_s)
+ expect(stdboth).to eq(path)
+ end
+ end
+
+ it "should return the GEM_PATH present before bundle was activated" do
+ create_file("source.rb", <<-RUBY)
+ print Bundler.original_env['GEM_PATH']
+ RUBY
+ gem_path = ENV["GEM_PATH"] + "#{File::PATH_SEPARATOR}/foo"
+ with_gem_path_as(gem_path) do
+ bundle_exec_ruby(bundled_app("source.rb").to_s)
+ expect(stdboth).to eq(gem_path)
+ end
+ end
+
+ it "works with nested bundle exec invocations", :ruby_repo do
+ create_file("exe.rb", <<-'RUBY')
+ count = ARGV.first.to_i
+ exit if count < 0
+ STDERR.puts "#{count} #{ENV["PATH"].end_with?("#{File::PATH_SEPARATOR}/foo")}"
+ if count == 2
+ ENV["PATH"] = "#{ENV["PATH"]}#{File::PATH_SEPARATOR}/foo"
+ end
+ exec(Gem.ruby, __FILE__, (count - 1).to_s)
+ RUBY
+ path = `getconf PATH`.strip + File::PATH_SEPARATOR + File.dirname(Gem.ruby)
+ with_path_as(path) do
+ build_bundler_context
+ bundle_exec_ruby("#{bundled_app("exe.rb")} 2")
+ end
+ expect(err).to eq <<-EOS.strip
+2 false
+1 true
+0 true
+ EOS
+ end
+
+ it "removes variables that bundler added", :ruby_repo do
+ original = ruby('puts ENV.to_a.map {|e| e.join("=") }.sort.join("\n")', artifice: "fail")
+ create_file("source.rb", <<-RUBY)
+ puts Bundler.original_env.to_a.map {|e| e.join("=") }.sort.join("\n")
+ RUBY
+ bundle_exec_ruby bundled_app("source.rb"), artifice: "fail"
+ expect(out).to eq original
+ end
+ end
+
+ describe "Bundler.unbundled_env" do
+ it "should delete BUNDLE_PATH" do
+ create_file("source.rb", <<-RUBY)
+ print Bundler.unbundled_env.has_key?('BUNDLE_PATH')
+ RUBY
+ ENV["BUNDLE_PATH"] = "./foo"
+ bundle_exec_ruby bundled_app("source.rb")
+ expect(stdboth).to include "false"
+ end
+
+ it "should remove absolute path to 'bundler/setup' from RUBYOPT even if it was present in original env" do
+ create_file("source.rb", <<-RUBY)
+ print Bundler.unbundled_env['RUBYOPT']
+ RUBY
+ setup_require = "-r#{lib_dir}/bundler/setup"
+ ENV["BUNDLER_ORIG_RUBYOPT"] = "-W2 #{setup_require} #{ENV["RUBYOPT"]}"
+ bundle_exec_ruby bundled_app("source.rb")
+ expect(stdboth).not_to include(setup_require)
+ end
+
+ it "should remove relative path to 'bundler/setup' from RUBYOPT even if it was present in original env" do
+ create_file("source.rb", <<-RUBY)
+ print Bundler.unbundled_env['RUBYOPT']
+ RUBY
+ ENV["BUNDLER_ORIG_RUBYOPT"] = "-W2 -rbundler/setup #{ENV["RUBYOPT"]}"
+ bundle_exec_ruby bundled_app("source.rb")
+ expect(stdboth).not_to include("-rbundler/setup")
+ end
+
+ it "should delete BUNDLER_SETUP even if it was present in original env" do
+ create_file("source.rb", <<-RUBY)
+ print Bundler.unbundled_env.has_key?('BUNDLER_SETUP')
+ RUBY
+ ENV["BUNDLER_ORIG_BUNDLER_SETUP"] = system_gem_path("gems/bundler-#{Bundler::VERSION}/lib/bundler/setup").to_s
+ bundle_exec_ruby bundled_app("source.rb")
+ expect(stdboth).to include "false"
+ end
+
+ it "should restore RUBYLIB", :ruby_repo do
+ create_file("source.rb", <<-RUBY)
+ print Bundler.unbundled_env['RUBYLIB']
+ RUBY
+ ENV["RUBYLIB"] = lib_dir.to_s + File::PATH_SEPARATOR + "/foo"
+ ENV["BUNDLER_ORIG_RUBYLIB"] = lib_dir.to_s + File::PATH_SEPARATOR + "/foo-original"
+ bundle_exec_ruby bundled_app("source.rb")
+ expect(stdboth).to include("/foo-original")
+ end
+
+ it "should restore the original MANPATH" do
+ create_file("source.rb", <<-RUBY)
+ print Bundler.unbundled_env['MANPATH']
+ RUBY
+ ENV["MANPATH"] = "/foo"
+ ENV["BUNDLER_ORIG_MANPATH"] = "/foo-original"
+ bundle_exec_ruby bundled_app("source.rb")
+ expect(stdboth).to include("/foo-original")
+ end
+ end
+
+ describe "Bundler.with_original_env" do
+ it "should set ENV to original_env in the block" do
+ expected = Bundler.original_env
+ actual = Bundler.with_original_env { ENV.to_hash }
+ expect(actual).to eq(expected)
+ end
+
+ it "should restore the environment after execution" do
+ Bundler.with_original_env do
+ ENV["FOO"] = "hello"
+ end
+
+ expect(ENV).not_to have_key("FOO")
+ end
+ end
+
+ describe "Bundler.with_unbundled_env" do
+ it "should set ENV to unbundled_env in the block" do
+ expected = Bundler.unbundled_env
+ actual = Bundler.with_unbundled_env { ENV.to_hash }
+ expect(actual).to eq(expected)
+ end
+
+ it "should restore the environment after execution" do
+ Bundler.with_unbundled_env do
+ ENV["FOO"] = "hello"
+ end
+
+ expect(ENV).not_to have_key("FOO")
+ end
+ end
+
+ describe "Bundler.original_system" do
+ before do
+ create_file("source.rb", <<-'RUBY')
+ Bundler.original_system("ruby", "-e", "exit(42) if ENV['BUNDLE_FOO'] == 'bar'")
+
+ exit $?.exitstatus
+ RUBY
+ end
+
+ it "runs system inside with_original_env" do
+ run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
+ expect($?.exitstatus).to eq(42)
+ end
+ end
+
+ describe "Bundler.unbundled_system" do
+ before do
+ create_file("source.rb", <<-'RUBY')
+ Bundler.unbundled_system("ruby", "-e", "exit(42) unless ENV['BUNDLE_FOO'] == 'bar'")
+
+ exit $?.exitstatus
+ RUBY
+ end
+
+ it "runs system inside with_unbundled_env" do
+ run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
+ expect($?.exitstatus).to eq(42)
+ end
+ end
+
+ describe "Bundler.original_exec" do
+ before do
+ create_file("source.rb", <<-'RUBY')
+ Process.fork do
+ exit Bundler.original_exec(%(test "\$BUNDLE_FOO" = "bar"))
+ end
+
+ _, status = Process.wait2
+
+ exit(status.exitstatus)
+ RUBY
+ end
+
+ it "runs exec inside with_original_env" do
+ skip "Fork not implemented" if Gem.win_platform?
+
+ run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
+ expect($?.exitstatus).to eq(0)
+ end
+ end
+
+ describe "Bundler.unbundled_exec" do
+ before do
+ create_file("source.rb", <<-'RUBY')
+ Process.fork do
+ exit Bundler.unbundled_exec(%(test "\$BUNDLE_FOO" = "bar"))
+ end
+
+ _, status = Process.wait2
+
+ exit(status.exitstatus)
+ RUBY
+ end
+
+ it "runs exec inside with_unbundled_env" do
+ skip "Fork not implemented" if Gem.win_platform?
+
+ run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
+ expect($?.exitstatus).to eq(1)
+ end
+ end
+end
diff --git a/spec/bundler/runtime/executable_spec.rb b/spec/bundler/runtime/executable_spec.rb
index 003be97cd6..89cee21b00 100644
--- a/spec/bundler/runtime/executable_spec.rb
+++ b/spec/bundler/runtime/executable_spec.rb
@@ -2,164 +2,133 @@
RSpec.describe "Running bin/* commands" do
before :each do
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
G
end
it "runs the bundled command when in the bundle" do
- bundle! "binstubs rack"
+ bundle "binstubs myrack"
- build_gem "rack", "2.0", :to_system => true do |s|
- s.executables = "rackup"
+ build_gem "myrack", "2.0", to_system: true do |s|
+ s.executables = "myrackup"
end
- gembin "rackup"
+ gembin "myrackup"
expect(out).to eq("1.0.0")
end
- it "allows the location of the gem stubs to be specified" do
- bundle! "binstubs rack", :path => "gbin"
+ it "allows the location of the gem stubs to be configured" do
+ bundle_config "bin gbin"
+ bundle "binstubs myrack"
expect(bundled_app("bin")).not_to exist
- expect(bundled_app("gbin/rackup")).to exist
+ expect(bundled_app("gbin/myrackup")).to exist
- gembin bundled_app("gbin/rackup")
+ gembin bundled_app("gbin/myrackup")
expect(out).to eq("1.0.0")
end
it "allows absolute paths as a specification of where to install bin stubs" do
- bundle! "binstubs rack", :path => tmp("bin")
+ bundle_config "bin #{tmp("bin")}"
+ bundle "binstubs myrack"
- gembin tmp("bin/rackup")
+ gembin tmp("bin/myrackup")
expect(out).to eq("1.0.0")
end
it "uses the default ruby install name when shebang is not specified" do
- bundle! "binstubs rack"
- expect(File.open("bin/rackup").gets).to eq("#!/usr/bin/env #{RbConfig::CONFIG["ruby_install_name"]}\n")
+ bundle "binstubs myrack"
+ expect(File.readlines(bundled_app("bin/myrackup")).first).to eq("#!/usr/bin/env #{RbConfig::CONFIG["ruby_install_name"]}\n")
end
it "allows the name of the shebang executable to be specified" do
- bundle! "binstubs rack", :shebang => "ruby-foo"
- expect(File.open("bin/rackup").gets).to eq("#!/usr/bin/env ruby-foo\n")
+ bundle "binstubs myrack", shebang: "ruby-foo"
+ expect(File.readlines(bundled_app("bin/myrackup")).first).to eq("#!/usr/bin/env ruby-foo\n")
end
it "runs the bundled command when out of the bundle" do
- bundle! "binstubs rack"
+ bundle "binstubs myrack"
- build_gem "rack", "2.0", :to_system => true do |s|
- s.executables = "rackup"
+ build_gem "myrack", "2.0", to_system: true do |s|
+ s.executables = "myrackup"
end
- Dir.chdir(tmp) do
- gembin "rackup"
- expect(out).to eq("1.0.0")
- end
+ gembin "myrackup", dir: tmp
+ expect(out).to eq("1.0.0")
end
it "works with gems in path" do
- build_lib "rack", :path => lib_path("rack") do |s|
- s.executables = "rackup"
+ build_lib "myrack", path: lib_path("myrack") do |s|
+ s.executables = "myrackup"
end
gemfile <<-G
- gem "rack", :path => "#{lib_path("rack")}"
+ source "https://gem.repo1"
+ gem "myrack", :path => "#{lib_path("myrack")}"
G
- bundle! "binstubs rack"
+ bundle "binstubs myrack"
- build_gem "rack", "2.0", :to_system => true do |s|
- s.executables = "rackup"
+ build_gem "myrack", "2.0", to_system: true do |s|
+ s.executables = "myrackup"
end
- gembin "rackup"
+ gembin "myrackup"
expect(out).to eq("1.0")
end
- it "creates a bundle binstub" do
- build_gem "bundler", Bundler::VERSION, :to_system => true do |s|
- s.executables = "bundle"
- end
-
+ it "does not create a bundle binstub" do
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
+ source "https://gem.repo1"
gem "bundler"
G
- bundle! "binstubs bundler"
-
- expect(bundled_app("bin/bundle")).to exist
- end
+ bundle "binstubs bundler"
- it "does not generate bin stubs if the option was not specified" do
- bundle! "install"
+ expect(bundled_app("bin/bundle")).not_to exist
- expect(bundled_app("bin/rackup")).not_to exist
+ expect(err).to include("Bundler itself does not use binstubs because its version is selected by RubyGems")
end
- it "allows you to stop installing binstubs", :bundler => "< 3" do
- bundle! "install --binstubs bin/"
- bundled_app("bin/rackup").rmtree
- bundle! "install --binstubs \"\""
-
- expect(bundled_app("bin/rackup")).not_to exist
-
- bundle! "config bin"
- expect(out).to include("You have not configured a value for `bin`")
- end
-
- it "remembers that the option was specified", :bundler => "< 3" do
- gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "activesupport"
- G
-
- bundle! :install, :binstubs => "bin"
-
- gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "activesupport"
- gem "rack"
- G
-
+ it "does not generate bin stubs if the option was not specified" do
bundle "install"
- expect(bundled_app("bin/rackup")).to exist
+ expect(bundled_app("bin/myrackup")).not_to exist
end
- it "rewrites bins on binstubs (to maintain backwards compatibility)" do
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ it "rewrites bins on binstubs with --force option" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
G
- create_file("bin/rackup", "OMG")
+ create_file("bin/myrackup", "OMG")
- bundle! "binstubs rack"
+ bundle "binstubs myrack", { force: true }
- expect(bundled_app("bin/rackup").read).to_not eq("OMG")
+ expect(bundled_app("bin/myrackup").read.strip).to_not eq("OMG")
end
it "use BUNDLE_GEMFILE gemfile for binstub" do
# context with bin/bundler w/ default Gemfile
- bundle! "binstubs bundler"
+ bundle "binstubs bundler"
# generate other Gemfile with executable gem
build_repo2 do
build_gem("bindir") {|s| s.executables = "foo" }
end
- create_file("OtherGemfile", <<-G)
- source "#{file_uri_for(gem_repo2)}"
+ gemfile("OtherGemfile", <<-G)
+ source "https://gem.repo2"
gem 'bindir'
G
# generate binstub for executable from non default Gemfile (other then bin/bundler version)
ENV["BUNDLE_GEMFILE"] = "OtherGemfile"
bundle "install"
- bundle! "binstubs bindir"
+ bundle "binstubs bindir"
# remove user settings
ENV["BUNDLE_GEMFILE"] = nil
@@ -167,7 +136,6 @@ RSpec.describe "Running bin/* commands" do
# run binstub for non default Gemfile
gembin "foo"
- expect(exitstatus).to eq(0) if exitstatus
expect(out).to eq("1.0")
end
end
diff --git a/spec/bundler/runtime/gem_tasks_spec.rb b/spec/bundler/runtime/gem_tasks_spec.rb
index 4760b6a749..b855142e60 100644
--- a/spec/bundler/runtime/gem_tasks_spec.rb
+++ b/spec/bundler/runtime/gem_tasks_spec.rb
@@ -1,28 +1,74 @@
# frozen_string_literal: true
RSpec.describe "require 'bundler/gem_tasks'" do
- before :each do
+ let(:define_local_gem_using_gem_tasks) do
bundled_app("foo.gemspec").open("w") do |f|
f.write <<-GEMSPEC
Gem::Specification.new do |s|
s.name = "foo"
+ s.version = "1.0"
+ s.summary = "dummy"
+ s.author = "Perry Mason"
end
GEMSPEC
end
+
bundled_app("Rakefile").open("w") do |f|
f.write <<-RAKEFILE
- $:.unshift("#{lib_dir}")
require "bundler/gem_tasks"
RAKEFILE
end
+
+ install_gemfile <<-G
+ source "https://gem.repo1"
+
+ gem "rake"
+ G
end
- it "includes the relevant tasks" do
- with_gem_path_as(Spec::Path.base_system_gems.to_s) do
- sys_exec "#{rake} -T", "RUBYOPT" => "-I#{lib_dir}"
+ let(:define_local_gem_with_extensions_using_gem_tasks_and_gemspec_dsl) do
+ bundled_app("foo.gemspec").open("w") do |f|
+ f.write <<-GEMSPEC
+ Gem::Specification.new do |s|
+ s.name = "foo"
+ s.version = "1.0"
+ s.summary = "dummy"
+ s.author = "Perry Mason"
+ s.extensions = "ext/extconf.rb"
+ end
+ GEMSPEC
+ end
+
+ bundled_app("Rakefile").open("w") do |f|
+ f.write <<-RAKEFILE
+ require "bundler/gem_tasks"
+ RAKEFILE
+ end
+
+ Dir.mkdir bundled_app("ext")
+
+ bundled_app("ext/extconf.rb").open("w") do |f|
+ f.write <<-EXTCONF
+ require "mkmf"
+ File.write("Makefile", dummy_makefile($srcdir).join)
+ EXTCONF
end
- expect(err).to eq("")
+ install_gemfile <<-G
+ source "https://gem.repo1"
+
+ gemspec
+
+ gem "rake"
+ G
+ end
+
+ it "includes the relevant tasks" do
+ define_local_gem_using_gem_tasks
+
+ in_bundled_app "rake -T"
+
+ expect(err).to be_empty
expected_tasks = [
"rake build",
"rake clean",
@@ -32,13 +78,81 @@ RSpec.describe "require 'bundler/gem_tasks'" do
]
tasks = out.lines.to_a.map {|s| s.split("#").first.strip }
expect(tasks & expected_tasks).to eq(expected_tasks)
- expect(exitstatus).to eq(0) if exitstatus
end
- it "adds 'pkg' to rake/clean's CLOBBER" do
- with_gem_path_as(Spec::Path.base_system_gems.to_s) do
- sys_exec! %(#{rake} -e 'load "Rakefile"; puts CLOBBER.inspect')
+ it "defines a working `rake install` task", :ruby_repo do
+ define_local_gem_using_gem_tasks
+
+ in_bundled_app "rake install"
+
+ expect(err).to be_empty
+
+ bundle "exec rake install"
+
+ expect(err).to be_empty
+ end
+
+ it "defines a working `rake install` task for local gems with extensions", :ruby_repo do
+ define_local_gem_with_extensions_using_gem_tasks_and_gemspec_dsl
+
+ bundle "exec rake install"
+
+ expect(err).to be_empty
+ end
+
+ context "rake build when path has spaces", :ruby_repo do
+ before do
+ define_local_gem_using_gem_tasks
+
+ spaced_bundled_app = tmp("bundled app")
+ FileUtils.cp_r bundled_app, spaced_bundled_app
+ bundle "exec rake build", dir: spaced_bundled_app
+ end
+
+ it "still runs successfully" do
+ expect(err).to be_empty
+ end
+ end
+
+ context "rake build when path has brackets", :ruby_repo do
+ before do
+ define_local_gem_using_gem_tasks
+
+ bracketed_bundled_app = tmp("bundled[app")
+ FileUtils.cp_r bundled_app, bracketed_bundled_app
+ bundle "exec rake build", dir: bracketed_bundled_app
+ end
+
+ it "still runs successfully" do
+ expect(err).to be_empty
+ end
+ end
+
+ context "bundle path configured locally" do
+ before do
+ define_local_gem_using_gem_tasks
+
+ bundle_config "path vendor/bundle"
end
+
+ it "works", :ruby_repo do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+
+ gem "rake"
+ G
+
+ bundle "exec rake -T"
+
+ expect(err).to be_empty
+ end
+ end
+
+ it "adds 'pkg' to rake/clean's CLOBBER" do
+ define_local_gem_using_gem_tasks
+
+ in_bundled_app %(rake -e 'load "Rakefile"; puts CLOBBER.inspect')
+
expect(out).to eq '["pkg"]'
end
end
diff --git a/spec/bundler/runtime/inline_spec.rb b/spec/bundler/runtime/inline_spec.rb
index 06be2ef83d..c6f9bbdbd7 100644
--- a/spec/bundler/runtime/inline_spec.rb
+++ b/spec/bundler/runtime/inline_spec.rb
@@ -2,10 +2,9 @@
RSpec.describe "bundler/inline#gemfile" do
def script(code, options = {})
- requires = ["#{lib_dir}/bundler/inline"]
- requires.unshift "#{spec_dir}/support/artifice/" + options.delete(:artifice) if options.key?(:artifice)
- requires = requires.map {|r| "require '#{r}'" }.join("\n")
- @out = ruby("#{requires}\n\n" + code, options)
+ options[:artifice] ||= "compact_index"
+ options[:env] ||= { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
+ ruby("require 'bundler/inline'\n\n" + code, options)
end
before :each do
@@ -28,7 +27,7 @@ RSpec.describe "bundler/inline#gemfile" do
s.write "lib/four.rb", "puts 'four'"
end
- build_lib "five", "1.0.0", :no_default => true do |s|
+ build_lib "five", "1.0.0", no_default: true do |s|
s.write "lib/mofive.rb", "puts 'five'"
end
@@ -48,6 +47,7 @@ RSpec.describe "bundler/inline#gemfile" do
it "requires the gems" do
script <<-RUBY
gemfile do
+ source "https://gem.repo1"
path "#{lib_path}" do
gem "two"
end
@@ -55,10 +55,10 @@ RSpec.describe "bundler/inline#gemfile" do
RUBY
expect(out).to eq("two")
- expect(exitstatus).to be_zero if exitstatus
- script <<-RUBY
+ script <<-RUBY, raise_on_error: false
gemfile do
+ source "https://gem.repo1"
path "#{lib_path}" do
gem "eleven"
end
@@ -72,53 +72,51 @@ RSpec.describe "bundler/inline#gemfile" do
script <<-RUBY
gemfile(true) do
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
end
RUBY
- expect(out).to include("Rack's post install message")
- expect(exitstatus).to be_zero if exitstatus
+ expect(out).to include("Myrack's post install message")
- script <<-RUBY, :artifice => "endpoint"
+ script <<-RUBY, artifice: "endpoint"
gemfile(true) do
- source "https://notaserver.com"
+ source "https://notaserver.test"
gem "activesupport", :require => true
end
RUBY
expect(out).to include("Installing activesupport")
- err.gsub! %r{(.*lib/sinatra/base\.rb:\d+: warning: constant ::Fixnum is deprecated$)}, ""
err_lines = err.split("\n")
- err_lines.reject!{|line| line =~ /\.rb:\d+: warning: / }
+ err_lines.reject! {|line| line =~ /\.rb:\d+: warning: / }
expect(err_lines).to be_empty
- expect(exitstatus).to be_zero if exitstatus
end
it "lets me use my own ui object" do
- script <<-RUBY, :artifice => "endpoint"
- require '#{lib_dir}/bundler'
- class MyBundlerUI < Bundler::UI::Silent
+ script <<-RUBY, artifice: "endpoint"
+ require 'bundler'
+ class MyBundlerUI < Bundler::UI::Shell
def confirm(msg, newline = nil)
puts "CONFIRMED!"
end
end
- gemfile(true, :ui => MyBundlerUI.new) do
- source "https://notaserver.com"
+ my_ui = MyBundlerUI.new
+ my_ui.level = "confirm"
+ gemfile(true, :ui => my_ui) do
+ source "https://notaserver.test"
gem "activesupport", :require => true
end
RUBY
expect(out).to eq("CONFIRMED!\nCONFIRMED!")
- expect(exitstatus).to be_zero if exitstatus
end
it "has an option for quiet installation" do
- script <<-RUBY, :artifice => "endpoint"
- require '#{lib_dir}/bundler/inline'
+ script <<-RUBY, artifice: "endpoint"
+ require 'bundler/inline'
gemfile(true, :quiet => true) do
- source "https://notaserver.com"
+ source "https://notaserver.test"
gem "activesupport", :require => true
end
RUBY
@@ -127,7 +125,7 @@ RSpec.describe "bundler/inline#gemfile" do
end
it "raises an exception if passed unknown arguments" do
- script <<-RUBY
+ script <<-RUBY, raise_on_error: false
gemfile(true, :arglebargle => true) do
path "#{lib_path}"
gem "two"
@@ -141,9 +139,10 @@ RSpec.describe "bundler/inline#gemfile" do
it "does not mutate the option argument" do
script <<-RUBY
- require '#{lib_dir}/bundler'
+ require 'bundler'
options = { :ui => Bundler::UI::Shell.new }
gemfile(false, options) do
+ source "https://gem.repo1"
path "#{lib_path}" do
gem "two"
end
@@ -152,22 +151,68 @@ RSpec.describe "bundler/inline#gemfile" do
RUBY
expect(out).to match("OKAY")
- expect(exitstatus).to be_zero if exitstatus
end
it "installs quietly if necessary when the install option is not set" do
script <<-RUBY
gemfile do
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
+ end
+
+ puts MYRACK
+ RUBY
+
+ expect(out).to eq("1.0.0")
+ expect(err).to be_empty
+ end
+
+ it "installs subdependencies quietly if necessary when the install option is not set" do
+ build_repo4 do
+ build_gem "myrack" do |s|
+ s.add_dependency "myrackdep"
+ end
+
+ build_gem "myrackdep", "1.0.0"
+ end
+
+ script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ gemfile do
+ source "https://gem.repo4"
+ gem "myrack"
+ end
+
+ require "myrackdep"
+ puts MYRACKDEP
+ RUBY
+
+ expect(out).to eq("1.0.0")
+ expect(err).to be_empty
+ end
+
+ it "installs subdependencies quietly if necessary when the install option is not set, and multiple sources used" do
+ build_repo4 do
+ build_gem "myrack" do |s|
+ s.add_dependency "myrackdep"
+ end
+
+ build_gem "myrackdep", "1.0.0"
+ end
+
+ script <<-RUBY, artifice: "compact_index_extra_api"
+ gemfile do
+ source "https://test.repo"
+ source "https://test.repo/extra" do
+ gem "myrack"
+ end
end
- puts RACK
+ require "myrackdep"
+ puts MYRACKDEP
RUBY
expect(out).to eq("1.0.0")
expect(err).to be_empty
- expect(exitstatus).to be_zero if exitstatus
end
it "installs quietly from git if necessary when the install option is not set" do
@@ -175,6 +220,7 @@ RSpec.describe "bundler/inline#gemfile" do
baz_ref = build_git("baz", "2.0.0").ref_for("HEAD")
script <<-RUBY
gemfile do
+ source "https://gem.repo1"
gem "foo", :git => #{lib_path("foo-1.0.0").to_s.dump}
gem "baz", :git => #{lib_path("baz-2.0.0").to_s.dump}, :ref => #{baz_ref.dump}
end
@@ -185,19 +231,20 @@ RSpec.describe "bundler/inline#gemfile" do
expect(out).to eq("1.0.0\n2.0.0")
expect(err).to be_empty
- expect(exitstatus).to be_zero if exitstatus
end
it "allows calling gemfile twice" do
script <<-RUBY
gemfile do
path "#{lib_path}" do
+ source "https://gem.repo1"
gem "two"
end
end
gemfile do
path "#{lib_path}" do
+ source "https://gem.repo1"
gem "four"
end
end
@@ -205,12 +252,118 @@ RSpec.describe "bundler/inline#gemfile" do
expect(out).to eq("two\nfour")
expect(err).to be_empty
- expect(exitstatus).to be_zero if exitstatus
+ end
+
+ it "doesn't reinstall already installed gems" do
+ system_gems "myrack-1.0.0"
+
+ script <<-RUBY
+ require 'bundler'
+ ui = Bundler::UI::Shell.new
+ ui.level = "confirm"
+
+ gemfile(true, ui: ui) do
+ source "https://gem.repo1"
+ gem "activesupport"
+ gem "myrack"
+ end
+ RUBY
+
+ expect(out).to include("Installing activesupport")
+ expect(out).not_to include("Installing myrack")
+ expect(err).to be_empty
+ end
+
+ it "installs gems in later gemfile calls" do
+ system_gems "myrack-1.0.0"
+
+ script <<-RUBY
+ require 'bundler'
+ ui = Bundler::UI::Shell.new
+ ui.level = "confirm"
+ gemfile(true, ui: ui) do
+ source "https://gem.repo1"
+ gem "myrack"
+ end
+
+ gemfile(true, ui: ui) do
+ source "https://gem.repo1"
+ gem "activesupport"
+ end
+ RUBY
+
+ expect(out).to include("Installing activesupport")
+ expect(out).not_to include("Installing myrack")
+ expect(err).to be_empty
+ end
+
+ it "doesn't reinstall already installed gems in later gemfile calls" do
+ system_gems "myrack-1.0.0"
+
+ script <<-RUBY
+ require 'bundler'
+ ui = Bundler::UI::Shell.new
+ ui.level = "confirm"
+ gemfile(true, ui: ui) do
+ source "https://gem.repo1"
+ gem "activesupport"
+ end
+
+ gemfile(true, ui: ui) do
+ source "https://gem.repo1"
+ gem "myrack"
+ end
+ RUBY
+
+ expect(out).to include("Installing activesupport")
+ expect(out).not_to include("Installing myrack")
+ expect(err).to be_empty
+ end
+
+ it "installs gems with native extensions in later gemfile calls" do
+ system_gems "myrack-1.0.0"
+
+ build_git "foo" do |s|
+ s.add_dependency "rake"
+ s.extensions << "Rakefile"
+ s.write "Rakefile", <<-RUBY
+ task :default do
+ path = File.expand_path("lib", __dir__)
+ FileUtils.mkdir_p(path)
+ File.open("\#{path}/foo.rb", "w") do |f|
+ f.puts "FOO = 'YES'"
+ end
+ end
+ RUBY
+ end
+
+ script <<-RUBY
+ require 'bundler'
+ ui = Bundler::UI::Shell.new
+ ui.level = "confirm"
+ gemfile(true, ui: ui) do
+ source "https://gem.repo1"
+ gem "myrack"
+ end
+
+ gemfile(true, ui: ui) do
+ source "https://gem.repo1"
+ gem "foo", :git => "#{lib_path("foo-1.0")}"
+ end
+
+ require 'foo'
+ puts FOO
+ puts $:.grep(/ext/)
+ RUBY
+
+ expect(out).to include("YES")
+ expect(out).to include(Pathname.glob(default_bundle_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s)
+ expect(err).to be_empty
end
it "installs inline gems when a Gemfile.lock is present" do
gemfile <<-G
- source "https://notaserver.com"
+ source "https://notaserver.test"
gem "rake"
G
@@ -227,54 +380,94 @@ RSpec.describe "bundler/inline#gemfile" do
rake
BUNDLED WITH
- 1.13.6
+ #{Bundler::VERSION}
G
- in_app_root do
- script <<-RUBY
- gemfile do
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
- end
+ script <<-RUBY
+ gemfile do
+ source "https://gem.repo1"
+ gem "myrack"
+ end
- puts RACK
- RUBY
- end
+ puts MYRACK
+ RUBY
+
+ expect(err).to be_empty
+ end
+
+ it "does not leak Gemfile.lock versions to the installation output" do
+ gemfile <<-G
+ source "https://notaserver.test"
+ gem "rake"
+ G
+
+ lockfile <<-G
+ GEM
+ remote: https://rubygems.org/
+ specs:
+ rake (11.3.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ rake
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ G
+ script <<-RUBY
+ gemfile(true) do
+ source "https://gem.repo1"
+ gem "rake", "#{rake_version}"
+ end
+ RUBY
+
+ expect(out).to include("Installing rake #{rake_version}")
+ expect(out).not_to include("was 11.3.0")
expect(err).to be_empty
- expect(exitstatus).to be_zero if exitstatus
end
it "installs inline gems when frozen is set" do
- script <<-RUBY, :env => { "BUNDLE_FROZEN" => "true" }
+ script <<-RUBY, env: { "BUNDLE_FROZEN" => "true", "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
+ gemfile do
+ source "https://gem.repo1"
+ gem "myrack"
+ end
+
+ puts MYRACK
+ RUBY
+
+ expect(last_command.stderr).to be_empty
+ end
+
+ it "installs inline gems when deployment is set" do
+ script <<-RUBY, env: { "BUNDLE_DEPLOYMENT" => "true", "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
gemfile do
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
end
- puts RACK
+ puts MYRACK
RUBY
expect(last_command.stderr).to be_empty
- expect(exitstatus).to be_zero if exitstatus
end
it "installs inline gems when BUNDLE_GEMFILE is set to an empty string" do
ENV["BUNDLE_GEMFILE"] = ""
- in_app_root do
- script <<-RUBY
- gemfile do
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
- end
+ script <<-RUBY
+ gemfile do
+ source "https://gem.repo1"
+ gem "myrack"
+ end
- puts RACK
- RUBY
- end
+ puts MYRACK
+ RUBY
expect(err).to be_empty
- expect(exitstatus).to be_zero if exitstatus
end
it "installs inline gems when BUNDLE_BIN is set" do
@@ -282,11 +475,11 @@ RSpec.describe "bundler/inline#gemfile" do
script <<-RUBY
gemfile do
- source "#{file_uri_for(gem_repo1)}"
- gem "rack" # has the rackup executable
+ source "https://gem.repo1"
+ gem "myrack" # has the myrackup executable
end
- puts RACK
+ puts MYRACK
RUBY
expect(last_command).to be_success
expect(out).to eq "1.0.0"
@@ -294,27 +487,265 @@ RSpec.describe "bundler/inline#gemfile" do
context "when BUNDLE_PATH is set" do
it "installs inline gems to the system path regardless" do
- script <<-RUBY, :env => { "BUNDLE_PATH" => "./vendor/inline" }
+ script <<-RUBY, env: { "BUNDLE_PATH" => "./vendor/inline", "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
gemfile(true) do
- source "file://#{gem_repo1}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
end
RUBY
expect(last_command).to be_success
- expect(system_gem_path("gems/rack-1.0.0")).to exist
+ expect(system_gem_path("gems/myrack-1.0.0")).to exist
end
end
it "skips platform warnings" do
- simulate_platform "ruby"
+ bundle_config "force_ruby_platform true"
+
+ script <<-RUBY
+ gemfile(true) do
+ source "https://gem.repo1"
+ gem "myrack", platform: :jruby
+ end
+ RUBY
+
+ expect(err).to be_empty
+ end
+
+ it "still installs if the application has `bundle package` no_install config set" do
+ bundle_config "no_install true"
+
+ script <<-RUBY
+ gemfile do
+ source "https://gem.repo1"
+ gem "myrack"
+ end
+ RUBY
+
+ expect(last_command).to be_success
+ expect(system_gem_path("gems/myrack-1.0.0")).to exist
+ end
+
+ it "preserves previous BUNDLE_GEMFILE value" do
+ ENV["BUNDLE_GEMFILE"] = ""
+ script <<-RUBY
+ gemfile do
+ source "https://gem.repo1"
+ gem "myrack"
+ end
+
+ puts "BUNDLE_GEMFILE is empty" if ENV["BUNDLE_GEMFILE"].empty?
+ system("#{Gem.ruby} -w -e '42'") # this should see original value of BUNDLE_GEMFILE
+ exit $?.exitstatus
+ RUBY
+
+ expect(last_command).to be_success
+ expect(out).to include("BUNDLE_GEMFILE is empty")
+ end
+
+ it "resets BUNDLE_GEMFILE to the empty string if it wasn't set previously" do
+ ENV["BUNDLE_GEMFILE"] = nil
+ script <<-RUBY
+ gemfile do
+ source "https://gem.repo1"
+ gem "myrack"
+ end
+
+ puts "BUNDLE_GEMFILE is empty" if ENV["BUNDLE_GEMFILE"].empty?
+ system("#{Gem.ruby} -w -e '42'") # this should see original value of BUNDLE_GEMFILE
+ exit $?.exitstatus
+ RUBY
+
+ expect(last_command).to be_success
+ expect(out).to include("BUNDLE_GEMFILE is empty")
+ end
+
+ it "does not error out if library requires optional dependencies" do
+ Dir.mkdir tmp("path_without_gemfile")
+
+ foo_code = <<~RUBY
+ begin
+ gem "bar"
+ rescue LoadError
+ end
+
+ puts "WIN"
+ RUBY
+
+ build_lib "foo", "1.0.0" do |s|
+ s.write "lib/foo.rb", foo_code
+ end
+
+ script <<-RUBY, dir: tmp("path_without_gemfile"), env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ gemfile do
+ source "https://gem.repo2"
+ path "#{lib_path}" do
+ gem "foo", require: false
+ end
+ end
+
+ require "foo"
+ RUBY
+
+ expect(out).to eq("WIN")
+ expect(err).to be_empty
+ end
+
+ it "does not load default timeout", rubygems: ">= 3.5.0" do
+ default_timeout_version = ruby "gem 'timeout', '< 999999'; require 'timeout'; puts Timeout::VERSION", raise_on_error: false
+ skip "timeout isn't a default gem" if default_timeout_version.empty?
+
+ build_repo4 do
+ build_gem "timeout", "999"
+ end
+
+ script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ require "bundler/inline"
+
+ gemfile(true) do
+ source "https://gem.repo4"
+
+ gem "timeout"
+ end
+ RUBY
+
+ expect(out).to include("Installing timeout 999")
+ end
+
+ it "does not upcase ENV" do
+ script <<-RUBY
+ require 'bundler/inline'
+
+ ENV['Test_Variable'] = 'value string'
+ puts("before: \#{ENV.each_key.select { |key| key.match?(/test_variable/i) }}")
+
+ gemfile do
+ source "https://gem.repo1"
+ end
+
+ puts("after: \#{ENV.each_key.select { |key| key.match?(/test_variable/i) }}")
+ RUBY
+
+ expect(out).to include("before: [\"Test_Variable\"]")
+ expect(out).to include("after: [\"Test_Variable\"]")
+ end
+
+ it "does not create a lockfile" do
+ script <<-RUBY
+ require 'bundler/inline'
+
+ gemfile do
+ source "https://gem.repo1"
+ end
+
+ puts Dir.glob("Gemfile.lock")
+ RUBY
+
+ expect(out).to be_empty
+ end
+ it "does not reset ENV" do
script <<-RUBY
+ require 'bundler/inline'
+
+ gemfile do
+ source "https://gem.repo1"
+
+ ENV['FOO'] = 'bar'
+ end
+
+ puts ENV['FOO']
+ RUBY
+
+ expect(out).to eq("bar")
+ end
+
+ it "does not load specified version of psych and stringio", :ruby_repo do
+ build_repo4 do
+ build_gem "psych", "999"
+ build_gem "stringio", "999"
+ end
+
+ script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ require "bundler/inline"
+
+ gemfile(true) do
+ source "https://gem.repo4"
+
+ gem "psych"
+ gem "stringio"
+ end
+ RUBY
+
+ expect(out).to include("Installing psych 999")
+ expect(out).to include("Installing stringio 999")
+ if Gem.respond_to?(:use_psych?) && Gem.use_psych?
+ expect(out).to include("The psych gem was resolved to 999")
+ expect(out).to include("The stringio gem was resolved to 999")
+ end
+ end
+
+ it "installs a conflicting default gem and non-default gems together" do
+ build_repo4 do
+ build_gem "securerandom", "999"
+ build_gem "myrack", "1.0.0"
+ end
+
+ script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ gemfile(true) do
+ source "https://gem.repo4"
+ gem "securerandom"
+ gem "myrack"
+ end
+
+ puts MYRACK
+ RUBY
+
+ expect(out).to include("Installing securerandom 999")
+ expect(out).to include("Installing myrack 1.0.0")
+ expect(out).to include("1.0.0")
+ expect(err).to be_empty
+ end
+
+ it "installs a conflicting default gem alongside git sources" do
+ build_repo4 do
+ build_gem "securerandom", "999"
+ end
+
+ build_git "foo", "1.0.0"
+
+ script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
gemfile(true) do
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", platform: :jruby
+ source "https://gem.repo4"
+ gem "securerandom"
+ gem "foo", :git => #{lib_path("foo-1.0.0").to_s.dump}
end
+
+ puts FOO
RUBY
+ expect(out).to include("Installing securerandom 999")
+ expect(out).to include("1.0.0")
expect(err).to be_empty
end
+
+ it "leaves a lockfile in the same directory as the inline script alone" do
+ install_gemfile <<~G
+ source "https://gem.repo1"
+ gem "foo"
+ G
+
+ original_lockfile = lockfile
+
+ script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
+ require "bundler/inline"
+
+ gemfile(true) do
+ source "https://gem.repo1"
+
+ gem "myrack"
+ end
+ RUBY
+
+ expect(lockfile).to eq(original_lockfile)
+ end
end
diff --git a/spec/bundler/runtime/load_spec.rb b/spec/bundler/runtime/load_spec.rb
index 7de67e247c..472cde87c5 100644
--- a/spec/bundler/runtime/load_spec.rb
+++ b/spec/bundler/runtime/load_spec.rb
@@ -3,18 +3,19 @@
RSpec.describe "Bundler.load" do
describe "with a gemfile" do
before(:each) do
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
G
+ allow(Bundler::SharedHelpers).to receive(:pwd).and_return(bundled_app)
end
it "provides a list of the env dependencies" do
- expect(Bundler.load.dependencies).to have_dep("rack", ">= 0")
+ expect(Bundler.load.dependencies).to have_dep("myrack", ">= 0")
end
it "provides a list of the resolved gems" do
- expect(Bundler.load.gems).to have_gem("rack-1.0.0", "bundler-#{Bundler::VERSION}")
+ expect(Bundler.load.gems).to have_gem("myrack-1.0.0", "bundler-#{Bundler::VERSION}")
end
it "ignores blank BUNDLE_GEMFILEs" do
@@ -27,19 +28,20 @@ RSpec.describe "Bundler.load" do
describe "with a gems.rb file" do
before(:each) do
- create_file "gems.rb", <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ gemfile "gems.rb", <<-G
+ source "https://gem.repo1"
+ gem "myrack"
G
- bundle! :install
+ bundle :install
+ allow(Bundler::SharedHelpers).to receive(:pwd).and_return(bundled_app)
end
it "provides a list of the env dependencies" do
- expect(Bundler.load.dependencies).to have_dep("rack", ">= 0")
+ expect(Bundler.load.dependencies).to have_dep("myrack", ">= 0")
end
it "provides a list of the resolved gems" do
- expect(Bundler.load.gems).to have_gem("rack-1.0.0", "bundler-#{Bundler::VERSION}")
+ expect(Bundler.load.gems).to have_gem("myrack-1.0.0", "bundler-#{Bundler::VERSION}")
end
end
@@ -66,24 +68,24 @@ RSpec.describe "Bundler.load" do
begin
expect { Bundler.load }.to raise_error(Bundler::GemfileNotFound)
ensure
- bundler_gemfile.rmtree if @remove_bundler_gemfile
+ FileUtils.rm_rf bundler_gemfile if @remove_bundler_gemfile
end
end
end
describe "when called twice" do
it "doesn't try to load the runtime twice" do
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
gem "activesupport", :group => :test
G
- ruby! <<-RUBY
- require "#{lib_dir}/bundler"
+ ruby <<-RUBY
+ require "bundler"
Bundler.setup :default
Bundler.require :default
- puts RACK
+ puts MYRACK
begin
require "activesupport"
rescue LoadError
@@ -97,11 +99,11 @@ RSpec.describe "Bundler.load" do
describe "not hurting brittle rubygems" do
it "does not inject #source into the generated YAML of the gem specs" do
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo1)}"
+ install_gemfile <<-G
+ source "https://gem.repo1"
gem "activerecord"
G
-
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
Bundler.load.specs.each do |spec|
expect(spec.to_yaml).not_to match(/^\s+source:/)
expect(spec.to_yaml).not_to match(/^\s+groups:/)
diff --git a/spec/bundler/runtime/platform_spec.rb b/spec/bundler/runtime/platform_spec.rb
index f7e93eacf1..6d96758956 100644
--- a/spec/bundler/runtime/platform_spec.rb
+++ b/spec/bundler/runtime/platform_spec.rb
@@ -3,21 +3,21 @@
RSpec.describe "Bundler.setup with multi platform stuff" do
it "raises a friendly error when gems are missing locally" do
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
G
lockfile <<-G
GEM
- remote: #{file_uri_for(gem_repo1)}/
+ remote: https://gem.repo1/
specs:
- rack (1.0)
+ myrack (1.0)
PLATFORMS
#{local_tag}
DEPENDENCIES
- rack
+ myrack
G
ruby <<-R
@@ -35,7 +35,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
it "will resolve correctly on the current platform when the lockfile was targeted for a different one" do
lockfile <<-G
GEM
- remote: #{file_uri_for(gem_repo1)}/
+ remote: https://gem.repo1/
specs:
nokogiri (1.4.2-java)
weakling (= 0.0.3)
@@ -48,19 +48,147 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
nokogiri
G
- simulate_platform "x86-darwin-10"
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo1)}"
+ simulate_platform "x86-darwin-10" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "nokogiri"
+ G
+
+ expect(the_bundle).to include_gems "nokogiri 1.4.2"
+ end
+ end
+
+ it "will keep both platforms when both ruby and a specific ruby platform are locked and the bundle is unlocked" do
+ build_repo4 do
+ build_gem "nokogiri", "1.11.1" do |s|
+ s.add_dependency "mini_portile2", "~> 2.5.0"
+ s.add_dependency "racca", "~> 1.5.2"
+ end
+
+ build_gem "nokogiri", "1.11.1" do |s|
+ s.platform = Bundler.local_platform
+ s.add_dependency "racca", "~> 1.4"
+ end
+
+ build_gem "mini_portile2", "2.5.0"
+ build_gem "racca", "1.5.2"
+ end
+
+ checksums = checksums_section do |c|
+ c.checksum gem_repo4, "mini_portile2", "2.5.0"
+ c.checksum gem_repo4, "nokogiri", "1.11.1"
+ c.checksum gem_repo4, "nokogiri", "1.11.1", Bundler.local_platform
+ c.checksum gem_repo4, "racca", "1.5.2"
+ end
+
+ good_lockfile = <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ mini_portile2 (2.5.0)
+ nokogiri (1.11.1)
+ mini_portile2 (~> 2.5.0)
+ racca (~> 1.5.2)
+ nokogiri (1.11.1-#{Bundler.local_platform})
+ racca (~> 1.4)
+ racca (1.5.2)
+
+ PLATFORMS
+ #{lockfile_platforms("ruby")}
+
+ DEPENDENCIES
+ nokogiri (~> 1.11)
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ gemfile <<-G
+ source "https://gem.repo4"
+ gem "nokogiri", "~> 1.11"
+ G
+
+ lockfile good_lockfile
+
+ bundle "update nokogiri"
+
+ expect(lockfile).to eq(good_lockfile)
+ end
+
+ it "will not try to install platform specific gems when they don't match the current ruby if locked only to ruby" do
+ build_repo4 do
+ build_gem "nokogiri", "1.11.1"
+
+ build_gem "nokogiri", "1.11.1" do |s|
+ s.platform = Bundler.local_platform
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo4"
gem "nokogiri"
G
- expect(the_bundle).to include_gems "nokogiri 1.4.2"
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ nokogiri (1.11.1)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ nokogiri
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install"
+
+ expect(out).to include("Fetching nokogiri 1.11.1")
+ expect(the_bundle).to include_gems "nokogiri 1.11.1"
+ expect(the_bundle).not_to include_gems "nokogiri 1.11.1 #{Bundler.local_platform}"
+ end
+
+ it "will use the java platform if both generic java and generic ruby platforms are locked", :jruby_only do
+ gemfile <<-G
+ source "https://gem.repo1"
+ gem "nokogiri"
+ G
+
+ lockfile <<-G
+ GEM
+ remote: https://gem.repo1/
+ specs:
+ nokogiri (1.4.2)
+ nokogiri (1.4.2-java)
+ weakling (>= 0.0.3)
+ weakling (0.0.3)
+
+ PLATFORMS
+ java
+ ruby
+
+ DEPENDENCIES
+ nokogiri
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ G
+
+ bundle "install"
+
+ expect(out).to include("Fetching nokogiri 1.4.2 (java)")
+ expect(the_bundle).to include_gems "nokogiri 1.4.2 java"
end
it "will add the resolve for the current platform" do
lockfile <<-G
GEM
- remote: #{file_uri_for(gem_repo1)}/
+ remote: https://gem.repo1/
specs:
nokogiri (1.4.2-java)
weakling (= 0.0.3)
@@ -73,65 +201,207 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
nokogiri
G
- simulate_platform "x86-darwin-100"
+ simulate_platform "x86-darwin-100" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "nokogiri"
+ gem "platform_specific"
+ G
+
+ expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 x86-darwin-100"
+ end
+ end
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo1)}"
+ it "allows specifying only-ruby-platform on jruby", :jruby_only do
+ install_gemfile <<-G
+ source "https://gem.repo1"
gem "nokogiri"
gem "platform_specific"
G
- expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 x86-darwin-100"
+ bundle_config "force_ruby_platform true"
+
+ bundle "install"
+
+ expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 ruby"
end
it "allows specifying only-ruby-platform" do
- simulate_platform "java"
+ gemfile <<-G
+ source "https://gem.repo1"
+ gem "nokogiri"
+ gem "platform_specific"
+ G
+
+ bundle_config "force_ruby_platform true"
+
+ bundle "install"
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo1)}"
+ expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 ruby"
+ end
+
+ it "allows specifying only-ruby-platform even if the lockfile is locked to a specific compatible platform" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
gem "nokogiri"
gem "platform_specific"
G
- bundle! "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
+
+ bundle "install"
+
+ expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 ruby"
+ end
- bundle! "install"
+ it "doesn't pull platform specific gems on truffleruby", :truffleruby_only do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "platform_specific"
+ G
- expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 RUBY"
+ expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
+ end
+
+ it "doesn't pull platform specific gems on truffleruby (except when whitelisted) even if lockfile was generated with an older version that declared ruby as platform", :truffleruby_only do
+ gemfile <<-G
+ source "https://gem.repo1"
+ gem "platform_specific"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo1/
+ specs:
+ platform_specific (1.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ platform_specific
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install"
+
+ expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
+
+ simulate_platform "x86_64-linux" do
+ build_repo4 do
+ build_gem "libv8"
+
+ build_gem "libv8" do |s|
+ s.platform = "x86_64-linux"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo4"
+ gem "libv8"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ libv8 (1.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ libv8
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install"
+
+ expect(the_bundle).to include_gems "libv8 1.0 x86_64-linux"
+ end
+ end
+
+ it "doesn't pull platform specific gems on truffleruby, even if lockfile only includes those", :truffleruby_only do
+ gemfile <<-G
+ source "https://gem.repo1"
+ gem "platform_specific"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo1/
+ specs:
+ platform_specific (1.0-x86-darwin-100)
+
+ PLATFORMS
+ x86-darwin-100
+
+ DEPENDENCIES
+ platform_specific
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install"
+
+ expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
+ end
+
+ it "pulls platform specific gems correctly on musl" do
+ build_repo4 do
+ build_gem "nokogiri", "1.13.8" do |s|
+ s.platform = "aarch64-linux"
+ end
+ end
+
+ simulate_platform "aarch64-linux-musl" do
+ install_gemfile <<-G, verbose: true
+ source "https://gem.repo4"
+ gem "nokogiri"
+ G
+ end
+
+ expect(out).to include("Fetching nokogiri 1.13.8 (aarch64-linux)")
end
it "allows specifying only-ruby-platform on windows with dependency platforms" do
- simulate_windows do
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "nokogiri", :platforms => [:mingw, :mswin, :x64_mingw, :jruby]
+ simulate_platform "x86-mswin32" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "nokogiri", :platforms => [:windows, :jruby]
gem "platform_specific"
G
- bundle! "config set force_ruby_platform true"
+ bundle_config "force_ruby_platform true"
- bundle! "install"
+ bundle "install"
- expect(the_bundle).to include_gems "platform_specific 1.0 RUBY"
+ expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
+ expect(the_bundle).to not_include_gems "nokogiri"
end
end
it "allows specifying only-ruby-platform on windows with gemspec dependency" do
- build_lib("foo", "1.0", :path => ".") do |s|
- s.add_dependency "rack"
+ build_lib("foo", "1.0", path: bundled_app) do |s|
+ s.add_dependency "myrack"
end
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
+ source "https://gem.repo1"
gemspec
G
- bundle! :lock
+ bundle :lock
- simulate_windows do
- bundle! "config set force_ruby_platform true"
- bundle! "install"
+ simulate_platform "x86-mswin32" do
+ bundle_config "force_ruby_platform true"
+ bundle "install"
- expect(the_bundle).to include_gems "rack 1.0"
+ expect(the_bundle).to include_gems "myrack 1.0"
end
end
@@ -141,29 +411,58 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
s.add_dependency "platform_specific"
end
end
- simulate_windows x64_mingw do
+ simulate_platform "x64-mingw-ucrt" do
lockfile <<-L
GEM
- remote: #{file_uri_for(gem_repo2)}/
+ remote: https://gem.repo2/
specs:
platform_specific (1.0-x86-mingw32)
requires_platform_specific (1.0)
platform_specific
PLATFORMS
- x64-mingw32
+ x64-mingw-ucrt
x86-mingw32
DEPENDENCIES
requires_platform_specific
L
- install_gemfile! <<-G, :verbose => true
- source "#{file_uri_for(gem_repo2)}"
+ install_gemfile <<-G, verbose: true
+ source "https://gem.repo2"
gem "requires_platform_specific"
G
- expect(the_bundle).to include_gem "platform_specific 1.0 x64-mingw32"
+ expect(out).to include("lockfile does not have all gems needed for the current platform")
+ expect(the_bundle).to include_gem "platform_specific 1.0 x64-mingw-ucrt"
+ end
+ end
+
+ %w[x86-mswin32 x64-mswin64 x86-mingw32 x64-mingw-ucrt aarch64-mingw-ucrt].each do |platform|
+ it "allows specifying platform windows on #{platform} platform" do
+ simulate_platform platform do
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo1/
+ specs:
+ platform_specific (1.0-#{platform})
+ requires_platform_specific (1.0)
+ platform_specific
+
+ PLATFORMS
+ #{platform}
+
+ DEPENDENCIES
+ requires_platform_specific
+ L
+
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "platform_specific", :platforms => [:windows]
+ G
+
+ expect(the_bundle).to include_gems "platform_specific 1.0 #{platform}"
+ end
end
end
end
diff --git a/spec/bundler/runtime/require_spec.rb b/spec/bundler/runtime/require_spec.rb
index 490b8c7631..46613286d2 100644
--- a/spec/bundler/runtime/require_spec.rb
+++ b/spec/bundler/runtime/require_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe "Bundler.require" do
s.write "lib/four.rb", "puts 'four'"
end
- build_lib "five", "1.0.0", :no_default => true do |s|
+ build_lib "five", "1.0.0", no_default: true do |s|
s.write "lib/mofive.rb", "puts 'five'"
end
@@ -46,6 +46,7 @@ RSpec.describe "Bundler.require" do
end
gemfile <<-G
+ source "https://gem.repo1"
path "#{lib_path}" do
gem "one", :group => :bar, :require => %w[baz qux]
gem "two"
@@ -112,16 +113,15 @@ RSpec.describe "Bundler.require" do
it "raises an exception if a require is specified but the file does not exist" do
gemfile <<-G
+ source "https://gem.repo1"
path "#{lib_path}" do
gem "two", :require => 'fail'
end
G
- load_error_run <<-R, "fail"
- Bundler.require
- R
+ run "Bundler.require", raise_on_error: false
- expect(err_without_deprecations).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to include("cannot load such file -- fail")
end
it "displays a helpful message if the required gem throws an error" do
@@ -130,12 +130,13 @@ RSpec.describe "Bundler.require" do
end
gemfile <<-G
+ source "https://gem.repo1"
path "#{lib_path}" do
gem "faulty"
end
G
- run "Bundler.require"
+ run "Bundler.require", raise_on_error: false
expect(err).to match("error while trying to load the gem 'faulty'")
expect(err).to match("Gem Internal Error Message")
end
@@ -146,21 +147,15 @@ RSpec.describe "Bundler.require" do
end
gemfile <<-G
+ source "https://gem.repo1"
path "#{lib_path}" do
gem "loadfuuu"
end
G
- cmd = <<-RUBY
- begin
- Bundler.require
- rescue LoadError => e
- $stderr.puts "ZOMG LOAD ERROR: \#{e.message}"
- end
- RUBY
- run(cmd)
+ run "Bundler.require", raise_on_error: false
- expect(err_without_deprecations).to eq("ZOMG LOAD ERROR: cannot load such file -- load-bar")
+ expect(err_without_deprecations).to include("cannot load such file -- load-bar")
end
describe "with namespaced gems" do
@@ -168,11 +163,11 @@ RSpec.describe "Bundler.require" do
build_lib "jquery-rails", "1.0.0" do |s|
s.write "lib/jquery/rails.rb", "puts 'jquery/rails'"
end
- lib_path("jquery-rails-1.0.0/lib/jquery-rails.rb").rmtree
end
it "requires gem names that are namespaced" do
gemfile <<-G
+ source "https://gem.repo1"
path '#{lib_path}' do
gem 'jquery-rails'
end
@@ -183,17 +178,19 @@ RSpec.describe "Bundler.require" do
end
it "silently passes if the require fails" do
- build_lib "bcrypt-ruby", "1.0.0", :no_default => true do |s|
+ build_lib "bcrypt-ruby", "1.0.0", no_default: true do |s|
s.write "lib/brcrypt.rb", "BCrypt = '1.0.0'"
end
gemfile <<-G
+ source "https://gem.repo1"
+
path "#{lib_path}" do
gem "bcrypt-ruby"
end
G
cmd = <<-RUBY
- require '#{lib_dir}/bundler'
+ require 'bundler'
Bundler.require
RUBY
ruby(cmd)
@@ -203,15 +200,15 @@ RSpec.describe "Bundler.require" do
it "does not mangle explicitly given requires" do
gemfile <<-G
+ source "https://gem.repo1"
path "#{lib_path}" do
gem 'jquery-rails', :require => 'jquery-rails'
end
G
- load_error_run <<-R, "jquery-rails"
- Bundler.require
- R
- expect(err_without_deprecations).to eq("ZOMG LOAD ERROR")
+ run "Bundler.require", raise_on_error: false
+
+ expect(err_without_deprecations).to include("cannot load such file -- jquery-rails")
end
it "handles the case where regex fails" do
@@ -220,45 +217,32 @@ RSpec.describe "Bundler.require" do
end
gemfile <<-G
+ source "https://gem.repo1"
path "#{lib_path}" do
gem "load-fuuu"
end
G
- cmd = <<-RUBY
- begin
- Bundler.require
- rescue LoadError => e
- $stderr.puts "ZOMG LOAD ERROR" if e.message.include?("Could not open library 'libfuuu-1.0'")
- end
- RUBY
- run(cmd)
+ run "Bundler.require", raise_on_error: false
- expect(err_without_deprecations).to eq("ZOMG LOAD ERROR")
+ expect(err_without_deprecations).to include("libfuuu-1.0").and include("cannot open shared object file")
end
it "doesn't swallow the error when the library has an unrelated error" do
build_lib "load-fuuu", "1.0.0" do |s|
s.write "lib/load/fuuu.rb", "raise LoadError.new(\"cannot load such file -- load-bar\")"
end
- lib_path("load-fuuu-1.0.0/lib/load-fuuu.rb").rmtree
gemfile <<-G
+ source "https://gem.repo1"
path "#{lib_path}" do
gem "load-fuuu"
end
G
- cmd = <<-RUBY
- begin
- Bundler.require
- rescue LoadError => e
- $stderr.puts "ZOMG LOAD ERROR: \#{e.message}"
- end
- RUBY
- run(cmd)
+ run "Bundler.require", raise_on_error: false
- expect(err_without_deprecations).to eq("ZOMG LOAD ERROR: cannot load such file -- load-bar")
+ expect(err_without_deprecations).to include("cannot load such file -- load-bar")
end
end
@@ -302,6 +286,7 @@ RSpec.describe "Bundler.require" do
it "works when the gems are in the Gemfile in the correct order" do
gemfile <<-G
+ source "https://gem.repo1"
path "#{lib_path}" do
gem "two"
gem "one"
@@ -314,12 +299,13 @@ RSpec.describe "Bundler.require" do
describe "a gem with different requires for different envs" do
before(:each) do
- build_gem "multi_gem", :to_bundle => true do |s|
+ build_gem "multi_gem", to_bundle: true do |s|
s.write "lib/one.rb", "puts 'ONE'"
s.write "lib/two.rb", "puts 'TWO'"
end
install_gemfile <<-G
+ source "https://gem.repo1"
gem "multi_gem", :require => "one", :group => :one
gem "multi_gem", :require => "two", :group => :two
G
@@ -343,6 +329,7 @@ RSpec.describe "Bundler.require" do
it "fails when the gems are in the Gemfile in the wrong order" do
gemfile <<-G
+ source "https://gem.repo1"
path "#{lib_path}" do
gem "one"
gem "two"
@@ -355,30 +342,30 @@ RSpec.describe "Bundler.require" do
describe "with busted gems" do
it "should be busted" do
- build_gem "busted_require", :to_bundle => true do |s|
+ build_gem "busted_require", to_bundle: true do |s|
s.write "lib/busted_require.rb", "require 'no_such_file_omg'"
end
install_gemfile <<-G
+ source "https://gem.repo1"
gem "busted_require"
G
- load_error_run <<-R, "no_such_file_omg"
- Bundler.require
- R
- expect(err_without_deprecations).to eq("ZOMG LOAD ERROR")
+ run "Bundler.require", raise_on_error: false
+
+ expect(err_without_deprecations).to include("cannot load such file -- no_such_file_omg")
end
end
end
it "does not load rubygems gemspecs that are used" do
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
G
- run! <<-R
- path = File.join(Gem.dir, "specifications", "rack-1.0.0.gemspec")
+ run <<-R
+ path = File.join(Gem.dir, "specifications", "myrack-1.0.0.gemspec")
contents = File.read(path)
contents = contents.lines.to_a.insert(-2, "\n raise 'broken gemspec'\n").join
File.open(path, "w") do |f|
@@ -386,7 +373,7 @@ RSpec.describe "Bundler.require" do
end
R
- run! <<-R
+ run <<-R
Bundler.require
puts "WIN"
R
@@ -397,11 +384,12 @@ RSpec.describe "Bundler.require" do
it "does not load git gemspecs that are used" do
build_git "foo"
- install_gemfile! <<-G
+ install_gemfile <<-G
+ source "https://gem.repo1"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
- run! <<-R
+ run <<-R
path = Gem.loaded_specs["foo"].loaded_from
contents = File.read(path)
contents = contents.lines.to_a.insert(-2, "\n raise 'broken gemspec'\n").join
@@ -410,7 +398,47 @@ RSpec.describe "Bundler.require" do
end
R
- run! <<-R
+ run <<-R
+ Bundler.require
+ puts "WIN"
+ R
+
+ expect(out).to eq("WIN")
+ end
+
+ it "does not load plugins" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ create_file "plugins/rubygems_plugin.rb", "puts 'FAIL'"
+
+ run <<~R, env: { "RUBYLIB" => rubylib.unshift(bundled_app("plugins").to_s).join(File::PATH_SEPARATOR) }
+ Bundler.require
+ puts "WIN"
+ R
+
+ expect(out).to eq("WIN")
+ end
+
+ it "does not extract gemspecs from application cache packages" do
+ gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ bundle :cache
+
+ path = cached_gem("myrack-1.0.0")
+
+ run <<-R
+ File.open("#{path}", "w") do |f|
+ f.write "broken package"
+ end
+ R
+
+ run <<-R
Bundler.require
puts "WIN"
R
@@ -422,13 +450,13 @@ end
RSpec.describe "Bundler.require with platform specific dependencies" do
it "does not require the gems that are pinned to other platforms" do
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
+ source "https://gem.repo1"
platforms :#{not_local_tag} do
- gem "fail", :require => "omgomg"
+ gem "platform_specific", :require => "omgomg"
end
- gem "rack", "1.0.0"
+ gem "myrack", "1.0.0"
G
run "Bundler.require"
@@ -437,14 +465,14 @@ RSpec.describe "Bundler.require with platform specific dependencies" do
it "requires gems pinned to multiple platforms, including the current one" do
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
+ source "https://gem.repo1"
platforms :#{not_local_tag}, :#{local_tag} do
- gem "rack", :require => "rack"
+ gem "myrack", :require => "myrack"
end
G
- run "Bundler.require; puts RACK"
+ run "Bundler.require; puts MYRACK"
expect(out).to eq("1.0.0")
expect(err).to be_empty
diff --git a/spec/bundler/runtime/requiring_spec.rb b/spec/bundler/runtime/requiring_spec.rb
new file mode 100644
index 0000000000..f0e0aeacaf
--- /dev/null
+++ b/spec/bundler/runtime/requiring_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+RSpec.describe "Requiring bundler" do
+ it "takes care of requiring rubygems when entrypoint is bundler/setup" do
+ sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler/setup -e'puts true'", env: { "RUBYOPT" => "--disable=gems" })
+
+ expect(stdboth).to eq("true")
+ end
+
+ it "takes care of requiring rubygems when requiring just bundler" do
+ sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler -e'puts true'", env: { "RUBYOPT" => "--disable=gems" })
+
+ expect(stdboth).to eq("true")
+ end
+end
diff --git a/spec/bundler/runtime/self_management_spec.rb b/spec/bundler/runtime/self_management_spec.rb
new file mode 100644
index 0000000000..176c2a3121
--- /dev/null
+++ b/spec/bundler/runtime/self_management_spec.rb
@@ -0,0 +1,279 @@
+# frozen_string_literal: true
+
+RSpec.describe "Self management" do
+ describe "auto switching" do
+ let(:previous_minor) do
+ "9.3.0"
+ end
+
+ let(:current_version) do
+ "9.4.0"
+ end
+
+ before do
+ build_repo4 do
+ build_bundler previous_minor
+
+ build_bundler current_version
+
+ build_gem "myrack", "1.0.0"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo4"
+
+ gem "myrack"
+ G
+
+ pristine_system_gems "bundler-#{current_version}"
+ end
+
+ it "installs locked version when using system path and uses it" do
+ lockfile_bundled_with(previous_minor)
+
+ bundle_config "path.system true"
+ bundle "install"
+ expect(out).to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+
+ # It uninstalls the older system bundler
+ bundle "clean --force", artifice: nil
+ expect(out).to eq("Removing bundler (#{current_version})")
+
+ # App now uses locked version
+ bundle "-v", artifice: nil
+ expect(out).to eq(previous_minor)
+
+ # ruby-core test setup has always "lib" in $LOAD_PATH so `require "bundler/setup"` always activate the local version rather than using RubyGems gem activation stuff
+ unless ruby_core?
+ # App now uses locked version, even when not using the CLI directly
+ file = bundled_app("bin/bundle_version.rb")
+ create_file file, <<-RUBY
+ #!#{Gem.ruby}
+ require 'bundler/setup'
+ puts '#{previous_minor}'
+ RUBY
+ file.chmod(0o777)
+ cmd = Gem.win_platform? ? "#{Gem.ruby} bin/bundle_version.rb" : "bin/bundle_version.rb"
+ in_bundled_app cmd
+ expect(out).to eq(previous_minor)
+ end
+
+ # Subsequent installs use the locked version without reinstalling
+ bundle "install --verbose", artifice: nil
+ expect(out).to include("Using bundler #{previous_minor}")
+ expect(out).not_to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ end
+
+ it "installs locked version when using local path and uses it" do
+ lockfile_bundled_with(previous_minor)
+
+ bundle_config "path vendor/bundle"
+ bundle "install"
+ expect(out).to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ expect(vendored_gems("gems/bundler-#{previous_minor}")).to exist
+
+ # It does not uninstall the locked bundler
+ bundle "clean"
+ expect(out).to be_empty
+
+ # App now uses locked version
+ bundle "-v"
+ expect(out).to eq(previous_minor)
+
+ # Preserves original gem home when auto-switching
+ bundle "exec ruby -e 'puts Bundler.original_env[\"GEM_HOME\"]'"
+ expect(out).to eq(ENV["GEM_HOME"])
+
+ # ruby-core test setup has always "lib" in $LOAD_PATH so `require "bundler/setup"` always activate the local version rather than using RubyGems gem activation stuff
+ unless ruby_core?
+ # App now uses locked version, even when not using the CLI directly
+ file = bundled_app("bin/bundle_version.rb")
+ create_file file, <<-RUBY
+ #!#{Gem.ruby}
+ require 'bundler/setup'
+ puts '#{previous_minor}'
+ RUBY
+ file.chmod(0o777)
+ cmd = Gem.win_platform? ? "#{Gem.ruby} bin/bundle_version.rb" : "bin/bundle_version.rb"
+ in_bundled_app cmd
+ expect(out).to eq(previous_minor)
+ end
+
+ # Subsequent installs use the locked version without reinstalling
+ bundle "install --verbose"
+ expect(out).to include("Using bundler #{previous_minor}")
+ expect(out).not_to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ end
+
+ it "installs locked version when using deployment option and uses it" do
+ lockfile_bundled_with(previous_minor)
+
+ bundle_config "deployment true"
+ bundle "install"
+ expect(out).to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ expect(vendored_gems("gems/bundler-#{previous_minor}")).to exist
+
+ # It does not uninstall the locked bundler
+ bundle "clean"
+ expect(out).to be_empty
+
+ # App now uses locked version
+ bundle "-v"
+ expect(out).to eq(previous_minor)
+
+ # Subsequent installs use the locked version without reinstalling
+ bundle "install --verbose"
+ expect(out).to include("Using bundler #{previous_minor}")
+ expect(out).not_to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ end
+
+ it "does not try to install a development version" do
+ lockfile_bundled_with("#{previous_minor}.dev")
+
+ bundle "install --verbose"
+ expect(out).not_to match(/restarting using that version/)
+
+ bundle "-v"
+ expect(out).to eq(current_version)
+ end
+
+ it "does not try to install when --local is passed" do
+ lockfile_bundled_with(previous_minor)
+ system_gems "myrack-1.0.0", path: local_gem_path
+
+ bundle "install --local"
+ expect(out).not_to match(/Installing Bundler/)
+
+ bundle "-v"
+ expect(out).to eq(current_version)
+ end
+
+ it "shows a discrete message if locked bundler does not exist" do
+ missing_minor = "#{current_version[0]}.999.999"
+
+ lockfile_bundled_with(missing_minor)
+
+ bundle "install"
+ expect(err).to eq("Your lockfile is locked to a version of bundler (#{missing_minor}) that doesn't exist at https://rubygems.org/. Going on using #{current_version}")
+
+ bundle "-v"
+ expect(out).to eq(current_version)
+ end
+
+ it "installs BUNDLE_VERSION version when using bundle config version x.y.z" do
+ lockfile_bundled_with(current_version)
+
+ bundle_config "version #{previous_minor}"
+ bundle "install"
+ expect(out).to include("Bundler #{current_version} is running, but your configuration was #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+
+ bundle "-v"
+ expect(out).to eq(previous_minor)
+ end
+
+ it "requires the right bundler version from the config and run bundle CLI without re-exec" do
+ unless Bundler.rubygems.provides?(">= 4.1.0.dev")
+ skip "This spec can only run when Gem::BundlerVersionFinder.bundler_versions reads bundler configs"
+ end
+
+ lockfile_bundled_with(current_version)
+
+ bundle_config "version #{previous_minor}"
+ bundle_config "path.system true"
+ bundle "install"
+
+ script = bundled_app("script.rb")
+ create_file(script, "p 'executed once'")
+
+ bundle "-v", env: { "RUBYOPT" => "-r#{script}" }
+ expect(out).to eq(%("executed once"\n9.3.0))
+ end
+
+ it "does not try to install when using bundle config version global" do
+ lockfile_bundled_with(previous_minor)
+
+ bundle_config "version system"
+ bundle "install"
+ expect(out).not_to match(/restarting using that version/)
+
+ bundle "-v"
+ expect(out).to eq(current_version)
+ end
+
+ it "does not try to install when using bundle config version <dev-version>" do
+ lockfile_bundled_with(previous_minor)
+
+ bundle_config "version #{previous_minor}.dev"
+ bundle "install"
+ expect(out).not_to match(/restarting using that version/)
+
+ bundle "-v"
+ expect(out).to eq(current_version)
+ end
+
+ it "ignores malformed lockfile version" do
+ lockfile_bundled_with("2.3.")
+
+ bundle "install --verbose"
+ expect(out).to include("Using bundler #{current_version}")
+ end
+
+ it "uses the right original script when re-execing, if `$0` has been changed to something that's not a script", :ruby_repo do
+ system_gems "bundler-9.9.9", path: local_gem_path
+
+ test = bundled_app("test.rb")
+
+ create_file test, <<~RUBY
+ $0 = "this is the program name"
+ require "bundler/setup"
+ RUBY
+
+ lockfile_bundled_with("9.9.9")
+
+ in_bundled_app "#{Gem.ruby} #{test}", raise_on_error: false
+ expect(err).to include("Could not find myrack-1.0.0")
+ expect(err).not_to include("this is the program name")
+ end
+
+ it "uses modified $0 when re-execing, if `$0` has been changed to a script", :ruby_repo do
+ system_gems "bundler-9.9.9", path: local_gem_path
+
+ runner = bundled_app("runner.rb")
+
+ create_file runner, <<~RUBY
+ $0 = ARGV.shift
+ load $0
+ RUBY
+
+ script = bundled_app("script.rb")
+ create_file script, <<~RUBY
+ require "bundler/setup"
+ RUBY
+
+ lockfile_bundled_with("9.9.9")
+
+ in_bundled_app "#{Gem.ruby} #{runner} #{script}", raise_on_error: false
+ expect(err).to include("Could not find myrack-1.0.0")
+ end
+
+ private
+
+ def lockfile_bundled_with(version)
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ myrack (1.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ myrack
+
+ BUNDLED WITH
+ #{version}
+ L
+ end
+ end
+end
diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb
index 4a754945b7..ceb6fcf66a 100644
--- a/spec/bundler/runtime/setup_spec.rb
+++ b/spec/bundler/runtime/setup_spec.rb
@@ -1,22 +1,21 @@
# frozen_string_literal: true
require "tmpdir"
-require "tempfile"
RSpec.describe "Bundler.setup" do
describe "with no arguments" do
it "makes all groups available" do
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", :group => :test
+ source "https://gem.repo1"
+ gem "myrack", :group => :test
G
ruby <<-RUBY
- require '#{lib_dir}/bundler'
+ require 'bundler'
Bundler.setup
- require 'rack'
- puts RACK
+ require 'myrack'
+ puts MYRACK
RUBY
expect(err).to be_empty
expect(out).to eq("1.0.0")
@@ -26,19 +25,19 @@ RSpec.describe "Bundler.setup" do
describe "when called with groups" do
before(:each) do
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
+ source "https://gem.repo1"
gem "yard"
- gem "rack", :group => :test
+ gem "myrack", :group => :test
G
end
it "doesn't make all groups available" do
ruby <<-RUBY
- require '#{lib_dir}/bundler'
+ require 'bundler'
Bundler.setup(:default)
begin
- require 'rack'
+ require 'myrack'
rescue LoadError
puts "WIN"
end
@@ -49,11 +48,11 @@ RSpec.describe "Bundler.setup" do
it "accepts string for group name" do
ruby <<-RUBY
- require '#{lib_dir}/bundler'
+ require 'bundler'
Bundler.setup(:default, 'test')
- require 'rack'
- puts RACK
+ require 'myrack'
+ puts MYRACK
RUBY
expect(err).to be_empty
expect(out).to eq("1.0.0")
@@ -61,12 +60,12 @@ RSpec.describe "Bundler.setup" do
it "leaves all groups available if they were already" do
ruby <<-RUBY
- require '#{lib_dir}/bundler'
+ require 'bundler'
Bundler.setup
Bundler.setup(:default)
- require 'rack'
- puts RACK
+ require 'myrack'
+ puts MYRACK
RUBY
expect(err).to be_empty
expect(out).to eq("1.0.0")
@@ -74,7 +73,7 @@ RSpec.describe "Bundler.setup" do
it "leaves :default available if setup is called twice" do
ruby <<-RUBY
- require '#{lib_dir}/bundler'
+ require 'bundler'
Bundler.setup(:default)
Bundler.setup(:default, :test)
@@ -90,16 +89,16 @@ RSpec.describe "Bundler.setup" do
end
it "handles multiple non-additive invocations" do
- ruby <<-RUBY
- require '#{lib_dir}/bundler'
+ ruby <<-RUBY, raise_on_error: false
+ require 'bundler'
Bundler.setup(:default, :test)
Bundler.setup(:default)
- require 'rack'
+ require 'myrack'
puts "FAIL"
RUBY
- expect(err).to match("rack")
+ expect(err).to match("myrack")
expect(err).to match("LoadError")
expect(out).not_to match("FAIL")
end
@@ -107,44 +106,45 @@ RSpec.describe "Bundler.setup" do
context "load order" do
def clean_load_path(lp)
- without_bundler_load_path = ruby!("puts $LOAD_PATH").split("\n")
- lp -= without_bundler_load_path
- lp.map! {|p| p.sub(/^#{Regexp.union system_gem_path.to_s, default_bundle_path.to_s, lib_dir.to_s}/i, "") }
+ without_bundler_load_path = ruby("puts $LOAD_PATH").split("\n")
+ lp -= [*without_bundler_load_path, lib_dir.to_s]
+ lp.map! {|p| p.sub(system_gem_path.to_s, "") }
end
it "puts loaded gems after -I and RUBYLIB", :ruby_repo do
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
G
ENV["RUBYOPT"] = "#{ENV["RUBYOPT"]} -Idash_i_dir"
ENV["RUBYLIB"] = "rubylib_dir"
ruby <<-RUBY
- require '#{lib_dir}/bundler'
+ require 'bundler'
Bundler.setup
puts $LOAD_PATH
RUBY
load_path = out.split("\n")
- rack_load_order = load_path.index {|path| path.include?("rack") }
+ myrack_load_order = load_path.index {|path| path.include?("myrack") }
- expect(err).to eq("")
+ expect(err).to be_empty
expect(load_path).to include(a_string_ending_with("dash_i_dir"), "rubylib_dir")
- expect(rack_load_order).to be > 0
+ expect(myrack_load_order).to be > 0
end
it "orders the load path correctly when there are dependencies" do
- system_gems :bundler
+ bundle_config "path.system true"
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
+ source "https://gem.repo1"
gem "rails"
G
- ruby! <<-RUBY
- require '#{lib_dir}/bundler'
+ ruby <<-RUBY
+ require 'bundler'
+ gem "bundler", "#{Bundler::VERSION}" if #{ruby_core?}
Bundler.setup
puts $LOAD_PATH
RUBY
@@ -153,26 +153,27 @@ RSpec.describe "Bundler.setup" do
expect(load_path).to start_with(
"/gems/rails-2.3.2/lib",
- "/gems/bundler-#{Bundler::VERSION}/lib",
"/gems/activeresource-2.3.2/lib",
"/gems/activerecord-2.3.2/lib",
"/gems/actionpack-2.3.2/lib",
"/gems/actionmailer-2.3.2/lib",
"/gems/activesupport-2.3.2/lib",
- "/gems/rake-12.3.2/lib"
+ "/gems/rake-#{rake_version}/lib"
)
end
it "falls back to order the load path alphabetically for backwards compatibility" do
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo1)}"
+ bundle_config "path.system true"
+
+ install_gemfile <<-G
+ source "https://gem.repo1"
gem "weakling"
gem "duradura"
gem "terranova"
G
- ruby! <<-RUBY
- require '#{lib_dir}/bundler/setup'
+ ruby <<-RUBY
+ require 'bundler/setup'
puts $LOAD_PATH
RUBY
@@ -188,12 +189,12 @@ RSpec.describe "Bundler.setup" do
it "raises if the Gemfile was not yet installed" do
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
G
ruby <<-R
- require '#{lib_dir}/bundler'
+ require 'bundler'
begin
Bundler.setup
@@ -208,66 +209,66 @@ RSpec.describe "Bundler.setup" do
it "doesn't create a Gemfile.lock if the setup fails" do
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
G
- ruby <<-R
- require '#{lib_dir}/bundler'
+ ruby <<-R, raise_on_error: false
+ require 'bundler'
Bundler.setup
R
- expect(bundled_app("Gemfile.lock")).not_to exist
+ expect(bundled_app_lock).not_to exist
end
it "doesn't change the Gemfile.lock if the setup fails" do
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
G
- lockfile = File.read(bundled_app("Gemfile.lock"))
+ lockfile = File.read(bundled_app_lock)
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
gem "nosuchgem", "10.0"
G
- ruby <<-R
- require '#{lib_dir}/bundler'
+ ruby <<-R, raise_on_error: false
+ require 'bundler'
Bundler.setup
R
- expect(File.read(bundled_app("Gemfile.lock"))).to eq(lockfile)
+ expect(File.read(bundled_app_lock)).to eq(lockfile)
end
it "makes a Gemfile.lock if setup succeeds" do
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
G
- File.read(bundled_app("Gemfile.lock"))
+ File.read(bundled_app_lock)
- FileUtils.rm(bundled_app("Gemfile.lock"))
+ FileUtils.rm(bundled_app_lock)
run "1"
- expect(bundled_app("Gemfile.lock")).to exist
+ expect(bundled_app_lock).to exist
end
describe "$BUNDLE_GEMFILE" do
context "user provides an absolute path" do
it "uses BUNDLE_GEMFILE to locate the gemfile if present" do
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
G
gemfile bundled_app("4realz"), <<-G
- source "#{file_uri_for(gem_repo1)}"
+ source "https://gem.repo1"
gem "activesupport", "2.3.5"
G
@@ -279,17 +280,17 @@ RSpec.describe "Bundler.setup" do
end
context "an absolute path is not provided" do
- it "uses BUNDLE_GEMFILE to locate the gemfile if present" do
+ it "uses BUNDLE_GEMFILE to locate the gemfile if present and doesn't fail in deployment mode" do
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
+ source "https://gem.repo1"
G
bundle "install"
- bundle "install --deployment"
+ bundle_config "deployment true"
ENV["BUNDLE_GEMFILE"] = "Gemfile"
ruby <<-R
- require '#{lib_dir}/bundler'
+ require 'bundler'
begin
Bundler.setup
@@ -302,28 +303,54 @@ RSpec.describe "Bundler.setup" do
expect(out).to eq("WIN")
end
end
+
+ context "user sets it via `config set --local gemfile`" do
+ it "uses the value in the config" do
+ gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ gemfile bundled_app("CustomGemfile"), <<-G
+ source "https://gem.repo1"
+ gem "activesupport", "2.3.5"
+ G
+
+ bundle_config "gemfile #{bundled_app("CustomGemfile")}"
+ bundle "install"
+
+ ruby <<-R
+ require 'bundler'
+ Bundler.setup
+ require 'activesupport'
+ puts ACTIVESUPPORT
+ R
+
+ expect(out).to eq("2.3.5")
+ end
+ end
end
it "prioritizes gems in BUNDLE_PATH over gems in GEM_HOME" do
ENV["BUNDLE_PATH"] = bundled_app(".bundle").to_s
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", "1.0.0"
+ source "https://gem.repo1"
+ gem "myrack", "1.0.0"
G
- build_gem "rack", "1.0", :to_system => true do |s|
- s.write "lib/rack.rb", "RACK = 'FAIL'"
+ build_gem "myrack", "1.0", to_system: true do |s|
+ s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
end
- expect(the_bundle).to include_gems "rack 1.0.0"
+ expect(the_bundle).to include_gems "myrack 1.0.0"
end
describe "integrate with rubygems" do
describe "by replacing #gem" do
before :each do
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", "0.9.1"
+ source "https://gem.repo1"
+ gem "myrack", "0.9.1"
G
end
@@ -340,23 +367,10 @@ RSpec.describe "Bundler.setup" do
expect(out).to eq("WIN")
end
- it "version_requirement is now deprecated in rubygems 1.4.0+ when gem is missing" do
- run <<-R
- begin
- gem "activesupport"
- puts "FAIL"
- rescue LoadError
- puts "WIN"
- end
- R
-
- expect(err).to be_empty
- end
-
it "replaces #gem but raises when the version is wrong" do
run <<-R
begin
- gem "rack", "1.0.0"
+ gem "myrack", "1.0.0"
puts "FAIL"
rescue LoadError
puts "WIN"
@@ -365,39 +379,27 @@ RSpec.describe "Bundler.setup" do
expect(out).to eq("WIN")
end
-
- it "version_requirement is now deprecated in rubygems 1.4.0+ when the version is wrong" do
- run <<-R
- begin
- gem "rack", "1.0.0"
- puts "FAIL"
- rescue LoadError
- puts "WIN"
- end
- R
-
- expect(err).to be_empty
- end
end
describe "by hiding system gems" do
before :each do
system_gems "activesupport-2.3.5"
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
+ source "https://gem.repo1"
gem "yard"
G
end
it "removes system gems from Gem.source_index" do
run "require 'yard'"
- expect(out).to eq("bundler-#{Bundler::VERSION}\nyard-1.0")
+ expect(out).to include("bundler-#{Bundler::VERSION}").and include("yard-1.0")
+ expect(out).not_to include("activesupport-2.3.5")
end
context "when the ruby stdlib is a substring of Gem.path" do
it "does not reject the stdlib from $LOAD_PATH" do
- substring = "/" + $LOAD_PATH.find {|p| p =~ /vendor_ruby/ }.split("/")[2]
- run "puts 'worked!'", :env => { "GEM_PATH" => substring }
+ substring = "/" + $LOAD_PATH.find {|p| p.include?("vendor_ruby") }.split("/")[2]
+ run "puts 'worked!'", env: { "GEM_PATH" => substring }
expect(out).to eq("worked!")
end
end
@@ -406,36 +408,37 @@ RSpec.describe "Bundler.setup" do
describe "with paths" do
it "activates the gems in the path source" do
- system_gems "rack-1.0.0"
+ system_gems "myrack-1.0.0"
- build_lib "rack", "1.0.0" do |s|
- s.write "lib/rack.rb", "puts 'WIN'"
+ build_lib "myrack", "1.0.0" do |s|
+ s.write "lib/myrack.rb", "puts 'WIN'"
end
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- path "#{lib_path("rack-1.0.0")}" do
- gem "rack"
+ source "https://gem.repo1"
+ path "#{lib_path("myrack-1.0.0")}" do
+ gem "myrack"
end
G
- run "require 'rack'"
+ run "require 'myrack'"
expect(out).to eq("WIN")
end
end
describe "with git" do
before do
- build_git "rack", "1.0.0"
+ build_git "myrack", "1.0.0"
gemfile <<-G
- gem "rack", :git => "#{lib_path("rack-1.0.0")}"
+ source "https://gem.repo1"
+ gem "myrack", :git => "#{lib_path("myrack-1.0.0")}"
G
end
it "provides a useful exception when the git repo is not checked out yet" do
- run "1"
- expect(err).to match(/the git source #{lib_path('rack-1.0.0')} is not yet checked out. Please run `bundle install`/i)
+ run "1", raise_on_error: false
+ expect(err).to match(/the git source #{lib_path("myrack-1.0.0")} is not yet checked out. Please run `bundle install`/i)
end
it "does not hit the git binary if the lockfile is available and up to date" do
@@ -444,7 +447,7 @@ RSpec.describe "Bundler.setup" do
break_git!
ruby <<-R
- require '#{lib_dir}/bundler'
+ require 'bundler'
begin
Bundler.setup
@@ -460,12 +463,12 @@ RSpec.describe "Bundler.setup" do
it "provides a good exception if the lockfile is unavailable" do
bundle "install"
- FileUtils.rm(bundled_app("Gemfile.lock"))
+ FileUtils.rm(bundled_app_lock)
break_git!
ruby <<-R
- require "#{lib_dir}/bundler"
+ require "bundler"
begin
Bundler.setup
@@ -475,122 +478,125 @@ RSpec.describe "Bundler.setup" do
end
R
- run "puts 'FAIL'"
+ run "puts 'FAIL'", raise_on_error: false
expect(err).not_to include "This is not the git you are looking for"
end
it "works even when the cache directory has been deleted" do
- bundle! :install, forgotten_command_line_options(:path => "vendor/bundle")
- FileUtils.rm_rf vendored_gems("cache")
- expect(the_bundle).to include_gems "rack 1.0.0"
+ bundle :install
+ FileUtils.rm_r default_cache_path
+ expect(the_bundle).to include_gems "myrack 1.0.0"
end
it "does not randomly change the path when specifying --path and the bundle directory becomes read only" do
- bundle! :install, forgotten_command_line_options(:path => "vendor/bundle")
+ bundle_config "path vendor/bundle"
+ bundle :install
- with_read_only("**/*") do
- expect(the_bundle).to include_gems "rack 1.0.0"
+ with_read_only("#{bundled_app}/**/*") do
+ expect(the_bundle).to include_gems "myrack 1.0.0"
end
end
it "finds git gem when default bundle path becomes read only" do
+ bundle_config "path .bundle"
bundle "install"
- with_read_only("#{Bundler.bundle_path}/**/*") do
- expect(the_bundle).to include_gems "rack 1.0.0"
+ with_read_only("#{bundled_app(".bundle")}/**/*") do
+ expect(the_bundle).to include_gems "myrack 1.0.0"
end
end
end
describe "when specifying local override" do
it "explodes if given path does not exist on runtime" do
- build_git "rack", "0.8"
+ build_git "myrack", "0.8"
- FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
+ FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ source "https://gem.repo1"
+ gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
G
- bundle %(config set local.rack #{lib_path("local-rack")})
- bundle! :install
+ bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle :install
- FileUtils.rm_rf(lib_path("local-rack"))
- run "require 'rack'"
- expect(err).to match(/Cannot use local override for rack-0.8 because #{Regexp.escape(lib_path('local-rack').to_s)} does not exist/)
+ FileUtils.rm_r(lib_path("local-myrack"))
+ run "require 'myrack'", raise_on_error: false
+ expect(err).to match(/Cannot use local override for myrack-0.8 because #{Regexp.escape(lib_path("local-myrack").to_s)} does not exist/)
end
it "explodes if branch is not given on runtime" do
- build_git "rack", "0.8"
+ build_git "myrack", "0.8"
- FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
+ FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ source "https://gem.repo1"
+ gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
G
- bundle %(config set local.rack #{lib_path("local-rack")})
- bundle! :install
+ bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle :install
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}"
+ source "https://gem.repo1"
+ gem "myrack", :git => "#{lib_path("myrack-0.8")}"
G
- run "require 'rack'"
+ run "require 'myrack'", raise_on_error: false
expect(err).to match(/because :branch is not specified in Gemfile/)
end
it "explodes on different branches on runtime" do
- build_git "rack", "0.8"
+ build_git "myrack", "0.8"
- FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
+ FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ source "https://gem.repo1"
+ gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
G
- bundle %(config set local.rack #{lib_path("local-rack")})
- bundle! :install
+ bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle :install
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "changed"
+ source "https://gem.repo1"
+ gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "changed"
G
- run "require 'rack'"
- expect(err).to match(/is using branch master but Gemfile specifies changed/)
+ run "require 'myrack'", raise_on_error: false
+ expect(err).to match(/is using branch main but Gemfile specifies changed/)
end
it "explodes on refs with different branches on runtime" do
- build_git "rack", "0.8"
+ build_git "myrack", "0.8"
- FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
+ FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "master", :branch => "master"
+ source "https://gem.repo1"
+ gem "myrack", :git => "#{lib_path("myrack-0.8")}", :ref => "main", :branch => "main"
G
gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "master", :branch => "nonexistant"
+ source "https://gem.repo1"
+ gem "myrack", :git => "#{lib_path("myrack-0.8")}", :ref => "main", :branch => "nonexistent"
G
- bundle %(config set local.rack #{lib_path("local-rack")})
- run "require 'rack'"
- expect(err).to match(/is using branch master but Gemfile specifies nonexistant/)
+ bundle %(config set local.myrack #{lib_path("local-myrack")})
+ run "require 'myrack'", raise_on_error: false
+ expect(err).to match(/is using branch main but Gemfile specifies nonexistent/)
end
end
describe "when excluding groups" do
it "doesn't change the resolve if --without is used" do
- install_gemfile <<-G, forgotten_command_line_options(:without => :rails)
- source "#{file_uri_for(gem_repo1)}"
+ bundle_config "without rails"
+ install_gemfile <<-G
+ source "https://gem.repo1"
gem "activesupport"
group :rails do
@@ -598,14 +604,15 @@ RSpec.describe "Bundler.setup" do
end
G
- install_gems "activesupport-2.3.5"
+ system_gems "activesupport-2.3.5"
- expect(the_bundle).to include_gems "activesupport 2.3.2", :groups => :default
+ expect(the_bundle).to include_gems "activesupport 2.3.2", groups: :default
end
it "remembers --without and does not bail on bare Bundler.setup" do
- install_gemfile <<-G, forgotten_command_line_options(:without => :rails)
- source "#{file_uri_for(gem_repo1)}"
+ bundle_config "without rails"
+ install_gemfile <<-G
+ source "https://gem.repo1"
gem "activesupport"
group :rails do
@@ -613,18 +620,85 @@ RSpec.describe "Bundler.setup" do
end
G
- install_gems "activesupport-2.3.5"
+ system_gems "activesupport-2.3.5"
expect(the_bundle).to include_gems "activesupport 2.3.2"
end
+ it "remembers --without and does not bail on bare Bundler.setup, even in the case of path gems no longer available" do
+ bundle_config "without development"
+
+ path = bundled_app(File.join("vendor", "foo"))
+ build_lib "foo", path: path
+
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "activesupport", "2.3.2"
+ gem 'foo', :path => 'vendor/foo', :group => :development
+ G
+
+ FileUtils.rm_r(path)
+
+ ruby "require 'bundler'; Bundler.setup", env: { "DEBUG" => "1" }
+ expect(out).to include("Assuming that source at `vendor/foo` has not changed since fetching its specs errored")
+ expect(out).to include("Found no changes, using resolution from the lockfile")
+ expect(err).to be_empty
+ end
+
+ it "doesn't re-resolve when a pre-release bundler is used and a dependency includes a dependency on bundler" do
+ system_gems "bundler-9.99.9.beta1"
+
+ build_repo4 do
+ build_gem "depends_on_bundler", "1.0" do |s|
+ s.add_dependency "bundler", ">= 1.5.0"
+ end
+ end
+
+ install_gemfile <<~G
+ source "https://gem.repo4"
+ gem "depends_on_bundler"
+ G
+
+ ruby "require '#{system_gem_path("gems/bundler-9.99.9.beta1/lib/bundler.rb")}'; Bundler.setup", env: { "DEBUG" => "1" }
+ expect(out).to include("Found no changes, using resolution from the lockfile")
+ expect(out).not_to include("lockfile does not have all gems needed for the current platform")
+ expect(err).to be_empty
+ end
+
+ it "doesn't fail in frozen mode when bundler is a Gemfile dependency" do
+ install_gemfile <<~G
+ source "https://gem.repo4"
+ gem "bundler"
+ G
+
+ bundle "install --verbose", env: { "BUNDLE_FROZEN" => "true" }
+ expect(err).to be_empty
+ end
+
+ it "doesn't re-resolve when deleting dependencies" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ gem "actionpack"
+ G
+
+ install_gemfile <<-G, verbose: true
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ expect(out).to include("Some dependencies were deleted, using a subset of the resolution from the lockfile")
+ expect(err).to be_empty
+ end
+
it "remembers --without and does not include groups passed to Bundler.setup" do
- install_gemfile <<-G, forgotten_command_line_options(:without => :rails)
- source "#{file_uri_for(gem_repo1)}"
+ bundle_config "without rails"
+ install_gemfile <<-G
+ source "https://gem.repo1"
gem "activesupport"
- group :rack do
- gem "rack"
+ group :myrack do
+ gem "myrack"
end
group :rails do
@@ -632,19 +706,19 @@ RSpec.describe "Bundler.setup" do
end
G
- expect(the_bundle).not_to include_gems "activesupport 2.3.2", :groups => :rack
- expect(the_bundle).to include_gems "rack 1.0.0", :groups => :rack
+ expect(the_bundle).not_to include_gems "activesupport 2.3.2", groups: :myrack
+ expect(the_bundle).to include_gems "myrack 1.0.0", groups: :myrack
end
end
# RubyGems returns loaded_from as a string
it "has loaded_from as a string on all specs" do
build_git "foo"
- build_git "no-gemspec", :gemspec => false
+ build_git "no-gemspec", gemspec: false
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
gem "foo", :git => "#{lib_path("foo-1.0")}"
gem "no-gemspec", "1.0", :git => "#{lib_path("no-gemspec-1.0")}"
G
@@ -658,38 +732,80 @@ RSpec.describe "Bundler.setup" do
expect(out).to be_empty
end
+ it "has gem_dir pointing to local repo" do
+ build_lib "foo", "1.0", path: bundled_app
+
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gemspec
+ G
+
+ run <<-R
+ puts Gem.loaded_specs['foo'].gem_dir
+ R
+
+ expect(out).to eq(bundled_app.to_s)
+ end
+
it "does not load all gemspecs" do
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
G
- run! <<-R
- File.open(File.join(Gem.dir, "specifications", "broken.gemspec"), "w") do |f|
+ run <<-R
+ File.open(File.join(Gem.dir, "specifications", "invalid.gemspec"), "w") do |f|
f.write <<-RUBY
# -*- encoding: utf-8 -*-
-# stub: broken 1.0.0 ruby lib
+# stub: invalid 1.0.0 ruby lib
Gem::Specification.new do |s|
- s.name = "broken"
+ s.name = "invalid"
s.version = "1.0.0"
- raise "BROKEN GEMSPEC"
+ s.authors = ["Invalid Author"]
+ s.files = ["lib/invalid.rb"]
+ s.add_dependency "nonexistent-gem", "~> 999.999.999"
+ s.validate!
end
RUBY
end
R
- run! <<-R
- puts "WIN"
+ run <<-R
+ File.open(File.join(Gem.dir, "specifications", "invalid-ext.gemspec"), "w") do |f|
+ f.write <<-RUBY
+# -*- encoding: utf-8 -*-
+# stub: invalid-ext 1.0.0 ruby lib
+# stub: a.ext\\0b.ext
+
+Gem::Specification.new do |s|
+ s.name = "invalid-ext"
+ s.version = "1.0.0"
+ s.authors = ["Invalid Author"]
+ s.files = ["lib/invalid.rb"]
+ s.required_ruby_version = "~> 0.8.0"
+ s.validate!
+end
+ RUBY
+ end
+ # Need to write the gem.build_complete file,
+ # otherwise the full spec is loaded to check the installed_by_version
+ extensions_dir = Gem.default_ext_dir_for(Gem.dir) || File.join(Gem.dir, "extensions", Gem::Platform.local.to_s, Gem.extension_api_version)
+ Bundler::FileUtils.mkdir_p(File.join(extensions_dir, "invalid-ext-1.0.0"))
+ File.open(File.join(extensions_dir, "invalid-ext-1.0.0", "gem.build_complete"), "w") {}
R
- expect(out).to eq("WIN")
+ run <<-R
+ puts "Success"
+ R
+
+ expect(out).to eq("Success")
end
it "ignores empty gem paths" do
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
G
ENV["GEM_HOME"] = ""
@@ -698,41 +814,80 @@ end
expect(err).to be_empty
end
- describe "$MANPATH" do
- before do
+ it "can require rubygems without warnings, when using a local cache", :truffleruby do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
+ G
+
+ bundle "package"
+ bundle %(exec ruby -w -e "require 'rubygems'")
+
+ expect(err).to be_empty
+ end
+
+ context "when the user has `MANPATH` set", :man do
+ before { ENV["MANPATH"] = "/foo#{File::PATH_SEPARATOR}" }
+
+ it "adds the gem's man dir to the MANPATH" do
build_repo4 do
build_gem "with_man" do |s|
s.write("man/man1/page.1", "MANPAGE")
end
end
+
+ install_gemfile <<-G
+ source "https://gem.repo4"
+ gem "with_man"
+ G
+
+ run "puts ENV['MANPATH']"
+ expect(out).to eq("#{default_bundle_path("gems/with_man-1.0/man")}#{File::PATH_SEPARATOR}/foo")
end
+ end
- context "when the user has one set" do
- before { ENV["MANPATH"] = "/foo:" }
+ context "when the user does not have `MANPATH` set", :man do
+ before { ENV.delete("MANPATH") }
- it "adds the gem's man dir to the MANPATH" do
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo4)}"
- gem "with_man"
- G
+ it "adds the gem's man dir to the MANPATH, leaving : in the end so that system man pages still work" do
+ build_repo4 do
+ build_gem "with_man" do |s|
+ s.write("man/man1/page.1", "MANPAGE")
+ end
- run! "puts ENV['MANPATH']"
- expect(out).to eq("#{default_bundle_path("gems/with_man-1.0/man")}:/foo")
+ build_gem "with_man_overriding_system_man" do |s|
+ s.write("man/man1/ls.1", "LS MANPAGE")
+ end
end
- end
- context "when the user does not have one set" do
- before { ENV.delete("MANPATH") }
+ install_gemfile <<-G
+ source "https://gem.repo4"
+ gem "with_man"
+ G
- it "adds the gem's man dir to the MANPATH" do
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo4)}"
- gem "with_man"
- G
+ run <<~RUBY
+ puts ENV['MANPATH']
+ require "open3"
+ puts Open3.capture2e("man", "ls")[1].success?
+ RUBY
- run! "puts ENV['MANPATH']"
- expect(out).to eq(default_bundle_path("gems/with_man-1.0/man").to_s)
- end
+ expect(out).to eq("#{default_bundle_path("gems/with_man-1.0/man")}#{File::PATH_SEPARATOR}\ntrue")
+
+ install_gemfile <<-G
+ source "https://gem.repo4"
+ gem "with_man_overriding_system_man"
+ G
+
+ run <<~RUBY
+ puts ENV['MANPATH']
+ require "open3"
+ puts Open3.capture2e({ "LC_ALL" => "C" }, "man", "ls")[0]
+ RUBY
+
+ lines = out.split("\n")
+
+ expect(lines).to include("#{default_bundle_path("gems/with_man_overriding_system_man-1.0/man")}#{File::PATH_SEPARATOR}")
+ expect(lines).to include("LS MANPAGE")
end
end
@@ -746,7 +901,7 @@ end
end
install_gemfile <<-G
- source "#{file_uri_for(gem_repo2)}"
+ source "https://gem.repo2"
gem "requirepaths", :require => nil
G
@@ -754,27 +909,18 @@ end
expect(out).to eq("yay")
end
- it "should clean $LOAD_PATH properly", :ruby_repo do
+ it "should clean $LOAD_PATH properly" do
gem_name = "very_simple_binary"
full_gem_name = gem_name + "-1.0"
- ext_dir = File.join(tmp("extensions", full_gem_name))
- install_gems full_gem_name
+ system_gems full_gem_name
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
+ source "https://gem.repo1"
G
ruby <<-R
- if Gem::Specification.method_defined? :extension_dir
- s = Gem::Specification.find_by_name '#{gem_name}'
- s.extension_dir = '#{ext_dir}'
-
- # Don't build extensions.
- s.class.send(:define_method, :build_extensions) { nil }
- end
-
- require '#{lib_dir}/bundler'
+ require 'bundler'
gem '#{gem_name}'
puts $LOAD_PATH.count {|path| path =~ /#{gem_name}/} >= 2
@@ -789,21 +935,21 @@ end
context "with bundler is located in symlinked GEM_HOME" do
let(:gem_home) { Dir.mktmpdir }
- let(:symlinked_gem_home) { Tempfile.new("gem_home").path }
+ let(:symlinked_gem_home) { tmp("gem_home-symlink").to_s }
let(:full_name) { "bundler-#{Bundler::VERSION}" }
before do
- FileUtils.ln_sf(gem_home, symlinked_gem_home)
+ File.symlink(gem_home, symlinked_gem_home)
gems_dir = File.join(gem_home, "gems")
specifications_dir = File.join(gem_home, "specifications")
Dir.mkdir(gems_dir)
Dir.mkdir(specifications_dir)
- FileUtils.ln_s(root, File.join(gems_dir, full_name))
+ File.symlink(source_root, File.join(gems_dir, full_name))
gemspec_content = File.binread(gemspec).
sub("Bundler::VERSION", %("#{Bundler::VERSION}")).
- lines.reject {|line| line =~ %r{lib/bundler/version} }.join
+ lines.reject {|line| line.include?("lib/bundler/version") }.join
File.open(File.join(specifications_dir, "#{full_name}.gemspec"), "wb") do |f|
f.write(gemspec_content)
@@ -811,11 +957,11 @@ end
end
it "should not remove itself from the LOAD_PATH and require a different copy of 'bundler/setup'" do
- install_gemfile ""
+ install_gemfile "source 'https://gem.repo1'"
- ruby <<-R, :env => { "GEM_PATH" => symlinked_gem_home }, :no_lib => true
+ ruby <<-R, env: { "GEM_PATH" => symlinked_gem_home }
TracePoint.trace(:class) do |tp|
- if tp.path.include?("bundler") && !tp.path.start_with?("#{root}")
+ if tp.path.include?("bundler") && !tp.path.start_with?("#{source_root}")
puts "OMG. Defining a class from another bundler at \#{tp.path}:\#{tp.lineno}"
end
end
@@ -828,64 +974,68 @@ end
end
it "does not reveal system gems even when Gem.refresh is called" do
- system_gems "rack-1.0.0"
+ system_gems "myrack-1.0.0"
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
+ source "https://gem.repo1"
gem "activesupport"
G
run <<-R
- puts Bundler.rubygems.all_specs.map(&:name)
+ puts Bundler.rubygems.installed_specs.map(&:name)
Gem.refresh
- puts Bundler.rubygems.all_specs.map(&:name)
+ puts Bundler.rubygems.installed_specs.map(&:name)
R
expect(out).to eq("activesupport\nbundler\nactivesupport\nbundler")
end
describe "when a vendored gem specification uses the :path option" do
+ let(:filesystem_root) do
+ current = Pathname.new(Dir.pwd)
+ current = current.parent until current == current.parent
+ current
+ end
+
it "should resolve paths relative to the Gemfile" do
path = bundled_app(File.join("vendor", "foo"))
- build_lib "foo", :path => path
+ build_lib "foo", path: path
# If the .gemspec exists, then Bundler handles the path differently.
# See Source::Path.load_spec_files for details.
FileUtils.rm(File.join(path, "foo.gemspec"))
install_gemfile <<-G
+ source "https://gem.repo1"
gem 'foo', '1.2.3', :path => 'vendor/foo'
G
- Dir.chdir(bundled_app.parent) do
- run <<-R, :env => { "BUNDLE_GEMFILE" => bundled_app("Gemfile") }
- require 'foo'
- R
- end
+ run <<-R, env: { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, dir: bundled_app.parent
+ require 'foo'
+ R
expect(err).to be_empty
end
it "should make sure the Bundler.root is really included in the path relative to the Gemfile" do
- relative_path = File.join("vendor", Dir.pwd[1..-1], "foo")
+ relative_path = File.join("vendor", Dir.pwd.gsub(/^#{filesystem_root}/, ""))
absolute_path = bundled_app(relative_path)
FileUtils.mkdir_p(absolute_path)
- build_lib "foo", :path => absolute_path
+ build_lib "foo", path: absolute_path
# If the .gemspec exists, then Bundler handles the path differently.
# See Source::Path.load_spec_files for details.
FileUtils.rm(File.join(absolute_path, "foo.gemspec"))
gemfile <<-G
+ source "https://gem.repo1"
gem 'foo', '1.2.3', :path => '#{relative_path}'
G
bundle :install
- Dir.chdir(bundled_app.parent) do
- run <<-R, :env => { "BUNDLE_GEMFILE" => bundled_app("Gemfile") }
- require 'foo'
- R
- end
+ run <<-R, env: { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, dir: bundled_app.parent
+ require 'foo'
+ R
expect(err).to be_empty
end
@@ -893,17 +1043,18 @@ end
describe "with git gems that don't have gemspecs" do
before :each do
- build_git "no-gemspec", :gemspec => false
+ build_git "no_gemspec", gemspec: false
install_gemfile <<-G
- gem "no-gemspec", "1.0", :git => "#{lib_path("no-gemspec-1.0")}"
+ source "https://gem.repo1"
+ gem "no_gemspec", "1.0", :git => "#{lib_path("no_gemspec-1.0")}"
G
end
it "loads the library via a virtual spec" do
run <<-R
- require 'no-gemspec'
- puts NOGEMSPEC
+ require 'no_gemspec'
+ puts NO_GEMSPEC
R
expect(out).to eq("1.0")
@@ -912,10 +1063,10 @@ end
describe "with bundled and system gems" do
before :each do
- system_gems "rack-1.0.0"
+ system_gems "myrack-1.0.0"
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
+ source "https://gem.repo1"
gem "activesupport", "2.3.5"
G
@@ -924,7 +1075,7 @@ end
it "does not pull in system gems" do
run <<-R
begin;
- require 'rack'
+ require 'myrack'
rescue LoadError
puts 'WIN'
end
@@ -946,13 +1097,13 @@ end
it "raises an exception if gem is used to invoke a system gem not in the bundle" do
run <<-R
begin
- gem 'rack'
+ gem 'myrack'
rescue LoadError => e
puts e.message
end
R
- expect(out).to eq("rack is not part of the bundle. Add it to your Gemfile.")
+ expect(out).to eq("myrack is not part of the bundle. Add it to your Gemfile.")
end
it "sets GEM_HOME appropriately" do
@@ -963,12 +1114,12 @@ end
describe "with system gems in the bundle" do
before :each do
- bundle! "config set path.system true"
- system_gems "rack-1.0.0"
+ bundle_config "path.system true"
+ system_gems "myrack-1.0.0"
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", "1.0.0"
+ source "https://gem.repo1"
+ gem "myrack", "1.0.0"
gem "activesupport", "2.3.5"
G
end
@@ -982,7 +1133,7 @@ end
describe "with a gemspec that requires other files" do
before :each 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
require_relative 'lib/bar/version'
@@ -998,6 +1149,7 @@ end
end
gemfile <<-G
+ source "https://gem.repo1"
gem "bar", :git => "#{lib_path("bar-1.0")}"
G
end
@@ -1009,14 +1161,15 @@ end
end
it "error intelligently if the gemspec has a LoadError" do
- ref = update_git "bar", :gemspec => false do |s|
+ skip "whitespace issue?" if Gem.win_platform?
+
+ ref = update_git "bar", gemspec: false do |s|
s.write "bar.gemspec", "require 'foobarbaz'"
end.ref_for("HEAD")
- bundle :install
+ bundle :install, raise_on_error: false
expect(err.lines.map(&:chomp)).to include(
a_string_starting_with("[!] There was an error while loading `bar.gemspec`:"),
- a_string_starting_with("Does it try to require a relative path? That's been removed in Ruby 1.9."),
" # from #{default_bundle_path "bundler", "gems", "bar-1.0-#{ref[0, 12]}", "bar.gemspec"}:1",
" > require 'foobarbaz'"
)
@@ -1026,21 +1179,24 @@ end
bundle "install"
ruby <<-RUBY
- require '#{lib_dir}/bundler'
+ require 'bundler'
+ bundler_module = class << Bundler; self; end
+ bundler_module.send(:remove_method, :require)
def Bundler.require(path)
- raise "LOSE"
+ raise StandardError, "didn't use binding from top level"
end
Bundler.load
RUBY
expect(err).to be_empty
- expect(out).to eq("")
+ expect(out).to be_empty
end
end
describe "when Bundler is bundled" do
it "doesn't blow up" do
install_gemfile <<-G
+ source "https://gem.repo1"
gem "bundler", :path => "#{root}"
G
@@ -1051,56 +1207,59 @@ end
describe "when BUNDLED WITH" do
def lock_with(bundler_version = nil)
- lock = <<-L
+ lock = <<~L
GEM
- remote: #{file_uri_for(gem_repo1)}/
+ remote: https://gem.repo1/
specs:
- rack (1.0.0)
+ myrack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- rack
+ myrack
L
if bundler_version
- lock += "\n BUNDLED WITH\n #{bundler_version}\n"
+ lock += "\nBUNDLED WITH\n #{bundler_version}\n"
end
lock
end
before do
+ bundle_config "path.system true"
+
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
G
end
context "is not present" do
it "does not change the lock" do
lockfile lock_with(nil)
- ruby "require '#{lib_dir}/bundler/setup'"
- lockfile_should_be lock_with(nil)
+ ruby "require 'bundler/setup'"
+ expect(lockfile).to eq lock_with(nil)
end
end
context "is newer" do
it "does not change the lock or warn" do
lockfile lock_with(Bundler::VERSION.succ)
- ruby "require '#{lib_dir}/bundler/setup'"
- expect(out).to eq("")
- expect(err).to eq("")
- lockfile_should_be lock_with(Bundler::VERSION.succ)
+ ruby "require 'bundler/setup'"
+ expect(out).to be_empty
+ expect(err).to be_empty
+ expect(lockfile).to eq lock_with(Bundler::VERSION.succ)
end
end
context "is older" do
it "does not change the lock" do
+ system_gems "bundler-1.10.1"
lockfile lock_with("1.10.1")
- ruby "require '#{lib_dir}/bundler/setup'"
- lockfile_should_be lock_with("1.10.1")
+ ruby "require 'bundler/setup'"
+ expect(lockfile).to eq lock_with("1.10.1")
end
end
end
@@ -1109,27 +1268,32 @@ end
let(:ruby_version) { nil }
def lock_with(ruby_version = nil)
- lock = <<-L
+ checksums = checksums_section do |c|
+ c.checksum gem_repo1, "myrack", "1.0.0"
+ end
+
+ lock = <<~L
GEM
- remote: #{file_uri_for(gem_repo1)}/
+ remote: https://gem.repo1/
specs:
- rack (1.0.0)
+ myrack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- rack
+ myrack
+ #{checksums}
L
if ruby_version
- lock += "\n RUBY VERSION\n ruby #{ruby_version}\n"
+ lock += "\nRUBY VERSION\n ruby #{ruby_version}\n"
end
- lock += <<-L
+ lock += <<~L
BUNDLED WITH
- #{Bundler::VERSION}
+ #{Bundler::VERSION}
L
lock
@@ -1138,40 +1302,78 @@ end
before do
install_gemfile <<-G
ruby ">= 0"
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
G
lockfile lock_with(ruby_version)
end
context "is not present" do
- it "does not change the lock" do
- expect { ruby! "require '#{lib_dir}/bundler/setup'" }.not_to change { lockfile }
+ # Skipped on ruby-core because `ruby "require 'bundler/setup'"` does not
+ # activate bundler as a gem there, so Source::Metadata falls back to a
+ # synthetic spec whose cache_file does not exist on disk and
+ # LockfileGenerator#bundler_checksum drops the bundler checksum, while
+ # the on-disk lockfile still has it.
+ it "does not change the lock", :ruby_repo do
+ expect { ruby "require 'bundler/setup'" }.not_to change { lockfile }
end
end
context "is newer" do
let(:ruby_version) { "5.5.5" }
it "does not change the lock or warn" do
- expect { ruby! "require '#{lib_dir}/bundler/setup'" }.not_to change { lockfile }
- expect(out).to eq("")
- expect(err).to eq("")
+ expect { ruby "require 'bundler/setup'" }.not_to change { lockfile }
+ expect(out).to be_empty
+ expect(err).to be_empty
end
end
context "is older" do
let(:ruby_version) { "1.0.0" }
it "does not change the lock" do
- expect { ruby! "require '#{lib_dir}/bundler/setup'" }.not_to change { lockfile }
+ expect { ruby "require 'bundler/setup'" }.not_to change { lockfile }
end
end
end
describe "with gemified standard libraries" do
+ it "does not load Digest", :ruby_repo do
+ build_git "bar", gemspec: false do |s|
+ s.write "lib/bar/version.rb", %(BAR_VERSION = '1.0')
+ s.write "bar.gemspec", <<-G
+ require_relative 'lib/bar/version'
+
+ Gem::Specification.new do |s|
+ s.name = 'bar'
+ s.version = BAR_VERSION
+ s.summary = 'Bar'
+ s.files = Dir["lib/**/*.rb"]
+ s.author = 'no one'
+
+ s.add_dependency 'digest'
+ end
+ G
+ end
+
+ gemfile <<-G
+ source "https://gem.repo1"
+ gem "bar", :git => "#{lib_path("bar-1.0")}"
+ G
+
+ bundle :install, env: { "BUNDLE_LOCKFILE_CHECKSUMS" => "false" }
+
+ ruby <<-RUBY, artifice: nil
+ require 'bundler/setup'
+ puts defined?(::Digest) ? "Digest defined" : "Digest undefined"
+ require 'digest'
+ RUBY
+ expect(out).to eq("Digest undefined")
+ end
+
it "does not load Psych" do
- gemfile ""
+ gemfile "source 'https://gem.repo1'"
ruby <<-RUBY
- require '#{lib_dir}/bundler/setup'
+ require 'bundler/setup'
puts defined?(Psych::VERSION) ? Psych::VERSION : "undefined"
require 'psych'
puts Psych::VERSION
@@ -1182,9 +1384,9 @@ end
end
it "does not load openssl" do
- install_gemfile! ""
- ruby! <<-RUBY
- require "#{lib_dir}/bundler/setup"
+ install_gemfile "source 'https://gem.repo1'"
+ ruby <<-RUBY, artifice: nil
+ require "bundler/setup"
puts defined?(OpenSSL) || "undefined"
require "openssl"
puts defined?(OpenSSL) || "undefined"
@@ -1192,29 +1394,73 @@ end
expect(out).to eq("undefined\nconstant")
end
+ it "does not load uri while reading gemspecs", rubygems: ">= 3.6.0.dev" do
+ Dir.mkdir bundled_app("test")
+
+ create_file(bundled_app("test/test.gemspec"), <<-G)
+ Gem::Specification.new do |s|
+ s.name = "test"
+ s.version = "1.0.0"
+ s.summary = "test"
+ s.authors = ['John Doe']
+ s.homepage = 'https://example.com'
+ end
+ G
+
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "test", path: "#{bundled_app("test")}"
+ G
+
+ ruby <<-RUBY, artifice: nil
+ require "bundler/setup"
+ puts defined?(URI) || "undefined"
+ require "uri"
+ puts defined?(URI) || "undefined"
+ RUBY
+ expect(out).to eq("undefined\nconstant")
+ end
+
+ it "activates default gems when they are part of the bundle, but not installed explicitly", :ruby_repo do
+ default_delegate_version = ruby "gem 'delegate'; require 'delegate'; puts Delegator::VERSION"
+
+ build_repo2 do
+ build_gem "delegate", default_delegate_version
+ end
+
+ gemfile "source \"https://gem.repo2\"; gem 'delegate'"
+
+ ruby <<-RUBY
+ require "bundler/setup"
+ require "delegate"
+ puts defined?(::Delegator) ? "Delegator defined" : "Delegator undefined"
+ RUBY
+
+ expect(out).to eq("Delegator defined")
+ expect(err).to be_empty
+ end
+
describe "default gem activation" do
let(:exemptions) do
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new("2.7")
- []
- else
- %w[io-console openssl]
- end << "bundler"
+ exempts = %w[did_you_mean bundler uri pathname]
+ exempts << "error_highlight" # added in Ruby 3.1 as a default gem
+ exempts << "ruby2_keywords" # added in Ruby 3.1 as a default gem
+ exempts << "syntax_suggest" # added in Ruby 3.2 as a default gem
+ exempts
end
- let(:activation_warning_hack) { strip_whitespace(<<-RUBY) }
+ let(:activation_warning_hack) { <<~RUBY }
require #{spec_dir.join("support/hax").to_s.dump}
- if Gem::Specification.instance_methods.map(&:to_sym).include?(:activate)
- Gem::Specification.send(:alias_method, :bundler_spec_activate, :activate)
- Gem::Specification.send(:define_method, :activate) do
- unless #{exemptions.inspect}.include?(name)
- warn '-' * 80
- warn "activating \#{full_name}"
- warn *caller
- warn '*' * 80
- end
- bundler_spec_activate
+ Gem::Specification.send(:alias_method, :bundler_spec_activate, :activate)
+ Gem::Specification.send(:define_method, :activate) do
+ unless #{exemptions.inspect}.include?(name)
+ warn '-' * 80
+ warn "activating \#{full_name}"
+ warn(*caller)
+ warn '*' * 80
end
+ bundler_spec_activate
end
RUBY
@@ -1223,7 +1469,7 @@ end
"-r#{bundled_app("activation_warning_hack.rb")} #{ENV["RUBYOPT"]}"
end
- let(:code) { strip_whitespace(<<-RUBY) }
+ let(:code) { <<~RUBY }
require "pp"
loaded_specs = Gem.loaded_specs.dup
#{exemptions.inspect}.each {|s| loaded_specs.delete(s) }
@@ -1237,120 +1483,228 @@ end
RUBY
it "activates no gems with -rbundler/setup" do
- install_gemfile! ""
- ruby! code, :env => { :RUBYOPT => activation_warning_hack_rubyopt + " -r#{lib_dir}/bundler/setup" }
+ install_gemfile "source 'https://gem.repo1'"
+ ruby code, env: { "RUBYOPT" => activation_warning_hack_rubyopt + " -rbundler/setup" }, artifice: nil
expect(out).to eq("{}")
end
it "activates no gems with bundle exec" do
- install_gemfile! ""
+ install_gemfile "source 'https://gem.repo1'"
create_file("script.rb", code)
- bundle! "exec ruby ./script.rb", :env => { :RUBYOPT => activation_warning_hack_rubyopt }
+ bundle "exec ruby ./script.rb", env: { "RUBYOPT" => activation_warning_hack_rubyopt }
expect(out).to eq("{}")
end
it "activates no gems with bundle exec that is loaded" do
- install_gemfile! ""
+ skip "not executable" if Gem.win_platform?
+
+ install_gemfile "source 'https://gem.repo1'"
create_file("script.rb", "#!/usr/bin/env ruby\n\n#{code}")
FileUtils.chmod(0o777, bundled_app("script.rb"))
- bundle! "exec ./script.rb", :artifice => nil, :env => { :RUBYOPT => activation_warning_hack_rubyopt }
+ bundle "exec ./script.rb", env: { "RUBYOPT" => activation_warning_hack_rubyopt }
expect(out).to eq("{}")
end
- let(:default_gems) do
- ruby!(<<-RUBY).split("\n")
- if Gem::Specification.is_a?(Enumerable)
- puts Gem::Specification.select(&:default_gem?).map(&:name)
- end
- RUBY
- end
-
- it "activates newer versions of default gems" do
+ it "does not load net-http-pipeline too early" do
build_repo4 do
- default_gems.each do |g|
- build_gem g, "999999"
- end
+ build_gem "net-http-pipeline", "1.0.1"
end
- default_gems.reject! {|g| exemptions.include?(g) }
+ system_gems "net-http-pipeline-1.0.1", gem_repo: gem_repo4
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo4)}"
- #{default_gems}.each do |g|
- gem g, "999999"
- end
+ gemfile <<-G
+ source "https://gem.repo4"
+ gem "net-http-pipeline", "1.0.1"
G
- expect(the_bundle).to include_gems(*default_gems.map {|g| "#{g} 999999" })
+ bundle_config "path vendor/bundle"
+
+ bundle :install
+
+ bundle :check
+
+ expect(out).to eq("The Gemfile's dependencies are satisfied")
end
- it "activates older versions of default gems" do
- build_repo4 do
- default_gems.each do |g|
- build_gem g, "0.0.0.a"
+ Gem::Specification.select(&:default_gem?).map(&:name).each do |g|
+ it "activates newer versions of #{g}", :ruby_repo do
+ skip if exemptions.include?(g)
+
+ build_repo4 do
+ build_gem g, "999999"
end
+
+ install_gemfile <<-G
+ source "https://gem.repo4"
+ gem "#{g}", "999999"
+ G
+
+ expect(the_bundle).to include_gem("#{g} 999999", env: { "RUBYOPT" => activation_warning_hack_rubyopt }, artifice: nil)
end
- default_gems.reject! {|g| exemptions.include?(g) }
+ it "activates older versions of #{g}", :ruby_repo do
+ skip if exemptions.include?(g)
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo4)}"
- #{default_gems}.each do |g|
- gem g, "0.0.0.a"
+ build_repo4 do
+ build_gem g, "0.0.0.a"
end
- G
- expect(the_bundle).to include_gems(*default_gems.map {|g| "#{g} 0.0.0.a" })
+ install_gemfile <<-G
+ source "https://gem.repo4"
+ gem "#{g}", "0.0.0.a"
+ G
+
+ expect(the_bundle).to include_gem("#{g} 0.0.0.a", env: { "RUBYOPT" => activation_warning_hack_rubyopt }, artifice: nil)
+ end
end
end
end
describe "after setup" do
- it "allows calling #gem on random objects", :bundler => "< 3" do
+ it "keeps Kernel#gem private" do
install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ source "https://gem.repo1"
+ gem "myrack"
G
- ruby! <<-RUBY
- require "#{lib_dir}/bundler/setup"
- Object.new.gem "rack"
- puts Gem.loaded_specs["rack"].full_name
+ ruby <<-RUBY, raise_on_error: false
+ require "bundler/setup"
+ Object.new.gem "myrack"
+ puts "FAIL"
RUBY
- expect(out).to eq("rack-1.0.0")
+ expect(stdboth).not_to include "FAIL"
+ expect(err).to match(/private method [`']gem'/)
end
- it "keeps Kernel#gem private", :bundler => "3" do
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ it "keeps Kernel#require private" do
+ install_gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack"
G
- ruby <<-RUBY
- require "#{lib_dir}/bundler/setup"
- Object.new.gem "rack"
+ ruby <<-RUBY, raise_on_error: false
+ require "bundler/setup"
+ Object.new.require "myrack"
puts "FAIL"
RUBY
- expect(last_command.stdboth).not_to include "FAIL"
- expect(err).to include "private method `gem'"
+ expect(stdboth).not_to include "FAIL"
+ expect(err).to match(/private method [`']require'/)
end
- it "keeps Kernel#require private" do
- install_gemfile! <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
+ it "memoizes initial set of specs when requiring bundler/setup, so that even if further code mutates dependencies, Bundler.definition.specs is not affected" do
+ install_gemfile <<~G
+ source "https://gem.repo1"
+ gem "yard"
+ gem "myrack", :group => :test
G
+ ruby <<-RUBY, raise_on_error: false
+ require "bundler/setup"
+ Bundler.require(:test).select! {|d| (d.groups & [:test]).any? }
+ puts Bundler.definition.specs.map(&:name).join(", ")
+ RUBY
+
+ expect(out).to include("myrack, yard")
+ end
+
+ it "does not cause double loads when higher versions of default gems are activated before bundler" do
+ build_repo2 do
+ build_gem "json", "999.999.999" do |s|
+ s.write "lib/json.rb", <<~RUBY
+ module JSON
+ VERSION = "999.999.999"
+ end
+ RUBY
+ end
+ end
+
+ system_gems "json-999.999.999", gem_repo: gem_repo2
+
+ install_gemfile "source 'https://gem.repo1'"
ruby <<-RUBY
- require "#{lib_dir}/bundler/setup"
- Object.new.require "rack"
- puts "FAIL"
+ require "json"
+ require "bundler/setup"
+ require "json"
RUBY
- expect(last_command.stdboth).not_to include "FAIL"
- expect(err).to include "private method `require'"
+ expect(err).to be_empty
+ end
+ end
+
+ it "does not undo the Kernel.require decorations", rubygems: ">= 3.4.6" do
+ install_gemfile "source 'https://gem.repo1'"
+ script = bundled_app("bin/script")
+ create_file(script, <<~RUBY)
+ module Kernel
+ module_function
+
+ alias_method :require_before_extra_monkeypatches, :require
+
+ def require(path)
+ puts "requiring \#{path} used the monkeypatch"
+
+ require_before_extra_monkeypatches(path)
+ end
+ end
+
+ require "bundler/setup"
+
+ require "foo"
+ RUBY
+
+ sys_exec "#{Gem.ruby} #{script}", raise_on_error: false
+ expect(out).to include("requiring foo used the monkeypatch")
+ end
+
+ it "performs an automatic bundle install" do
+ build_repo4 do
+ build_gem "myrack", "1.0.0"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo1"
+ gem "myrack", :group => :test
+ G
+
+ bundle_config "auto_install 1"
+
+ ruby <<-RUBY, artifice: "compact_index"
+ require 'bundler/setup'
+ RUBY
+ expect(err).to be_empty
+ expect(out).to include("Installing myrack 1.0.0")
+ end
+
+ context "in a read-only filesystem" do
+ before do
+ gemfile <<-G
+ source "https://gem.repo4"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo4/
+
+ PLATFORMS
+ x86_64-darwin-19
+
+ DEPENDENCIES
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "should fail loudly if the lockfile platforms don't include the current platform" do
+ simulate_platform "x86_64-linux" do
+ ruby <<-RUBY, raise_on_error: false, env: { "BUNDLER_SPEC_READ_ONLY" => "true", "BUNDLER_FORCE_TTY" => "true" }
+ require "bundler/setup"
+ RUBY
+ end
+
+ expect(err).to include("Your lockfile is missing the current platform, but can't be updated because file system is read-only")
end
end
end
diff --git a/spec/bundler/runtime/with_unbundled_env_spec.rb b/spec/bundler/runtime/with_unbundled_env_spec.rb
deleted file mode 100644
index 4aaf9d499c..0000000000
--- a/spec/bundler/runtime/with_unbundled_env_spec.rb
+++ /dev/null
@@ -1,270 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "Bundler.with_env helpers" do
- def bundle_exec_ruby!(code, options = {})
- build_bundler_context options
- bundle! "exec '#{Gem.ruby}' -e #{code}", options
- end
-
- def build_bundler_context(options = {})
- bundle "config set path vendor/bundle"
- gemfile ""
- bundle "install", options
- end
-
- describe "Bundler.original_env" do
- it "should return the PATH present before bundle was activated" do
- code = "print Bundler.original_env['PATH']"
- path = `getconf PATH`.strip + "#{File::PATH_SEPARATOR}/foo"
- with_path_as(path) do
- bundle_exec_ruby!(code.dump)
- expect(last_command.stdboth).to eq(path)
- end
- end
-
- it "should return the GEM_PATH present before bundle was activated" do
- code = "print Bundler.original_env['GEM_PATH']"
- gem_path = ENV["GEM_PATH"] + ":/foo"
- with_gem_path_as(gem_path) do
- bundle_exec_ruby!(code.dump)
- expect(last_command.stdboth).to eq(gem_path)
- end
- end
-
- it "works with nested bundle exec invocations" do
- create_file("exe.rb", <<-'RB')
- count = ARGV.first.to_i
- exit if count < 0
- STDERR.puts "#{count} #{ENV["PATH"].end_with?(":/foo")}"
- if count == 2
- ENV["PATH"] = "#{ENV["PATH"]}:/foo"
- end
- exec(Gem.ruby, __FILE__, (count - 1).to_s)
- RB
- path = `getconf PATH`.strip + File::PATH_SEPARATOR + File.dirname(Gem.ruby)
- with_path_as(path) do
- build_bundler_context
- bundle! "exec '#{Gem.ruby}' #{bundled_app("exe.rb")} 2"
- end
- expect(err).to eq <<-EOS.strip
-2 false
-1 true
-0 true
- EOS
- end
-
- it "removes variables that bundler added", :ruby_repo do
- # Simulate bundler has not yet been loaded
- ENV.replace(ENV.to_hash.delete_if {|k, _v| k.start_with?(Bundler::EnvironmentPreserver::BUNDLER_PREFIX) })
-
- original = ruby!('puts ENV.to_a.map {|e| e.join("=") }.sort.join("\n")')
- code = 'puts Bundler.original_env.to_a.map {|e| e.join("=") }.sort.join("\n")'
- bundle_exec_ruby! code.dump
- expect(out).to eq original
- end
- end
-
- shared_examples_for "an unbundling helper" do
- it "should delete BUNDLE_PATH" do
- code = "print #{modified_env}.has_key?('BUNDLE_PATH')"
- ENV["BUNDLE_PATH"] = "./foo"
- bundle_exec_ruby! code.dump
- expect(last_command.stdboth).to include "false"
- end
-
- it "should remove '-rbundler/setup' from RUBYOPT" do
- code = "print #{modified_env}['RUBYOPT']"
- ENV["RUBYOPT"] = "-W2 -rbundler/setup #{ENV["RUBYOPT"]}"
- bundle_exec_ruby! code.dump, :env => { "BUNDLER_SPEC_DISABLE_DEFAULT_BUNDLER_GEM" => "true" }
- expect(last_command.stdboth).not_to include("-rbundler/setup")
- end
-
- it "should restore RUBYLIB", :ruby_repo do
- code = "print #{modified_env}['RUBYLIB']"
- ENV["RUBYLIB"] = lib_dir.to_s + File::PATH_SEPARATOR + "/foo"
- ENV["BUNDLER_ORIG_RUBYLIB"] = lib_dir.to_s + File::PATH_SEPARATOR + "/foo-original"
- bundle_exec_ruby! code.dump
- expect(last_command.stdboth).to include("/foo-original")
- end
-
- it "should restore the original MANPATH" do
- code = "print #{modified_env}['MANPATH']"
- ENV["MANPATH"] = "/foo"
- ENV["BUNDLER_ORIG_MANPATH"] = "/foo-original"
- bundle_exec_ruby! code.dump
- expect(last_command.stdboth).to include("/foo-original")
- end
- end
-
- describe "Bundler.unbundled_env" do
- let(:modified_env) { "Bundler.unbundled_env" }
-
- it_behaves_like "an unbundling helper"
- end
-
- describe "Bundler.clean_env", :bundler => 2 do
- let(:modified_env) { "Bundler.clean_env" }
-
- it_behaves_like "an unbundling helper"
- end
-
- describe "Bundler.with_original_env" do
- it "should set ENV to original_env in the block" do
- expected = Bundler.original_env
- actual = Bundler.with_original_env { ENV.to_hash }
- expect(actual).to eq(expected)
- end
-
- it "should restore the environment after execution" do
- Bundler.with_original_env do
- ENV["FOO"] = "hello"
- end
-
- expect(ENV).not_to have_key("FOO")
- end
- end
-
- describe "Bundler.with_clean_env", :bundler => 2 do
- it "should set ENV to unbundled_env in the block" do
- expected = Bundler.unbundled_env
-
- actual = Bundler.ui.silence do
- Bundler.with_clean_env { ENV.to_hash }
- end
-
- expect(actual).to eq(expected)
- end
-
- it "should restore the environment after execution" do
- Bundler.ui.silence do
- Bundler.with_clean_env { ENV["FOO"] = "hello" }
- end
-
- expect(ENV).not_to have_key("FOO")
- end
- end
-
- describe "Bundler.with_unbundled_env" do
- it "should set ENV to unbundled_env in the block" do
- expected = Bundler.unbundled_env
- actual = Bundler.with_unbundled_env { ENV.to_hash }
- expect(actual).to eq(expected)
- end
-
- it "should restore the environment after execution" do
- Bundler.with_unbundled_env do
- ENV["FOO"] = "hello"
- end
-
- expect(ENV).not_to have_key("FOO")
- end
- end
-
- describe "Bundler.original_system" do
- let(:code) do
- <<~RUBY
- Bundler.original_system(%([ "\$BUNDLE_FOO" = "bar" ] && exit 42))
-
- exit $?.exitstatus
- RUBY
- end
-
- it "runs system inside with_original_env" do
- system({ "BUNDLE_FOO" => "bar" }, "ruby -I#{lib_dir} -rbundler -e '#{code}'")
- expect($?.exitstatus).to eq(42)
- end
- end
-
- describe "Bundler.clean_system", :bundler => 2 do
- let(:code) do
- <<~RUBY
- Bundler.ui.silence { Bundler.clean_system(%([ "\$BUNDLE_FOO" = "bar" ] || exit 42)) }
-
- exit $?.exitstatus
- RUBY
- end
-
- it "runs system inside with_clean_env" do
- system({ "BUNDLE_FOO" => "bar" }, "ruby -I#{lib_dir} -rbundler -e '#{code}'")
- expect($?.exitstatus).to eq(42)
- end
- end
-
- describe "Bundler.unbundled_system" do
- let(:code) do
- <<~RUBY
- Bundler.unbundled_system(%([ "\$BUNDLE_FOO" = "bar" ] || exit 42))
-
- exit $?.exitstatus
- RUBY
- end
-
- it "runs system inside with_unbundled_env" do
- system({ "BUNDLE_FOO" => "bar" }, "ruby -I#{lib_dir} -rbundler -e '#{code}'")
- expect($?.exitstatus).to eq(42)
- end
- end
-
- describe "Bundler.original_exec" do
- let(:code) do
- <<~RUBY
- Process.fork do
- exit Bundler.original_exec(%(test "\$BUNDLE_FOO" = "bar"))
- end
-
- _, status = Process.wait2
-
- exit(status.exitstatus)
- RUBY
- end
-
- it "runs exec inside with_original_env" do
- skip "Fork not implemented" if Gem.win_platform?
-
- system({ "BUNDLE_FOO" => "bar" }, "ruby -I#{lib_dir} -rbundler -e '#{code}'")
- expect($?.exitstatus).to eq(0)
- end
- end
-
- describe "Bundler.clean_exec", :bundler => 2 do
- let(:code) do
- <<~RUBY
- Process.fork do
- exit Bundler.ui.silence { Bundler.clean_exec(%(test "\$BUNDLE_FOO" = "bar")) }
- end
-
- _, status = Process.wait2
-
- exit(status.exitstatus)
- RUBY
- end
-
- it "runs exec inside with_clean_env" do
- skip "Fork not implemented" if Gem.win_platform?
-
- system({ "BUNDLE_FOO" => "bar" }, "ruby -I#{lib_dir} -rbundler -e '#{code}'")
- expect($?.exitstatus).to eq(1)
- end
- end
-
- describe "Bundler.unbundled_exec" do
- let(:code) do
- <<~RUBY
- Process.fork do
- exit Bundler.unbundled_exec(%(test "\$BUNDLE_FOO" = "bar"))
- end
-
- _, status = Process.wait2
-
- exit(status.exitstatus)
- RUBY
- end
-
- it "runs exec inside with_clean_env" do
- skip "Fork not implemented" if Gem.win_platform?
-
- system({ "BUNDLE_FOO" => "bar" }, "ruby -I#{lib_dir} -rbundler -e '#{code}'")
- expect($?.exitstatus).to eq(1)
- end
- end
-end