|
|
|
@ -29,23 +29,24 @@ let print_error_and_exit ?(exit_code=1) fmt =
|
|
|
|
|
Format.str_formatter fmt
|
|
|
|
|
|
|
|
|
|
(** Executes a command and catches a potential exception and prints it. *)
|
|
|
|
|
let exec_command cmd args env =
|
|
|
|
|
try Unix.execve cmd args env
|
|
|
|
|
let exec_command ~prog ~args env =
|
|
|
|
|
try Unix.execve prog (Array.of_list (prog :: args)) env
|
|
|
|
|
with (Unix.Unix_error _ as e) ->
|
|
|
|
|
print_unix_error cmd e
|
|
|
|
|
print_unix_error (String.concat ~sep:" " (prog :: args)) e
|
|
|
|
|
|
|
|
|
|
(** Given a command to be executed, create a process to execute this command, and wait for it to
|
|
|
|
|
terminate. The standard out and error are not redirected. If the command fails to execute,
|
|
|
|
|
print an error message and exit. *)
|
|
|
|
|
let create_process_and_wait cmd =
|
|
|
|
|
let pid = Unix.create_process cmd.(0) cmd Unix.stdin Unix.stdout Unix.stderr in
|
|
|
|
|
let create_process_and_wait ~prog ~args =
|
|
|
|
|
let pid =
|
|
|
|
|
Unix.create_process prog (Array.of_list (prog :: args)) Unix.stdin Unix.stdout Unix.stderr in
|
|
|
|
|
let _, status = Unix.waitpid [] pid in
|
|
|
|
|
let exit_code = match status with
|
|
|
|
|
| Unix.WEXITED i -> i
|
|
|
|
|
| _ -> 1 in
|
|
|
|
|
if exit_code <> 0 then
|
|
|
|
|
print_error_and_exit ~exit_code:exit_code
|
|
|
|
|
"Failed to execute: %s\n" (String.concat ~sep:" " (Array.to_list cmd))
|
|
|
|
|
"Failed to execute: %s\n" (String.concat ~sep:" " (prog :: args))
|
|
|
|
|
|
|
|
|
|
(** Given a process id and a function that describes the command that the process id
|
|
|
|
|
represents, prints a message explaining the command and its status, if in debug or stats mode.
|
|
|
|
@ -86,28 +87,27 @@ let pid_to_program jobsMap pid =
|
|
|
|
|
IntMap.find pid jobsMap
|
|
|
|
|
with Not_found -> ""
|
|
|
|
|
|
|
|
|
|
(** [run_jobs_in_parallel jobs_stack gen_cmd cmd_to_string] runs the jobs in the given stack, by
|
|
|
|
|
(** [run_jobs_in_parallel jobs_stack gen_prog prog_to_string] runs the jobs in the given stack, by
|
|
|
|
|
spawning the jobs in batches of n, where n is [Config.jobs]. It then waits for all those jobs
|
|
|
|
|
and starts a new batch and so on. [gen_cmd] should return a tuple [(dir_opt, command, args,
|
|
|
|
|
env)] where [dir_opt] is an optional directory to chdir to before executing the process, and
|
|
|
|
|
[command], [args], [env] are the same as for [exec_command]. [cmd_to_string] is used for
|
|
|
|
|
printing information about the job's status. *)
|
|
|
|
|
let run_jobs_in_parallel jobs_stack gen_cmd cmd_to_string =
|
|
|
|
|
and starts a new batch and so on. [gen_prog] should return a tuple [(dir_opt, command, args,
|
|
|
|
|
env)] where [dir_opt] is an optional directory to chdir to before executing [command] with
|
|
|
|
|
[args] in [env]. [prog_to_string] is used for printing information about the job's status. *)
|
|
|
|
|
let run_jobs_in_parallel jobs_stack gen_prog prog_to_string =
|
|
|
|
|
let run_job () =
|
|
|
|
|
let jobs_map = ref IntMap.empty in
|
|
|
|
|
let current_jobs_count = start_current_jobs_count () in
|
|
|
|
|
while not (Stack.is_empty jobs_stack) do
|
|
|
|
|
let job_cmd = Stack.pop jobs_stack in
|
|
|
|
|
let (dir_opt, cmd, args, env) = gen_cmd job_cmd in
|
|
|
|
|
let job_prog = Stack.pop jobs_stack in
|
|
|
|
|
let (dir_opt, prog, args, env) = gen_prog job_prog in
|
|
|
|
|
Pervasives.incr current_jobs_count;
|
|
|
|
|
match Unix.fork () with
|
|
|
|
|
| 0 ->
|
|
|
|
|
(match dir_opt with
|
|
|
|
|
| Some dir -> Unix.chdir dir
|
|
|
|
|
| None -> ());
|
|
|
|
|
exec_command cmd args env
|
|
|
|
|
exec_command ~prog ~args env
|
|
|
|
|
| pid_child ->
|
|
|
|
|
jobs_map := IntMap.add pid_child (cmd_to_string job_cmd) !jobs_map;
|
|
|
|
|
jobs_map := IntMap.add pid_child (prog_to_string job_prog) !jobs_map;
|
|
|
|
|
if Stack.length jobs_stack = 0 || !current_jobs_count >= Config.jobs then
|
|
|
|
|
wait_for_child (pid_to_program !jobs_map) current_jobs_count jobs_map
|
|
|
|
|
done in
|
|
|
|
|