-
Notifications
You must be signed in to change notification settings - Fork 82
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
No longer call into cmd.exe to execute a posix shell on windows #339
Changes from 6 commits
0910c7b
95a5fda
afda9fe
bc11d49
f40543e
8b0520a
d834dd0
bfb1eb0
4402763
389d255
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -275,13 +275,80 @@ let sys_file_exists x = | |
try Array.iter (fun x -> if x = basename then raise Exit) a; false | ||
with Exit -> true | ||
|
||
(* https://github.com/ocaml/opam/blame/master/src/core/opamStd.ml *) | ||
let split_quoted path sep = | ||
let length = String.length path in | ||
let rec f acc index current last normal = | ||
if (index : int) = length then | ||
let current = current ^ String.sub path last (index - last) in | ||
List.rev (if current <> "" then current::acc else acc) | ||
else | ||
let c = path.[index] | ||
and next = succ index in | ||
if (c : char) = sep && normal || c = '"' then | ||
let current = current ^ String.sub path last (index - last) in | ||
if c = '"' then | ||
f acc next current next (not normal) | ||
else | ||
let acc = if current = "" then acc else current::acc in | ||
f acc next "" next true | ||
else | ||
f acc next current last normal in | ||
f [] 0 "" 0 true | ||
|
||
(* Here to break the circular dep *) | ||
let log3 = ref (fun _ -> failwith "My_std.log3 not initialized") | ||
|
||
let windows_shell = lazy begin | ||
let rec iter = function | ||
| [] -> raise Not_found | ||
| hd::tl -> | ||
let dash = Filename.concat hd "dash.exe" in | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A possible stronger trick for this, to avoid calling either WSL or the bash which gets exposed by Git-for-Windows (e.g. in Scoop, or when selecting the not-recommended "make all the utilities available" option). First of all attempt to resolve cygcheck.exe. If that resolves, look for the shells in that directory (note that both MSYS2 and Cygwin have a cygcheck binary). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you suggesting
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I implemented 2. for now |
||
if Sys.file_exists dash then [|dash|] else | ||
let bash = Filename.concat hd "bash.exe" in | ||
if not (Sys.file_exists bash) then iter tl else | ||
(* if sh.exe and bash.exe exist in the same dir, choose sh.exe *) | ||
let sh = Filename.concat hd "sh.exe" in | ||
if Sys.file_exists sh then [|sh|] else [|bash ; "--norc" ; "--noprofile"|] | ||
in | ||
let paths = split_quoted (try Sys.getenv "PATH" with Not_found -> "") ';' in | ||
let shell = | ||
try | ||
let path = | ||
List.find (fun path -> | ||
Sys.file_exists (Filename.concat path "cygcheck.exe")) paths | ||
in | ||
iter [path] | ||
with Not_found -> | ||
(try iter paths with Not_found -> failwith "no posix shell found in PATH") | ||
in | ||
!log3 (Printf.sprintf "Using shell %s" (Array.to_list shell |> String.concat " ")); | ||
shell | ||
end | ||
|
||
let prepare_command_for_windows cmd = | ||
(* The best way to prevent bash from switching to its windows-style | ||
* quote-handling is to prepend an empty string before the command name. *) | ||
let cmd = "''" ^ cmd in | ||
Array.append (Lazy.force windows_shell) [|"-c"; cmd|] | ||
|
||
let sys_command_win32 cmd = | ||
let args = prepare_command_for_windows cmd in | ||
let oc = Unix.open_process_args_out args.(0) args in | ||
match Unix.close_process_out oc with | ||
| WEXITED x -> x | ||
| WSIGNALED _ -> 2 (* like OCaml's uncaught exceptions *) | ||
| WSTOPPED _ -> 127 | ||
|
||
let sys_command = | ||
match Sys.win32 with | ||
| true -> fun cmd -> | ||
if cmd = "" then 0 else | ||
let cmd = "bash --norc -c " ^ Filename.quote cmd in | ||
Sys.command cmd | ||
| false -> fun cmd -> if cmd = "" then 0 else Sys.command cmd | ||
if Sys.win32 then | ||
sys_command_win32 | ||
else | ||
Sys.command | ||
|
||
let sys_command cmd = | ||
if cmd = "" then 0 else | ||
sys_command cmd | ||
|
||
(* FIXME warning fix and use Filename.concat *) | ||
let filename_concat x y = | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -136,13 +136,13 @@ let execute | |
(* ***) | ||
(*** add_job *) | ||
let add_job cmd rest result id = | ||
let cmd = | ||
if Sys.win32 | ||
then "bash --norc -c " ^ Filename.quote cmd | ||
else cmd | ||
in | ||
(*display begin fun oc -> fp oc "Job %a is %s\n%!" print_job_id id cmd; end;*) | ||
let (stdout', stdin', stderr') = open_process_full cmd env in | ||
let (stdout', stdin', stderr') = | ||
if Sys.win32 | ||
then | ||
let args = My_std.prepare_command_for_windows cmd in | ||
open_process_args_full args.(0) args (Unix.environment ()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are you calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no reason, I've changed it back. |
||
else open_process_full cmd env in | ||
incr jobs_active; | ||
if not Sys.win32 then begin | ||
set_nonblock (doi stdout'); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Luckily opam uses the same license so reusing code as-is is just fine.)
@hhugo could you maybe tweak your URL to contain a hash of a recent commit, instead of
master
? This would be helpful if someone in the future wants to now whether our local copy should be updated.(I would have considered moving the copied-almost-exactly-as-is code to a separate file, to make such future tracking easier, but oh well.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the comment