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
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?
options = {}
spec.runtime_dependencies.each do |dep|
@ -115,10 +120,6 @@ module Bundler
ruby_command = Thor::Util.ruby_command
ruby_command = ruby_command
template_path = File.expand_path("templates/Executable", __dir__)
if spec.name == "bundler"
template_path += ".bundler"
spec.executables = %(bundle)
end
template = File.read(template_path)
exists = []

View File

@ -10,17 +10,6 @@
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 "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")
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
FileUtils.mkdir_p(lib_path("foo/bin"))
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")
end
it "creates a bundle binstub" do
it "does not create a bundle binstub" do
gemfile <<-G
source "https://gem.repo1"
gem "bundler"
@ -85,7 +85,9 @@ RSpec.describe "Running bin/* commands" do
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
it "does not generate bin stubs if the option was not specified" do