Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows [find_executable] fixes #16

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
- Add `Process.call_xxx` functions that are equivalent to their
`Process.run_xxx` counterpart except that they take a single string
list as argument (#8, David Chemouil)
- Use `;` as PATH seperator on Windows. Find executables with `.exe`
extension on Windows. Workaround `Sys.file_exists` being true for
directories on Windows (#16, Jonah Beckford)
27 changes: 24 additions & 3 deletions process-lib/src/env.ml
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ module Uenv = struct

let split_path str =
let len = String.length str in
let is_sep c = c = ':' in
let sep = if Sys.win32 then ';' else ':' in
let is_sep c = c = sep in
let rec loop i j =
if j = len
then [ String.sub str ~pos:i ~len:(j - i) ]
Expand Down Expand Up @@ -257,12 +258,32 @@ let chdir t dir =
{ t with cwd; unix_env }
;;

let find_executable t exe =
let get_executable_if_exists fn =
if Sys.win32 then
(* Only some file extensions are executable. `.exe` is always
executable. The extensions in PATHEXT (`.exe`, `.bat`, `.cmd`,
etc.) are also executable by the Command Prompt shell. We'll
just use `.exe` since it is the only correct extension in all
contexts. *)
let fn_exe = (Filename.remove_extension fn) ^ ".exe" in
(* [Sys.file_exists] can return true even if [Sys.is_directory]
is true. *)
if Sys.file_exists fn_exe && not (Sys.is_directory fn_exe) then
Some fn_exe
else
None
else
(* Unix *)
if Sys.file_exists fn then Some fn else None

let find_executable t exe =
let rec loop = function
| [] -> None
| path :: rest ->
let fn = path ^/ exe in
if Sys.file_exists fn then Some fn else loop rest
match get_executable_if_exists fn with
| Some found_fn -> Some found_fn
| None -> loop rest
in
if not (Filename.is_relative exe)
then Some exe
Expand Down