From 4fe882e2c925c067693fbd432228d92548481ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= Date: Mon, 17 Mar 2025 20:10:17 +0100 Subject: [PATCH] [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 --- lib/rubygems/commands/exec_command.rb | 21 +++++++++++++------ .../test_gem_commands_exec_command.rb | 7 +++++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/rubygems/commands/exec_command.rb b/lib/rubygems/commands/exec_command.rb index 519539c694..82f1734b58 100644 --- a/lib/rubygems/commands/exec_command.rb +++ b/lib/rubygems/commands/exec_command.rb @@ -195,7 +195,7 @@ to the same gem path as user-installed gems. argv = ARGV.clone ARGV.replace options[:args] - exe = executable = options[:executable] + executable = options[:executable] contains_executable = Gem.loaded_specs.values.select do |spec| spec.executables.include?(executable) @@ -206,13 +206,22 @@ to the same gem path as user-installed gems. end if contains_executable.empty? - if (spec = Gem.loaded_specs[executable]) && (exe = spec.executable) - contains_executable << spec - else + spec = Gem.loaded_specs[executable] + + if spec.nil? || spec.executables.empty? alert_error "Failed to load executable `#{executable}`," \ " are you sure the gem `#{options[:gem_name]}` contains it?" terminate_interaction 1 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 if contains_executable.size > 1 @@ -223,8 +232,8 @@ to the same gem path as user-installed gems. end old_exe = $0 - $0 = exe - load Gem.activate_bin_path(contains_executable.first.name, exe, ">= 0.a") + $0 = executable + load Gem.activate_bin_path(contains_executable.first.name, executable, ">= 0.a") ensure $0 = old_exe if old_exe ARGV.replace argv diff --git a/test/rubygems/test_gem_commands_exec_command.rb b/test/rubygems/test_gem_commands_exec_command.rb index b9d5888068..806a6b5424 100644 --- a/test/rubygems/test_gem_commands_exec_command.rb +++ b/test/rubygems/test_gem_commands_exec_command.rb @@ -370,8 +370,11 @@ class TestGemCommandsExecCommand < Gem::TestCase util_clear_gems use_ui @ui do - @cmd.invoke "a:2" - assert_equal "a-2 foo\n", @ui.output + e = assert_raise Gem::MockGemUi::TermError do + @cmd.invoke "a:2" + 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