Stop generating binstubs for Bundler itself

This commit is contained in:
David Rodríguez 2024-12-19 21:50:51 +01:00 committed by Hiroshi SHIBATA
parent 56e2ef2468
commit 451d848a76
No known key found for this signature in database
GPG Key ID: F9CF13417264FAC2
5 changed files with 9 additions and 340 deletions

View File

@ -91,6 +91,11 @@ module Bundler
end end
def generate_bundler_executable_stubs(spec, options = {}) def generate_bundler_executable_stubs(spec, options = {})
if spec.name == "bundler"
Bundler.ui.warn "Bundler itself does not use binstubs because its version is selected by RubyGems"
return
end
if options[:binstubs_cmd] && spec.executables.empty? if options[:binstubs_cmd] && spec.executables.empty?
options = {} options = {}
spec.runtime_dependencies.each do |dep| spec.runtime_dependencies.each do |dep|
@ -115,10 +120,6 @@ module Bundler
ruby_command = Thor::Util.ruby_command ruby_command = Thor::Util.ruby_command
ruby_command = ruby_command ruby_command = ruby_command
template_path = File.expand_path("templates/Executable", __dir__) template_path = File.expand_path("templates/Executable", __dir__)
if spec.name == "bundler"
template_path += ".bundler"
spec.executables = %(bundle)
end
template = File.read(template_path) template = File.read(template_path)
exists = [] exists = []

View File

@ -10,17 +10,6 @@
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("<%= relative_gemfile_path %>", __dir__) ENV["BUNDLE_GEMFILE"] ||= File.expand_path("<%= relative_gemfile_path %>", __dir__)
bundle_binstub = File.expand_path("bundle", __dir__)
if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end
require "rubygems" require "rubygems"
require "bundler/setup" require "bundler/setup"

View File

@ -1,109 +0,0 @@
#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %>
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
# The application '<%= executable %>' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require "rubygems"
m = Module.new do
module_function
def invoked_as_script?
File.expand_path($0) == File.expand_path(__FILE__)
end
def env_var_version
ENV["BUNDLER_VERSION"]
end
def cli_arg_version
return unless invoked_as_script? # don't want to hijack other binstubs
return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
bundler_version = nil
update_index = nil
ARGV.each_with_index do |a, i|
if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN)
bundler_version = a
end
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
bundler_version = $1
update_index = i
end
bundler_version
end
def gemfile
gemfile = ENV["BUNDLE_GEMFILE"]
return gemfile if gemfile && !gemfile.empty?
File.expand_path("<%= relative_gemfile_path %>", __dir__)
end
def lockfile
lockfile =
case File.basename(gemfile)
when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
else "#{gemfile}.lock"
end
File.expand_path(lockfile)
end
def lockfile_version
return unless File.file?(lockfile)
lockfile_contents = File.read(lockfile)
return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
Regexp.last_match(1)
end
def bundler_requirement
@bundler_requirement ||=
env_var_version ||
cli_arg_version ||
bundler_requirement_for(lockfile_version)
end
def bundler_requirement_for(version)
return "#{Gem::Requirement.default}.a" unless version
bundler_gem_version = Gem::Version.new(version)
bundler_gem_version.approximate_recommendation
end
def load_bundler!
ENV["BUNDLE_GEMFILE"] ||= gemfile
activate_bundler
end
def activate_bundler
gem_error = activation_error_handling do
gem "bundler", bundler_requirement
end
return if gem_error.nil?
require_error = activation_error_handling do
require "bundler/version"
end
return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
exit 42
end
def activation_error_handling
yield
nil
rescue StandardError, LoadError => e
e
end
end
m.load_bundler!
if m.invoked_as_script?
load Gem.bin_path("<%= spec.name %>", "<%= executable %>")
end

View File

@ -85,220 +85,6 @@ RSpec.describe "bundle binstubs <gem>" do
expect(err).to include("Cannot specify --all with specific gems") expect(err).to include("Cannot specify --all with specific gems")
end end
context "when generating bundle binstub outside bundler" do
it "should abort" do
install_gemfile <<-G
source "https://gem.repo1"
gem "myrack"
G
bundle "binstubs myrack"
File.open(bundled_app("bin/bundle"), "wb") do |file|
file.print "OMG"
end
sys_exec "bin/myrackup", raise_on_error: false
expect(err).to include("was not generated by Bundler")
end
end
context "the bundle binstub" do
before do
pristine_system_gems "bundler-#{system_bundler_version}"
build_repo2 do
build_gem "myrack", "1.2" do |s|
s.executables = "myrackup"
end
build_gem "prints_loaded_gems", "1.0" do |s|
s.executables = "print_loaded_gems"
s.bindir = "exe"
s.write "exe/print_loaded_gems", <<~R
#!/usr/bin/env ruby
specs = Gem.loaded_specs.values.reject {|s| s.default_gem? }
puts specs.map(&:full_name).sort.inspect
R
end
build_bundler locked_bundler_version
end
install_gemfile <<-G
source "https://gem.repo2"
gem "myrack"
gem "prints_loaded_gems"
G
bundle "binstubs bundler myrack prints_loaded_gems"
end
let(:system_bundler_version) { Bundler::VERSION }
let(:locked_bundler_version) { nil }
let(:lockfile_content) { lockfile.gsub(system_bundler_version, locked_bundler_version) }
it "runs bundler" do
bundle "install --verbose", bundle_bin: "bin/bundle"
expect(out).to include %(Using bundler #{system_bundler_version}\n)
end
context "when BUNDLER_VERSION is set" do
it "runs the correct version of bundler" do
bundle "install", env: { "BUNDLER_VERSION" => "999.999.999" }, raise_on_error: false, bundle_bin: "bin/bundle"
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (999.999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '999.999.999'`")
end
it "runs the correct version of bundler even if a higher version is installed" do
system_gems "bundler-999.999.998", "bundler-999.999.999"
bundle "install --verbose", env: { "BUNDLER_VERSION" => "999.999.998" }, raise_on_error: false, bundle_bin: "bin/bundle"
expect(out).to include %(Using bundler 999.999.998\n)
end
end
context "when a lockfile exists with a locked bundler version" do
let(:locked_bundler_version) { "999.999" }
context "and the version is newer" do
before do
lockfile lockfile_content
end
it "runs the correct version of bundler" do
bundle "install", raise_on_error: false, bundle_bin: "bin/bundle"
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 999.999'`")
end
end
context "and the version is newer when given `gems.rb` and `gems.locked`" do
before do
gemfile bundled_app("gems.rb"), gemfile
lockfile bundled_app("gems.locked"), lockfile_content
end
it "runs the correct version of bundler" do
bundle "install", env: { "BUNDLE_GEMFILE" => "gems.rb" }, raise_on_error: false, bundle_bin: "bin/bundle"
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 999.999'`")
end
end
context "and the version is older and a different major" do
let(:system_bundler_version) { "55" }
let(:locked_bundler_version) { "44" }
before do
lockfile lockfile_content
end
it "runs the correct version of bundler" do
bundle "install", raise_on_error: false, bundle_bin: "bin/bundle"
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 44.0) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 44.0'`")
end
end
context "and the version is older and a different major when given `gems.rb` and `gems.locked`" do
let(:system_bundler_version) { "55" }
let(:locked_bundler_version) { "44" }
before do
gemfile bundled_app("gems.rb"), gemfile
lockfile bundled_app("gems.locked"), lockfile_content
end
it "runs the correct version of bundler" do
bundle "install", env: { "BUNDLE_GEMFILE" => "gems.rb" }, raise_on_error: false, bundle_bin: "bin/bundle"
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 44.0) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 44.0'`")
end
end
context "and the version is older and the same major" do
let(:system_bundler_version) { "2.999.999" }
let(:locked_bundler_version) { "2.3.0" }
before do
lockfile lockfile_content
end
it "installs and runs the exact version of bundler" do
bundle "install --verbose", bundle_bin: "bin/bundle"
expect(exitstatus).not_to eq(42)
expect(out).to include("Bundler 2.999.999 is running, but your lockfile was generated with 2.3.0. Installing Bundler 2.3.0 and restarting using that version.")
expect(out).to include("Using bundler 2.3.0")
expect(err).not_to include("Activating bundler (~> 2.3.0) failed:")
end
end
context "and the version is a pre-releaser" do
let(:system_bundler_version) { "55" }
let(:locked_bundler_version) { "2.12.0.a" }
before do
lockfile lockfile_content
end
it "runs the correct version of bundler when the version is a pre-release" do
bundle "install", raise_on_error: false, bundle_bin: "bin/bundle"
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 2.12.a) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 2.12.a'`")
end
end
end
context "when update --bundler is called" do
it "calls through to the latest bundler version" do
bundle "update --bundler --verbose", bundle_bin: "bin/bundle"
using_bundler_line = /Using bundler ([\w\.]+)\n/.match(out)
expect(using_bundler_line).to_not be_nil
latest_version = using_bundler_line[1]
expect(Gem::Version.new(latest_version)).to be >= Gem::Version.new(system_bundler_version)
end
it "calls through to the explicit bundler version" do
bundle "update --bundler=999.999.999", raise_on_error: false, bundle_bin: "bin/bundle"
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (999.999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '999.999.999'`")
end
end
context "without a lockfile" do
it "falls back to the latest installed bundler" do
FileUtils.rm bundled_app_lock
bundle "install --verbose", bundle_bin: "bin/bundle"
expect(out).to include "Using bundler #{system_bundler_version}\n"
end
end
context "using another binstub" do
it "loads all gems" do
sys_exec bundled_app("bin/print_loaded_gems").to_s
expect(out).to eq %(["bundler-#{Bundler::VERSION}", "myrack-1.2", "prints_loaded_gems-1.0"])
end
context "when requesting a different bundler version" do
before { lockfile lockfile.gsub(Bundler::VERSION, "999.999.999") }
it "attempts to load that version" do
sys_exec bundled_app("bin/myrackup").to_s, raise_on_error: false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 999.999'`")
end
end
end
end
it "installs binstubs from git gems" do it "installs binstubs from git gems" do
FileUtils.mkdir_p(lib_path("foo/bin")) FileUtils.mkdir_p(lib_path("foo/bin"))
FileUtils.touch(lib_path("foo/bin/foo")) FileUtils.touch(lib_path("foo/bin/foo"))

View File

@ -77,7 +77,7 @@ RSpec.describe "Running bin/* commands" do
expect(out).to eq("1.0") expect(out).to eq("1.0")
end end
it "creates a bundle binstub" do it "does not create a bundle binstub" do
gemfile <<-G gemfile <<-G
source "https://gem.repo1" source "https://gem.repo1"
gem "bundler" gem "bundler"
@ -85,7 +85,9 @@ RSpec.describe "Running bin/* commands" do
bundle "binstubs bundler" bundle "binstubs bundler"
expect(bundled_app("bin/bundle")).to exist expect(bundled_app("bin/bundle")).not_to exist
expect(err).to include("Bundler itself does not use binstubs because its version is selected by RubyGems")
end end
it "does not generate bin stubs if the option was not specified" do it "does not generate bin stubs if the option was not specified" do