diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb index 650395c53e..d4cc4f6216 100644 --- a/lib/bundler/rubygems_ext.rb +++ b/lib/bundler/rubygems_ext.rb @@ -30,20 +30,31 @@ module Gem end end - # Can be removed once RubyGems 3.5.14 support is dropped - unless Gem.respond_to?(:open_file_with_flock) - def self.open_file_with_flock(path, &block) - mode = IO::RDONLY | IO::APPEND | IO::CREAT | IO::BINARY - mode |= IO::SHARE_DELETE if IO.const_defined?(:SHARE_DELETE) + # Can be removed once RubyGems 3.5.18 support is dropped + unless Gem.respond_to?(:open_file_with_lock) + class << self + remove_method :open_file_with_flock if Gem.respond_to?(:open_file_with_flock) - File.open(path, mode) do |io| - begin - io.flock(File::LOCK_EX) - rescue Errno::ENOSYS, Errno::ENOTSUP - rescue Errno::ENOLCK # NFS - raise unless Thread.main == Thread.current + def open_file_with_flock(path, &block) + mode = IO::RDONLY | IO::APPEND | IO::CREAT | IO::BINARY + mode |= IO::SHARE_DELETE if IO.const_defined?(:SHARE_DELETE) + + File.open(path, mode) do |io| + begin + io.flock(File::LOCK_EX) + rescue Errno::ENOSYS, Errno::ENOTSUP + rescue Errno::ENOLCK # NFS + raise unless Thread.main == Thread.current + end + yield io end - yield io + end + + def open_file_with_lock(path, &block) + file_lock = "#{path}.lock" + open_file_with_flock(file_lock, &block) + ensure + FileUtils.rm_f file_lock end end end diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb index 858ebf32cf..62756680e7 100644 --- a/lib/bundler/rubygems_gem_installer.rb +++ b/lib/bundler/rubygems_gem_installer.rb @@ -81,11 +81,11 @@ module Bundler end end - if Bundler.rubygems.provides?("< 3.5.15") + if Bundler.rubygems.provides?("< 3.5.19") def generate_bin_script(filename, bindir) bin_script_path = File.join bindir, formatted_program_filename(filename) - Gem.open_file_with_flock("#{bin_script_path}.lock") do + Gem.open_file_with_lock(bin_script_path) do require "fileutils" FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers diff --git a/lib/rubygems.rb b/lib/rubygems.rb index ded0aa3b43..43c0d8f13c 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -794,6 +794,16 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} File.open(path, flags, &block) end + ## + # Open a file with given flags, and protect access with a file lock + + def self.open_file_with_lock(path, &block) + file_lock = "#{path}.lock" + open_file_with_flock(file_lock, &block) + ensure + FileUtils.rm_f file_lock + end + ## # Open a file with given flags, and protect access with flock diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 1085f73fca..735d30ab9e 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -538,7 +538,7 @@ class Gem::Installer def generate_bin_script(filename, bindir) bin_script_path = File.join bindir, formatted_program_filename(filename) - Gem.open_file_with_flock("#{bin_script_path}.lock") do |lock| + Gem.open_file_with_lock(bin_script_path) do require "fileutils" FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers @@ -546,8 +546,6 @@ class Gem::Installer file.write app_script_text(filename) file.chmod(options[:prog_mode] || 0o755) end - ensure - FileUtils.rm_f lock.path end verbose bin_script_path diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb index 9353d24d95..19711045c2 100644 --- a/spec/bundler/commands/install_spec.rb +++ b/spec/bundler/commands/install_spec.rb @@ -1591,4 +1591,17 @@ RSpec.describe "bundle install with gem sources" do expect(err).to include("The running version of Bundler (9.99.9) does not match the version of the specification installed for it (9.99.8)") end end + + it "only installs executable files in bin" do + bundle "config set --local path vendor/bundle" + + install_gemfile <<~G + source "https://gem.repo1" + gem "myrack" + G + + expected_executables = [vendored_gems("bin/myrackup").to_s] + expected_executables << vendored_gems("bin/myrackup.bat").to_s if Gem.win_platform? + expect(Dir.glob(vendored_gems("bin/*"))).to eq(expected_executables) + end end