Source file transom_codegen.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
module Manifest = Manifest
module Gen_ocaml_server = Gen_ocaml_server
module Gen_ts_client = Gen_ts_client

let rec mkdir_p dir =
  if dir = "" || dir = Filename.dirname dir then Ok ()
  else if Sys.file_exists dir then
    if Sys.is_directory dir then Ok ()
    else Error (dir ^ " exists and is not a directory")
  else
    match mkdir_p (Filename.dirname dir) with
    | Error message -> Error message
    | Ok () -> (
        try Ok (Unix.mkdir dir 0o755)
        with Unix.Unix_error (err, _, _) ->
          Error (dir ^ ": " ^ Unix.error_message err))

let write_file path content =
  match mkdir_p (Filename.dirname path) with
  | Error message -> Error message
  | Ok () -> (
      try
        let output = open_out_bin path in
        Fun.protect
          ~finally:(fun () -> close_out_noerr output)
          (fun () -> output_string output content);
        Ok ()
      with Sys_error message -> Error message)

let generated_files manifest =
  let server =
    manifest.Manifest.service_module |> Manifest.ocaml_module_to_string
    |> Gen_ocaml_server.lower_module_filename
  in
  [
    (server ^ ".mli", Gen_ocaml_server.interface manifest);
    (server ^ ".ml", Gen_ocaml_server.implementation manifest);
    ("api_client.ts", Gen_ts_client.implementation manifest);
  ]

let generate ~manifest_file ~out_dir =
  match Manifest.load_file manifest_file with
  | Error message -> Error message
  | Ok manifest ->
      let rec write acc = function
        | [] -> Ok (List.rev acc)
        | (name, content) :: rest -> (
            let path = Filename.concat out_dir name in
            match write_file path content with
            | Ok () -> write (path :: acc) rest
            | Error message -> Error message)
      in
      write [] (generated_files manifest)

let template_dirs ?cwd ?opam_switch_prefix ?env_template_dir () =
  let cwd = Option.value cwd ~default:(Sys.getcwd ()) in
  let add value acc =
    match value with None | Some "" -> acc | Some value -> value :: acc
  in
  []
  |> add
       (Option.map
          (fun prefix ->
            Filename.concat (Filename.concat prefix "share") "transom")
          opam_switch_prefix
       |> Option.map (fun share -> Filename.concat share "templates"))
  |> add (Some (Filename.concat cwd "templates"))
  |> add env_template_dir

let template_dirs_from_env ?cwd () =
  template_dirs ?cwd
    ?env_template_dir:(Sys.getenv_opt "TRANSOM_TEMPLATE_DIR")
    ?opam_switch_prefix:(Sys.getenv_opt "OPAM_SWITCH_PREFIX")
    ()