1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/spec/bundler/runtime/setup_spec.rb

1433 lines
37 KiB
Ruby
Raw Normal View History

# 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
G
ruby <<-RUBY
require '#{lib_dir}/bundler'
Bundler.setup
require 'rack'
puts RACK
RUBY
expect(err).to be_empty
expect(out).to eq("1.0.0")
end
end
describe "when called with groups" do
before(:each) do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "yard"
gem "rack", :group => :test
G
end
it "doesn't make all groups available" do
ruby <<-RUBY
require '#{lib_dir}/bundler'
Bundler.setup(:default)
begin
require 'rack'
rescue LoadError
puts "WIN"
end
RUBY
expect(err).to be_empty
expect(out).to eq("WIN")
end
it "accepts string for group name" do
ruby <<-RUBY
require '#{lib_dir}/bundler'
Bundler.setup(:default, 'test')
require 'rack'
puts RACK
RUBY
expect(err).to be_empty
expect(out).to eq("1.0.0")
end
it "leaves all groups available if they were already" do
ruby <<-RUBY
require '#{lib_dir}/bundler'
Bundler.setup
Bundler.setup(:default)
require 'rack'
puts RACK
RUBY
expect(err).to be_empty
expect(out).to eq("1.0.0")
end
it "leaves :default available if setup is called twice" do
ruby <<-RUBY
require '#{lib_dir}/bundler'
Bundler.setup(:default)
Bundler.setup(:default, :test)
begin
require 'yard'
puts "WIN"
rescue LoadError
puts "FAIL"
end
RUBY
expect(err).to be_empty
expect(out).to match("WIN")
end
it "handles multiple non-additive invocations" do
ruby <<-RUBY, :raise_on_error => false
require '#{lib_dir}/bundler'
Bundler.setup(:default, :test)
Bundler.setup(:default)
require 'rack'
puts "FAIL"
RUBY
expect(err).to match("rack")
expect(err).to match("LoadError")
expect(out).not_to match("FAIL")
end
end
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, "") }
end
it "puts loaded gems after -I and RUBYLIB", :ruby_repo do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
ENV["RUBYOPT"] = "#{ENV["RUBYOPT"]} -Idash_i_dir"
ENV["RUBYLIB"] = "rubylib_dir"
ruby <<-RUBY
require '#{lib_dir}/bundler'
Bundler.setup
puts $LOAD_PATH
RUBY
load_path = out.split("\n")
rack_load_order = load_path.index {|path| path.include?("rack") }
2019-12-14 05:49:16 -05:00
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
end
it "orders the load path correctly when there are dependencies" do
2020-05-15 08:31:12 -04:00
bundle "config set path.system true"
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
ruby <<-RUBY
require '#{lib_dir}/bundler'
Bundler.setup
puts $LOAD_PATH
RUBY
load_path = clean_load_path(out.split("\n"))
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-13.0.1/lib"
)
end
it "falls back to order the load path alphabetically for backwards compatibility" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "weakling"
gem "duradura"
gem "terranova"
G
ruby <<-RUBY
require '#{lib_dir}/bundler/setup'
puts $LOAD_PATH
RUBY
load_path = clean_load_path(out.split("\n"))
expect(load_path).to start_with(
"/gems/weakling-0.0.3/lib",
"/gems/terranova-8/lib",
"/gems/duradura-7.0/lib"
)
end
end
it "raises if the Gemfile was not yet installed" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
ruby <<-R
require '#{lib_dir}/bundler'
begin
Bundler.setup
puts "FAIL"
rescue Bundler::GemNotFound
puts "WIN"
end
R
expect(out).to eq("WIN")
end
it "doesn't create a Gemfile.lock if the setup fails" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
ruby <<-R, :raise_on_error => false
require '#{lib_dir}/bundler'
Bundler.setup
R
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"
G
lockfile = File.read(bundled_app_lock)
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
gem "nosuchgem", "10.0"
G
ruby <<-R, :raise_on_error => false
require '#{lib_dir}/bundler'
Bundler.setup
R
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"
G
File.read(bundled_app_lock)
FileUtils.rm(bundled_app_lock)
run "1"
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"
G
gemfile bundled_app("4realz"), <<-G
source "#{file_uri_for(gem_repo1)}"
gem "activesupport", "2.3.5"
G
ENV["BUNDLE_GEMFILE"] = bundled_app("4realz").to_s
bundle :install
expect(the_bundle).to include_gems "activesupport 2.3.5"
end
end
context "an absolute path is not provided" 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)}"
G
bundle "install"
bundle "config set --local deployment true"
ENV["BUNDLE_GEMFILE"] = "Gemfile"
ruby <<-R
require '#{lib_dir}/bundler'
begin
Bundler.setup
puts "WIN"
rescue ArgumentError => e
puts "FAIL"
end
R
expect(out).to eq("WIN")
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"
G
build_gem "rack", "1.0", :to_system => true do |s|
s.write "lib/rack.rb", "RACK = 'FAIL'"
end
expect(the_bundle).to include_gems "rack 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"
G
end
it "replaces #gem but raises when the gem is missing" do
run <<-R
begin
gem "activesupport"
puts "FAIL"
rescue LoadError
puts "WIN"
end
R
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"
puts "FAIL"
rescue LoadError
puts "WIN"
end
R
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)}"
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")
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 }
expect(out).to eq("worked!")
end
end
end
end
describe "with paths" do
it "activates the gems in the path source" do
system_gems "rack-1.0.0"
build_lib "rack", "1.0.0" do |s|
s.write "lib/rack.rb", "puts 'WIN'"
end
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
path "#{lib_path("rack-1.0.0")}" do
gem "rack"
end
G
run "require 'rack'"
expect(out).to eq("WIN")
end
end
describe "with git" do
before do
build_git "rack", "1.0.0"
gemfile <<-G
gem "rack", :git => "#{lib_path("rack-1.0.0")}"
G
end
it "provides a useful exception when the git repo is not checked out yet" do
run "1", :raise_on_error => false
expect(err).to match(/the git source #{lib_path('rack-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
bundle "install"
break_git!
ruby <<-R
require '#{lib_dir}/bundler'
begin
Bundler.setup
puts "WIN"
rescue Exception => e
puts "FAIL"
end
R
expect(out).to eq("WIN")
end
it "provides a good exception if the lockfile is unavailable" do
bundle "install"
FileUtils.rm(bundled_app_lock)
break_git!
ruby <<-R
require "#{lib_dir}/bundler"
begin
Bundler.setup
puts "FAIL"
rescue Bundler::GitError => e
puts e.message
end
R
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 "config --local path vendor/bundle"
bundle :install
FileUtils.rm_rf vendored_gems("cache")
expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does not randomly change the path when specifying --path and the bundle directory becomes read only" do
bundle "config --local path vendor/bundle"
bundle :install
with_read_only("#{bundled_app}/**/*") do
expect(the_bundle).to include_gems "rack 1.0.0"
end
end
it "finds git gem when default bundle path becomes read only" do
bundle "config set --local path .bundle"
bundle "install"
with_read_only("#{bundled_app(".bundle")}/**/*") do
expect(the_bundle).to include_gems "rack 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"
FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
G
bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install
FileUtils.rm_rf(lib_path("local-rack"))
run "require 'rack'", :raise_on_error => false
expect(err).to match(/Cannot use local override for rack-0.8 because #{Regexp.escape(lib_path('local-rack').to_s)} does not exist/)
end
it "explodes if branch is not given on runtime" do
build_git "rack", "0.8"
FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
G
bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", :git => "#{lib_path("rack-0.8")}"
G
run "require 'rack'", :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"
FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
G
bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "changed"
G
run "require 'rack'", :raise_on_error => false
expect(err).to match(/is using branch master but Gemfile specifies changed/)
end
it "explodes on refs with different branches on runtime" do
build_git "rack", "0.8"
FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "master", :branch => "master"
G
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "master", :branch => "nonexistant"
G
bundle %(config set local.rack #{lib_path("local-rack")})
run "require 'rack'", :raise_on_error => false
expect(err).to match(/is using branch master but Gemfile specifies nonexistant/)
end
end
describe "when excluding groups" do
it "doesn't change the resolve if --without is used" do
bundle "config --local without rails"
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
group :rails do
gem "rails", "2.3.2"
end
G
system_gems "activesupport-2.3.5"
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
bundle "config --local without rails"
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
group :rails do
gem "rails", "2.3.2"
end
G
system_gems "activesupport-2.3.5"
expect(the_bundle).to include_gems "activesupport 2.3.2"
end
2020-10-15 00:20:25 -04:00
it "remembers --without and does not bail on bare Bundler.setup, even in the case of path gems no longer available" do
bundle "config --local without development"
path = bundled_app(File.join("vendor", "foo"))
build_lib "foo", :path => path
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "activesupport", "2.3.2"
gem 'foo', :path => 'vendor/foo', :group => :development
G
FileUtils.rm_rf(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 "remembers --without and does not include groups passed to Bundler.setup" do
bundle "config --local without rails"
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
group :rack do
gem "rack"
end
group :rails do
gem "rails", "2.3.2"
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
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
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
gem "foo", :git => "#{lib_path("foo-1.0")}"
gem "no-gemspec", "1.0", :git => "#{lib_path("no-gemspec-1.0")}"
G
run <<-R
Gem.loaded_specs.each do |n, s|
puts "FAIL" unless s.loaded_from.is_a?(String)
end
R
expect(out).to be_empty
end
it "does not load all gemspecs" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
run <<-R
File.open(File.join(Gem.dir, "specifications", "broken.gemspec"), "w") do |f|
f.write <<-RUBY
# -*- encoding: utf-8 -*-
# stub: broken 1.0.0 ruby lib
Gem::Specification.new do |s|
s.name = "broken"
s.version = "1.0.0"
raise "BROKEN GEMSPEC"
end
RUBY
end
R
run <<-R
puts "WIN"
R
expect(out).to eq("WIN")
end
it "ignores empty gem paths" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
ENV["GEM_HOME"] = ""
bundle %(exec ruby -e "require 'set'")
expect(err).to be_empty
end
describe "$MANPATH" do
before do
build_repo4 do
build_gem "with_man" do |s|
s.write("man/man1/page.1", "MANPAGE")
end
end
end
context "when the user has one set" do
before { ENV["MANPATH"] = "/foo#{File::PATH_SEPARATOR}" }
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 "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 does not have one set" 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
run "puts ENV['MANPATH']"
expect(out).to eq(default_bundle_path("gems/with_man-1.0/man").to_s)
end
end
end
it "should prepend gemspec require paths to $LOAD_PATH in order" do
update_repo2 do
build_gem("requirepaths") do |s|
s.write("lib/rq.rb", "puts 'yay'")
s.write("src/rq.rb", "puts 'nooo'")
s.require_paths = %w[lib src]
end
end
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gem "requirepaths", :require => nil
G
run "require 'rq'"
expect(out).to eq("yay")
end
it "should clean $LOAD_PATH properly", :ruby_repo do
gem_name = "very_simple_binary"
full_gem_name = gem_name + "-1.0"
ext_dir = File.join(tmp("extensions", full_gem_name))
system_gems full_gem_name
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
G
ruby <<-R
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 }
require '#{lib_dir}/bundler'
gem '#{gem_name}'
puts $LOAD_PATH.count {|path| path =~ /#{gem_name}/} >= 2
Bundler.setup
puts $LOAD_PATH.count {|path| path =~ /#{gem_name}/} == 0
R
expect(out).to eq("true\ntrue")
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(:full_name) { "bundler-#{Bundler::VERSION}" }
before do
skip "symlink destination exists" if Gem.win_platform?
FileUtils.ln_sf(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)
2020-05-15 08:31:12 -04:00
FileUtils.ln_s(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
File.open(File.join(specifications_dir, "#{full_name}.gemspec"), "wb") do |f|
f.write(gemspec_content)
end
end
Fix some bundler specs (#2380) * These seem to consistenly pass already * Show actual command when running `make test-bundler` Current the setup command that installs the necessary gems for testing bundler was printed, but not the actual command that runs the tests. That was a bit confusing. * Borrow trick from setproctitle specs * A title that long doesn't get set sometimes No idea why, but the test doesn't need that the title is that long. * Fix most gem helper spec ruby-core failures * Fix the rest of the gem helper failures * Fix version spec by improving the assertion * Remove unnecessary `BUNDLE_RUBY` environment var We can use `RUBY` when necessary, and `BUNDLE_RUBY` is not a good name because bundler considers `BUNDLE_*` variables as settings. * Rename `BUNDLE_GEM` to `GEM_COMMAND` This is more descriptive I think, and also friendlier for bundler because `BUNDLE_` env variables are interpreted by bundler as settings, and this is not a bundler setting. This fixes one bundler spec failure in config specs against ruby-core. * Fix quality spec when run in core Use the proper path helper. * Fix dummy lib builder to never load default gems If a dummy library is named as a default gem, when requiring the library from its executable, the default gem would be loaded when running from core, because in core all default gems share path with bundler, and thus they are always in the $LOAD_PATH. We fix the issue by loading lib relatively inside dummy lib executables. * More exact assertions Sometimes I have the problem that I do some "print debugging" inside specs, and suddently the spec passes. This happens when the assertion is too relaxed, and the things I print make it match, specially when they are simple strings like "1.0" than can be easily be part of gem paths that I print for debugging. I fix this by making a more exact assertion. * Detect the correct shebang when ENV["RUBY"] is set * Relax assertion So that the spec passes even if another paths containing "ext" are in the load path. This works to fix a ruby-core issue, but it's a better assertion in general. We just want to know that the extension path was added. * Use folder structure independent path helper It should fix this spec for ruby-core. * Fix the last failing spec on ruby-core * Skip `bundle open <default_gem>` spec when no default gems
2019-08-19 20:46:31 -04:00
it "should not remove itself from the LOAD_PATH and require a different copy of 'bundler/setup'" do
install_gemfile ""
2020-05-15 08:31:12 -04:00
ruby <<-R, :env => { "GEM_PATH" => symlinked_gem_home }
TracePoint.trace(:class) do |tp|
2020-05-15 08:31:12 -04:00
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
gem 'bundler', '#{Bundler::VERSION}'
require 'bundler/setup'
R
expect(out).to be_empty
end
end
it "does not reveal system gems even when Gem.refresh is called" do
system_gems "rack-1.0.0"
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
G
run <<-R
puts Bundler.rubygems.all_specs.map(&:name)
Gem.refresh
puts Bundler.rubygems.all_specs.map(&:name)
R
expect(out).to eq("activesupport\nbundler\nactivesupport\nbundler")
end
describe "when a vendored gem specification uses the :path option" do
2019-12-14 05:49:16 -05:00
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
# 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
gem 'foo', '1.2.3', :path => 'vendor/foo'
G
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
2019-12-14 05:49:16 -05:00
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
# 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
gem 'foo', '1.2.3', :path => '#{relative_path}'
G
bundle :install
run <<-R, :env => { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, :dir => bundled_app.parent
require 'foo'
R
expect(err).to be_empty
end
end
describe "with git gems that don't have gemspecs" do
before :each do
2020-01-08 02:11:52 -05:00
build_git "no_gemspec", :gemspec => false
install_gemfile <<-G
2020-01-08 02:11:52 -05:00
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
2020-01-08 02:11:52 -05:00
require 'no_gemspec'
puts NO_GEMSPEC
R
expect(out).to eq("1.0")
end
end
describe "with bundled and system gems" do
before :each do
system_gems "rack-1.0.0"
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "activesupport", "2.3.5"
G
end
it "does not pull in system gems" do
run <<-R
begin;
require 'rack'
rescue LoadError
puts 'WIN'
end
R
expect(out).to eq("WIN")
end
it "provides a gem method" do
run <<-R
gem 'activesupport'
require 'activesupport'
puts ACTIVESUPPORT
R
expect(out).to eq("2.3.5")
end
it "raises an exception if gem is used to invoke a system gem not in the bundle" do
run <<-R
begin
gem 'rack'
rescue LoadError => e
puts e.message
end
R
expect(out).to eq("rack is not part of the bundle. Add it to your Gemfile.")
end
it "sets GEM_HOME appropriately" do
run "puts ENV['GEM_HOME']"
expect(out).to eq(default_bundle_path.to_s)
end
end
describe "with system gems in the bundle" do
before :each do
bundle "config set path.system true"
system_gems "rack-1.0.0"
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", "1.0.0"
gem "activesupport", "2.3.5"
G
end
it "sets GEM_PATH appropriately" do
run "puts Gem.path"
paths = out.split("\n")
expect(paths).to include(system_gem_path.to_s)
end
end
describe "with a gemspec that requires other files" do
before :each 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'
end
G
end
gemfile <<-G
gem "bar", :git => "#{lib_path("bar-1.0")}"
G
end
it "evals each gemspec in the context of its parent directory" do
bundle :install
run "require 'bar'; puts BAR"
expect(out).to eq("1.0")
end
it "error intelligently if the gemspec has a LoadError" do
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, :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'"
)
end
it "evals each gemspec with a binding from the top level" do
bundle "install"
ruby <<-RUBY
require '#{lib_dir}/bundler'
2019-12-14 05:49:16 -05:00
bundler_module = class << Bundler; self; end
bundler_module.send(:remove_method, :require)
def Bundler.require(path)
raise "LOSE"
end
Bundler.load
RUBY
expect(err).to be_empty
2019-12-14 05:49:16 -05:00
expect(out).to be_empty
end
end
describe "when Bundler is bundled" do
it "doesn't blow up" do
install_gemfile <<-G
gem "bundler", :path => "#{root}"
G
bundle %(exec ruby -e "require 'bundler'; Bundler.setup")
expect(err).to be_empty
end
end
describe "when BUNDLED WITH" do
def lock_with(bundler_version = nil)
lock = <<-L
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
rack
L
if bundler_version
lock += "\n BUNDLED WITH\n #{bundler_version}\n"
end
lock
end
before do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
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)
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'"
2019-12-14 05:49:16 -05:00
expect(out).to be_empty
expect(err).to be_empty
lockfile_should_be lock_with(Bundler::VERSION.succ)
end
end
context "is older" do
it "does not change the lock" do
lockfile lock_with("1.10.1")
ruby "require '#{lib_dir}/bundler/setup'"
lockfile_should_be lock_with("1.10.1")
end
end
end
describe "when RUBY VERSION" do
let(:ruby_version) { nil }
def lock_with(ruby_version = nil)
lock = <<-L
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
rack
L
if ruby_version
lock += "\n RUBY VERSION\n ruby #{ruby_version}\n"
end
lock += <<-L
BUNDLED WITH
#{Bundler::VERSION}
L
lock
end
before do
install_gemfile <<-G
ruby ">= 0"
source "#{file_uri_for(gem_repo1)}"
gem "rack"
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 }
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 }
2019-12-14 05:49:16 -05:00
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 }
end
end
end
describe "with gemified standard libraries" do
it "does not load Psych" do
gemfile ""
ruby <<-RUBY
require '#{lib_dir}/bundler/setup'
puts defined?(Psych::VERSION) ? Psych::VERSION : "undefined"
require 'psych'
puts Psych::VERSION
RUBY
pre_bundler, post_bundler = out.split("\n")
expect(pre_bundler).to eq("undefined")
expect(post_bundler).to match(/\d+\.\d+\.\d+/)
end
it "does not load openssl" do
install_gemfile ""
ruby <<-RUBY
require "#{lib_dir}/bundler/setup"
puts defined?(OpenSSL) || "undefined"
require "openssl"
puts defined?(OpenSSL) || "undefined"
RUBY
expect(out).to eq("undefined\nconstant")
end
describe "default gem activation" do
let(:exemptions) do
exempts = if Gem::Version.new(Gem::VERSION) >= Gem::Version.new("2.7")
%w[did_you_mean]
else
%w[io-console openssl]
end << "bundler"
exempts << "fiddle" if Gem.win_platform? && Gem::Version.new(Gem::VERSION) >= Gem::Version.new("2.7")
2020-05-15 08:31:12 -04:00
exempts << "uri" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7")
2020-12-08 02:36:29 -05:00
exempts << "pathname" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0")
exempts << "set" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0")
exempts << "tsort" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0")
exempts
end
let(:activation_warning_hack) { strip_whitespace(<<-RUBY) }
require #{spec_dir.join("support/hax").to_s.dump}
2019-12-14 05:49:16 -05:00
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
2019-12-14 05:49:16 -05:00
bundler_spec_activate
end
RUBY
let(:activation_warning_hack_rubyopt) do
create_file("activation_warning_hack.rb", activation_warning_hack)
"-r#{bundled_app("activation_warning_hack.rb")} #{ENV["RUBYOPT"]}"
end
let(:code) { strip_whitespace(<<-RUBY) }
require "pp"
loaded_specs = Gem.loaded_specs.dup
#{exemptions.inspect}.each {|s| loaded_specs.delete(s) }
pp loaded_specs
# not a default gem, but harmful to have loaded
open_uri = $LOADED_FEATURES.grep(/open.uri/)
unless open_uri.empty?
warn "open_uri: \#{open_uri}"
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" }
expect(out).to eq("{}")
end
it "activates no gems with bundle exec" do
install_gemfile ""
create_file("script.rb", code)
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
skip "not executable" if Gem.win_platform?
install_gemfile ""
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 }
expect(out).to eq("{}")
end
2020-01-08 02:11:52 -05:00
it "does not load net-http-pipeline too early" do
build_repo4 do
build_gem "net-http-pipeline", "1.0.1"
end
2020-05-15 08:31:12 -04:00
system_gems "net-http-pipeline-1.0.1", :gem_repo => gem_repo4
gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
gem "net-http-pipeline", "1.0.1"
G
bundle "config set --local path vendor/bundle"
2020-01-08 02:11:52 -05:00
bundle :install
2020-01-08 02:11:52 -05:00
bundle :check
2020-01-08 02:11:52 -05:00
2020-05-15 08:31:12 -04:00
expect(out).to eq("The Gemfile's dependencies are satisfied")
end
2020-01-08 02:11:52 -05:00
2020-12-20 20:54:24 -05:00
# bundler respects paths specified directly in RUBYLIB or RUBYOPT, and
2020-05-15 08:31:12 -04:00
# that happens when running ruby from the ruby-core setup. To
# workaround, we manually remove those for these tests when they would
# override the default gem.
def load_path_exclusions_hack_for(name)
if ruby_core?
ext_folder = source_root.join(".ext/common")
require_name = name.tr("-", "/")
if File.exist?(ext_folder.join("#{require_name}.rb"))
{ :exclude_from_load_path => ext_folder.to_s }
else
lib_folder = source_root.join("lib")
if File.exist?(lib_folder.join("#{require_name}.rb"))
{ :exclude_from_load_path => lib_folder.to_s }
else
{}
end
end
else
{}
2020-01-08 02:11:52 -05:00
end
end
2019-12-14 05:49:16 -05:00
Gem::Specification.select(&:default_gem?).map(&:name).each do |g|
it "activates newer versions of #{g}" do
skip if exemptions.include?(g)
2019-12-14 05:49:16 -05:00
build_repo4 do
build_gem g, "999999"
end
install_gemfile <<-G
2019-12-14 05:49:16 -05:00
source "#{file_uri_for(gem_repo4)}"
gem "#{g}", "999999"
G
2020-05-15 08:31:12 -04:00
opts = { :env => { "RUBYOPT" => activation_warning_hack_rubyopt } }
expect(the_bundle).to include_gem("#{g} 999999", opts.merge(load_path_exclusions_hack_for(g)))
2019-12-14 05:49:16 -05:00
end
2019-12-14 05:49:16 -05:00
it "activates older versions of #{g}" do
skip if exemptions.include?(g)
2019-12-14 05:49:16 -05:00
build_repo4 do
build_gem g, "0.0.0.a"
end
install_gemfile <<-G
2019-12-14 05:49:16 -05:00
source "#{file_uri_for(gem_repo4)}"
gem "#{g}", "0.0.0.a"
G
2020-05-15 08:31:12 -04:00
opts = { :env => { "RUBYOPT" => activation_warning_hack_rubyopt } }
expect(the_bundle).to include_gem("#{g} 0.0.0.a", opts.merge(load_path_exclusions_hack_for(g)))
2019-12-14 05:49:16 -05:00
end
end
end
end
describe "after setup" do
it "allows calling #gem on random objects", :bundler => "< 3" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
ruby <<-RUBY
require "#{lib_dir}/bundler/setup"
Object.new.gem "rack"
puts Gem.loaded_specs["rack"].full_name
RUBY
expect(out).to eq("rack-1.0.0")
end
it "keeps Kernel#gem private", :bundler => "3" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
ruby <<-RUBY, :raise_on_error => false
require "#{lib_dir}/bundler/setup"
Object.new.gem "rack"
puts "FAIL"
RUBY
expect(last_command.stdboth).not_to include "FAIL"
expect(err).to include "private method `gem'"
end
it "keeps Kernel#require private" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
ruby <<-RUBY, :raise_on_error => false
require "#{lib_dir}/bundler/setup"
Object.new.require "rack"
puts "FAIL"
RUBY
expect(last_command.stdboth).not_to include "FAIL"
expect(err).to include "private method `require'"
end
it "takes care of requiring rubygems" do
sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler/setup -e'puts true'", :env => { "RUBYOPT" => opt_add("--disable=gems", ENV["RUBYOPT"]) })
expect(last_command.stdboth).to eq("true")
end
end
end