# frozen_string_literal: true RSpec.shared_examples "bundle install --standalone" do shared_examples "common functionality" do it "still makes the gems available to normal bundler" do args = expected_gems.map {|k, v| "#{k} #{v}" } expect(the_bundle).to include_gems(*args) end it "generates a bundle/bundler/setup.rb" do expect(bundled_app("bundle/bundler/setup.rb")).to exist end it "makes the gems available without bundler" do testrb = String.new <<-RUBY $:.unshift File.expand_path("bundle") require "bundler/setup" RUBY expected_gems.each do |k, _| testrb << "\nrequire \"#{k}\"" testrb << "\nputs #{k.upcase}" end Dir.chdir(bundled_app) do ruby testrb, :no_lib => true end expect(out).to eq(expected_gems.values.join("\n")) end it "works on a different system" do FileUtils.mv(bundled_app, "#{bundled_app}2") testrb = String.new <<-RUBY $:.unshift File.expand_path("bundle") require "bundler/setup" RUBY expected_gems.each do |k, _| testrb << "\nrequire \"#{k}\"" testrb << "\nputs #{k.upcase}" end Dir.chdir("#{bundled_app}2") do ruby testrb, :no_lib => true end expect(out).to eq(expected_gems.values.join("\n")) end end describe "with simple gems" do before do gemfile <<-G source "file://#{gem_repo1}" gem "rails" G bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true) end let(:expected_gems) do { "actionpack" => "2.3.2", "rails" => "2.3.2", } end include_examples "common functionality" end describe "with gems with native extension", :ruby_repo do before do install_gemfile <<-G, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true) source "file://#{gem_repo1}" gem "very_simple_binary" G end it "generates a bundle/bundler/setup.rb with the proper paths", :rubygems => "2.4" do expected_path = bundled_app("bundle/bundler/setup.rb") extension_line = File.read(expected_path).each_line.find {|line| line.include? "/extensions/" }.strip expect(extension_line).to start_with '$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/' expect(extension_line).to end_with '/very_simple_binary-1.0"' end end describe "with gem that has an invalid gemspec" do before do build_git "bar", :gemspec => false do |s| s.write "lib/bar/version.rb", %(BAR_VERSION = '1.0') s.write "bar.gemspec", <<-G lib = File.expand_path('../lib/', __FILE__) $:.unshift lib unless $:.include?(lib) require 'bar/version' Gem::Specification.new do |s| s.name = 'bar' s.version = BAR_VERSION s.summary = 'Bar' s.files = Dir["lib/**/*.rb"] s.author = 'Anonymous' s.require_path = [1,2] end G end install_gemfile <<-G, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true) gem "bar", :git => "#{lib_path("bar-1.0")}" G end it "outputs a helpful error message" do expect(out).to include("You have one or more invalid gemspecs that need to be fixed.") expect(out).to include("bar 1.0 has an invalid gemspec") end end describe "with a combination of gems and git repos" do before do build_git "devise", "1.0" gemfile <<-G source "file://#{gem_repo1}" gem "rails" gem "devise", :git => "#{lib_path("devise-1.0")}" G bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true) end let(:expected_gems) do { "actionpack" => "2.3.2", "devise" => "1.0", "rails" => "2.3.2", } end include_examples "common functionality" end describe "with groups" do before do build_git "devise", "1.0" gemfile <<-G source "file://#{gem_repo1}" gem "rails" group :test do gem "rspec" gem "rack-test" end G bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true) end let(:expected_gems) do { "actionpack" => "2.3.2", "rails" => "2.3.2", } end include_examples "common functionality" it "allows creating a standalone file with limited groups" do bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => "default") Dir.chdir(bundled_app) do load_error_ruby <<-RUBY, "spec", :no_lib => true $:.unshift File.expand_path("bundle") require "bundler/setup" require "actionpack" puts ACTIONPACK require "spec" RUBY end expect(last_command.stdout).to eq("2.3.2") expect(last_command.stderr).to eq("ZOMG LOAD ERROR") end it "allows --without to limit the groups used in a standalone" do bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle"), :without => "test").merge(:standalone => true) Dir.chdir(bundled_app) do load_error_ruby <<-RUBY, "spec", :no_lib => true $:.unshift File.expand_path("bundle") require "bundler/setup" require "actionpack" puts ACTIONPACK require "spec" RUBY end expect(last_command.stdout).to eq("2.3.2") expect(last_command.stderr).to eq("ZOMG LOAD ERROR") end it "allows --path to change the location of the standalone bundle", :bundler => "< 3" do bundle! "install", forgotten_command_line_options(:path => "path/to/bundle").merge(:standalone => true) Dir.chdir(bundled_app) do ruby <<-RUBY, :no_lib => true $:.unshift File.expand_path("path/to/bundle") require "bundler/setup" require "actionpack" puts ACTIONPACK RUBY end expect(last_command.stdout).to eq("2.3.2") end it "allows --path to change the location of the standalone bundle", :bundler => "3" do bundle! "install", forgotten_command_line_options(:path => "path/to/bundle").merge(:standalone => true) path = File.expand_path("path/to/bundle") Dir.chdir(bundled_app) do ruby <<-RUBY, :no_lib => true $:.unshift File.expand_path(#{path.dump}) require "bundler/setup" require "actionpack" puts ACTIONPACK RUBY end expect(last_command.stdout).to eq("2.3.2") end it "allows remembered --without to limit the groups used in a standalone" do bundle! :install, forgotten_command_line_options(:without => "test") bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true) Dir.chdir(bundled_app) do load_error_ruby <<-RUBY, "spec", :no_lib => true $:.unshift File.expand_path("bundle") require "bundler/setup" require "actionpack" puts ACTIONPACK require "spec" RUBY end expect(last_command.stdout).to eq("2.3.2") expect(last_command.stderr).to eq("ZOMG LOAD ERROR") end end describe "with gemcutter's dependency API" do let(:source_uri) { "http://localgemserver.test" } describe "simple gems" do before do gemfile <<-G source "#{source_uri}" gem "rails" G bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true, :artifice => "endpoint") end let(:expected_gems) do { "actionpack" => "2.3.2", "rails" => "2.3.2", } end include_examples "common functionality" end end describe "with --binstubs", :bundler => "< 3" do before do gemfile <<-G source "file://#{gem_repo1}" gem "rails" G bundle! :install, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true, :binstubs => true) end let(:expected_gems) do { "actionpack" => "2.3.2", "rails" => "2.3.2", } end include_examples "common functionality" it "creates stubs that use the standalone load path" do Dir.chdir(bundled_app) do expect(`bin/rails -v`.chomp).to eql "2.3.2" end end it "creates stubs that can be executed from anywhere" do require "tmpdir" Dir.chdir(Dir.tmpdir) do sys_exec!(%(#{bundled_app("bin/rails")} -v)) expect(out).to eq("2.3.2") end end it "creates stubs that can be symlinked" do pending "File.symlink is unsupported on Windows" if Bundler::WINDOWS symlink_dir = tmp("symlink") FileUtils.mkdir_p(symlink_dir) symlink = File.join(symlink_dir, "rails") File.symlink(bundled_app("bin/rails"), symlink) sys_exec!("#{symlink} -v") expect(out).to eq("2.3.2") end it "creates stubs with the correct load path" do extension_line = File.read(bundled_app("bin/rails")).each_line.find {|line| line.include? "$:.unshift" }.strip expect(extension_line).to eq %($:.unshift File.expand_path "../../bundle", path.realpath) end end end RSpec.describe "bundle install --standalone" do include_examples("bundle install --standalone") end RSpec.describe "bundle install --standalone run in a subdirectory" do before do Dir.chdir(bundled_app("bob").tap(&:mkpath)) end include_examples("bundle install --standalone") end