Richard W.M. Jones
2018-Aug-20 16:02 UTC
[Libguestfs] [PATCH 0/4] mltools: JSON unification
An evolution of: https://www.redhat.com/archives/libguestfs/2018-August/msg00155.html
Richard W.M. Jones
2018-Aug-20 16:02 UTC
[Libguestfs] [PATCH 1/4] mltools: JSON: Rename Yajl module as JSON_parser and move to common/mltools.
Commit bd1c5c9f4dcf38458099db8a0bf4659a07ef055d changed all the code
to use Jansson instead of yajl. However it didn't change the OCaml
module name (still Yajl).
This commit changes the module to a neutral name ("JSON_parser") and
moves it into common/mltools so it can be used by other tools.
This leaves us in a slightly awkward situation of having two JSON-ish
OCaml modules (JSON for creating trees and JSON_parser for parsing
them) with incompatible types. That is left for future work to
resolve. (It should be easier to do now that both modules live in the
same directory.)
This is just renaming and general refactoring. There should be no
change in functionality.
---
.gitignore | 2 +-
builder/Makefile.am | 57 ++++---------------
builder/index_parser.ml | 2 +-
builder/repository_main.ml | 2 +-
builder/simplestreams_parser.ml | 6 +-
builder/utils.ml | 2 +-
builder/utils.mli | 4 +-
.../mltools/JSON_parser-c.c | 8 +--
.../yajl.ml => common/mltools/JSON_parser.ml | 38 ++++++-------
.../mltools/JSON_parser.mli | 42 +++++++-------
.../mltools/JSON_parser_tests.ml | 56 +++++++++---------
common/mltools/Makefile.am | 39 ++++++++++++-
docs/C_SOURCE_FILES | 4 +-
po/POTFILES | 3 +-
po/POTFILES-ml | 4 +-
15 files changed, 135 insertions(+), 134 deletions(-)
diff --git a/.gitignore b/.gitignore
index 41219f4a1..b714b1a43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -113,7 +113,6 @@ Makefile.in
/builder/virt-index-validate
/builder/virt-index-validate.1
/builder/*.xz
-/builder/yajl_tests
/cat/stamp-virt-*.pod
/cat/virt-cat
/cat/virt-cat.1
@@ -146,6 +145,7 @@ Makefile.in
/common/mltools/.depend
/common/mltools/getopt_tests
/common/mltools/JSON_tests
+/common/mltools/JSON_parser_tests
/common/mltools/tools_utils_tests
/common/mltools/oUnit-*
/common/mlutils/.depend
diff --git a/builder/Makefile.am b/builder/Makefile.am
index 7ede544b7..f64750c7f 100644
--- a/builder/Makefile.am
+++ b/builder/Makefile.am
@@ -45,8 +45,7 @@ EXTRA_DIST = \
test-virt-index-validate-good-4 \
virt-builder.pod \
virt-builder-repository.pod \
- virt-index-validate.pod \
- yajl_tests.ml
+ virt-index-validate.pod
SOURCES_MLI = \
builder.mli \
@@ -67,11 +66,9 @@ SOURCES_MLI = \
sigchecker.mli \
simplestreams_parser.mli \
sources.mli \
- utils.mli \
- yajl.mli
+ utils.mli
SOURCES_ML = \
- yajl.ml \
utils.ml \
osinfo_config.ml \
osinfo.ml \
@@ -97,11 +94,9 @@ SOURCES_C = \
index-parse.c \
index-parser-c.c \
pxzcat-c.c \
- setlocale-c.c \
- yajl-c.c
+ setlocale-c.c
REPOSITORY_SOURCES_ML = \
- yajl.ml \
utils.ml \
index.ml \
cache.ml \
@@ -122,15 +117,13 @@ REPOSITORY_SOURCES_MLI = \
index_parser.mli \
ini_reader.mli \
sigchecker.mli \
- sources.mli \
- yajl.mli
+ sources.mli
REPOSITORY_SOURCES_C = \
index-scan.c \
index-struct.c \
index-parse.c \
- index-parser-c.c \
- yajl-c.c
+ index-parser-c.c
man_MANS noinst_DATA @@ -156,8 +149,7 @@ virt_builder_CFLAGS = \
-Wno-unused-macros \
$(LIBLZMA_CFLAGS) \
$(LIBTINFO_CFLAGS) \
- $(LIBXML2_CFLAGS) \
- $(JANSSON_CFLAGS)
+ $(LIBXML2_CFLAGS)
BOBJECTS = $(SOURCES_ML:.ml=.cmo)
XOBJECTS = $(BOBJECTS:.cmo=.cmx)
@@ -175,8 +167,7 @@ virt_builder_repository_CFLAGS = \
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
-Wno-unused-macros \
$(LIBTINFO_CFLAGS) \
- $(LIBXML2_CFLAGS) \
- $(YAJL_CFLAGS)
+ $(LIBXML2_CFLAGS)
REPOSITORY_BOBJECTS = $(REPOSITORY_SOURCES_ML:.ml=.cmo)
REPOSITORY_XOBJECTS = $(REPOSITORY_BOBJECTS:.cmo=.cmx)
@@ -323,22 +314,13 @@ fedora.qcow2.xz: fedora.qcow2
xz --best -c $< > $@-t
mv $@-t $@
-yajl_tests_SOURCES = yajl-c.c
-yajl_tests_CPPFLAGS = $(virt_builder_CPPFLAGS)
-yajl_tests_BOBJECTS = \
- yajl.cmo \
- yajl_tests.cmo
-yajl_tests_XOBJECTS = $(yajl_tests_BOBJECTS:.cmo=.cmx)
-
index_parser_tests_SOURCES = \
index-scan.c \
index-struct.c \
index-parser-c.c \
- index-parse.c \
- yajl-c.c
+ index-parse.c
index_parser_tests_CPPFLAGS = $(virt_builder_CPPFLAGS)
index_parser_tests_BOBJECTS = \
- yajl.cmo \
utils.cmo \
index.cmo \
cache.cmo \
@@ -351,32 +333,13 @@ index_parser_tests_XOBJECTS =
$(index_parser_tests_BOBJECTS:.cmo=.cmx)
# Can't call the following as <test>_OBJECTS because automake gets
confused.
if HAVE_OCAMLOPT
-yajl_tests_THEOBJECTS = $(yajl_tests_XOBJECTS)
-yajl_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
-
index_parser_tests_THEOBJECTS = $(index_parser_tests_XOBJECTS)
index_parser_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
else
-yajl_tests_THEOBJECTS = $(yajl_tests_BOBJECTS)
-yajl_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
-
index_parser_tests_THEOBJECTS = $(index_parser_tests_BOBJECTS)
index_parser_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
endif
-yajl_tests_DEPENDENCIES = \
- $(yajl_tests_THEOBJECTS) \
- ../common/mlpcre/mlpcre.$(MLARCHIVE) \
- ../common/mlstdutils/mlstdutils.$(MLARCHIVE) \
- ../common/mlutils/mlcutils.$(MLARCHIVE) \
- ../common/mltools/mltools.$(MLARCHIVE) \
- ../customize/customize.$(MLARCHIVE) \
- $(top_srcdir)/ocaml-link.sh
-yajl_tests_LINK = \
- $(top_srcdir)/ocaml-link.sh -cclib '$(OCAMLCLIBS)' -- \
- $(OCAMLFIND) $(BEST) $(OCAMLFLAGS) $(OCAMLPACKAGES) $(OCAMLPACKAGES_TESTS)
$(OCAMLLINKFLAGS) \
- $(yajl_tests_THEOBJECTS) -o $@
-
index_parser_tests_DEPENDENCIES = \
$(index_parser_tests_THEOBJECTS) \
../common/mltools/mltools.$(MLARCHIVE) \
@@ -400,8 +363,8 @@ if ENABLE_APPLIANCE
TESTS += test-virt-builder.sh
endif ENABLE_APPLIANCE
if HAVE_OCAML_PKG_OUNIT
-check_PROGRAMS += yajl_tests index_parser_tests
-TESTS += yajl_tests index_parser_tests
+check_PROGRAMS += index_parser_tests
+TESTS += index_parser_tests
endif
check-valgrind:
diff --git a/builder/index_parser.ml b/builder/index_parser.ml
index 79653a91b..59fa5097d 100644
--- a/builder/index_parser.ml
+++ b/builder/index_parser.ml
@@ -140,7 +140,7 @@ let get_index ~downloader ~sigchecker ?(template = false) {
Sources.uri; proxy }
match detect_file_type filepath with
| `Unknown ->
let infos = Utils.get_image_infos filepath in
- Yajl.object_get_number "virtual-size" infos
+ JSON_parser.object_get_number "virtual-size" infos
| `XZ | `GZip | `Tar | ` Zip ->
eprintf (f_"%s: cannot determine the virtual size of %s
due to compression")
prog filepath;
diff --git a/builder/repository_main.ml b/builder/repository_main.ml
index 03d6ed13e..4ec434e57 100644
--- a/builder/repository_main.ml
+++ b/builder/repository_main.ml
@@ -22,7 +22,7 @@ open Tools_utils
open Unix_utils
open Getopt.OptionName
open Utils
-open Yajl
+open JSON_parser
open Xpath_helpers
open Printf
diff --git a/builder/simplestreams_parser.ml b/builder/simplestreams_parser.ml
index 18f45a6fd..fa5b887ac 100644
--- a/builder/simplestreams_parser.ml
+++ b/builder/simplestreams_parser.ml
@@ -20,7 +20,7 @@ open Std_utils
open Tools_utils
open Common_gettext.Gettext
-open Yajl
+open JSON_parser
open Utils
open Printf
@@ -44,7 +44,7 @@ let get_index ~downloader ~sigchecker { Sources.uri; proxy }
| Some f -> f
) else
tmpfile in
- yajl_tree_parse (read_whole_file file) in
+ json_parser_tree_parse (read_whole_file file) in
let downloads let uri_index @@ -106,7 +106,7 @@ let get_index
~downloader ~sigchecker { Sources.uri; proxy } * the ones
related to checksums, explicitly filter
* the supported checksums.
*)
- | ("sha256"|"sha512" as t, Yajl_string c)
->
+ | ("sha256"|"sha512" as t,
JSON_parser_string c) ->
Some (Checksums.of_string t c)
| _ -> None
) disk_item in
diff --git a/builder/utils.ml b/builder/utils.ml
index 1446561b0..538a43be9 100644
--- a/builder/utils.ml
+++ b/builder/utils.ml
@@ -43,4 +43,4 @@ let get_image_infos filepath let qemuimg_cmd =
"qemu-img info --output json " ^ quote filepath in
let lines = external_command qemuimg_cmd in
let line = String.concat "\n" lines in
- Yajl.yajl_tree_parse line
+ JSON_parser.json_parser_tree_parse line
diff --git a/builder/utils.mli b/builder/utils.mli
index 4249fd956..5dde43a01 100644
--- a/builder/utils.mli
+++ b/builder/utils.mli
@@ -29,9 +29,9 @@ and revision val string_of_revision : revision -> string
(** Convert a {!revision} into a string. *)
-val get_image_infos : string -> Yajl.yajl_val
+val get_image_infos : string -> JSON_parser.json_parser_val
(** [get_image_infos path] Run qemu-img info on the image pointed at
- path as YAJL tree. *)
+ path as JSON tree. *)
val increment_revision : revision -> revision
(** Add one to the revision number *)
diff --git a/builder/yajl-c.c b/common/mltools/JSON_parser-c.c
similarity index 94%
rename from builder/yajl-c.c
rename to common/mltools/JSON_parser-c.c
index e53755f55..32432dc5b 100644
--- a/builder/yajl-c.c
+++ b/common/mltools/JSON_parser-c.c
@@ -1,5 +1,5 @@
-/* virt-builder
- * Copyright (C) 2015 Red Hat Inc.
+/* JSON parser
+ * Copyright (C) 2015-2018 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@
#define Val_none (Val_int (0))
-value virt_builder_yajl_tree_parse (value stringv);
+value virt_builder_json_parser_tree_parse (value stringv);
static value
convert_json_t (json_t *val, int level)
@@ -95,7 +95,7 @@ convert_json_t (json_t *val, int level)
}
value
-virt_builder_yajl_tree_parse (value stringv)
+virt_builder_json_parser_tree_parse (value stringv)
{
CAMLparam1 (stringv);
CAMLlocal1 (rv);
diff --git a/builder/yajl.ml b/common/mltools/JSON_parser.ml
similarity index 75%
rename from builder/yajl.ml
rename to common/mltools/JSON_parser.ml
index d95f3932a..a82127454 100644
--- a/builder/yajl.ml
+++ b/common/mltools/JSON_parser.ml
@@ -1,5 +1,5 @@
-(* virt-builder
- * Copyright (C) 2015 Red Hat Inc.
+(* JSON parser
+ * Copyright (C) 2015-2018 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,19 +20,19 @@ open Std_utils
open Tools_utils
open Common_gettext.Gettext
-type yajl_val -| Yajl_null
-| Yajl_string of string
-| Yajl_number of int64
-| Yajl_double of float
-| Yajl_object of (string * yajl_val) array
-| Yajl_array of yajl_val array
-| Yajl_bool of bool
+type json_parser_val +| JSON_parser_null
+| JSON_parser_string of string
+| JSON_parser_number of int64
+| JSON_parser_double of float
+| JSON_parser_object of (string * json_parser_val) array
+| JSON_parser_array of json_parser_val array
+| JSON_parser_bool of bool
-external yajl_tree_parse : string -> yajl_val =
"virt_builder_yajl_tree_parse"
+external json_parser_tree_parse : string -> json_parser_val =
"virt_builder_json_parser_tree_parse"
let object_find_optional key = function
- | Yajl_object o ->
+ | JSON_parser_object o ->
(match List.filter (fun (k, _) -> k = key) (Array.to_list o) with
| [(k, v)] -> Some v
| [] -> None
@@ -46,27 +46,27 @@ let object_find key yv
let object_get_string key yv match object_find key yv with
- | Yajl_string s -> s
+ | JSON_parser_string s -> s
| _ -> error (f_"the value for the key ‘%s’ is not a string")
key
let object_find_object key yv match object_find key yv with
- | Yajl_object _ as o -> o
+ | JSON_parser_object _ as o -> o
| _ -> error (f_"the value for the key ‘%s’ is not an object")
key
let object_find_objects fn = function
- | Yajl_object o -> List.filter_map fn (Array.to_list o)
+ | JSON_parser_object o -> List.filter_map fn (Array.to_list o)
| _ -> error (f_"the value is not an object")
let object_get_object key yv match object_find_object key yv with
- | Yajl_object o -> o
+ | JSON_parser_object o -> o
| _ -> assert false (* object_find_object already errors out. *)
let object_get_number key yv match object_find key yv with
- | Yajl_number n -> n
- | Yajl_double d -> Int64.of_float d
+ | JSON_parser_number n -> n
+ | JSON_parser_double d -> Int64.of_float d
| _ -> error (f_"the value for the key ‘%s’ is not an integer")
key
let objects_get_string key yvs @@ -74,7 +74,7 @@ let objects_get_string key yvs
| [] -> None
| x :: xs ->
(match object_find_optional key x with
- | Some (Yajl_string s) -> Some s
+ | Some (JSON_parser_string s) -> Some s
| Some _ -> error (f_"the value for key ‘%s’ is not a string as
expected") key
| None -> loop xs
)
diff --git a/builder/yajl.mli b/common/mltools/JSON_parser.mli
similarity index 60%
rename from builder/yajl.mli
rename to common/mltools/JSON_parser.mli
index ca0eb92f4..f505953f2 100644
--- a/builder/yajl.mli
+++ b/common/mltools/JSON_parser.mli
@@ -1,5 +1,5 @@
-(* virt-builder
- * Copyright (C) 2015 Red Hat Inc.
+(* JSON parser
+ * Copyright (C) 2015-2018 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,43 +16,43 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*)
-type yajl_val -| Yajl_null
-| Yajl_string of string
-| Yajl_number of int64
-| Yajl_double of float
-| Yajl_object of (string * yajl_val) array
-| Yajl_array of yajl_val array
-| Yajl_bool of bool
+type json_parser_val +| JSON_parser_null
+| JSON_parser_string of string
+| JSON_parser_number of int64
+| JSON_parser_double of float
+| JSON_parser_object of (string * json_parser_val) array
+| JSON_parser_array of json_parser_val array
+| JSON_parser_bool of bool
-val yajl_tree_parse : string -> yajl_val
+val json_parser_tree_parse : string -> json_parser_val
(** Parse the JSON string. *)
-val object_get_string : string -> yajl_val -> string
+val object_get_string : string -> json_parser_val -> string
(** [object_get_string key yv] gets the value of the [key] field as a string
in the [yv] structure *)
-val object_find_object : string -> yajl_val -> yajl_val
-(** [object_get_object key yv] gets the value of the [key] field as a yajl
+val object_find_object : string -> json_parser_val -> json_parser_val
+(** [object_get_object key yv] gets the value of the [key] field as a JSON
value in the [yv] structure.
Mind the returned type is different from [object_get_object] *)
-val object_get_object : string -> yajl_val -> (string * yajl_val) array
-(** [object_get_object key yv] gets the value of the [key] field as a Yajl
+val object_get_object : string -> json_parser_val -> (string *
json_parser_val) array
+(** [object_get_object key yv] gets the value of the [key] field as a JSON
object in the [yv] structure *)
-val object_get_number : string -> yajl_val -> int64
+val object_get_number : string -> json_parser_val -> int64
(** [object_get_number key yv] gets the value of the [key] field as an
integer in the [yv] structure *)
-val objects_get_string : string -> yajl_val list -> string
+val objects_get_string : string -> json_parser_val list -> string
(** [objects_get_string key yvs] gets the value of the [key] field as a string
- in an [yvs] list of yajl_val structure.
+ in an [yvs] list of json_parser_val structure.
The key may not be found at all in the list, in which case an error
is raised *)
-val object_find_objects : ((string * yajl_val) -> 'a option) ->
yajl_val -> 'a list
-(** [object_find_objects fn obj] returns all the Yajl objects matching the [fn]
+val object_find_objects : ((string * json_parser_val) -> 'a option)
-> json_parser_val -> 'a list
+(** [object_find_objects fn obj] returns all the JSON objects matching the [fn]
function in [obj] list. *)
diff --git a/builder/yajl_tests.ml b/common/mltools/JSON_parser_tests.ml
similarity index 73%
rename from builder/yajl_tests.ml
rename to common/mltools/JSON_parser_tests.ml
index f5a44f2fa..42045122d 100644
--- a/builder/yajl_tests.ml
+++ b/common/mltools/JSON_parser_tests.ml
@@ -16,10 +16,10 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*)
-(* This file tests the Yajl module. *)
+(* This file tests the JSON_parser module. *)
open OUnit2
-open Yajl
+open JSON_parser
(* Utils. *)
let assert_equal_string = assert_equal ~printer:(fun x -> x)
@@ -27,16 +27,16 @@ let assert_equal_int = assert_equal ~printer:(fun x ->
string_of_int x)
let assert_equal_int64 = assert_equal ~printer:(fun x -> Int64.to_string x)
let assert_equal_bool = assert_equal ~printer:(fun x -> string_of_bool x)
-let string_of_yajl_val_type = function
- | Yajl_null -> "null"
- | Yajl_string _ -> "string"
- | Yajl_number _ -> "number"
- | Yajl_double _ -> "float"
- | Yajl_object _ -> "object"
- | Yajl_array _ -> "array"
- | Yajl_bool _ -> "bool"
+let string_of_json_parser_val_type = function
+ | JSON_parser_null -> "null"
+ | JSON_parser_string _ -> "string"
+ | JSON_parser_number _ -> "number"
+ | JSON_parser_double _ -> "float"
+ | JSON_parser_object _ -> "object"
+ | JSON_parser_array _ -> "array"
+ | JSON_parser_bool _ -> "bool"
let type_mismatch_string exp value - Printf.sprintf "value is not %s but
%s" exp (string_of_yajl_val_type value)
+ Printf.sprintf "value is not %s but %s" exp
(string_of_json_parser_val_type value)
let assert_raises_invalid_argument str (* Replace the Invalid_argument
string with a fixed one, just to check
@@ -44,37 +44,37 @@ let assert_raises_invalid_argument str *)
let mock = "parse_error" in
let wrapped_tree_parse str - try yajl_tree_parse str
+ try json_parser_tree_parse str
with Invalid_argument _ -> raise (Invalid_argument mock) in
assert_raises (Invalid_argument mock) (fun () -> wrapped_tree_parse str)
let assert_raises_nested str let err = "too many levels of object/array
nesting" in
- assert_raises (Invalid_argument err) (fun () -> yajl_tree_parse str)
+ assert_raises (Invalid_argument err) (fun () -> json_parser_tree_parse
str)
let assert_is_object value assert_bool
(type_mismatch_string "object" value)
- (match value with | Yajl_object _ -> true | _ -> false)
+ (match value with | JSON_parser_object _ -> true | _ -> false)
let assert_is_string exp = function
- | Yajl_string s -> assert_equal_string exp s
+ | JSON_parser_string s -> assert_equal_string exp s
| _ as v -> assert_failure (type_mismatch_string "string" v)
let assert_is_number exp = function
- | Yajl_number n -> assert_equal_int64 exp n
- | Yajl_double d -> assert_equal_int64 exp (Int64.of_float d)
+ | JSON_parser_number n -> assert_equal_int64 exp n
+ | JSON_parser_double d -> assert_equal_int64 exp (Int64.of_float d)
| _ as v -> assert_failure (type_mismatch_string "number/double"
v)
let assert_is_array value assert_bool
(type_mismatch_string "array" value)
- (match value with | Yajl_array _ -> true | _ -> false)
+ (match value with | JSON_parser_array _ -> true | _ -> false)
let assert_is_bool exp = function
- | Yajl_bool b -> assert_equal_bool exp b
+ | JSON_parser_bool b -> assert_equal_bool exp b
| _ as v -> assert_failure (type_mismatch_string "bool" v)
let get_object_list = function
- | Yajl_object x -> x
+ | JSON_parser_object x -> x
| _ as v -> assert_failure (type_mismatch_string "object" v)
let get_array = function
- | Yajl_array x -> x
+ | JSON_parser_array x -> x
| _ as v -> assert_failure (type_mismatch_string "array" v)
@@ -90,29 +90,29 @@ let test_tree_parse_invalid ctx assert_raises_nested str
let test_tree_parse_basic ctx - let value = yajl_tree_parse "{}" in
+ let value = json_parser_tree_parse "{}" in
assert_is_object value;
- let value = yajl_tree_parse "\"foo\"" in
+ let value = json_parser_tree_parse "\"foo\"" in
assert_is_string "foo" value;
- let value = yajl_tree_parse "[]" in
+ let value = json_parser_tree_parse "[]" in
assert_is_array value
let test_tree_parse_inspect ctx - let value = yajl_tree_parse
"{\"foo\":5}" in
+ let value = json_parser_tree_parse "{\"foo\":5}" in
let l = get_object_list value in
assert_equal_int 1 (Array.length l);
assert_equal_string "foo" (fst (l.(0)));
assert_is_number 5_L (snd (l.(0)));
- let value = yajl_tree_parse "[\"foo\", true]" in
+ let value = json_parser_tree_parse "[\"foo\", true]" in
let a = get_array value in
assert_equal_int 2 (Array.length a);
assert_is_string "foo" (a.(0));
assert_is_bool true (a.(1));
- let value = yajl_tree_parse "{\"foo\":[false, {}, 10],
\"second\":2}" in
+ let value = json_parser_tree_parse "{\"foo\":[false, {}, 10],
\"second\":2}" in
let l = get_object_list value in
assert_equal_int 2 (Array.length l);
assert_equal_string "foo" (fst (l.(0)));
@@ -126,7 +126,7 @@ let test_tree_parse_inspect ctx
(* Suites declaration. *)
let suite - "builder Yajl" >:::
+ "mltools JSON_parser" >:::
[
"tree_parse.invalid" >:: test_tree_parse_invalid;
"tree_parse.basic" >:: test_tree_parse_basic;
diff --git a/common/mltools/Makefile.am b/common/mltools/Makefile.am
index 66b18f5de..ac5f53651 100644
--- a/common/mltools/Makefile.am
+++ b/common/mltools/Makefile.am
@@ -23,6 +23,7 @@ EXTRA_DIST = \
$(SOURCES_C) \
getopt_tests.ml \
JSON_tests.ml \
+ JSON_parser_tests.ml \
test-getopt.sh \
tools_utils_tests.ml
@@ -31,6 +32,7 @@ SOURCES_MLI = \
curl.mli \
getopt.mli \
JSON.mli \
+ JSON_parser.mli \
planner.mli \
regedit.mli \
registry.mli \
@@ -47,6 +49,7 @@ SOURCES_ML = \
registry.ml \
regedit.ml \
JSON.ml \
+ JSON_parser.ml \
curl.ml \
checksums.ml \
xpath_helpers.ml \
@@ -57,6 +60,7 @@ SOURCES_C = \
../options/keys.c \
../options/uri.c \
getopt-c.c \
+ JSON_parser-c.c \
tools_utils-c.c \
uri-c.c
@@ -94,6 +98,7 @@ libmltools_a_CPPFLAGS = \
libmltools_a_CFLAGS = \
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
$(LIBVIRT_CFLAGS) $(LIBXML2_CFLAGS) \
+ $(JANSSON_CFLAGS) \
-fPIC
BOBJECTS = $(SOURCES_ML:.ml=.cmo)
@@ -128,6 +133,7 @@ OCAMLCLIBS = \
$(LIBCRYPT_LIBS) \
$(LIBVIRT_LIBS) \
$(LIBXML2_LIBS) \
+ $(JANSSON_LIBS) \
$(LIBINTL) \
-lgnu
@@ -169,6 +175,16 @@ JSON_tests_SOURCES = dummy.c
JSON_tests_BOBJECTS = JSON_tests.cmo
JSON_tests_XOBJECTS = $(JSON_tests_BOBJECTS:.cmo=.cmx)
+JSON_parser_tests_SOURCES = dummy.c
+JSON_parser_tests_CPPFLAGS = \
+ -I . \
+ -I$(top_builddir) \
+ -I$(shell $(OCAMLC) -where) \
+ -I$(top_srcdir)/lib
+JSON_parser_tests_BOBJECTS = \
+ JSON_parser_tests.cmo
+JSON_parser_tests_XOBJECTS = $(JSON_parser_tests_BOBJECTS:.cmo=.cmx)
+
# Can't call the following as <test>_OBJECTS because automake gets
confused.
if !HAVE_OCAMLOPT
tools_utils_tests_THEOBJECTS = $(tools_utils_tests_BOBJECTS)
@@ -179,6 +195,9 @@ getopt_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
JSON_tests_THEOBJECTS = $(JSON_tests_BOBJECTS)
JSON_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
+
+JSON_parser_tests_THEOBJECTS = $(JSON_parser_tests_BOBJECTS)
+JSON_parser_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
else
tools_utils_tests_THEOBJECTS = $(tools_utils_tests_XOBJECTS)
tools_utils_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
@@ -188,6 +207,9 @@ getopt_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
JSON_tests_THEOBJECTS = $(JSON_tests_XOBJECTS)
JSON_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
+
+JSON_parser_tests_THEOBJECTS = $(JSON_parser_tests_XOBJECTS)
+JSON_parser_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
endif
OCAMLLINKFLAGS = \
@@ -237,6 +259,19 @@ JSON_tests_LINK = \
$(OCAMLPACKAGES) $(OCAMLPACKAGES_TESTS) \
$(JSON_tests_THEOBJECTS) -o $@
+JSON_parser_tests_DEPENDENCIES = \
+ $(JSON_parser_tests_THEOBJECTS) \
+ ../mlstdutils/mlstdutils.$(MLARCHIVE) \
+ ../mlgettext/mlgettext.$(MLARCHIVE) \
+ ../mlpcre/mlpcre.$(MLARCHIVE) \
+ $(MLTOOLS_CMA) \
+ $(top_srcdir)/ocaml-link.sh
+JSON_parser_tests_LINK = \
+ $(top_srcdir)/ocaml-link.sh -cclib '$(OCAMLCLIBS)' -- \
+ $(OCAMLFIND) $(BEST) $(OCAMLFLAGS) $(OCAMLLINKFLAGS) \
+ $(OCAMLPACKAGES) $(OCAMLPACKAGES_TESTS) \
+ $(JSON_parser_tests_THEOBJECTS) -o $@
+
TESTS_ENVIRONMENT = $(top_builddir)/run --test
TESTS = \
@@ -245,8 +280,8 @@ check_PROGRAMS = \
getopt_tests
if HAVE_OCAML_PKG_OUNIT
-check_PROGRAMS += JSON_tests tools_utils_tests
-TESTS += JSON_tests tools_utils_tests
+check_PROGRAMS += JSON_tests JSON_parser_tests tools_utils_tests
+TESTS += JSON_tests JSON_parser_tests tools_utils_tests
endif
check-valgrind:
diff --git a/docs/C_SOURCE_FILES b/docs/C_SOURCE_FILES
index f0d1f6c9d..b1db59cf5 100644
--- a/docs/C_SOURCE_FILES
+++ b/docs/C_SOURCE_FILES
@@ -5,7 +5,6 @@ builder/index-struct.h
builder/index-validate.c
builder/pxzcat-c.c
builder/setlocale-c.c
-builder/yajl-c.c
cat/cat.c
cat/filesystems.c
cat/log.c
@@ -21,6 +20,7 @@ common/mlpcre/dummy.c
common/mlpcre/pcre-c.c
common/mlprogress/progress-c.c
common/mlstdutils/dummy.c
+common/mltools/JSON_parser-c.c
common/mltools/dummy.c
common/mltools/getopt-c.c
common/mltools/tools_utils-c.c
@@ -62,6 +62,8 @@ common/utils/cleanups.h
common/utils/gnulib-cleanups.c
common/utils/guestfs-utils.h
common/utils/libxml2-cleanups.c
+common/utils/libxml2-utils.c
+common/utils/libxml2-utils.h
common/utils/utils.c
common/visit/visit.c
common/visit/visit.h
diff --git a/po/POTFILES b/po/POTFILES
index 55d7e6894..4e53b694f 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -6,7 +6,6 @@ builder/index-struct.c
builder/index-validate.c
builder/pxzcat-c.c
builder/setlocale-c.c
-builder/yajl-c.c
cat/cat.c
cat/filesystems.c
cat/log.c
@@ -22,6 +21,7 @@ common/mlpcre/dummy.c
common/mlpcre/pcre-c.c
common/mlprogress/progress-c.c
common/mlstdutils/dummy.c
+common/mltools/JSON_parser-c.c
common/mltools/dummy.c
common/mltools/getopt-c.c
common/mltools/tools_utils-c.c
@@ -51,6 +51,7 @@ common/structs/structs-print.c
common/utils/cleanups.c
common/utils/gnulib-cleanups.c
common/utils/libxml2-cleanups.c
+common/utils/libxml2-utils.c
common/utils/utils.c
common/visit/visit.c
common/windows/windows.c
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index b18ff7410..de07e37d4 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -18,8 +18,6 @@ builder/sigchecker.ml
builder/simplestreams_parser.ml
builder/sources.ml
builder/utils.ml
-builder/yajl.ml
-builder/yajl_tests.ml
common/mlaugeas/augeas.ml
common/mlgettext/common_gettext.ml
common/mlpcre/PCRE.ml
@@ -31,6 +29,8 @@ common/mlstdutils/std_utils_tests.ml
common/mlstdutils/stringMap.ml
common/mlstdutils/stringSet.ml
common/mltools/JSON.ml
+common/mltools/JSON_parser.ml
+common/mltools/JSON_parser_tests.ml
common/mltools/JSON_tests.ml
common/mltools/URI.ml
common/mltools/checksums.ml
--
2.18.0
Richard W.M. Jones
2018-Aug-20 16:02 UTC
[Libguestfs] [PATCH 2/4] mltools: JSON: Implement JSON.Float.
This is not actually used anywhere, but it completes the JSON
implementation and it will be useful for unifying JSON with
JSON_parser.
---
common/mltools/JSON.ml | 6 ++++++
common/mltools/JSON.mli | 1 +
common/mltools/JSON_tests.ml | 20 ++++++++++++++++++++
3 files changed, 27 insertions(+)
diff --git a/common/mltools/JSON.ml b/common/mltools/JSON.ml
index 1a88f8b1f..a51037ab4 100644
--- a/common/mltools/JSON.ml
+++ b/common/mltools/JSON.ml
@@ -23,6 +23,7 @@ and json_t | String of string
| Int of int
| Int64 of int64
+ | Float of float
| Bool of bool
| List of json_t list
| Dict of field list
@@ -110,6 +111,11 @@ and output_field ~indent ~fmt = function
| Int i -> string_of_int i
| Bool b -> if b then "true" else "false"
| Int64 i -> Int64.to_string i
+ (* The JSON standard permits either "1" or "1.0" but not
"1.".
+ * OCaml string_of_float will generate "1.", but the %g formatter
+ * will only generate the valid JSON values.
+ *)
+ | Float f -> Printf.sprintf "%g" f
| List l -> output_list ~indent:(indent + 1) ~fmt l
| Dict d -> output_dict ~indent:(indent + 1) ~fmt d
diff --git a/common/mltools/JSON.mli b/common/mltools/JSON.mli
index 5b487af8e..06a777c20 100644
--- a/common/mltools/JSON.mli
+++ b/common/mltools/JSON.mli
@@ -23,6 +23,7 @@ and json_t = (** JSON value. *)
| String of string (** string value, eg. ["string"] *)
| Int of int (** int value, eg. [99] *)
| Int64 of int64 (** int64 value, eg. [99] *)
+ | Float of float (** floating point value, eg. [9.9] *)
| Bool of bool (** boolean value, [true] or [false] *)
| List of json_t list (** array value, eg. [[1,2,3]] *)
| Dict of field list (** object, eg. [{ "a": 1,
"b": "c" }] *)
diff --git a/common/mltools/JSON_tests.ml b/common/mltools/JSON_tests.ml
index 55a474474..2f3998e6e 100644
--- a/common/mltools/JSON_tests.ml
+++ b/common/mltools/JSON_tests.ml
@@ -71,6 +71,25 @@ let test_int ctx }"
(JSON.string_of_doc ~fmt:JSON.Indented doc)
+let test_float ctx + let doc = [ "test_zero", JSON.Float 0.;
+ "test_one", JSON.Float 1.;
+ "test_frac", JSON.Float 1.5;
+ "test_neg_frac", JSON.Float (-1.5);
+ "test_exp", JSON.Float 1e100 ] in
+ assert_equal_string
+ "{ \"test_zero\": 0, \"test_one\": 1,
\"test_frac\": 1.5, \"test_neg_frac\": -1.5,
\"test_exp\": 1e+100 }"
+ (JSON.string_of_doc doc);
+ assert_equal_string
+ "{
+ \"test_zero\": 0,
+ \"test_one\": 1,
+ \"test_frac\": 1.5,
+ \"test_neg_frac\": -1.5,
+ \"test_exp\": 1e+100
+}"
+ (JSON.string_of_doc ~fmt:JSON.Indented doc)
+
let test_list ctx let doc = [ "item", JSON.List [ JSON.String
"foo"; JSON.Int 10; JSON.Bool true ] ] in
assert_equal_string
@@ -227,6 +246,7 @@ let suite "basic.string" >::
test_string;
"basic.bool" >:: test_bool;
"basic.int" >:: test_int;
+ "basic.float" >:: test_float;
"basic.list" >:: test_list;
"basic.nested_dict" >:: test_nested_dict;
"basic.nested_nested dict" >:: test_nested_nested_dict;
--
2.18.0
Richard W.M. Jones
2018-Aug-20 16:02 UTC
[Libguestfs] [PATCH 3/4] mltools: JSON: combine JSON.Int and JSON.Int64 into a single variant.
It was convenient to have these as separate variants when we were only
using this type to generate JSON. However if we also use it to parse
JSON documents then integers in the document should only map to a
single variant.
---
builder/list_entries.ml | 4 ++--
common/mltools/JSON.ml | 8 +++-----
common/mltools/JSON.mli | 3 +--
common/mltools/JSON_tests.ml | 40 +++++++++++++++++++-----------------
v2v/input_libvirt_xen_ssh.ml | 2 +-
v2v/input_ova.ml | 4 ++--
v2v/input_vmx.ml | 2 +-
v2v/output_rhv_upload.ml | 2 +-
v2v/parse_libvirt_xml.ml | 4 ++--
v2v/utils.ml | 4 ++--
v2v/vCenter.ml | 4 ++--
11 files changed, 38 insertions(+), 39 deletions(-)
diff --git a/builder/list_entries.ml b/builder/list_entries.ml
index c64d554a2..f1f67290c 100644
--- a/builder/list_entries.ml
+++ b/builder/list_entries.ml
@@ -117,7 +117,7 @@ and list_entries_json ~sources index | None ->
item
| Some str -> ("full-name", JSON.String str) :: item in
let item = ("arch", JSON.String (Index.string_of_arch arch))
:: item in
- let item = ("size", JSON.Int64 size) :: item in
+ let item = ("size", JSON.Int size) :: item in
let item match compressed_size with
| None -> item
@@ -148,7 +148,7 @@ and list_entries_json ~sources index JSON.Dict
(List.rev item)
) index in
let doc = [
- "version", JSON.Int 1;
+ "version", JSON.Int 1L;
"sources", JSON.List json_sources;
"templates", JSON.List json_templates;
] in
diff --git a/common/mltools/JSON.ml b/common/mltools/JSON.ml
index a51037ab4..8c2e695e2 100644
--- a/common/mltools/JSON.ml
+++ b/common/mltools/JSON.ml
@@ -21,8 +21,7 @@
type field = string * json_t
and json_t | String of string
- | Int of int
- | Int64 of int64
+ | Int of int64
| Float of float
| Bool of bool
| List of json_t list
@@ -108,14 +107,13 @@ and output_list fields ~fmt ~indent
and output_field ~indent ~fmt = function
| String s -> json_quote_string s
- | Int i -> string_of_int i
- | Bool b -> if b then "true" else "false"
- | Int64 i -> Int64.to_string i
+ | Int i -> Int64.to_string i
(* The JSON standard permits either "1" or "1.0" but not
"1.".
* OCaml string_of_float will generate "1.", but the %g formatter
* will only generate the valid JSON values.
*)
| Float f -> Printf.sprintf "%g" f
+ | Bool b -> if b then "true" else "false"
| List l -> output_list ~indent:(indent + 1) ~fmt l
| Dict d -> output_dict ~indent:(indent + 1) ~fmt d
diff --git a/common/mltools/JSON.mli b/common/mltools/JSON.mli
index 06a777c20..c85b786ff 100644
--- a/common/mltools/JSON.mli
+++ b/common/mltools/JSON.mli
@@ -21,8 +21,7 @@
type field = string * json_t (** ["field": "value"] *)
and json_t = (** JSON value. *)
| String of string (** string value, eg. ["string"] *)
- | Int of int (** int value, eg. [99] *)
- | Int64 of int64 (** int64 value, eg. [99] *)
+ | Int of int64 (** int value, eg. [99] *)
| Float of float (** floating point value, eg. [9.9] *)
| Bool of bool (** boolean value, [true] or [false] *)
| List of json_t list (** array value, eg. [[1,2,3]] *)
diff --git a/common/mltools/JSON_tests.ml b/common/mltools/JSON_tests.ml
index 2f3998e6e..6bd98af26 100644
--- a/common/mltools/JSON_tests.ml
+++ b/common/mltools/JSON_tests.ml
@@ -18,6 +18,8 @@
(* This file tests the JSON module. *)
+open Std_utils
+
open OUnit2
(* Utils. *)
@@ -53,21 +55,21 @@ let test_bool ctx (JSON.string_of_doc
~fmt:JSON.Indented doc)
let test_int ctx - let doc = [ "test_zero", JSON.Int 0;
- "test_pos", JSON.Int 5;
- "test_neg", JSON.Int (-5);
- "test_pos64", JSON.Int64 (Int64.of_int 10);
- "test_neg64", JSON.Int64 (Int64.of_int (-10)); ] in
+ let doc = [ "test_zero", JSON.Int 0L;
+ "test_pos", JSON.Int 5L;
+ "test_neg", JSON.Int (-5L);
+ "test_pos64", JSON.Int 1_000_000_000_000L;
+ "test_neg64", JSON.Int (-1_000_000_000_000L); ] in
assert_equal_string
- "{ \"test_zero\": 0, \"test_pos\": 5,
\"test_neg\": -5, \"test_pos64\": 10,
\"test_neg64\": -10 }"
+ "{ \"test_zero\": 0, \"test_pos\": 5,
\"test_neg\": -5, \"test_pos64\": 1000000000000,
\"test_neg64\": -1000000000000 }"
(JSON.string_of_doc doc);
assert_equal_string
"{
\"test_zero\": 0,
\"test_pos\": 5,
\"test_neg\": -5,
- \"test_pos64\": 10,
- \"test_neg64\": -10
+ \"test_pos64\": 1000000000000,
+ \"test_neg64\": -1000000000000
}"
(JSON.string_of_doc ~fmt:JSON.Indented doc)
@@ -91,7 +93,7 @@ let test_float ctx (JSON.string_of_doc ~fmt:JSON.Indented
doc)
let test_list ctx - let doc = [ "item", JSON.List [ JSON.String
"foo"; JSON.Int 10; JSON.Bool true ] ] in
+ let doc = [ "item", JSON.List [ JSON.String "foo";
JSON.Int 10L; JSON.Bool true ] ] in
assert_equal_string
"{ \"item\": [ \"foo\", 10, true ] }"
(JSON.string_of_doc doc);
@@ -107,8 +109,8 @@ let test_list ctx
let test_nested_dict ctx let doc = [
- "item", JSON.Dict [ "int", JSON.Int 5;
"string", JSON.String "foo"; ];
- "last", JSON.Int 10;
+ "item", JSON.Dict [ "int", JSON.Int 5L;
"string", JSON.String "foo"; ];
+ "last", JSON.Int 10L;
] in
assert_equal_string
"{ \"item\": { \"int\": 5, \"string\":
\"foo\" }, \"last\": 10 }"
@@ -125,10 +127,10 @@ let test_nested_dict ctx
let test_nested_nested_dict ctx let doc = [
- "item", JSON.Dict [ "int", JSON.Int 5;
- "item2", JSON.Dict [ "int", JSON.Int 0; ];
+ "item", JSON.Dict [ "int", JSON.Int 5L;
+ "item2", JSON.Dict [ "int", JSON.Int 0L; ];
];
- "last", JSON.Int 10;
+ "last", JSON.Int 10L;
] in
assert_equal_string
"{ \"item\": { \"int\": 5, \"item2\": {
\"int\": 0 } }, \"last\": 10 }"
@@ -159,8 +161,8 @@ let test_qemu ctx let doc = [
"file.driver", JSON.String "https";
"file.url", JSON.String "https://libguestfs.org";
- "file.timeout", JSON.Int 60;
- "file.readahead", JSON.Int (64 * 1024 * 1024);
+ "file.timeout", JSON.Int 60L;
+ "file.readahead", JSON.Int (64L *^ 1024L *^ 1024L);
] in
assert_equal_string
"{ \"file.driver\": \"https\",
\"file.url\": \"https://libguestfs.org\",
\"file.timeout\": 60, \"file.readahead\": 67108864 }"
@@ -176,7 +178,7 @@ let test_qemu ctx
let test_builder ctx let doc = [
- "version", JSON.Int 1;
+ "version", JSON.Int 1L;
"sources", JSON.List [
JSON.Dict [
"uri", JSON.String "http://libguestfs.org/index";
@@ -187,7 +189,7 @@ let test_builder ctx "os-version",
JSON.String "phony-debian";
"full-name", JSON.String "Phony Debian";
"arch", JSON.String "x86_64";
- "size", JSON.Int64 536870912_L;
+ "size", JSON.Int 536870912_L;
"notes", JSON.Dict [
"C", JSON.String "Phony Debian look-alike used for
testing.";
];
@@ -197,7 +199,7 @@ let test_builder ctx "os-version",
JSON.String "phony-fedora";
"full-name", JSON.String "Phony Fedora";
"arch", JSON.String "x86_64";
- "size", JSON.Int64 1073741824_L;
+ "size", JSON.Int 1073741824_L;
"notes", JSON.Dict [
"C", JSON.String "Phony Fedora look-alike used for
testing.";
];
diff --git a/v2v/input_libvirt_xen_ssh.ml b/v2v/input_libvirt_xen_ssh.ml
index 597957f92..c4b671490 100644
--- a/v2v/input_libvirt_xen_ssh.ml
+++ b/v2v/input_libvirt_xen_ssh.ml
@@ -83,7 +83,7 @@ object
(* qemu will actually assert-fail if you send the port
* number as a string ...
*)
- | i -> ("file.port", JSON.Int i) :: json_params in
+ | i -> ("file.port", JSON.Int (Int64.of_int i)) ::
json_params in
let json_params match parsed_uri.uri_user with
diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml
index bfd72dee4..d5c9f1203 100644
--- a/v2v/input_ova.ml
+++ b/v2v/input_ova.ml
@@ -161,8 +161,8 @@ class input_ova ova = object
let doc = [
"file", JSON.Dict [
"driver", JSON.String "raw";
- "offset", JSON.Int64 offset;
- "size", JSON.Int64 size;
+ "offset", JSON.Int offset;
+ "size", JSON.Int size;
"file", JSON.Dict [
"driver", JSON.String
"file";
"filename", JSON.String
tar_path]
diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml
index 12fb975d6..30649b33b 100644
--- a/v2v/input_vmx.ml
+++ b/v2v/input_vmx.ml
@@ -245,7 +245,7 @@ and qemu_uri_of_filename vmx_source filename match
port_of_uri uri with
| None -> json_params
| Some port ->
- ("file.port", JSON.Int port) :: json_params in
+ ("file.port", JSON.Int (Int64.of_int port)) :: json_params
in
"json:" ^ JSON.string_of_doc json_params, format
diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml
index 966323cae..f03e1ede3 100644
--- a/v2v/output_rhv_upload.ml
+++ b/v2v/output_rhv_upload.ml
@@ -276,7 +276,7 @@ object
let disk_size = ov.ov_virtual_size in
let json_params - ("disk_size", JSON.Int64
disk_size) :: json_params in
+ ("disk_size", JSON.Int disk_size) :: json_params in
(* Ask the plugin to write the disk ID to a special file. *)
let diskid_file = diskid_file_of_id id in
diff --git a/v2v/parse_libvirt_xml.ml b/v2v/parse_libvirt_xml.ml
index dac99511c..255c935a6 100644
--- a/v2v/parse_libvirt_xml.ml
+++ b/v2v/parse_libvirt_xml.ml
@@ -63,8 +63,8 @@ let create_curl_qemu_uri driver host port path let
json_params = [
"file.driver", JSON.String driver; (* "http" or
"https" *)
"file.url", JSON.String url;
- "file.timeout", JSON.Int 2000;
- "file.readahead", JSON.Int (1024 * 1024);
+ "file.timeout", JSON.Int 2000_L;
+ "file.readahead", JSON.Int (1024_L *^ 1024_L);
(* "file.sslverify", JSON.String "off"; XXX *)
] in
diff --git a/v2v/utils.ml b/v2v/utils.ml
index 67e2028f3..63ef91c51 100644
--- a/v2v/utils.ml
+++ b/v2v/utils.ml
@@ -114,8 +114,8 @@ let qemu_img_supports_offset_and_size () let json = [
"file", JSON.Dict [
"driver", JSON.String "raw";
- "offset", JSON.Int 512;
- "size", JSON.Int 512;
+ "offset", JSON.Int 512_L;
+ "size", JSON.Int 512_L;
"file", JSON.Dict [
"filename", JSON.String tmp
]
diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml
index e97d25ce1..cf124f067 100644
--- a/v2v/vCenter.ml
+++ b/v2v/vCenter.ml
@@ -78,14 +78,14 @@ let rec map_source ?readahead ?password_file dcPath uri
server path "file.driver", JSON.String "https";
"file.url", JSON.String https_url;
(* https://bugzilla.redhat.com/show_bug.cgi?id=1146007#c10 *)
- "file.timeout", JSON.Int 2000;
+ "file.timeout", JSON.Int 2000_L;
] in
let json_params match readahead with
| None -> json_params
| Some readahead ->
- ("file.readahead", JSON.Int readahead) :: json_params in
+ ("file.readahead", JSON.Int (Int64.of_int readahead)) ::
json_params in
let json_params if sslverify then json_params
--
2.18.0
Richard W.M. Jones
2018-Aug-20 16:02 UTC
[Libguestfs] [PATCH 4/4] mltools: JSON: unify JSON_parser type with JSON.json_t.
---
builder/simplestreams_parser.ml | 9 +-
.../test-virt-builder-list-simplestreams.sh | 64 ++++++-------
builder/utils.mli | 2 +-
common/mltools/JSON_parser-c.c | 96 ++++++++++++-------
common/mltools/JSON_parser.ml | 29 ++----
common/mltools/JSON_parser.mli | 25 ++---
common/mltools/JSON_parser_tests.ml | 77 +++++++--------
7 files changed, 156 insertions(+), 146 deletions(-)
diff --git a/builder/simplestreams_parser.ml b/builder/simplestreams_parser.ml
index fa5b887ac..ccbfdff67 100644
--- a/builder/simplestreams_parser.ml
+++ b/builder/simplestreams_parser.ml
@@ -59,7 +59,7 @@ let get_index ~downloader ~sigchecker { Sources.uri; proxy }
error (f_"%s is not a Simple Streams (index) v1.0 JSON file (format:
%s)")
uri format;
- let index = Array.to_list (object_get_object "index" tree) in
+ let index = object_get_object "index" tree in
List.filter_map (
fun (_, desc) ->
let format = object_get_string "format" desc in
@@ -78,13 +78,12 @@ let get_index ~downloader ~sigchecker { Sources.uri; proxy }
error (f_"%s is not a Simple Streams (products) v1.0 JSON file (format:
%s)")
uri format;
- let products_node = object_get_object "products" tree in
+ let products = object_get_object "products" tree in
- let products = Array.to_list products_node in
List.filter_map (
fun (prod, prod_desc) ->
let arch = Index.Arch (object_get_string "arch" prod_desc) in
- let prods = Array.to_list (object_get_object "versions"
prod_desc) in
+ let prods = object_get_object "versions" prod_desc in
let prods = List.filter_map (
fun (rel, rel_desc) ->
let pubname = objects_get_string "pubname" [rel_desc;
prod_desc] in
@@ -106,7 +105,7 @@ let get_index ~downloader ~sigchecker { Sources.uri; proxy }
* the ones related to checksums, explicitly filter
* the supported checksums.
*)
- | ("sha256"|"sha512" as t,
JSON_parser_string c) ->
+ | ("sha256"|"sha512" as t, JSON.String c)
->
Some (Checksums.of_string t c)
| _ -> None
) disk_item in
diff --git a/builder/test-virt-builder-list-simplestreams.sh
b/builder/test-virt-builder-list-simplestreams.sh
index 29fbfacce..3158066b1 100755
--- a/builder/test-virt-builder-list-simplestreams.sh
+++ b/builder/test-virt-builder-list-simplestreams.sh
@@ -26,9 +26,9 @@ export
XDG_CONFIG_DIRS="$abs_builddir/test-simplestreams"
short_list=$($VG virt-builder --no-check-signature --no-cache --list)
-if [ "$short_list" != "net.cirros-cloud:standard:0.3:i386 i386
cirros-0.3.4-i386
+if [ "$short_list" != "net.cirros-cloud:standard:0.3:powerpc
powerpc cirros-0.3.4-powerpc
net.cirros-cloud:standard:0.3:x86_64 x86_64 cirros-0.3.4-x86_64
-net.cirros-cloud:standard:0.3:powerpc powerpc cirros-0.3.4-powerpc" ];
then
+net.cirros-cloud:standard:0.3:i386 i386 cirros-0.3.4-i386" ]; then
echo "$0: unexpected --list output:"
echo "$short_list"
exit 1
@@ -38,11 +38,11 @@ long_list=$(virt-builder --no-check-signature --no-cache
--list --long)
if [ "$long_list" != "Source URI:
file://$abs_builddir/test-simplestreams
-os-version: net.cirros-cloud:standard:0.3:i386
-Full name: cirros-0.3.4-i386
-Architecture: i386
-Minimum/default size: 11.9M
-Aliases: cirros-0.3.4-i386
+os-version: net.cirros-cloud:standard:0.3:powerpc
+Full name: cirros-0.3.4-powerpc
+Architecture: powerpc
+Minimum/default size: 16.4M
+Aliases: cirros-0.3.4-powerpc
os-version: net.cirros-cloud:standard:0.3:x86_64
Full name: cirros-0.3.4-x86_64
@@ -50,11 +50,11 @@ Architecture: x86_64
Minimum/default size: 12.7M
Aliases: cirros-0.3.4-x86_64
-os-version: net.cirros-cloud:standard:0.3:powerpc
-Full name: cirros-0.3.4-powerpc
-Architecture: powerpc
-Minimum/default size: 16.4M
-Aliases: cirros-0.3.4-powerpc" ]; then
+os-version: net.cirros-cloud:standard:0.3:i386
+Full name: cirros-0.3.4-i386
+Architecture: i386
+Minimum/default size: 11.9M
+Aliases: cirros-0.3.4-i386" ]; then
echo "$0: unexpected --list --long output:"
echo "$long_list"
exit 1
@@ -70,26 +70,6 @@ if [ "$json_list" != "{
}
],
\"templates\": [
- {
- \"os-version\":
\"net.cirros-cloud:standard:0.3:i386\",
- \"full-name\": \"cirros-0.3.4-i386\",
- \"arch\": \"i386\",
- \"size\": 12506112,
- \"aliases\": [
- \"cirros-0.3.4-i386\"
- ],
- \"hidden\": false
- },
- {
- \"os-version\":
\"net.cirros-cloud:standard:0.3:x86_64\",
- \"full-name\": \"cirros-0.3.4-x86_64\",
- \"arch\": \"x86_64\",
- \"size\": 13287936,
- \"aliases\": [
- \"cirros-0.3.4-x86_64\"
- ],
- \"hidden\": false
- },
{
\"os-version\":
\"net.cirros-cloud:standard:0.3:powerpc\",
\"full-name\": \"cirros-0.3.4-powerpc\",
@@ -99,6 +79,26 @@ if [ "$json_list" != "{
\"cirros-0.3.4-powerpc\"
],
\"hidden\": false
+ },
+ {
+ \"os-version\":
\"net.cirros-cloud:standard:0.3:x86_64\",
+ \"full-name\": \"cirros-0.3.4-x86_64\",
+ \"arch\": \"x86_64\",
+ \"size\": 13287936,
+ \"aliases\": [
+ \"cirros-0.3.4-x86_64\"
+ ],
+ \"hidden\": false
+ },
+ {
+ \"os-version\":
\"net.cirros-cloud:standard:0.3:i386\",
+ \"full-name\": \"cirros-0.3.4-i386\",
+ \"arch\": \"i386\",
+ \"size\": 12506112,
+ \"aliases\": [
+ \"cirros-0.3.4-i386\"
+ ],
+ \"hidden\": false
}
]
}" ]; then
diff --git a/builder/utils.mli b/builder/utils.mli
index 5dde43a01..c7631636c 100644
--- a/builder/utils.mli
+++ b/builder/utils.mli
@@ -29,7 +29,7 @@ and revision val string_of_revision : revision -> string
(** Convert a {!revision} into a string. *)
-val get_image_infos : string -> JSON_parser.json_parser_val
+val get_image_infos : string -> JSON.json_t
(** [get_image_infos path] Run qemu-img info on the image pointed at
path as JSON tree. *)
diff --git a/common/mltools/JSON_parser-c.c b/common/mltools/JSON_parser-c.c
index 32432dc5b..dce9f6a15 100644
--- a/common/mltools/JSON_parser-c.c
+++ b/common/mltools/JSON_parser-c.c
@@ -28,7 +28,12 @@
#include <stdio.h>
#include <string.h>
-#define Val_none (Val_int (0))
+#define JSON_STRING_TAG 0
+#define JSON_INT_TAG 1
+#define JSON_FLOAT_TAG 2
+#define JSON_BOOL_TAG 3
+#define JSON_LIST_TAG 4
+#define JSON_DICT_TAG 5
value virt_builder_json_parser_tree_parse (value stringv);
@@ -36,60 +41,87 @@ static value
convert_json_t (json_t *val, int level)
{
CAMLparam0 ();
- CAMLlocal4 (rv, lv, v, sv);
+ CAMLlocal5 (rv, v, tv, sv, consv);
if (level > 20)
caml_invalid_argument ("too many levels of object/array
nesting");
if (json_is_object (val)) {
- const size_t len = json_object_size (val);
- size_t i;
const char *key;
json_t *jvalue;
- rv = caml_alloc (1, 3);
- lv = caml_alloc_tuple (len);
- i = 0;
+
+ rv = caml_alloc (1, JSON_DICT_TAG);
+ v = Val_int (0);
+ /* This will create the OCaml list backwards, but JSON
+ * dictionaries are supposed to be unordered so that shouldn't
+ * matter, right? Well except that for some consumers this does
+ * matter (eg. simplestreams which incorrectly uses a dict when it
+ * really should use an array).
+ */
json_object_foreach (val, key, jvalue) {
- v = caml_alloc_tuple (2);
+ tv = caml_alloc_tuple (2);
sv = caml_copy_string (key);
- Store_field (v, 0, sv);
+ Store_field (tv, 0, sv);
sv = convert_json_t (jvalue, level + 1);
- Store_field (v, 1, sv);
- Store_field (lv, i, v);
- ++i;
+ Store_field (tv, 1, sv);
+ consv = caml_alloc (2, 0);
+ Store_field (consv, 1, v);
+ Store_field (consv, 0, tv);
+ v = consv;
}
- Store_field (rv, 0, lv);
- } else if (json_is_array (val)) {
+ Store_field (rv, 0, v);
+ }
+ else if (json_is_array (val)) {
const size_t len = json_array_size (val);
size_t i;
json_t *jvalue;
- rv = caml_alloc (1, 4);
- lv = caml_alloc_tuple (len);
- json_array_foreach (val, i, jvalue) {
- v = convert_json_t (jvalue, level + 1);
- Store_field (lv, i, v);
+
+ rv = caml_alloc (1, JSON_LIST_TAG);
+ v = Val_int (0);
+ for (i = 0; i < len; ++i) {
+ /* Note we have to create the OCaml list backwards. */
+ jvalue = json_array_get (val, len-i-1);
+ tv = convert_json_t (jvalue, level + 1);
+ consv = caml_alloc (2, 0);
+ Store_field (consv, 1, v);
+ Store_field (consv, 0, tv);
+ v = consv;
}
- Store_field (rv, 0, lv);
- } else if (json_is_string (val)) {
- rv = caml_alloc (1, 0);
+ Store_field (rv, 0, v);
+ }
+ else if (json_is_string (val)) {
+ rv = caml_alloc (1, JSON_STRING_TAG);
v = caml_copy_string (json_string_value (val));
Store_field (rv, 0, v);
- } else if (json_is_real (val)) {
- rv = caml_alloc (1, 2);
+ }
+ else if (json_is_real (val)) {
+ rv = caml_alloc (1, JSON_FLOAT_TAG);
v = caml_copy_double (json_real_value (val));
Store_field (rv, 0, v);
- } else if (json_is_integer (val)) {
- rv = caml_alloc (1, 1);
+ }
+ else if (json_is_integer (val)) {
+ rv = caml_alloc (1, JSON_INT_TAG);
v = caml_copy_int64 (json_integer_value (val));
Store_field (rv, 0, v);
- } else if (json_is_true (val)) {
- rv = caml_alloc (1, 5);
+ }
+ else if (json_is_true (val)) {
+ rv = caml_alloc (1, JSON_BOOL_TAG);
Store_field (rv, 0, Val_true);
- } else if (json_is_false (val)) {
- rv = caml_alloc (1, 5);
+ }
+ else if (json_is_false (val)) {
+ rv = caml_alloc (1, JSON_BOOL_TAG);
Store_field (rv, 0, Val_false);
- } else
- rv = Val_none;
+ }
+ else {
+ /* Previously we had a special JSON_parser_null value we could
+ * use here, making the returned type (sort of) an option.
+ * This is a best effort which is better than crashing /
+ * throwing an error.
+ */
+ rv = caml_alloc (1, JSON_STRING_TAG);
+ v = caml_copy_string ("");
+ Store_field (rv, 0, v);
+ }
CAMLreturn (rv);
}
diff --git a/common/mltools/JSON_parser.ml b/common/mltools/JSON_parser.ml
index a82127454..642e24d65 100644
--- a/common/mltools/JSON_parser.ml
+++ b/common/mltools/JSON_parser.ml
@@ -20,20 +20,11 @@ open Std_utils
open Tools_utils
open Common_gettext.Gettext
-type json_parser_val -| JSON_parser_null
-| JSON_parser_string of string
-| JSON_parser_number of int64
-| JSON_parser_double of float
-| JSON_parser_object of (string * json_parser_val) array
-| JSON_parser_array of json_parser_val array
-| JSON_parser_bool of bool
-
-external json_parser_tree_parse : string -> json_parser_val =
"virt_builder_json_parser_tree_parse"
+external json_parser_tree_parse : string -> JSON.json_t =
"virt_builder_json_parser_tree_parse"
let object_find_optional key = function
- | JSON_parser_object o ->
- (match List.filter (fun (k, _) -> k = key) (Array.to_list o) with
+ | JSON.Dict fields ->
+ (match List.filter (fun (k, _) -> k = key) fields with
| [(k, v)] -> Some v
| [] -> None
| _ -> error (f_"more than value for the key ‘%s’") key)
@@ -46,27 +37,27 @@ let object_find key yv
let object_get_string key yv match object_find key yv with
- | JSON_parser_string s -> s
+ | JSON.String s -> s
| _ -> error (f_"the value for the key ‘%s’ is not a string")
key
let object_find_object key yv match object_find key yv with
- | JSON_parser_object _ as o -> o
+ | JSON.Dict _ as o -> o
| _ -> error (f_"the value for the key ‘%s’ is not an object")
key
let object_find_objects fn = function
- | JSON_parser_object o -> List.filter_map fn (Array.to_list o)
+ | JSON.Dict fields -> List.filter_map fn fields
| _ -> error (f_"the value is not an object")
let object_get_object key yv match object_find_object key yv with
- | JSON_parser_object o -> o
+ | JSON.Dict fields -> fields
| _ -> assert false (* object_find_object already errors out. *)
let object_get_number key yv match object_find key yv with
- | JSON_parser_number n -> n
- | JSON_parser_double d -> Int64.of_float d
+ | JSON.Int n -> n
+ | JSON.Float f -> Int64.of_float f
| _ -> error (f_"the value for the key ‘%s’ is not an integer")
key
let objects_get_string key yvs @@ -74,7 +65,7 @@ let objects_get_string key yvs
| [] -> None
| x :: xs ->
(match object_find_optional key x with
- | Some (JSON_parser_string s) -> Some s
+ | Some (JSON.String s) -> Some s
| Some _ -> error (f_"the value for key ‘%s’ is not a string as
expected") key
| None -> loop xs
)
diff --git a/common/mltools/JSON_parser.mli b/common/mltools/JSON_parser.mli
index f505953f2..5ad0ef017 100644
--- a/common/mltools/JSON_parser.mli
+++ b/common/mltools/JSON_parser.mli
@@ -16,43 +16,34 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*)
-type json_parser_val -| JSON_parser_null
-| JSON_parser_string of string
-| JSON_parser_number of int64
-| JSON_parser_double of float
-| JSON_parser_object of (string * json_parser_val) array
-| JSON_parser_array of json_parser_val array
-| JSON_parser_bool of bool
-
-val json_parser_tree_parse : string -> json_parser_val
+val json_parser_tree_parse : string -> JSON.json_t
(** Parse the JSON string. *)
-val object_get_string : string -> json_parser_val -> string
+val object_get_string : string -> JSON.json_t -> string
(** [object_get_string key yv] gets the value of the [key] field as a string
in the [yv] structure *)
-val object_find_object : string -> json_parser_val -> json_parser_val
+val object_find_object : string -> JSON.json_t -> JSON.json_t
(** [object_get_object key yv] gets the value of the [key] field as a JSON
value in the [yv] structure.
Mind the returned type is different from [object_get_object] *)
-val object_get_object : string -> json_parser_val -> (string *
json_parser_val) array
+val object_get_object : string -> JSON.json_t -> (string * JSON.json_t)
list
(** [object_get_object key yv] gets the value of the [key] field as a JSON
object in the [yv] structure *)
-val object_get_number : string -> json_parser_val -> int64
+val object_get_number : string -> JSON.json_t -> int64
(** [object_get_number key yv] gets the value of the [key] field as an
integer in the [yv] structure *)
-val objects_get_string : string -> json_parser_val list -> string
+val objects_get_string : string -> JSON.json_t list -> string
(** [objects_get_string key yvs] gets the value of the [key] field as a string
- in an [yvs] list of json_parser_val structure.
+ in an [yvs] list of JSON.json_t structure.
The key may not be found at all in the list, in which case an error
is raised *)
-val object_find_objects : ((string * json_parser_val) -> 'a option)
-> json_parser_val -> 'a list
+val object_find_objects : ((string * JSON.json_t) -> 'a option) ->
JSON.json_t -> 'a list
(** [object_find_objects fn obj] returns all the JSON objects matching the [fn]
function in [obj] list. *)
diff --git a/common/mltools/JSON_parser_tests.ml
b/common/mltools/JSON_parser_tests.ml
index 42045122d..e7e3112b5 100644
--- a/common/mltools/JSON_parser_tests.ml
+++ b/common/mltools/JSON_parser_tests.ml
@@ -27,16 +27,15 @@ let assert_equal_int = assert_equal ~printer:(fun x ->
string_of_int x)
let assert_equal_int64 = assert_equal ~printer:(fun x -> Int64.to_string x)
let assert_equal_bool = assert_equal ~printer:(fun x -> string_of_bool x)
-let string_of_json_parser_val_type = function
- | JSON_parser_null -> "null"
- | JSON_parser_string _ -> "string"
- | JSON_parser_number _ -> "number"
- | JSON_parser_double _ -> "float"
- | JSON_parser_object _ -> "object"
- | JSON_parser_array _ -> "array"
- | JSON_parser_bool _ -> "bool"
+let string_of_json_t = function
+ | JSON.String _ -> "string"
+ | JSON.Int _ -> "int"
+ | JSON.Float _ -> "float"
+ | JSON.Dict _ -> "dict"
+ | JSON.List _ -> "list"
+ | JSON.Bool _ -> "bool"
let type_mismatch_string exp value - Printf.sprintf "value is not %s but
%s" exp (string_of_json_parser_val_type value)
+ Printf.sprintf "value is not %s but %s" exp (string_of_json_t
value)
let assert_raises_invalid_argument str (* Replace the Invalid_argument
string with a fixed one, just to check
@@ -54,28 +53,28 @@ let assert_raises_nested str let assert_is_object value
assert_bool
(type_mismatch_string "object" value)
- (match value with | JSON_parser_object _ -> true | _ -> false)
+ (match value with | JSON.Dict _ -> true | _ -> false)
let assert_is_string exp = function
- | JSON_parser_string s -> assert_equal_string exp s
+ | JSON.String s -> assert_equal_string exp s
| _ as v -> assert_failure (type_mismatch_string "string" v)
let assert_is_number exp = function
- | JSON_parser_number n -> assert_equal_int64 exp n
- | JSON_parser_double d -> assert_equal_int64 exp (Int64.of_float d)
+ | JSON.Int i -> assert_equal_int64 exp i
+ | JSON.Float f -> assert_equal_int64 exp (Int64.of_float f)
| _ as v -> assert_failure (type_mismatch_string "number/double"
v)
let assert_is_array value assert_bool
- (type_mismatch_string "array" value)
- (match value with | JSON_parser_array _ -> true | _ -> false)
+ (type_mismatch_string "list" value)
+ (match value with | JSON.List _ -> true | _ -> false)
let assert_is_bool exp = function
- | JSON_parser_bool b -> assert_equal_bool exp b
+ | JSON.Bool b -> assert_equal_bool exp b
| _ as v -> assert_failure (type_mismatch_string "bool" v)
-let get_object_list = function
- | JSON_parser_object x -> x
- | _ as v -> assert_failure (type_mismatch_string "object" v)
-let get_array = function
- | JSON_parser_array x -> x
- | _ as v -> assert_failure (type_mismatch_string "array" v)
+let get_dict = function
+ | JSON.Dict x -> x
+ | _ as v -> assert_failure (type_mismatch_string "dict" v)
+let get_list = function
+ | JSON.List x -> x
+ | _ as v -> assert_failure (type_mismatch_string "list" v)
let test_tree_parse_invalid ctx @@ -101,28 +100,26 @@ let test_tree_parse_basic
ctx
let test_tree_parse_inspect ctx let value = json_parser_tree_parse
"{\"foo\":5}" in
- let l = get_object_list value in
- assert_equal_int 1 (Array.length l);
- assert_equal_string "foo" (fst (l.(0)));
- assert_is_number 5_L (snd (l.(0)));
+ let l = get_dict value in
+ assert_equal_int 1 (List.length l);
+ assert_equal_string "foo" (fst (List.hd l));
+ assert_is_number 5_L (snd (List.hd l));
let value = json_parser_tree_parse "[\"foo\", true]" in
- let a = get_array value in
- assert_equal_int 2 (Array.length a);
- assert_is_string "foo" (a.(0));
- assert_is_bool true (a.(1));
+ let a = get_list value in
+ assert_equal_int 2 (List.length a);
+ assert_is_string "foo" (List.hd a);
+ assert_is_bool true (List.nth a 1);
let value = json_parser_tree_parse "{\"foo\":[false, {}, 10],
\"second\":2}" in
- let l = get_object_list value in
- assert_equal_int 2 (Array.length l);
- assert_equal_string "foo" (fst (l.(0)));
- let a = get_array (snd (l.(0))) in
- assert_equal_int 3 (Array.length a);
- assert_is_bool false (a.(0));
- assert_is_object (a.(1));
- assert_is_number 10_L (a.(2));
- assert_equal_string "second" (fst (l.(1)));
- assert_is_number 2_L (snd (l.(1)))
+ let l = get_dict value in
+ assert_equal_int 2 (List.length l);
+ let a = get_list (List.assoc "foo" l) in
+ assert_equal_int 3 (List.length a);
+ assert_is_bool false (List.hd a);
+ assert_is_object (List.nth a 1);
+ assert_is_number 10_L (List.nth a 2);
+ assert_is_number 2_L (List.assoc "second" l)
(* Suites declaration. *)
let suite --
2.18.0
Pino Toscano
2018-Aug-22 11:20 UTC
Re: [Libguestfs] [PATCH 4/4] mltools: JSON: unify JSON_parser type with JSON.json_t.
On Monday, 20 August 2018 18:02:06 CEST Richard W.M. Jones wrote:> - } else > - rv = Val_none; > + } > + else { > + /* Previously we had a special JSON_parser_null value we could > + * use here, making the returned type (sort of) an option. > + * This is a best effort which is better than crashing / > + * throwing an error. > + */ > + rv = caml_alloc (1, JSON_STRING_TAG); > + v = caml_copy_string (""); > + Store_field (rv, 0, v); > + }NACK, this is not correct. null is a proper type of value in JSON, and thus JSON.json_t must represent it as well. This is even used in other parts, for example the check of backing files of disks (see guestfs_impl_disk_has_backing_file). -- Pino Toscano
On Monday, 20 August 2018 18:02:02 CEST Richard W.M. Jones wrote:> An evolution of: > > https://www.redhat.com/archives/libguestfs/2018-August/msg00155.htmlPatches #1, #2, and #3 LGTM. Thanks, -- Pino Toscano
Apparently Analagous Threads
- [PATCH v2 0/2] mltools: JSON: unify JSON & JSON parser.
- [PATCH v3 4/4] v2v: Add --print-estimate option to print copy size
- [PATCH 4/4] mltools: JSON: unify JSON_parser type with JSON.json_t.
- [PATCH v3 1/4] mltools: Rename Yajl module as JSON_parser and move to common/mltools.
- Re: [PATCH v3 1/4] mltools: Rename Yajl module as JSON_parser and move to common/mltools.