You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

107 lines
3.9 KiB

(*
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
module U = Utils
module P = Process
(* Needed as a (pointer-stable) default value for atd specs. *)
let empty_string = ""
let ydump ?(compact_json= false) ?(std_json= false) ic oc =
let cmd =
["ydump"] @ (if compact_json then ["-c"] else []) @ if std_json then ["-std"] else []
in
P.exec (Array.of_list cmd) ic oc stderr
let read_data_from_file reader fname =
let input_gunzipped read_data ic =
let pid, icz = P.fork (P.gunzip ic) in
let data = read_data icz in
let r = P.wait pid in
P.close_in icz ;
if not r then failwith "read_data_from_file (gunzip)" else () ;
data
in
let ic = open_in fname in
let data =
if U.string_ends_with fname ".value.gz" then input_gunzipped Marshal.from_channel ic
else if U.string_ends_with fname ".gz" then
input_gunzipped (Atdgen_runtime.Util.Json.from_channel ~fname reader) ic
else if U.string_ends_with fname ".value" then Marshal.from_channel ic
else Atdgen_runtime.Util.Json.from_channel ~fname reader ic
in
close_in ic ; data
let write_data_to_file ?(pretty= false) ?(compact_json= false) ?(std_json= false) writer fname data =
let output_gzipped write_data oc data =
let pid, icz = P.fork (fun ocz -> write_data ocz data ; true) in
let r1 = P.gzip icz oc and r2 = P.wait pid in
P.close_in icz ;
if not (r1 && r2) then failwith "write_data_to_file (gzip)" else ()
and output_pretty write_data oc data =
(* TODO(mathieubaudet): find out how to write directly pretty json? *)
let pid, icp = P.fork (fun ocp -> write_data ocp data ; true) in
let r1 = ydump ~compact_json ~std_json icp oc and r2 = P.wait pid in
P.close_in icp ;
if not (r1 && r2) then failwith "write_data_to_file (pretty)" else ()
in
let write_json ocx data =
if pretty then output_pretty (Atdgen_runtime.Util.Json.to_channel writer) ocx data
else Atdgen_runtime.Util.Json.to_channel writer ocx data
in
let oc = open_out fname in
if U.string_ends_with fname ".value.gz" then
output_gzipped (fun oc data -> Marshal.to_channel oc data []) oc data
else if U.string_ends_with fname ".value" then Marshal.to_channel oc data []
else if U.string_ends_with fname ".gz" then output_gzipped write_json oc data
else write_json oc data ;
close_out oc
let convert ?(pretty= false) ?(compact_json= false) ?(std_json= false) reader writer fin fout =
try
read_data_from_file reader fin
|> write_data_to_file writer ~pretty ~compact_json ~std_json fout
with
| Yojson.Json_error s | Atdgen_runtime.Oj_run.Error s ->
prerr_string s ; prerr_newline () ; exit 1
let run_converter_tool reader writer =
let pretty = ref false
and std_json = ref false
and compact_json = ref false
and files = ref [] in
let add_files x = files := x :: !files
and usage_msg =
"Usage: " ^ Sys.argv.(0) ^ "[OPTIONS] INPUT_FILE [OUTPUT_FILE]\n"
^ "Parse yojson values and convert them to another format based on the extension"
^ " of the output file (default: ${INPUT_FILE}.value.gz).\n"
in
let spec =
Utils.fix_arg_spec
[ ("--pretty", Arg.Set pretty, " Pretty print outputs.")
; ("--std", Arg.Set std_json, " Use standard json for outputs.")
; ("--compact", Arg.Set compact_json, " Use compact json for outputs.")
; ("--", Arg.Rest add_files, " Mark the end of options.") ] usage_msg
in
(* Parse the command line. *)
Arg.parse spec add_files usage_msg ;
let input, output =
match List.rev !files with
| [input] ->
(input, input ^ ".value.gz")
| [input; output] ->
(input, output)
| _ ->
prerr_string usage_msg ; exit 1
in
convert ~pretty:!pretty ~std_json:!std_json ~compact_json:!compact_json reader writer input
output