Skip to content

Commit

Permalink
[rubygems/rubygems] Fix binstubs sometimes not getting regenerated wh…
Browse files Browse the repository at this point in the history
…en `--destdir` is given

This was only working for gems also installed in the default gem home.

rubygems/rubygems@47df02dbd9
  • Loading branch information
deivid-rodriguez authored and matzbot committed May 16, 2024
1 parent 35c5c7e commit c55c11d
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 29 deletions.
15 changes: 9 additions & 6 deletions lib/rubygems/commands/pristine_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def initialize
end

add_option("-i", "--install-dir DIR",
"Gem repository to get binstubs and plugins installed") do |value, options|
"Gem repository to get gems restored") do |value, options|
options[:install_dir] = File.expand_path(value)
end

Expand Down Expand Up @@ -103,21 +103,25 @@ def usage # :nodoc:
end

def execute
install_dir = options[:install_dir]

specification_record = install_dir ? Gem::SpecificationRecord.from_path(install_dir) : Gem::Specification.specification_record

specs = if options[:all]
Gem::Specification.map
specification_record.map

# `--extensions` must be explicitly given to pristine only gems
# with extensions.
elsif options[:extensions_set] &&
options[:extensions] && options[:args].empty?
Gem::Specification.select do |spec|
specification_record.select do |spec|
spec.extensions && !spec.extensions.empty?
end
elsif options[:only_missing_extensions]
Gem::Specification.select(&:missing_extensions?)
specification_record.select(&:missing_extensions?)
else
get_all_gem_names.sort.map do |gem_name|
Gem::Specification.find_all_by_name(gem_name, options[:version]).reverse
specification_record.find_all_by_name(gem_name, options[:version]).reverse
end.flatten
end

Expand Down Expand Up @@ -176,7 +180,6 @@ def execute
end

bin_dir = options[:bin_dir] if options[:bin_dir]
install_dir = options[:install_dir] if options[:install_dir]

installer_options = {
wrappers: true,
Expand Down
2 changes: 2 additions & 0 deletions lib/rubygems/commands/setup_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,8 @@ def regenerate_binstubs(bindir)

args = %w[--all --only-executables --silent]
args << "--bindir=#{bindir}"
args << "--install-dir=#{default_dir}"

if options[:env_shebang]
args << "--env-shebang"
end
Expand Down
2 changes: 1 addition & 1 deletion lib/rubygems/installer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ def install

say spec.post_install_message if options[:post_install_message] && !spec.post_install_message.nil?

Gem::Specification.add_spec(spec)
Gem::Specification.add_spec(spec) unless @install_dir

load_plugin

Expand Down
22 changes: 3 additions & 19 deletions lib/rubygems/specification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -925,31 +925,15 @@ def self.dirs=(dirs)
# Enumerate every known spec. See ::dirs= and ::add_spec to set the list of
# specs.

def self.each
return enum_for(:each) unless block_given?

_all.each do |x|
yield x
end
def self.each(&block)
specification_record.each(&block)
end

##
# Returns every spec that matches +name+ and optional +requirements+.

def self.find_all_by_name(name, *requirements)
req = Gem::Requirement.create(*requirements)
env_req = Gem.env_requirement(name)

matches = stubs_for(name).find_all do |spec|
req.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version)
end.map(&:to_spec)

if name == "bundler" && !req.specific?
require_relative "bundler_version_finder"
Gem::BundlerVersionFinder.prioritize!(matches)
end

matches
specification_record.find_all_by_name(name, *requirements)
end

##
Expand Down
32 changes: 32 additions & 0 deletions lib/rubygems/specification_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,38 @@ def all_names
all.map(&:full_name)
end

include Enumerable

##
# Enumerate every known spec.

def each
return enum_for(:each) unless block_given?

all.each do |x|
yield x
end
end

##
# Returns every spec in the record that matches +name+ and optional +requirements+.

def find_all_by_name(name, *requirements)
req = Gem::Requirement.create(*requirements)
env_req = Gem.env_requirement(name)

matches = stubs_for(name).find_all do |spec|
req.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version)
end.map(&:to_spec)

if name == "bundler" && !req.specific?
require_relative "bundler_version_finder"
Gem::BundlerVersionFinder.prioritize!(matches)
end

matches
end

##
# Return the best specification in the record that contains the file matching +path+.

Expand Down
23 changes: 20 additions & 3 deletions test/rubygems/test_gem_commands_setup_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,23 @@ def test_destdir_flag_does_not_try_to_write_to_the_default_gem_home
end
end

def test_destdir_flag_regenerates_binstubs
# install to destdir
destdir = File.join(@tempdir, "foo")
gem_bin_path = gem_install "destdir-only-gem", install_dir: destdir

# change binstub manually
write_file gem_bin_path do |io|
io.puts "I changed it!"
end

@cmd.options[:destdir] = destdir
@cmd.options[:prefix] = "/"
@cmd.execute

assert_match(/\A#!/, File.read(gem_bin_path))
end

def test_files_in
assert_equal %w[rubygems.rb rubygems/requirement.rb rubygems/ssl_certs/rubygems.org/foo.pem],
@cmd.files_in("lib").sort
Expand Down Expand Up @@ -412,16 +429,16 @@ def create_dummy_files(list)
end
end

def gem_install(name)
def gem_install(name, **options)
gem = util_spec name do |s|
s.executables = [name]
s.files = %W[bin/#{name}]
end
write_file File.join @tempdir, "bin", name do |f|
f.puts "#!/usr/bin/ruby"
end
install_gem gem
File.join @gemhome, "bin", name
install_gem gem, **options
File.join options[:install_dir] || @gemhome, "bin", name
end

def gem_install_with_plugin(name)
Expand Down

0 comments on commit c55c11d

Please sign in to comment.