mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			953 lines
		
	
	
	
		
			27 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			953 lines
		
	
	
	
		
			27 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
# frozen_string_literal: true
 | 
						|
 | 
						|
RSpec.describe "bundle exec" do
 | 
						|
  let(:system_gems_to_install) { %w[rack-1.0.0 rack-0.9.1] }
 | 
						|
  before :each do
 | 
						|
    system_gems(system_gems_to_install, :path => default_bundle_path)
 | 
						|
  end
 | 
						|
 | 
						|
  it "works with --gemfile flag" do
 | 
						|
    create_file "CustomGemfile", <<-G
 | 
						|
      gem "rack", "1.0.0"
 | 
						|
    G
 | 
						|
 | 
						|
    bundle "exec --gemfile CustomGemfile rackup"
 | 
						|
    expect(out).to eq("1.0.0")
 | 
						|
  end
 | 
						|
 | 
						|
  it "activates the correct gem" do
 | 
						|
    gemfile <<-G
 | 
						|
      gem "rack", "0.9.1"
 | 
						|
    G
 | 
						|
 | 
						|
    bundle "exec rackup"
 | 
						|
    expect(out).to eq("0.9.1")
 | 
						|
  end
 | 
						|
 | 
						|
  it "works when the bins are in ~/.bundle" do
 | 
						|
    install_gemfile <<-G
 | 
						|
      gem "rack"
 | 
						|
    G
 | 
						|
 | 
						|
    bundle "exec rackup"
 | 
						|
    expect(out).to eq("1.0.0")
 | 
						|
  end
 | 
						|
 | 
						|
  it "works when running from a random directory" do
 | 
						|
    install_gemfile <<-G
 | 
						|
      gem "rack"
 | 
						|
    G
 | 
						|
 | 
						|
    bundle "exec 'cd #{tmp("gems")} && rackup'"
 | 
						|
 | 
						|
    expect(out).to eq("1.0.0")
 | 
						|
  end
 | 
						|
 | 
						|
  it "works when exec'ing something else" do
 | 
						|
    install_gemfile 'gem "rack"'
 | 
						|
    bundle "exec echo exec"
 | 
						|
    expect(out).to eq("exec")
 | 
						|
  end
 | 
						|
 | 
						|
  it "works when exec'ing to ruby" do
 | 
						|
    install_gemfile 'gem "rack"'
 | 
						|
    bundle "exec ruby -e 'puts %{hi}'"
 | 
						|
    expect(out).to eq("hi")
 | 
						|
  end
 | 
						|
 | 
						|
  it "works when exec'ing to rubygems" do
 | 
						|
    install_gemfile 'gem "rack"'
 | 
						|
    bundle "exec #{gem_cmd} --version"
 | 
						|
    expect(out).to eq(Gem::VERSION)
 | 
						|
  end
 | 
						|
 | 
						|
  it "works when exec'ing to rubygems through sh -c" do
 | 
						|
    install_gemfile 'gem "rack"'
 | 
						|
    bundle "exec sh -c '#{gem_cmd} --version'"
 | 
						|
    expect(out).to eq(Gem::VERSION)
 | 
						|
  end
 | 
						|
 | 
						|
  it "respects custom process title when loading through ruby" do
 | 
						|
    skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform?
 | 
						|
 | 
						|
    script_that_changes_its_own_title_and_checks_if_picked_up_by_ps_unix_utility = <<~'RUBY'
 | 
						|
      Process.setproctitle("1-2-3-4-5-6-7")
 | 
						|
      puts `ps -ocommand= -p#{$$}`
 | 
						|
    RUBY
 | 
						|
    create_file "Gemfile"
 | 
						|
    create_file "a.rb", script_that_changes_its_own_title_and_checks_if_picked_up_by_ps_unix_utility
 | 
						|
    bundle "exec ruby a.rb"
 | 
						|
    expect(out).to eq("1-2-3-4-5-6-7")
 | 
						|
  end
 | 
						|
 | 
						|
  it "accepts --verbose" do
 | 
						|
    install_gemfile 'gem "rack"'
 | 
						|
    bundle "exec --verbose echo foobar"
 | 
						|
    expect(out).to eq("foobar")
 | 
						|
  end
 | 
						|
 | 
						|
  it "passes --verbose to command if it is given after the command" do
 | 
						|
    install_gemfile 'gem "rack"'
 | 
						|
    bundle "exec echo --verbose"
 | 
						|
    expect(out).to eq("--verbose")
 | 
						|
  end
 | 
						|
 | 
						|
  it "handles --keep-file-descriptors" do
 | 
						|
    skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform?
 | 
						|
 | 
						|
    require "tempfile"
 | 
						|
 | 
						|
    command = Tempfile.new("io-test")
 | 
						|
    command.sync = true
 | 
						|
    command.write <<-G
 | 
						|
      if ARGV[0]
 | 
						|
        IO.for_fd(ARGV[0].to_i)
 | 
						|
      else
 | 
						|
        require 'tempfile'
 | 
						|
        io = Tempfile.new("io-test-fd")
 | 
						|
        args = %W[#{Gem.ruby} -I#{lib_dir} #{bindir.join("bundle")} exec --keep-file-descriptors #{Gem.ruby} #{command.path} \#{io.to_i}]
 | 
						|
        args << { io.to_i => io }
 | 
						|
        exec(*args)
 | 
						|
      end
 | 
						|
    G
 | 
						|
 | 
						|
    install_gemfile ""
 | 
						|
    sys_exec "#{Gem.ruby} #{command.path}"
 | 
						|
 | 
						|
    expect(out).to be_empty
 | 
						|
    expect(err).to be_empty
 | 
						|
  end
 | 
						|
 | 
						|
  it "accepts --keep-file-descriptors" do
 | 
						|
    install_gemfile ""
 | 
						|
    bundle "exec --keep-file-descriptors echo foobar"
 | 
						|
 | 
						|
    expect(err).to be_empty
 | 
						|
  end
 | 
						|
 | 
						|
  it "can run a command named --verbose" do
 | 
						|
    skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform?
 | 
						|
 | 
						|
    install_gemfile 'gem "rack"'
 | 
						|
    File.open(bundled_app("--verbose"), "w") do |f|
 | 
						|
      f.puts "#!/bin/sh"
 | 
						|
      f.puts "echo foobar"
 | 
						|
    end
 | 
						|
    File.chmod(0o744, bundled_app("--verbose"))
 | 
						|
    with_path_as(".") do
 | 
						|
      bundle "exec -- --verbose"
 | 
						|
    end
 | 
						|
    expect(out).to eq("foobar")
 | 
						|
  end
 | 
						|
 | 
						|
  it "handles different versions in different bundles" do
 | 
						|
    build_repo2 do
 | 
						|
      build_gem "rack_two", "1.0.0" do |s|
 | 
						|
        s.executables = "rackup"
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    install_gemfile <<-G
 | 
						|
      source "#{file_uri_for(gem_repo1)}"
 | 
						|
      gem "rack", "0.9.1"
 | 
						|
    G
 | 
						|
 | 
						|
    install_gemfile bundled_app2("Gemfile"), <<-G, :dir => bundled_app2
 | 
						|
      source "#{file_uri_for(gem_repo2)}"
 | 
						|
      gem "rack_two", "1.0.0"
 | 
						|
    G
 | 
						|
 | 
						|
    bundle! "exec rackup"
 | 
						|
 | 
						|
    expect(out).to eq("0.9.1")
 | 
						|
 | 
						|
    bundle! "exec rackup", :dir => bundled_app2
 | 
						|
    expect(out).to eq("1.0.0")
 | 
						|
  end
 | 
						|
 | 
						|
  context "with default gems" do
 | 
						|
    let(:system_gems_to_install) { [] }
 | 
						|
 | 
						|
    let(:default_irb_version) { ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", :raise_on_error => false }
 | 
						|
 | 
						|
    context "when not specified in Gemfile" do
 | 
						|
      before do
 | 
						|
        skip "irb isn't a default gem" if default_irb_version.empty?
 | 
						|
 | 
						|
        install_gemfile ""
 | 
						|
      end
 | 
						|
 | 
						|
      it "uses version provided by ruby" do
 | 
						|
        bundle! "exec irb --version"
 | 
						|
 | 
						|
        expect(out).to include(default_irb_version)
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    context "when specified in Gemfile directly" do
 | 
						|
      let(:specified_irb_version) { "0.9.6" }
 | 
						|
 | 
						|
      before do
 | 
						|
        skip "irb isn't a default gem" if default_irb_version.empty?
 | 
						|
 | 
						|
        build_repo2 do
 | 
						|
          build_gem "irb", specified_irb_version do |s|
 | 
						|
            s.executables = "irb"
 | 
						|
          end
 | 
						|
        end
 | 
						|
 | 
						|
        install_gemfile <<-G
 | 
						|
          source "#{file_uri_for(gem_repo2)}"
 | 
						|
          gem "irb", "#{specified_irb_version}"
 | 
						|
        G
 | 
						|
      end
 | 
						|
 | 
						|
      it "uses version specified" do
 | 
						|
        bundle! "exec irb --version"
 | 
						|
 | 
						|
        expect(out).to eq(specified_irb_version)
 | 
						|
        expect(err).to be_empty
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    context "when specified in Gemfile indirectly" do
 | 
						|
      let(:indirect_irb_version) { "0.9.6" }
 | 
						|
 | 
						|
      before do
 | 
						|
        skip "irb isn't a default gem" if default_irb_version.empty?
 | 
						|
 | 
						|
        build_repo2 do
 | 
						|
          build_gem "irb", indirect_irb_version do |s|
 | 
						|
            s.executables = "irb"
 | 
						|
          end
 | 
						|
 | 
						|
          build_gem "gem_depending_on_old_irb" do |s|
 | 
						|
            s.add_dependency "irb", indirect_irb_version
 | 
						|
          end
 | 
						|
        end
 | 
						|
 | 
						|
        install_gemfile <<-G
 | 
						|
          source "#{file_uri_for(gem_repo2)}"
 | 
						|
          gem "gem_depending_on_old_irb"
 | 
						|
        G
 | 
						|
 | 
						|
        bundle! "exec irb --version"
 | 
						|
      end
 | 
						|
 | 
						|
      it "uses resolved version" do
 | 
						|
        expect(out).to eq(indirect_irb_version)
 | 
						|
        expect(err).to be_empty
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  it "warns about executable conflicts" do
 | 
						|
    build_repo2 do
 | 
						|
      build_gem "rack_two", "1.0.0" do |s|
 | 
						|
        s.executables = "rackup"
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    bundle "config set path.system true"
 | 
						|
 | 
						|
    install_gemfile <<-G
 | 
						|
      source "#{file_uri_for(gem_repo1)}"
 | 
						|
      gem "rack", "0.9.1"
 | 
						|
    G
 | 
						|
 | 
						|
    install_gemfile bundled_app2("Gemfile"), <<-G, :dir => bundled_app2
 | 
						|
      source "#{file_uri_for(gem_repo2)}"
 | 
						|
      gem "rack_two", "1.0.0"
 | 
						|
    G
 | 
						|
 | 
						|
    bundle! "exec rackup"
 | 
						|
 | 
						|
    expect(last_command.stderr).to eq(
 | 
						|
      "Bundler is using a binstub that was created for a different gem (rack).\n" \
 | 
						|
      "You should run `bundle binstub rack_two` to work around a system/bundle conflict."
 | 
						|
    )
 | 
						|
  end
 | 
						|
 | 
						|
  it "handles gems installed with --without" do
 | 
						|
    bundle "config --local without middleware"
 | 
						|
    install_gemfile <<-G
 | 
						|
      source "#{file_uri_for(gem_repo1)}"
 | 
						|
      gem "rack" # rack 0.9.1 and 1.0 exist
 | 
						|
 | 
						|
      group :middleware do
 | 
						|
        gem "rack_middleware" # rack_middleware depends on rack 0.9.1
 | 
						|
      end
 | 
						|
    G
 | 
						|
 | 
						|
    bundle "exec rackup"
 | 
						|
 | 
						|
    expect(out).to eq("0.9.1")
 | 
						|
    expect(the_bundle).not_to include_gems "rack_middleware 1.0"
 | 
						|
  end
 | 
						|
 | 
						|
  it "does not duplicate already exec'ed RUBYOPT" do
 | 
						|
    skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform?
 | 
						|
 | 
						|
    install_gemfile <<-G
 | 
						|
      gem "rack"
 | 
						|
    G
 | 
						|
 | 
						|
    bundler_setup_opt = "-r#{lib_dir}/bundler/setup"
 | 
						|
 | 
						|
    rubyopt = opt_add(bundler_setup_opt, ENV["RUBYOPT"])
 | 
						|
 | 
						|
    bundle "exec 'echo $RUBYOPT'"
 | 
						|
    expect(out.split(" ").count(bundler_setup_opt)).to eq(1)
 | 
						|
 | 
						|
    bundle "exec 'echo $RUBYOPT'", :env => { "RUBYOPT" => rubyopt }
 | 
						|
    expect(out.split(" ").count(bundler_setup_opt)).to eq(1)
 | 
						|
  end
 | 
						|
 | 
						|
  it "does not duplicate already exec'ed RUBYLIB" do
 | 
						|
    skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform?
 | 
						|
 | 
						|
    install_gemfile <<-G
 | 
						|
      gem "rack"
 | 
						|
    G
 | 
						|
 | 
						|
    rubylib = ENV["RUBYLIB"]
 | 
						|
    rubylib = rubylib.to_s.split(File::PATH_SEPARATOR).unshift lib_dir.to_s
 | 
						|
    rubylib = rubylib.uniq.join(File::PATH_SEPARATOR)
 | 
						|
 | 
						|
    bundle "exec 'echo $RUBYLIB'"
 | 
						|
    expect(out).to include(rubylib)
 | 
						|
 | 
						|
    bundle "exec 'echo $RUBYLIB'", :env => { "RUBYLIB" => rubylib }
 | 
						|
    expect(out).to include(rubylib)
 | 
						|
  end
 | 
						|
 | 
						|
  it "errors nicely when the argument doesn't exist" do
 | 
						|
    install_gemfile <<-G
 | 
						|
      gem "rack"
 | 
						|
    G
 | 
						|
 | 
						|
    bundle "exec foobarbaz", :raise_on_error => false
 | 
						|
    expect(exitstatus).to eq(127) if exitstatus
 | 
						|
    expect(err).to include("bundler: command not found: foobarbaz")
 | 
						|
    expect(err).to include("Install missing gem executables with `bundle install`")
 | 
						|
  end
 | 
						|
 | 
						|
  it "errors nicely when the argument is not executable" do
 | 
						|
    install_gemfile <<-G
 | 
						|
      gem "rack"
 | 
						|
    G
 | 
						|
 | 
						|
    bundle "exec touch foo"
 | 
						|
    bundle "exec ./foo", :raise_on_error => false
 | 
						|
    expect(exitstatus).to eq(126) if exitstatus
 | 
						|
    expect(err).to include("bundler: not executable: ./foo")
 | 
						|
  end
 | 
						|
 | 
						|
  it "errors nicely when no arguments are passed" do
 | 
						|
    install_gemfile <<-G
 | 
						|
      gem "rack"
 | 
						|
    G
 | 
						|
 | 
						|
    bundle "exec", :raise_on_error => false
 | 
						|
    expect(exitstatus).to eq(128) if exitstatus
 | 
						|
    expect(err).to include("bundler: exec needs a command to run")
 | 
						|
  end
 | 
						|
 | 
						|
  it "raises a helpful error when exec'ing to something outside of the bundle" do
 | 
						|
    bundle! "config set clean false" # want to keep the rackup binstub
 | 
						|
    install_gemfile! <<-G
 | 
						|
      source "#{file_uri_for(gem_repo1)}"
 | 
						|
      gem "with_license"
 | 
						|
    G
 | 
						|
    [true, false].each do |l|
 | 
						|
      bundle! "config set disable_exec_load #{l}"
 | 
						|
      bundle "exec rackup", :raise_on_error => false
 | 
						|
      expect(err).to include "can't find executable rackup for gem rack. rack is not currently included in the bundle, perhaps you meant to add it to your Gemfile?"
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  describe "with help flags" do
 | 
						|
    each_prefix = proc do |string, &blk|
 | 
						|
      1.upto(string.length) {|l| blk.call(string[0, l]) }
 | 
						|
    end
 | 
						|
    each_prefix.call("exec") do |exec|
 | 
						|
      describe "when #{exec} is used" do
 | 
						|
        before(:each) do
 | 
						|
          skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform?
 | 
						|
 | 
						|
          install_gemfile <<-G
 | 
						|
            gem "rack"
 | 
						|
          G
 | 
						|
 | 
						|
          create_file("print_args", <<-'RUBY')
 | 
						|
            #!/usr/bin/env ruby
 | 
						|
            puts "args: #{ARGV.inspect}"
 | 
						|
          RUBY
 | 
						|
          bundled_app("print_args").chmod(0o755)
 | 
						|
        end
 | 
						|
 | 
						|
        it "shows executable's man page when --help is after the executable" do
 | 
						|
          bundle "#{exec} print_args --help"
 | 
						|
          expect(out).to eq('args: ["--help"]')
 | 
						|
        end
 | 
						|
 | 
						|
        it "shows executable's man page when --help is after the executable and an argument" do
 | 
						|
          bundle "#{exec} print_args foo --help"
 | 
						|
          expect(out).to eq('args: ["foo", "--help"]')
 | 
						|
 | 
						|
          bundle "#{exec} print_args foo bar --help"
 | 
						|
          expect(out).to eq('args: ["foo", "bar", "--help"]')
 | 
						|
 | 
						|
          bundle "#{exec} print_args foo --help bar"
 | 
						|
          expect(out).to eq('args: ["foo", "--help", "bar"]')
 | 
						|
        end
 | 
						|
 | 
						|
        it "shows executable's man page when the executable has a -" do
 | 
						|
          FileUtils.mv(bundled_app("print_args"), bundled_app("docker-template"))
 | 
						|
          bundle "#{exec} docker-template build discourse --help"
 | 
						|
          expect(out).to eq('args: ["build", "discourse", "--help"]')
 | 
						|
        end
 | 
						|
 | 
						|
        it "shows executable's man page when --help is after another flag" do
 | 
						|
          bundle "#{exec} print_args --bar --help"
 | 
						|
          expect(out).to eq('args: ["--bar", "--help"]')
 | 
						|
        end
 | 
						|
 | 
						|
        it "uses executable's original behavior for -h" do
 | 
						|
          bundle "#{exec} print_args -h"
 | 
						|
          expect(out).to eq('args: ["-h"]')
 | 
						|
        end
 | 
						|
 | 
						|
        it "shows bundle-exec's man page when --help is between exec and the executable" do
 | 
						|
          with_fake_man do
 | 
						|
            bundle "#{exec} --help cat"
 | 
						|
          end
 | 
						|
          expect(out).to include(%(["#{root}/man/bundle-exec.1"]))
 | 
						|
        end
 | 
						|
 | 
						|
        it "shows bundle-exec's man page when --help is before exec" do
 | 
						|
          with_fake_man do
 | 
						|
            bundle "--help #{exec}"
 | 
						|
          end
 | 
						|
          expect(out).to include(%(["#{root}/man/bundle-exec.1"]))
 | 
						|
        end
 | 
						|
 | 
						|
        it "shows bundle-exec's man page when -h is before exec" do
 | 
						|
          with_fake_man do
 | 
						|
            bundle "-h #{exec}"
 | 
						|
          end
 | 
						|
          expect(out).to include(%(["#{root}/man/bundle-exec.1"]))
 | 
						|
        end
 | 
						|
 | 
						|
        it "shows bundle-exec's man page when --help is after exec" do
 | 
						|
          with_fake_man do
 | 
						|
            bundle "#{exec} --help"
 | 
						|
          end
 | 
						|
          expect(out).to include(%(["#{root}/man/bundle-exec.1"]))
 | 
						|
        end
 | 
						|
 | 
						|
        it "shows bundle-exec's man page when -h is after exec" do
 | 
						|
          with_fake_man do
 | 
						|
            bundle "#{exec} -h"
 | 
						|
          end
 | 
						|
          expect(out).to include(%(["#{root}/man/bundle-exec.1"]))
 | 
						|
        end
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  describe "with gem executables" do
 | 
						|
    describe "run from a random directory" do
 | 
						|
      before(:each) do
 | 
						|
        install_gemfile <<-G
 | 
						|
          gem "rack"
 | 
						|
        G
 | 
						|
      end
 | 
						|
 | 
						|
      it "works when unlocked" do
 | 
						|
        bundle "exec 'cd #{tmp("gems")} && rackup'"
 | 
						|
        expect(out).to eq("1.0.0")
 | 
						|
      end
 | 
						|
 | 
						|
      it "works when locked" do
 | 
						|
        expect(the_bundle).to be_locked
 | 
						|
        bundle "exec 'cd #{tmp("gems")} && rackup'"
 | 
						|
        expect(out).to eq("1.0.0")
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    describe "from gems bundled via :path" do
 | 
						|
      before(:each) do
 | 
						|
        build_lib "fizz", :path => home("fizz") do |s|
 | 
						|
          s.executables = "fizz"
 | 
						|
        end
 | 
						|
 | 
						|
        install_gemfile <<-G
 | 
						|
          gem "fizz", :path => "#{File.expand_path(home("fizz"))}"
 | 
						|
        G
 | 
						|
      end
 | 
						|
 | 
						|
      it "works when unlocked" do
 | 
						|
        bundle "exec fizz"
 | 
						|
        expect(out).to eq("1.0")
 | 
						|
      end
 | 
						|
 | 
						|
      it "works when locked" do
 | 
						|
        expect(the_bundle).to be_locked
 | 
						|
 | 
						|
        bundle "exec fizz"
 | 
						|
        expect(out).to eq("1.0")
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    describe "from gems bundled via :git" do
 | 
						|
      before(:each) do
 | 
						|
        build_git "fizz_git" do |s|
 | 
						|
          s.executables = "fizz_git"
 | 
						|
        end
 | 
						|
 | 
						|
        install_gemfile <<-G
 | 
						|
          gem "fizz_git", :git => "#{lib_path("fizz_git-1.0")}"
 | 
						|
        G
 | 
						|
      end
 | 
						|
 | 
						|
      it "works when unlocked" do
 | 
						|
        bundle "exec fizz_git"
 | 
						|
        expect(out).to eq("1.0")
 | 
						|
      end
 | 
						|
 | 
						|
      it "works when locked" do
 | 
						|
        expect(the_bundle).to be_locked
 | 
						|
        bundle "exec fizz_git"
 | 
						|
        expect(out).to eq("1.0")
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    describe "from gems bundled via :git with no gemspec" do
 | 
						|
      before(:each) do
 | 
						|
        build_git "fizz_no_gemspec", :gemspec => false do |s|
 | 
						|
          s.executables = "fizz_no_gemspec"
 | 
						|
        end
 | 
						|
 | 
						|
        install_gemfile <<-G
 | 
						|
          gem "fizz_no_gemspec", "1.0", :git => "#{lib_path("fizz_no_gemspec-1.0")}"
 | 
						|
        G
 | 
						|
      end
 | 
						|
 | 
						|
      it "works when unlocked" do
 | 
						|
        bundle "exec fizz_no_gemspec"
 | 
						|
        expect(out).to eq("1.0")
 | 
						|
      end
 | 
						|
 | 
						|
      it "works when locked" do
 | 
						|
        expect(the_bundle).to be_locked
 | 
						|
        bundle "exec fizz_no_gemspec"
 | 
						|
        expect(out).to eq("1.0")
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  it "performs an automatic bundle install" do
 | 
						|
    gemfile <<-G
 | 
						|
      source "#{file_uri_for(gem_repo1)}"
 | 
						|
      gem "rack", "0.9.1"
 | 
						|
      gem "foo"
 | 
						|
    G
 | 
						|
 | 
						|
    bundle "config set auto_install 1"
 | 
						|
    bundle "exec rackup"
 | 
						|
    expect(out).to include("Installing foo 1.0")
 | 
						|
  end
 | 
						|
 | 
						|
  describe "with gems bundled via :path with invalid gemspecs" do
 | 
						|
    it "outputs the gemspec validation errors" do
 | 
						|
      build_lib "foo"
 | 
						|
 | 
						|
      gemspec = lib_path("foo-1.0").join("foo.gemspec").to_s
 | 
						|
      File.open(gemspec, "w") do |f|
 | 
						|
        f.write <<-G
 | 
						|
          Gem::Specification.new do |s|
 | 
						|
            s.name    = 'foo'
 | 
						|
            s.version = '1.0'
 | 
						|
            s.summary = 'TODO: Add summary'
 | 
						|
            s.authors = 'Me'
 | 
						|
          end
 | 
						|
        G
 | 
						|
      end
 | 
						|
 | 
						|
      gemfile <<-G
 | 
						|
        gem "foo", :path => "#{lib_path("foo-1.0")}"
 | 
						|
      G
 | 
						|
 | 
						|
      bundle "exec irb", :raise_on_error => false
 | 
						|
 | 
						|
      expect(err).to match("The gemspec at #{lib_path("foo-1.0").join("foo.gemspec")} is not valid")
 | 
						|
      expect(err).to match('"TODO" is not a summary')
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  describe "with gems bundled for deployment" do
 | 
						|
    it "works when calling bundler from another script" do
 | 
						|
      skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform?
 | 
						|
 | 
						|
      gemfile <<-G
 | 
						|
      module Monkey
 | 
						|
        def bin_path(a,b,c)
 | 
						|
          raise Gem::GemNotFoundException.new('Fail')
 | 
						|
        end
 | 
						|
      end
 | 
						|
      Bundler.rubygems.extend(Monkey)
 | 
						|
      G
 | 
						|
      bundle! "config set path.system true"
 | 
						|
      bundle! "install"
 | 
						|
      bundle "exec ruby -e '`bundle -v`; puts $?.success?'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
 | 
						|
      expect(out).to match("true")
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  context "`load`ing a ruby file instead of `exec`ing" do
 | 
						|
    let(:path) { bundled_app("ruby_executable") }
 | 
						|
    let(:shebang) { "#!/usr/bin/env ruby" }
 | 
						|
    let(:executable) { <<-RUBY.gsub(/^ */, "").strip }
 | 
						|
      #{shebang}
 | 
						|
 | 
						|
      require "rack"
 | 
						|
      puts "EXEC: \#{caller.grep(/load/).empty? ? 'exec' : 'load'}"
 | 
						|
      puts "ARGS: \#{$0} \#{ARGV.join(' ')}"
 | 
						|
      puts "RACK: \#{RACK}"
 | 
						|
      process_title = `ps -o args -p \#{Process.pid}`.split("\n", 2).last.strip
 | 
						|
      puts "PROCESS: \#{process_title}"
 | 
						|
    RUBY
 | 
						|
 | 
						|
    before do
 | 
						|
      bundled_app(path).open("w") {|f| f << executable }
 | 
						|
      bundled_app(path).chmod(0o755)
 | 
						|
 | 
						|
      install_gemfile <<-G
 | 
						|
        gem "rack"
 | 
						|
      G
 | 
						|
    end
 | 
						|
 | 
						|
    let(:exec) { "EXEC: load" }
 | 
						|
    let(:args) { "ARGS: #{path} arg1 arg2" }
 | 
						|
    let(:rack) { "RACK: 1.0.0" }
 | 
						|
    let(:process) do
 | 
						|
      title = "PROCESS: #{path}"
 | 
						|
      title += " arg1 arg2"
 | 
						|
      title
 | 
						|
    end
 | 
						|
    let(:exit_code) { 0 }
 | 
						|
    let(:expected) { [exec, args, rack, process].join("\n") }
 | 
						|
    let(:expected_err) { "" }
 | 
						|
 | 
						|
    subject { bundle "exec #{path} arg1 arg2", :raise_on_error => false }
 | 
						|
 | 
						|
    shared_examples_for "it runs" do
 | 
						|
      it "like a normally executed executable" do
 | 
						|
        skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform?
 | 
						|
 | 
						|
        subject
 | 
						|
        expect(exitstatus).to eq(exit_code) if exitstatus
 | 
						|
        expect(err).to eq(expected_err)
 | 
						|
        expect(out).to eq(expected)
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    it_behaves_like "it runs"
 | 
						|
 | 
						|
    context "the executable exits explicitly" do
 | 
						|
      let(:executable) { super() << "\nexit #{exit_code}\nputs 'POST_EXIT'\n" }
 | 
						|
 | 
						|
      context "with exit 0" do
 | 
						|
        it_behaves_like "it runs"
 | 
						|
      end
 | 
						|
 | 
						|
      context "with exit 99" do
 | 
						|
        let(:exit_code) { 99 }
 | 
						|
        it_behaves_like "it runs"
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    context "the executable exits by SignalException" do
 | 
						|
      let(:executable) do
 | 
						|
        ex = super()
 | 
						|
        ex << "\n"
 | 
						|
        ex << "raise SignalException, 'SIGTERM'\n"
 | 
						|
        ex
 | 
						|
      end
 | 
						|
      let(:expected_err) { "" }
 | 
						|
      let(:exit_code) do
 | 
						|
        # signal mask 128 + plus signal 15 -> TERM
 | 
						|
        # this is specified by C99
 | 
						|
        128 + 15
 | 
						|
      end
 | 
						|
      it_behaves_like "it runs"
 | 
						|
    end
 | 
						|
 | 
						|
    context "the executable is empty" do
 | 
						|
      let(:executable) { "" }
 | 
						|
 | 
						|
      let(:exit_code) { 0 }
 | 
						|
      let(:expected_err) { "#{path} is empty" }
 | 
						|
      let(:expected) { "" }
 | 
						|
      it_behaves_like "it runs"
 | 
						|
    end
 | 
						|
 | 
						|
    context "the executable raises" do
 | 
						|
      let(:executable) { super() << "\nraise 'ERROR'" }
 | 
						|
      let(:exit_code) { 1 }
 | 
						|
      let(:expected_err) do
 | 
						|
        "bundler: failed to load command: #{path} (#{path})" \
 | 
						|
        "\nRuntimeError: ERROR\n  #{path}:10:in `<top (required)>'"
 | 
						|
      end
 | 
						|
      it_behaves_like "it runs"
 | 
						|
    end
 | 
						|
 | 
						|
    context "the executable raises an error without a backtrace" do
 | 
						|
      let(:executable) { super() << "\nclass Err < Exception\ndef backtrace; end;\nend\nraise Err" }
 | 
						|
      let(:exit_code) { 1 }
 | 
						|
      let(:expected_err) { "bundler: failed to load command: #{path} (#{path})\nErr: Err" }
 | 
						|
      let(:expected) { super() }
 | 
						|
 | 
						|
      it_behaves_like "it runs"
 | 
						|
    end
 | 
						|
 | 
						|
    context "when the file uses the current ruby shebang" do
 | 
						|
      let(:shebang) { "#!#{Gem.ruby}" }
 | 
						|
      it_behaves_like "it runs"
 | 
						|
    end
 | 
						|
 | 
						|
    context "when Bundler.setup fails", :bundler => "< 3" do
 | 
						|
      before do
 | 
						|
        gemfile <<-G
 | 
						|
          gem 'rack', '2'
 | 
						|
        G
 | 
						|
        ENV["BUNDLER_FORCE_TTY"] = "true"
 | 
						|
      end
 | 
						|
 | 
						|
      let(:exit_code) { Bundler::GemNotFound.new.status_code }
 | 
						|
      let(:expected) { "" }
 | 
						|
      let(:expected_err) { <<-EOS.strip }
 | 
						|
\e[31mCould not find gem 'rack (= 2)' in any of the gem sources listed in your Gemfile.\e[0m
 | 
						|
\e[33mRun `bundle install` to install missing gems.\e[0m
 | 
						|
      EOS
 | 
						|
 | 
						|
      it_behaves_like "it runs"
 | 
						|
    end
 | 
						|
 | 
						|
    context "when Bundler.setup fails", :bundler => "3" do
 | 
						|
      before do
 | 
						|
        gemfile <<-G
 | 
						|
          gem 'rack', '2'
 | 
						|
        G
 | 
						|
        ENV["BUNDLER_FORCE_TTY"] = "true"
 | 
						|
      end
 | 
						|
 | 
						|
      let(:exit_code) { Bundler::GemNotFound.new.status_code }
 | 
						|
      let(:expected) { "" }
 | 
						|
      let(:expected_err) { <<-EOS.strip }
 | 
						|
\e[31mCould not find gem 'rack (= 2)' in locally installed gems.
 | 
						|
The source contains 'rack' at: 1.0.0\e[0m
 | 
						|
\e[33mRun `bundle install` to install missing gems.\e[0m
 | 
						|
      EOS
 | 
						|
 | 
						|
      it_behaves_like "it runs"
 | 
						|
    end
 | 
						|
 | 
						|
    context "when the executable exits non-zero via at_exit" do
 | 
						|
      let(:executable) { super() + "\n\nat_exit { $! ? raise($!) : exit(1) }" }
 | 
						|
      let(:exit_code) { 1 }
 | 
						|
 | 
						|
      it_behaves_like "it runs"
 | 
						|
    end
 | 
						|
 | 
						|
    context "when disable_exec_load is set" do
 | 
						|
      let(:exec) { "EXEC: exec" }
 | 
						|
      let(:process) { "PROCESS: ruby #{path} arg1 arg2" }
 | 
						|
 | 
						|
      before do
 | 
						|
        bundle "config set disable_exec_load true"
 | 
						|
      end
 | 
						|
 | 
						|
      it_behaves_like "it runs"
 | 
						|
    end
 | 
						|
 | 
						|
    context "regarding $0 and __FILE__" do
 | 
						|
      let(:executable) { super() + <<-'RUBY' }
 | 
						|
 | 
						|
        puts "$0: #{$0.inspect}"
 | 
						|
        puts "__FILE__: #{__FILE__.inspect}"
 | 
						|
      RUBY
 | 
						|
 | 
						|
      let(:expected) { super() + <<-EOS.chomp }
 | 
						|
 | 
						|
$0: #{path.to_s.inspect}
 | 
						|
__FILE__: #{path.to_s.inspect}
 | 
						|
      EOS
 | 
						|
 | 
						|
      it_behaves_like "it runs"
 | 
						|
 | 
						|
      context "when the path is relative" do
 | 
						|
        let(:path) { super().relative_path_from(bundled_app) }
 | 
						|
 | 
						|
        it_behaves_like "it runs"
 | 
						|
      end
 | 
						|
 | 
						|
      context "when the path is relative with a leading ./" do
 | 
						|
        let(:path) { Pathname.new("./#{super().relative_path_from(bundled_app)}") }
 | 
						|
 | 
						|
        pending "relative paths with ./ have absolute __FILE__"
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    context "signal handling" do
 | 
						|
      let(:test_signals) do
 | 
						|
        open3_reserved_signals = %w[CHLD CLD PIPE]
 | 
						|
        reserved_signals = %w[SEGV BUS ILL FPE VTALRM KILL STOP EXIT]
 | 
						|
        bundler_signals = %w[INT]
 | 
						|
 | 
						|
        Signal.list.keys - (bundler_signals + reserved_signals + open3_reserved_signals)
 | 
						|
      end
 | 
						|
 | 
						|
      context "signals being trapped by bundler" do
 | 
						|
        let(:executable) { strip_whitespace <<-RUBY }
 | 
						|
          #{shebang}
 | 
						|
          begin
 | 
						|
            Thread.new do
 | 
						|
              puts 'Started' # For process sync
 | 
						|
              STDOUT.flush
 | 
						|
              sleep 1 # ignore quality_spec
 | 
						|
              raise "Didn't receive INT at all"
 | 
						|
            end.join
 | 
						|
          rescue Interrupt
 | 
						|
            puts "foo"
 | 
						|
          end
 | 
						|
        RUBY
 | 
						|
 | 
						|
        it "receives the signal" do
 | 
						|
          skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform?
 | 
						|
 | 
						|
          bundle!("exec #{path}") do |_, o, thr|
 | 
						|
            o.gets # Consumes 'Started' and ensures that thread has started
 | 
						|
            Process.kill("INT", thr.pid)
 | 
						|
          end
 | 
						|
 | 
						|
          expect(out).to eq("foo")
 | 
						|
        end
 | 
						|
      end
 | 
						|
 | 
						|
      context "signals not being trapped by bunder" do
 | 
						|
        let(:executable) { strip_whitespace <<-RUBY }
 | 
						|
          #{shebang}
 | 
						|
 | 
						|
          signals = #{test_signals.inspect}
 | 
						|
          result = signals.map do |sig|
 | 
						|
            Signal.trap(sig, "IGNORE")
 | 
						|
          end
 | 
						|
          puts result.select { |ret| ret == "IGNORE" }.count
 | 
						|
        RUBY
 | 
						|
 | 
						|
        it "makes sure no unexpected signals are restored to DEFAULT" do
 | 
						|
          skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform?
 | 
						|
 | 
						|
          test_signals.each do |n|
 | 
						|
            Signal.trap(n, "IGNORE")
 | 
						|
          end
 | 
						|
 | 
						|
          bundle!("exec #{path}")
 | 
						|
 | 
						|
          expect(out).to eq(test_signals.count.to_s)
 | 
						|
        end
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  context "nested bundle exec" do
 | 
						|
    context "when bundle in a local path" do
 | 
						|
      before do
 | 
						|
        gemfile <<-G
 | 
						|
          source "#{file_uri_for(gem_repo1)}"
 | 
						|
          gem "rack"
 | 
						|
        G
 | 
						|
        bundle "config set path vendor/bundler"
 | 
						|
        bundle! :install
 | 
						|
      end
 | 
						|
 | 
						|
      it "correctly shells out" do
 | 
						|
        skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform?
 | 
						|
 | 
						|
        file = bundled_app("file_that_bundle_execs.rb")
 | 
						|
        create_file(file, <<-RUBY)
 | 
						|
          #!#{Gem.ruby}
 | 
						|
          puts `bundle exec echo foo`
 | 
						|
        RUBY
 | 
						|
        file.chmod(0o777)
 | 
						|
        bundle! "exec #{file}", :env => { "PATH" => path }
 | 
						|
        expect(out).to eq("foo")
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    context "with a system gem that shadows a default gem" do
 | 
						|
      let(:openssl_version) { "99.9.9" }
 | 
						|
      let(:expected) { ruby "gem 'openssl', '< 999999'; require 'openssl'; puts OpenSSL::VERSION", :artifice => nil, :raise_on_error => false }
 | 
						|
 | 
						|
      it "only leaves the default gem in the stdlib available" do
 | 
						|
        skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform?
 | 
						|
        skip "openssl isn't a default gem" if expected.empty?
 | 
						|
 | 
						|
        install_gemfile! "" # must happen before installing the broken system gem
 | 
						|
 | 
						|
        build_repo4 do
 | 
						|
          build_gem "openssl", openssl_version do |s|
 | 
						|
            s.write("lib/openssl.rb", <<-RUBY)
 | 
						|
              raise "custom openssl should not be loaded, it's not in the gemfile!"
 | 
						|
            RUBY
 | 
						|
          end
 | 
						|
        end
 | 
						|
 | 
						|
        system_gems("openssl-#{openssl_version}", :gem_repo => gem_repo4)
 | 
						|
 | 
						|
        file = bundled_app("require_openssl.rb")
 | 
						|
        create_file(file, <<-RUBY)
 | 
						|
          #!/usr/bin/env ruby
 | 
						|
          require "openssl"
 | 
						|
          puts OpenSSL::VERSION
 | 
						|
          warn Gem.loaded_specs.values.map(&:full_name)
 | 
						|
        RUBY
 | 
						|
        file.chmod(0o777)
 | 
						|
 | 
						|
        env = { "PATH" => path }
 | 
						|
        aggregate_failures do
 | 
						|
          expect(bundle!("exec #{file}", :artifice => nil, :env => env)).to eq(expected)
 | 
						|
          expect(bundle!("exec bundle exec #{file}", :artifice => nil, :env => env)).to eq(expected)
 | 
						|
          expect(bundle!("exec ruby #{file}", :artifice => nil, :env => env)).to eq(expected)
 | 
						|
          expect(run!(file.read, :artifice => nil, :env => env)).to eq(expected)
 | 
						|
        end
 | 
						|
 | 
						|
        skip "ruby_core has openssl and rubygems in the same folder, and this test needs rubygems require but default openssl not in a directly added entry in $LOAD_PATH" if ruby_core?
 | 
						|
        # sanity check that we get the newer, custom version without bundler
 | 
						|
        sys_exec "#{Gem.ruby} #{file}", :env => env, :raise_on_error => false
 | 
						|
        expect(err).to include("custom openssl should not be loaded")
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    context "with a git gem that includes extensions", :ruby_repo do
 | 
						|
      before do
 | 
						|
        build_git "simple_git_binary", &:add_c_extension
 | 
						|
        bundle! "config set --local path .bundle"
 | 
						|
        install_gemfile! <<-G
 | 
						|
          gem "simple_git_binary", :git => '#{lib_path("simple_git_binary-1.0")}'
 | 
						|
        G
 | 
						|
      end
 | 
						|
 | 
						|
      it "allows calling bundle install" do
 | 
						|
        bundle! "exec bundle install"
 | 
						|
      end
 | 
						|
 | 
						|
      it "allows calling bundle install after removing gem.build_complete" do
 | 
						|
        FileUtils.rm_rf Dir[bundled_app(".bundle/**/gem.build_complete")]
 | 
						|
        bundle! "exec #{Gem.ruby} -S bundle install"
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 |