elpe_bin.ml
open Lwt.Syntax
let connection address port =
let open Lwt.Syntax in
(* Setup Http/2 connection *)
let* addresses =
Lwt_unix.getaddrinfo address (string_of_int port)
[ Unix.(AI_FAMILY PF_INET) ]
in
let socket = Lwt_unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
let* () = Lwt_unix.connect socket (List.hd addresses).Unix.ai_addr in
let error_handler e = raise (Elpe.Error e) in
H2_lwt_unix.Client.create_connection ~error_handler socket
let run_shell (spec : Elpe.derivation) cmd =
let* b = spec#setup in
let* bash = (Elpe.ubuntu "bash-static")#build in
let bash = List.hd bash.destdir in
let f = Filename.temp_dir "elpe-" "" ^ "/setup" in
Unix.mkfifo f 0o666;
let pid =
Unix.create_process
(bash ^ "/usr/bin/bash-static")
(match cmd with
| None -> [| "bash"; "--init-file"; f; "-i" |]
| Some cmd -> [| "bash"; "--init-file"; f; "-i"; "-c"; cmd |])
Unix.stdin Unix.stdout Unix.stderr
in
let p = Unix.openfile f [ Unix.O_WRONLY ] 0o644 in
let _ = Unix.write_substring p b 0 (String.length b) in
Unix.close p;
match Unix.waitpid [] pid with
| _, Unix.WEXITED e -> Lwt.return e
| _ -> failwith "Unknown"
let run_build (spec : Elpe.derivation) =
let* b = spec#build in
print_endline (List.fold_left (fun _ x -> x) "" b.destdir);
Lwt.return ()
let compile input_files =
(* Compile *)
let args =
Array.of_list
([
"ocamlfind";
(if Dynlink.is_native then "ocamlopt" else "ocamlc");
"-package";
"elpe";
"-c";
]
@ input_files)
in
let pid =
let rd, wr = Unix.pipe () in
let pid = Unix.create_process "ocamlfind" args rd Unix.stdout Unix.stderr in
Unix.close wr;
pid
in
let _ =
match Unix.waitpid [] pid with
| _, Unix.WEXITED 0 -> ()
| _, Unix.WEXITED e -> Unix._exit e
| _ -> print_endline "other"
in
let port = 50051 in
let address = "127.0.0.1" in
let* c = connection address port in
Elpe.backend_conn := Some c;
(* Link *)
Dynlink.set_allowed_units [ "Elpe" ];
let obj =
Dynlink.adapt_filename
(Filename.remove_extension (Array.get args (Array.length args - 1))
^ ".cmo")
in
Lwt.return (Dynlink.loadfile obj)
let shell =
Core.Command.basic ~summary:""
(let%map_open.Command cmd =
flag "-c" (optional string) ~doc:"Command to run in this shell"
and files = anon (sequence ("file" %: string)) in
fun () ->
Elpe.last_built_module := None;
Lwt_main.run
(let* _ = compile (if files = [] then [ "shell.ml" ] else files) in
match !Elpe.last_built_module with
| None -> Unix._exit 0
| Some last ->
let* last = last in
let* shell = run_shell last cmd in
Unix._exit shell))
let build =
Core.Command.basic ~summary:""
(let%map_open.Command files = anon (sequence ("file" %: string)) in
fun () ->
Elpe.last_built_module := None;
Lwt_main.run
(let* _ = compile (if files = [] then [ "build.ml" ] else files) in
match !Elpe.last_built_module with
| None -> Lwt.return ()
| Some last ->
let* last = last in
run_build (last :> Elpe.derivation)))
let command =
Core.Command.group ~summary:"Elpe" [ ("shell", shell); ("build", build) ]
let () = Command_unix.run command
(* if !input_files != [] then *)
(* let exit = compile_and_run () in *)
(* Unix._exit exit *)
(* else Printf.eprintf "\n" *)