From 121c0fa8c71a1d14b74d3fac41f6d63ef574b6d9 Mon Sep 17 00:00:00 2001 From: Alejandro R Mosteo Date: Mon, 24 Feb 2025 16:28:06 +0100 Subject: [PATCH] feat: check executable existence prior to spawn (#1862) * feat: check executable existence prior to spawn * Fix dependencies * New test * Fix related test * Bump aaa * Remove TODO --- alire.toml | 2 +- deps/aaa | 2 +- src/alire/alire-os_lib-subprocess.adb | 56 ++++++++++++++----- src/alr/alr-os_lib.adb | 17 +++++- .../tests/help/help-after-double-dash/test.py | 12 ++-- testsuite/tests/misc/exe-not-found/test.py | 20 +++++++ testsuite/tests/misc/exe-not-found/test.yaml | 1 + 7 files changed, 86 insertions(+), 24 deletions(-) create mode 100644 testsuite/tests/misc/exe-not-found/test.py create mode 100644 testsuite/tests/misc/exe-not-found/test.yaml diff --git a/alire.toml b/alire.toml index ce34a4ee..94f1fa27 100644 --- a/alire.toml +++ b/alire.toml @@ -53,7 +53,7 @@ windows = { ALIRE_OS = "windows" } [[pins]] [pins.aaa] url = "https://github.com/mosteo/aaa" -commit = "04450085232edda086d7376a6dcaf17ab6b45aa9" +commit = "73d99ae1ff2f5210dc41c2ea7afebe600f9e9916" [pins.ada_toml] url = "https://github.com/pmderodat/ada-toml" diff --git a/deps/aaa b/deps/aaa index 04450085..73d99ae1 160000 --- a/deps/aaa +++ b/deps/aaa @@ -1 +1 @@ -Subproject commit 04450085232edda086d7376a6dcaf17ab6b45aa9 +Subproject commit 73d99ae1ff2f5210dc41c2ea7afebe600f9e9916 diff --git a/src/alire/alire-os_lib-subprocess.adb b/src/alire/alire-os_lib-subprocess.adb index c0881512..c5dc2478 100644 --- a/src/alire/alire-os_lib-subprocess.adb +++ b/src/alire/alire-os_lib-subprocess.adb @@ -196,6 +196,17 @@ package body Alire.OS_Lib.Subprocess is Exit_Code : Integer; + --------- + -- Dim -- + --------- + + procedure Dim (State : States) is + begin + if CLIC.TTY.Is_TTY and then CLIC.TTY.Color_Enabled then + Ada.Text_IO.Put (Style (Dim, State)); + end if; + end Dim; + begin Trace.Detail ("Spawning: " & Image (Command, Full_Args)); @@ -204,17 +215,24 @@ package body Alire.OS_Lib.Subprocess is Arg_List (I) := new String'(Full_Args (I)); end loop; - if CLIC.TTY.Is_TTY and then CLIC.TTY.Color_Enabled then - Ada.Text_IO.Put (Style (Dim, On)); - end if; + Dim (On); - Exit_Code := GNAT.OS_Lib.Spawn - (Program_Name => Locate_In_Path (Command), - Args => Arg_List.all); + declare + Full_Path : constant String := Locate_In_Path (Command); + begin + if Full_Path = "" then + Dim (Off); + Raise_Checked_Error + ("Executable not found in PATH when spawning: " + & TTY.Terminal (Command & " " & Arguments.Flatten (" "))); + end if; - if CLIC.TTY.Is_TTY and then CLIC.TTY.Color_Enabled then - Ada.Text_IO.Put (Style (Dim, Off)); - end if; + Exit_Code := GNAT.OS_Lib.Spawn + (Program_Name => Full_Path, + Args => Arg_List.all); + end; + + Dim (Off); Cleanup (Arg_List); @@ -283,11 +301,21 @@ package body Alire.OS_Lib.Subprocess is Arg_List (I) := new String'(Full_Args (I)); end loop; - Spawn (Program_Name => Locate_In_Path (Command), - Args => Arg_List.all, - Output_File_Descriptor => Outfile.Create, - Return_Code => Exit_Code, - Err_To_Out => Err_To_Out); + declare + Full_Path : constant String := Locate_In_Path (Command); + begin + if Full_Path = "" then + Raise_Checked_Error + ("Executable not found in PATH when spawning: " + & TTY.Terminal (Command & " " & Arguments.Flatten (" "))); + end if; + + Spawn (Program_Name => Full_Path, + Args => Arg_List.all, + Output_File_Descriptor => Outfile.Create, + Return_Code => Exit_Code, + Err_To_Out => Err_To_Out); + end; Read_Output; diff --git a/src/alr/alr-os_lib.adb b/src/alr/alr-os_lib.adb index b02cd6d6..5a6dc260 100644 --- a/src/alr/alr-os_lib.adb +++ b/src/alr/alr-os_lib.adb @@ -52,9 +52,20 @@ package body Alr.OS_Lib is begin Trace.Debug ("Spawning " & Command & " " & Arguments); - Code := GNAT.OS_Lib.Spawn - (Alire.OS_Lib.Subprocess.Locate_In_Path (Command), - GNAT.OS_Lib.Argument_String_To_List (Arguments).all); + declare + Full_Path : constant String := + Alire.OS_Lib.Subprocess.Locate_In_Path (Command); + begin + if Full_Path = "" then + Alire.Raise_Checked_Error + ("Executable not found in PATH when spawning: " + & TTY.Terminal (Command & " " & Arguments)); + end if; + + Code := GNAT.OS_Lib.Spawn + (Full_Path, + GNAT.OS_Lib.Argument_String_To_List (Arguments).all); + end; if Code /= 0 then raise Child_Failed with "Exit code:" & Code'Image; diff --git a/testsuite/tests/help/help-after-double-dash/test.py b/testsuite/tests/help/help-after-double-dash/test.py index 549c62b1..3cc06113 100644 --- a/testsuite/tests/help/help-after-double-dash/test.py +++ b/testsuite/tests/help/help-after-double-dash/test.py @@ -3,9 +3,10 @@ Bug #1379: -h/--help must not trigger our help system after a "--" argument """ import re +import shutil from drivers.alr import init_local_crate, run_alr -from drivers.asserts import assert_match +from drivers.asserts import assert_match, assert_substring # For no command, "--" with help afterwards should simply trigger an error @@ -23,9 +24,10 @@ assert_match(".*" + re.escape("Unrecognized option '--' (command/topic \"show\") init_local_crate() -assert_match(".*" + re.escape('Command ["alr_fake", "--help"] exited with code'), - run_alr("exec", "--", "alr_fake", "--help", - complain_on_error=False).out) -# We don't match the code as it varies between OSes +assert shutil.which("alr_fake") is None + +assert_substring("Executable not found in PATH when spawning", + run_alr("exec", "--", "alr_fake", "--help", + complain_on_error=False).out) print("SUCCESS") diff --git a/testsuite/tests/misc/exe-not-found/test.py b/testsuite/tests/misc/exe-not-found/test.py new file mode 100644 index 00000000..19dabc68 --- /dev/null +++ b/testsuite/tests/misc/exe-not-found/test.py @@ -0,0 +1,20 @@ +""" +Verify proper feedback when trying to spawn a missing executable +""" + +import shutil +from drivers.alr import run_alr, init_local_crate +from drivers.asserts import assert_substring + +EXE = "madeUpC0mmand" + +# To be extra sure, check the command is not in path +assert shutil.which(EXE) is None + +init_local_crate() + +p = run_alr("exec", "--", EXE, complain_on_error=False) + +assert_substring("Executable not found in PATH when spawning", p.out) + +print('SUCCESS') diff --git a/testsuite/tests/misc/exe-not-found/test.yaml b/testsuite/tests/misc/exe-not-found/test.yaml new file mode 100644 index 00000000..32c747b3 --- /dev/null +++ b/testsuite/tests/misc/exe-not-found/test.yaml @@ -0,0 +1 @@ +driver: python-script -- 2.39.5