[rubygems/rubygems] Let gem exec raise an error in ambiguous cases

When `gem exec foo` is run, and "foo" is a gem that has multiple
executables, none of them named "foo", raise an error explaining the
situation and telling user to be more specific.

Currently the first command in the executables array is run, but this
may come as surprising sometimes, so better raise an error.

https://github.com/rubygems/rubygems/commit/acda5d8f6e
This commit is contained in:
David Rodríguez 2025-03-17 20:10:17 +01:00 committed by Hiroshi SHIBATA
parent ee7cfb1d1e
commit 4fe882e2c9
Notes: git 2025-03-24 04:25:31 +00:00
2 changed files with 20 additions and 8 deletions

View File

@ -195,7 +195,7 @@ to the same gem path as user-installed gems.
argv = ARGV.clone argv = ARGV.clone
ARGV.replace options[:args] ARGV.replace options[:args]
exe = executable = options[:executable] executable = options[:executable]
contains_executable = Gem.loaded_specs.values.select do |spec| contains_executable = Gem.loaded_specs.values.select do |spec|
spec.executables.include?(executable) spec.executables.include?(executable)
@ -206,13 +206,22 @@ to the same gem path as user-installed gems.
end end
if contains_executable.empty? if contains_executable.empty?
if (spec = Gem.loaded_specs[executable]) && (exe = spec.executable) spec = Gem.loaded_specs[executable]
contains_executable << spec
else if spec.nil? || spec.executables.empty?
alert_error "Failed to load executable `#{executable}`," \ alert_error "Failed to load executable `#{executable}`," \
" are you sure the gem `#{options[:gem_name]}` contains it?" " are you sure the gem `#{options[:gem_name]}` contains it?"
terminate_interaction 1 terminate_interaction 1
end end
if spec.executables.size > 1
alert_error "Ambiguous which executable from gem `#{executable}` should be run: " \
"the options are #{spec.executables}, specify one via COMMAND, and use `-g` and `-v` to specify gem and version"
terminate_interaction 1
end
contains_executable << spec
executable = spec.executable
end end
if contains_executable.size > 1 if contains_executable.size > 1
@ -223,8 +232,8 @@ to the same gem path as user-installed gems.
end end
old_exe = $0 old_exe = $0
$0 = exe $0 = executable
load Gem.activate_bin_path(contains_executable.first.name, exe, ">= 0.a") load Gem.activate_bin_path(contains_executable.first.name, executable, ">= 0.a")
ensure ensure
$0 = old_exe if old_exe $0 = old_exe if old_exe
ARGV.replace argv ARGV.replace argv

View File

@ -370,8 +370,11 @@ class TestGemCommandsExecCommand < Gem::TestCase
util_clear_gems util_clear_gems
use_ui @ui do use_ui @ui do
e = assert_raise Gem::MockGemUi::TermError do
@cmd.invoke "a:2" @cmd.invoke "a:2"
assert_equal "a-2 foo\n", @ui.output end
assert_equal 1, e.exit_code
assert_equal "ERROR: Ambiguous which executable from gem `a` should be run: the options are [\"foo\", \"bar\"], specify one via COMMAND, and use `-g` and `-v` to specify gem and version\n", @ui.error
end end
end end