Make Std_utils.which behave a bit more like which(1), checking the
existance of relative/absolute paths specified.
---
common/mlstdutils/std_utils.ml | 29 ++++++++++++++++------------
common/mlstdutils/std_utils.mli | 5 ++++-
common/mlstdutils/std_utils_tests.ml | 10 ++++++++++
3 files changed, 31 insertions(+), 13 deletions(-)
diff --git a/common/mlstdutils/std_utils.ml b/common/mlstdutils/std_utils.ml
index 5a92dccc9..70156d1ba 100644
--- a/common/mlstdutils/std_utils.ml
+++ b/common/mlstdutils/std_utils.ml
@@ -610,18 +610,23 @@ let failwithf fs = ksprintf failwith fs
exception Executable_not_found of string (* executable *)
let which executable =
- let paths =
- try String.nsplit ":" (Sys.getenv "PATH")
- with Not_found -> [] in
- let paths = List.filter_map (
- fun p ->
- let path = p // executable in
- try Unix.access path [Unix.X_OK]; Some path
- with Unix.Unix_error _ -> None
- ) paths in
- match paths with
- | [] -> raise (Executable_not_found executable)
- | x :: _ -> x
+ if String.find executable Filename.dir_sep <> -1 then (
+ try Unix.access executable [Unix.X_OK]; executable
+ with Unix.Unix_error _ -> raise (Executable_not_found executable)
+ ) else (
+ let paths =
+ try String.nsplit ":" (Sys.getenv "PATH")
+ with Not_found -> [] in
+ let paths = List.filter_map (
+ fun p ->
+ let path = p // executable in
+ try Unix.access path [Unix.X_OK]; Some path
+ with Unix.Unix_error _ -> None
+ ) paths in
+ match paths with
+ | [] -> raise (Executable_not_found executable)
+ | x :: _ -> x
+ )
(* Program name. *)
let prog = Filename.basename Sys.executable_name
diff --git a/common/mlstdutils/std_utils.mli b/common/mlstdutils/std_utils.mli
index ca4e940cf..5e5242f7a 100644
--- a/common/mlstdutils/std_utils.mli
+++ b/common/mlstdutils/std_utils.mli
@@ -359,7 +359,10 @@ exception Executable_not_found of string (* executable *)
in [$PATH]. *)
val which : string -> string
-(** Return the full path of the specified executable from [$PATH].
+(** Return the full path of the specified executable from [$PATH],
+ in case it is only a name. In case of a relative or absolute path
+ (i.e. more than just a name), return the same path specified if
+ exists.
Throw [Executable_not_found] if not available. *)
diff --git a/common/mlstdutils/std_utils_tests.ml b/common/mlstdutils/std_utils_tests.ml
index f7b0247a4..d161b5e7e 100644
--- a/common/mlstdutils/std_utils_tests.ml
+++ b/common/mlstdutils/std_utils_tests.ml
@@ -149,6 +149,16 @@ let test_string_chomp ctx =
let test_which ctx =
assert_nonempty_string (which "true");
assert_raises_executable_not_found "this-command-does-not-really-exist";
+ begin
+ let exe_name = "true" in
+ let exe = which exe_name in
+ assert_equal_string exe (which exe);
+ with_bracket_chdir ctx (Filename.dirname exe) (
+ fun ctx ->
+ let exe_relative = "./" ^ exe_name in
+ assert_equal_string exe_relative (which exe_relative)
+ )
+ end;
()
(* Suites declaration. *)
--
2.17.2