Pino Toscano
2015-Sep-07 14:38 UTC
[Libguestfs] [PATCH 0/4 v3] builder: support for Simple Streams metadata
Hi, this series adds a basic support for Simple Streams v1.0 metadata files. This makes it possible to create a repository .conf files with [cirros] uri=http://download.cirros-cloud.net format=simplestreams to read the latest version of each CirrOS image. Thanks, Pino Toscano (4): builder: add non-int revisions builder: add simple libyajl binding build: expose HAVE_YAJL to automake builder: support Simple Streams v1.0 as index metadata .gitignore | 3 + builder/Makefile.am | 51 ++- builder/builder.ml | 11 +- builder/cache.ml | 2 +- builder/cache.mli | 6 +- builder/downloader.mli | 2 +- builder/index.ml | 4 +- builder/index.mli | 2 +- builder/index_parser.ml | 4 +- builder/simplestreams_parser.ml | 204 ++++++++++ builder/simplestreams_parser.mli | 19 + builder/sources.ml | 9 + builder/sources.mli | 1 + builder/test-simplestreams/streams/v1/index.json | 18 + .../v1/net.cirros-cloud:released:download.json | 429 +++++++++++++++++++++ .../virt-builder/repos.d/cirros.conf.in | 3 + builder/test-virt-builder-list-simplestreams.sh | 108 ++++++ builder/utils.ml | 7 + builder/virt-builder.pod | 7 + builder/yajl-c.c | 143 +++++++ builder/yajl.ml | 30 ++ builder/yajl.mli | 33 ++ builder/yajl_tests.ml | 139 +++++++ configure.ac | 2 + po/POTFILES | 1 + po/POTFILES-ml | 3 + 26 files changed, 1226 insertions(+), 15 deletions(-) create mode 100644 builder/simplestreams_parser.ml create mode 100644 builder/simplestreams_parser.mli create mode 100644 builder/test-simplestreams/streams/v1/index.json create mode 100644 builder/test-simplestreams/streams/v1/net.cirros-cloud:released:download.json create mode 100644 builder/test-simplestreams/virt-builder/repos.d/cirros.conf.in create mode 100755 builder/test-virt-builder-list-simplestreams.sh create mode 100644 builder/yajl-c.c create mode 100644 builder/yajl.ml create mode 100644 builder/yajl.mli create mode 100644 builder/yajl_tests.ml -- 2.1.0
Pino Toscano
2015-Sep-07 14:38 UTC
[Libguestfs] [PATCH 1/4] builder: add non-int revisions
Add support for non-integer revisions of entries, comparing them as
integer when possible.
---
builder/builder.ml | 9 ++++++++-
builder/cache.ml | 2 +-
builder/cache.mli | 6 +++---
builder/downloader.mli | 2 +-
builder/index.ml | 4 ++--
builder/index.mli | 2 +-
builder/index_parser.ml | 4 ++--
builder/utils.ml | 7 +++++++
8 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/builder/builder.ml b/builder/builder.ml
index d59380b..dcfd437 100644
--- a/builder/builder.ml
+++ b/builder/builder.ml
@@ -34,6 +34,13 @@ open Printf
let () = Random.self_init ()
let remove_duplicates index + let compare_revisions rev1 rev2 + match rev1,
rev2 with
+ | Rev_int n1, Rev_int n2 -> compare n1 n2
+ | Rev_string s1, Rev_int n2 -> compare s1 (string_of_int n2)
+ | Rev_int n1, Rev_string s2 -> compare (string_of_int n1) s2
+ | Rev_string s1, Rev_string s2 -> compare s1 s2
+ in
(* Fill an hash with the higher revision of the available
* (name, arch) tuples, so it possible to ignore duplicates,
* and versions with a lower revision.
@@ -44,7 +51,7 @@ let remove_duplicates index let id = name, arch in
try
let rev = Hashtbl.find nseen id in
- if revision > rev then
+ if compare_revisions rev revision > 0 then
Hashtbl.replace nseen id revision
with Not_found ->
Hashtbl.add nseen id revision
diff --git a/builder/cache.ml b/builder/cache.ml
index e73bcfd..8b63a86 100644
--- a/builder/cache.ml
+++ b/builder/cache.ml
@@ -40,7 +40,7 @@ let create ~directory }
let cache_of_name t name arch revision - t.directory // sprintf
"%s.%s.%d" name arch revision
+ t.directory // sprintf "%s.%s.%s" name arch (string_of_revision
revision)
let is_cached t name arch revision let filename = cache_of_name t name arch
revision in
diff --git a/builder/cache.mli b/builder/cache.mli
index 7edc670..1ab8ede 100644
--- a/builder/cache.mli
+++ b/builder/cache.mli
@@ -27,16 +27,16 @@ type t
val create : directory:string -> t
(** Create the abstract type. *)
-val cache_of_name : t -> string -> string -> int -> string
+val cache_of_name : t -> string -> string -> Utils.revision ->
string
(** [cache_of_name t name arch revision] return the filename
of the cached file. (Note: It doesn't check if the filename
exists, this is just a simple string transformation). *)
-val is_cached : t -> string -> string -> int -> bool
+val is_cached : t -> string -> string -> Utils.revision -> bool
(** [is_cached t name arch revision] return whether the file with
specified name, architecture and revision is cached. *)
-val print_item_status : t -> header:bool -> (string * string * int) list
-> unit
+val print_item_status : t -> header:bool -> (string * string *
Utils.revision) list -> unit
(** [print_item_status t header items] print the status in the cache
of the specified items (which are tuples of name, architecture,
and revision).
diff --git a/builder/downloader.mli b/builder/downloader.mli
index 5e3cdaa..11ec498 100644
--- a/builder/downloader.mli
+++ b/builder/downloader.mli
@@ -35,7 +35,7 @@ type proxy_mode val create : curl:string -> cache:Cache.t
option -> t
(** Create the abstract type. *)
-val download : t -> ?template:(string*string*int) -> ?progress_bar:bool
-> ?proxy:proxy_mode -> uri -> (filename * bool)
+val download : t -> ?template:(string*string*Utils.revision) ->
?progress_bar:bool -> ?proxy:proxy_mode -> uri -> (filename * bool)
(** Download the URI, returning the downloaded filename and a
temporary file flag. The temporary file flag is [true] iff
the downloaded file is temporary and should be deleted by the
diff --git a/builder/index.ml b/builder/index.ml
index 3e8cb85..c59d6dd 100644
--- a/builder/index.ml
+++ b/builder/index.ml
@@ -32,7 +32,7 @@ and entry = {
arch : string;
signature_uri : string option; (* deprecated, will be removed in 1.26
*)
checksums : Checksums.csum_t list option;
- revision : int;
+ revision : Utils.revision;
format : string option;
size : int64;
compressed_size : int64 option;
@@ -86,7 +86,7 @@ let print_entry chan (name, { printable_name = printable_name;
(Checksums.string_of_csum_t c) (Checksums.string_of_csum c)
) checksums
);
- fp "revision=%d\n" revision;
+ fp "revision=%s\n" (string_of_revision revision);
(match format with
| None -> ()
| Some format -> fp "format=%s\n" format
diff --git a/builder/index.mli b/builder/index.mli
index 10ed15a..fadcad9 100644
--- a/builder/index.mli
+++ b/builder/index.mli
@@ -24,7 +24,7 @@ and entry = {
arch : string;
signature_uri : string option; (* deprecated, will be removed in 1.26
*)
checksums : Checksums.csum_t list option;
- revision : int;
+ revision : Utils.revision;
format : string option;
size : int64;
compressed_size : int64 option;
diff --git a/builder/index_parser.ml b/builder/index_parser.ml
index 845d0e9..2c78fd9 100644
--- a/builder/index_parser.ml
+++ b/builder/index_parser.ml
@@ -112,9 +112,9 @@ let get_index ~downloader ~sigchecker
try Some (List.assoc ("checksum", None) fields)
with Not_found -> None in
let revision - try int_of_string (List.assoc
("revision", None) fields)
+ try Rev_int (int_of_string (List.assoc ("revision", None)
fields))
with
- | Not_found -> 1
+ | Not_found -> Rev_int 1
| Failure "int_of_string" ->
eprintf (f_"%s: cannot parse 'revision' field for
'%s'\n") prog n;
corrupt_file () in
diff --git a/builder/utils.ml b/builder/utils.ml
index a6628eb..986bf68 100644
--- a/builder/utils.ml
+++ b/builder/utils.ml
@@ -26,5 +26,12 @@ type gpgkey_type | No_Key
| Fingerprint of string
| KeyFile of string
+and revision + | Rev_int of int
+ | Rev_string of string
let quote = Filename.quote
+
+let string_of_revision = function
+ | Rev_int n -> string_of_int n
+ | Rev_string s -> s
--
2.1.0
Pino Toscano
2015-Sep-07 14:38 UTC
[Libguestfs] [PATCH 2/4] builder: add simple libyajl binding
Only yajl_val and yajl_tree_parse are exposed for now.
---
.gitignore | 2 +
builder/Makefile.am | 45 ++++++++++++++--
builder/yajl-c.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++
builder/yajl.ml | 30 +++++++++++
builder/yajl.mli | 33 ++++++++++++
builder/yajl_tests.ml | 139 ++++++++++++++++++++++++++++++++++++++++++++++++
po/POTFILES | 1 +
po/POTFILES-ml | 2 +
8 files changed, 391 insertions(+), 4 deletions(-)
create mode 100644 builder/yajl-c.c
create mode 100644 builder/yajl.ml
create mode 100644 builder/yajl.mli
create mode 100644 builder/yajl_tests.ml
diff --git a/.gitignore b/.gitignore
index e502018..db8d0a2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -60,6 +60,7 @@ Makefile.in
/builder/index-parse.h
/builder/index-scan.c
/builder/libguestfs.conf
+/builder/oUnit-*
/builder/*.qcow2
/builder/stamp-virt-builder.pod
/builder/stamp-virt-index-validate.pod
@@ -70,6 +71,7 @@ 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
diff --git a/builder/Makefile.am b/builder/Makefile.am
index f48efb0..366b8db 100644
--- a/builder/Makefile.am
+++ b/builder/Makefile.am
@@ -32,7 +32,8 @@ EXTRA_DIST = \
test-virt-index-validate-good-2 \
test-virt-index-validate-good-3 \
virt-builder.pod \
- virt-index-validate.pod
+ virt-index-validate.pod \
+ yajl_tests.ml
CLEANFILES = *~ *.annot *.cmi *.cmo *.cmx *.cmxa *.o virt-builder
@@ -48,7 +49,8 @@ SOURCES_MLI = \
pxzcat.mli \
setlocale.mli \
sigchecker.mli \
- sources.mli
+ sources.mli \
+ yajl.mli
SOURCES_ML = \
utils.ml \
@@ -57,6 +59,7 @@ SOURCES_ML = \
checksums.ml \
index.ml \
ini_reader.ml \
+ yajl.ml \
paths.ml \
languages.ml \
cache.ml \
@@ -81,7 +84,8 @@ SOURCES_C = \
index-parse.c \
index-parser-c.c \
pxzcat-c.c \
- setlocale-c.c
+ setlocale-c.c \
+ yajl-c.c
man_MANS noinst_DATA @@ -106,7 +110,8 @@ virt_builder_CFLAGS = \
-Wno-unused-macros \
$(LIBLZMA_CFLAGS) \
$(LIBTINFO_CFLAGS) \
- $(LIBXML2_CFLAGS)
+ $(LIBXML2_CFLAGS) \
+ $(YAJL_CFLAGS)
BOBJECTS = \
$(top_builddir)/mllib/libdir.cmo \
@@ -145,9 +150,13 @@ OCAMLPACKAGES = \
-I $(top_builddir)/ocaml \
-I $(top_builddir)/mllib \
-I $(top_builddir)/customize
+OCAMLPACKAGES_TESTS if HAVE_OCAML_PKG_GETTEXT
OCAMLPACKAGES += -package gettext-stub
endif
+if HAVE_OCAML_PKG_OUNIT
+OCAMLPACKAGES_TESTS += -package oUnit
+endif
OCAMLCLIBS = \
-pthread -lpthread \
@@ -156,6 +165,7 @@ OCAMLCLIBS = \
$(LIBCRYPT_LIBS) \
$(LIBLZMA_LIBS) \
$(LIBXML2_LIBS) \
+ $(YAJL_LIBS) \
$(LIBINTL) \
-lgnu
@@ -232,13 +242,40 @@ 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)
+
+# 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)
+else
+yajl_tests_THEOBJECTS = $(yajl_tests_BOBJECTS)
+yajl_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
+endif
+
+yajl_tests_DEPENDENCIES = $(yajl_tests_THEOBJECTS) $(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 $@
+
TESTS = \
test-virt-builder-list.sh \
test-virt-index-validate.sh
+check_PROGRAMS
if ENABLE_APPLIANCE
TESTS += test-virt-builder.sh
endif ENABLE_APPLIANCE
+if HAVE_OCAML_PKG_OUNIT
+check_PROGRAMS += yajl_tests
+TESTS += yajl_tests
+endif
check-valgrind:
$(MAKE) VG="$(top_builddir)/run @VG@" check
diff --git a/builder/yajl-c.c b/builder/yajl-c.c
new file mode 100644
index 0000000..6a96d59
--- /dev/null
+++ b/builder/yajl-c.c
@@ -0,0 +1,143 @@
+/* virt-builder
+ * Copyright (C) 2015 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA.
+ */
+
+#include <config.h>
+
+#include <caml/alloc.h>
+#include <caml/fail.h>
+#include <caml/memory.h>
+#include <caml/mlvalues.h>
+
+#if HAVE_YAJL
+#include <yajl/yajl_tree.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#define Val_none (Val_int (0))
+
+extern value virt_builder_yajl_is_available (value unit);
+extern value virt_builder_yajl_tree_parse (value stringv);
+
+#if HAVE_YAJL
+static value
+convert_yajl_value (yajl_val val, int level)
+{
+ CAMLparam0 ();
+ CAMLlocal4 (rv, lv, v, sv);
+
+ if (level > 20)
+ caml_invalid_argument ("too many levels of object/array
nesting");
+
+ if (YAJL_IS_OBJECT (val)) {
+ size_t len = YAJL_GET_OBJECT(val)->len;
+ size_t i;
+ rv = caml_alloc (1, 3);
+ lv = caml_alloc_tuple (len);
+ for (i = 0; i < len; ++i) {
+ v = caml_alloc_tuple (2);
+ sv = caml_copy_string (YAJL_GET_OBJECT(val)->keys[i]);
+ Store_field (v, 0, sv);
+ sv = convert_yajl_value (YAJL_GET_OBJECT(val)->values[i], level + 1);
+ Store_field (v, 1, sv);
+ Store_field (lv, i, v);
+ }
+ Store_field (rv, 0, lv);
+ } else if (YAJL_IS_ARRAY (val)) {
+ size_t len = YAJL_GET_ARRAY(val)->len;
+ size_t i;
+ rv = caml_alloc (1, 4);
+ lv = caml_alloc_tuple (len);
+ for (i = 0; i < len; ++i) {
+ v = convert_yajl_value (YAJL_GET_ARRAY(val)->values[i], level + 1);
+ Store_field (lv, i, v);
+ }
+ Store_field (rv, 0, lv);
+ } else if (YAJL_IS_STRING (val)) {
+ rv = caml_alloc (1, 0);
+ v = caml_copy_string (YAJL_GET_STRING(val));
+ Store_field (rv, 0, v);
+ } else if (YAJL_IS_DOUBLE (val)) {
+ rv = caml_alloc (1, 2);
+ lv = caml_alloc_tuple (1);
+ Store_double_field (lv, 0, YAJL_GET_DOUBLE(val));
+ Store_field (rv, 0, lv);
+ } else if (YAJL_IS_INTEGER (val)) {
+ rv = caml_alloc (1, 1);
+ v = caml_copy_int64 (YAJL_GET_INTEGER(val));
+ Store_field (rv, 0, v);
+ } else if (YAJL_IS_TRUE (val)) {
+ rv = caml_alloc (1, 5);
+ Store_field (rv, 0, Val_true);
+ } else if (YAJL_IS_FALSE (val)) {
+ rv = caml_alloc (1, 5);
+ Store_field (rv, 0, Val_false);
+ } else
+ rv = Val_none;
+
+ CAMLreturn (rv);
+}
+
+value
+virt_builder_yajl_is_available (value unit)
+{
+ /* NB: noalloc */
+ return Val_true;
+}
+
+value
+virt_builder_yajl_tree_parse (value stringv)
+{
+ CAMLparam1 (stringv);
+ CAMLlocal1 (rv);
+ yajl_val tree;
+ char error_buf[256];
+
+ tree = yajl_tree_parse (String_val (stringv), error_buf, sizeof error_buf);
+ if (tree == NULL) {
+ char buf[256 + sizeof error_buf];
+ if (strlen (error_buf) > 0)
+ snprintf (buf, sizeof buf, "JSON parse error: %s", error_buf);
+ else
+ snprintf (buf, sizeof buf, "unknown JSON parse error");
+ caml_invalid_argument (buf);
+ }
+
+ rv = convert_yajl_value (tree, 1);
+ yajl_tree_free (tree);
+
+ CAMLreturn (rv);
+}
+
+#else
+
+value
+virt_builder_yajl_is_available (value unit)
+{
+ /* NB: noalloc */
+ return Val_false;
+}
+
+value
+virt_builder_yajl_tree_parse (value stringv)
+{
+ caml_invalid_argument ("virt-builder was compiled without yajl
support");
+}
+
+#endif
diff --git a/builder/yajl.ml b/builder/yajl.ml
new file mode 100644
index 0000000..f2d5c2b
--- /dev/null
+++ b/builder/yajl.ml
@@ -0,0 +1,30 @@
+(* virt-builder
+ * Copyright (C) 2015 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 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
+
+external yajl_is_available : unit -> bool =
"virt_builder_yajl_is_available" "noalloc"
+
+external yajl_tree_parse : string -> yajl_val =
"virt_builder_yajl_tree_parse"
diff --git a/builder/yajl.mli b/builder/yajl.mli
new file mode 100644
index 0000000..aaa9389
--- /dev/null
+++ b/builder/yajl.mli
@@ -0,0 +1,33 @@
+(* virt-builder
+ * Copyright (C) 2015 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 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
+
+val yajl_is_available : unit -> bool
+(** Is YAJL built in? If not, calling any of the other yajl_*
+ functions will result in an error. *)
+
+val yajl_tree_parse : string -> yajl_val
+(** Parse the JSON string. *)
diff --git a/builder/yajl_tests.ml b/builder/yajl_tests.ml
new file mode 100644
index 0000000..344a8db
--- /dev/null
+++ b/builder/yajl_tests.ml
@@ -0,0 +1,139 @@
+(* virt-builder
+ * Copyright (C) 2015 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+(* This file tests the Yajl module. *)
+
+open OUnit2
+open Yajl
+
+(* Utils. *)
+let assert_equal_string = assert_equal ~printer:(fun x -> x)
+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 type_mismatch_string exp value + Printf.sprintf "value is not %s but
%s" exp (string_of_yajl_val_type value)
+
+let assert_raises_invalid_argument str + (* Replace the Invalid_argument
string with a fixed one, just to check
+ * whether the exception has been raised.
+ *)
+ let mock = "parse_error" in
+ let wrapped_tree_parse str + try yajl_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)
+
+let assert_is_object value + assert_bool
+ (type_mismatch_string "object" value)
+ (match value with | Yajl_object _ -> true | _ -> false)
+let assert_is_string exp = function
+ | Yajl_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)
+ | _ 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)
+let assert_is_bool exp = function
+ | Yajl_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
+ | _ as v -> assert_failure (type_mismatch_string "object" v)
+let get_array = function
+ | Yajl_array x -> x
+ | _ as v -> assert_failure (type_mismatch_string "array" v)
+
+
+let test_tree_parse_invalid ctx + assert_raises_invalid_argument "";
+ assert_raises_invalid_argument "invalid";
+ assert_raises_invalid_argument ":5";
+
+ (* Nested objects/arrays. *)
+ let str = "[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]" in
+ assert_raises_nested str;
+ let str =
"{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":5}}}}}}}}}}}}}}}}}}}}}"
in
+ assert_raises_nested str
+
+let test_tree_parse_basic ctx + let value = yajl_tree_parse "{}" in
+ assert_is_object value;
+
+ let value = yajl_tree_parse "\"foo\"" in
+ assert_is_string "foo" value;
+
+ let value = yajl_tree_parse "[]" in
+ assert_is_array value
+
+let test_tree_parse_inspect ctx + let value = yajl_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 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 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)))
+
+(* Suites declaration. *)
+let suite + "builder Yajl" >:::
+ [
+ "tree_parse.invalid" >:: test_tree_parse_invalid;
+ "tree_parse.basic" >:: test_tree_parse_basic;
+ "tree_parse.inspect" >:: test_tree_parse_inspect;
+ ]
+
+let () + if not (yajl_is_available ()) then
+ exit 77;
+ run_test_tt_main suite
diff --git a/po/POTFILES b/po/POTFILES
index 6a0a3fc..bb68183 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -6,6 +6,7 @@ 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
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index 7933c8e..ff08a53 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -14,6 +14,8 @@ builder/setlocale.ml
builder/sigchecker.ml
builder/sources.ml
builder/utils.ml
+builder/yajl.ml
+builder/yajl_tests.ml
customize/crypt.ml
customize/customize_cmdline.ml
customize/customize_main.ml
--
2.1.0
Pino Toscano
2015-Sep-07 14:38 UTC
[Libguestfs] [PATCH 3/4] build: expose HAVE_YAJL to automake
This way it can be used in automake conditionals.
---
configure.ac | 1 +
1 file changed, 1 insertion(+)
diff --git a/configure.ac b/configure.ac
index 739cf06..2ce2456 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1072,6 +1072,7 @@ PKG_CHECK_MODULES([YAJL], [yajl >= 2.0.4], [
AC_SUBST([YAJL_LIBS])
AC_DEFINE([HAVE_YAJL],[1],[Define to 1 if you have yajl.])
],[AC_MSG_WARN([yajl not found, some features will be disabled])])
+AM_CONDITIONAL([HAVE_YAJL],[test "x$YAJL_LIBS" != "x"])
dnl Check for C++ (optional, we just use this to test the header works).
AC_PROG_CXX
--
2.1.0
Pino Toscano
2015-Sep-07 14:38 UTC
[Libguestfs] [PATCH 4/4] builder: support Simple Streams v1.0 as index metadata
Add a new "simplestreams" repository type, and a simple parser for
fetching and reading the JSON indexes of the Simple Streams v1.0
format.
Read only datatype=image-downloads contents, and only the latest
versions of each content available as disk image (disk.img or
disk1.img).
Add a simple test, using the "released" images from the CirrOS
project.
---
.gitignore | 1 +
builder/Makefile.am | 6 +
builder/builder.ml | 2 +
builder/simplestreams_parser.ml | 204 ++++++++++
builder/simplestreams_parser.mli | 19 +
builder/sources.ml | 9 +
builder/sources.mli | 1 +
builder/test-simplestreams/streams/v1/index.json | 18 +
.../v1/net.cirros-cloud:released:download.json | 429 +++++++++++++++++++++
.../virt-builder/repos.d/cirros.conf.in | 3 +
builder/test-virt-builder-list-simplestreams.sh | 108 ++++++
builder/virt-builder.pod | 7 +
configure.ac | 1 +
po/POTFILES-ml | 1 +
14 files changed, 809 insertions(+)
create mode 100644 builder/simplestreams_parser.ml
create mode 100644 builder/simplestreams_parser.mli
create mode 100644 builder/test-simplestreams/streams/v1/index.json
create mode 100644
builder/test-simplestreams/streams/v1/net.cirros-cloud:released:download.json
create mode 100644
builder/test-simplestreams/virt-builder/repos.d/cirros.conf.in
create mode 100755 builder/test-virt-builder-list-simplestreams.sh
diff --git a/.gitignore b/.gitignore
index db8d0a2..a430f6e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,6 +65,7 @@ Makefile.in
/builder/stamp-virt-builder.pod
/builder/stamp-virt-index-validate.pod
/builder/test-config/virt-builder/repos.d/test-index.conf
+/builder/test-simplestreams/virt-builder/repos.d/cirros.conf
/builder/test-website/virt-builder/repos.d/libguestfs.conf
/builder/virt-builder
/builder/virt-builder.1
diff --git a/builder/Makefile.am b/builder/Makefile.am
index 366b8db..e7cc444 100644
--- a/builder/Makefile.am
+++ b/builder/Makefile.am
@@ -49,6 +49,7 @@ SOURCES_MLI = \
pxzcat.mli \
setlocale.mli \
sigchecker.mli \
+ simplestreams_parser.mli \
sources.mli \
yajl.mli
@@ -67,6 +68,7 @@ SOURCES_ML = \
downloader.ml \
sigchecker.ml \
index_parser.ml \
+ simplestreams_parser.ml \
list_entries.ml \
cmdline.ml \
builder.ml
@@ -269,6 +271,10 @@ TESTS = \
test-virt-index-validate.sh
check_PROGRAMS
+if HAVE_YAJL
+TESTS += test-virt-builder-list-simplestreams.sh
+endif
+
if ENABLE_APPLIANCE
TESTS += test-virt-builder.sh
endif ENABLE_APPLIANCE
diff --git a/builder/builder.ml b/builder/builder.ml
index dcfd437..7d347b3 100644
--- a/builder/builder.ml
+++ b/builder/builder.ml
@@ -182,6 +182,8 @@ let main () match source.Sources.format with
| Sources.FormatNative ->
Index_parser.get_index ~downloader ~sigchecker source
+ | Sources.FormatSimpleStreams ->
+ Simplestreams_parser.get_index ~downloader ~sigchecker source
) sources
) in
let index = remove_duplicates index in
diff --git a/builder/simplestreams_parser.ml b/builder/simplestreams_parser.ml
new file mode 100644
index 0000000..13e0b5d
--- /dev/null
+++ b/builder/simplestreams_parser.ml
@@ -0,0 +1,204 @@
+(* virt-builder
+ * Copyright (C) 2015 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+open Common_gettext.Gettext
+open Common_utils
+
+open Yajl
+open Utils
+
+open Printf
+
+let ensure_trailing_slash str + if String.length str > 0 &&
str.[String.length str - 1] <> '/' then str ^ "/"
+ else str
+
+let object_find_optional key = function
+ | Yajl_object o ->
+ (match List.filter (fun (k, _) -> k = key) (Array.to_list o) with
+ | [(k, v)] -> Some v
+ | [] -> None
+ | _ -> error (f_"more than value for the key '%s'")
key)
+ | _ -> error (f_"the value of the key '%s' is not an
object") key
+
+let object_find key yv + match object_find_optional key yv with
+ | None -> error (f_"missing value for the key '%s'") key
+ | Some v -> v
+
+let object_get_string key yv + match object_find key yv with
+ | Yajl_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
+ | _ -> error (f_"the value for the key '%s' is not an
object") key
+
+let object_find_objects fn = function
+ | Yajl_object o -> 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
+ | _ -> 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
+ | _ -> error (f_"the value for the key '%s' is not an
integer") key
+
+let objects_get_string key yvs + let rec loop = function
+ | [] -> None
+ | x :: xs ->
+ (match object_find_optional key x with
+ | Some (Yajl_string s) -> Some s
+ | Some _ -> error (f_"the value for key '%s' is not a
string as expected") key
+ | None -> loop xs
+ )
+ in
+ match loop yvs with
+ | Some s -> s
+ | None -> error (f_"the key '%s' was not found in a list of
objects") key
+
+let get_index ~downloader ~sigchecker
+ { Sources.uri = uri; proxy = proxy } +
+ let uri = ensure_trailing_slash uri in
+
+ let download_and_parse uri + let tmpfile, delete_tmpfile =
Downloader.download downloader ~proxy uri in
+ if delete_tmpfile then
+ unlink_on_exit tmpfile;
+ let file + if Sigchecker.verifying_signatures sigchecker then (
+ let tmpunsigned + Sigchecker.verify_and_remove_signature
sigchecker tmpfile in
+ match tmpunsigned with
+ | None -> assert false (* only when not verifying signatures *)
+ | Some f -> f
+ ) else
+ tmpfile in
+ yajl_tree_parse (read_whole_file file) in
+
+ let downloads + let uri_index + if Sigchecker.verifying_signatures
sigchecker then
+ uri ^ "streams/v1/index.sjson"
+ else
+ uri ^ "streams/v1/index.json" in
+ let tree = download_and_parse uri_index in
+
+ let format = object_get_string "format" tree in
+ if format <> "index:1.0" then
+ 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
+ filter_map (
+ fun (_, desc) ->
+ let format = object_get_string "format" desc in
+ let datatype = object_get_string "datatype" desc in
+ match format, datatype with
+ | "products:1.0", "image-downloads" ->
+ Some (object_get_string "path" desc)
+ | _ -> None
+ ) index in
+
+ let scan_product_list path + let tree = download_and_parse (uri ^ path) in
+
+ let format = object_get_string "format" tree in
+ if format <> "products:1.0" then
+ 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 = Array.to_list products_node in
+ filter_map (
+ fun (prod, prod_desc) ->
+ let arch = object_get_string "arch" prod_desc in
+ let prods = Array.to_list (object_get_object "versions"
prod_desc) in
+ let prods = filter_map (
+ fun (rel, rel_desc) ->
+ let pubname = objects_get_string "pubname" [rel_desc;
prod_desc] in
+ let items = object_find_object "items" rel_desc in
+ let disk_items = object_find_objects (
+ function
+ | (("disk.img"|"disk1.img"), v) -> Some v
+ | _ -> None
+ ) items in
+ (match disk_items with
+ | [] -> None
+ | disk_item :: _ ->
+ let printable_name = Some pubname in
+ let file_uri = uri ^ (object_get_string "path"
disk_item) in
+ let checksums + let checksums =
object_find_objects (
+ function
+ | ("sha256", Yajl_string c) -> Some
(Checksums.SHA256 c)
+ | ("sha512", Yajl_string c) -> Some
(Checksums.SHA512 c)
+ | _ -> None
+ ) disk_item in
+ match checksums with
+ | [] -> None
+ | x -> Some x in
+ let revision = Rev_string rel in
+ let size = object_get_number "size" disk_item in
+ let aliases = Some [pubname;] in
+
+ let entry = { Index.printable_name = printable_name;
+ osinfo = None;
+ file_uri = file_uri;
+ arch = arch;
+ signature_uri = None;
+ checksums = checksums;
+ revision = revision;
+ format = None;
+ size = size;
+ compressed_size = None;
+ expand = None;
+ lvexpand = None;
+ notes = [];
+ hidden = false;
+ aliases = aliases;
+ sigchecker = sigchecker;
+ proxy = proxy; } in
+ Some (rel, (prod, entry))
+ )
+ ) prods in
+ (* Select the disk image with the bigger version (i.e. usually
+ * the most recent one. *)
+ let reverse_revision_compare (rev1, _) (rev2, _) = compare rev2 rev1 in
+ let prods = List.sort reverse_revision_compare prods in
+ match prods with
+ | [] -> None
+ | (_, entry) :: _ -> Some entry
+ ) products in
+
+ let entries = List.flatten (List.map scan_product_list downloads) in
+ if verbose () then (
+ printf "simplestreams tree (%s) after parsing:\n" uri;
+ List.iter (Index.print_entry Pervasives.stdout) entries
+ );
+ entries
diff --git a/builder/simplestreams_parser.mli b/builder/simplestreams_parser.mli
new file mode 100644
index 0000000..a4b91ba
--- /dev/null
+++ b/builder/simplestreams_parser.mli
@@ -0,0 +1,19 @@
+(* virt-builder
+ * Copyright (C) 2015 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+val get_index : downloader:Downloader.t -> sigchecker:Sigchecker.t ->
Sources.source -> Index.index
diff --git a/builder/sources.ml b/builder/sources.ml
index b21e8fc..149db6f 100644
--- a/builder/sources.ml
+++ b/builder/sources.ml
@@ -31,6 +31,7 @@ type source = {
}
and source_format | FormatNative
+| FormatSimpleStreams
module StringSet = Set.Make (String)
@@ -82,6 +83,14 @@ let parse_conf file try
(match (List.assoc ("format", None) fields) with
| "native" | "" -> FormatNative
+ | "simplestreams" as fmt ->
+ if not (Yajl.yajl_is_available ()) then (
+ if verbose () then (
+ eprintf (f_"%s: repository type '%s' not
supported (missing YAJL support), skipping it\n") prog fmt;
+ );
+ invalid_arg fmt
+ ) else
+ FormatSimpleStreams
| fmt ->
if verbose () then (
eprintf (f_"%s: unknown repository type '%s' in
%s, skipping it\n") prog fmt file;
diff --git a/builder/sources.mli b/builder/sources.mli
index e861310..e621a9f 100644
--- a/builder/sources.mli
+++ b/builder/sources.mli
@@ -25,5 +25,6 @@ type source = {
}
and source_format | FormatNative
+| FormatSimpleStreams
val read_sources : unit -> source list
diff --git a/builder/test-simplestreams/streams/v1/index.json
b/builder/test-simplestreams/streams/v1/index.json
new file mode 100644
index 0000000..3180af7
--- /dev/null
+++ b/builder/test-simplestreams/streams/v1/index.json
@@ -0,0 +1,18 @@
+{
+ "format": "index:1.0",
+ "updated": "Fri, 08 May 2015 13:20:51 +0000",
+ "index": {
+ "net.cirros-cloud:released:download": {
+ "products": [
+ "net.cirros-cloud:standard:0.3:i386",
+ "net.cirros-cloud:standard:0.3:x86_64",
+ "net.cirros-cloud:standard:0.3:powerpc",
+ "net.cirros-cloud:standard:0.3:arm"
+ ],
+ "datatype": "image-downloads",
+ "format": "products:1.0",
+ "updated": "Fri, 08 May 2015 13:20:51 +0000",
+ "path":
"streams/v1/net.cirros-cloud:released:download.json"
+ }
+ }
+}
diff --git
a/builder/test-simplestreams/streams/v1/net.cirros-cloud:released:download.json
b/builder/test-simplestreams/streams/v1/net.cirros-cloud:released:download.json
new file mode 100644
index 0000000..0fb57b4
--- /dev/null
+++
b/builder/test-simplestreams/streams/v1/net.cirros-cloud:released:download.json
@@ -0,0 +1,429 @@
+{
+ "products": {
+ "net.cirros-cloud:standard:0.3:i386": {
+ "arch": "i386",
+ "versions": {
+ "20140908": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "785c524f55bf2493dcddeedba25172f1",
+ "sha256":
"bc20b950cc20e66e0b915748ad6b1ea2360ec03f08ffe6c68dc1b4a82331ab66",
+ "size": 3204602,
+ "path": "0.3.3/cirros-0.3.3-i386-lxc.tar.gz"
+ },
+ "disk.img": {
+ "ftype": "disk.img",
+ "md5": "283c77db6fc79b2d47c585ec241e7edc",
+ "sha256":
"837cc3c79de14de62b8691c08a6913b7c0c62427870c7c1921ac43b9580748a9",
+ "size": 12268032,
+ "path": "0.3.3/cirros-0.3.3-i386-disk.img"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "861ef94d90ea220ae72b84d258ff5620",
+ "sha256":
"5c7e685d42f0f1c5c70398e8b7388fc21b84dcbb4dc4a37c1c1645fe5c5ed3a4",
+ "size": 8231317,
+ "path": "0.3.3/cirros-0.3.3-i386-uec.tar.gz"
+ }
+ },
+ "version": "0.3.3",
+ "pubname": "cirros-0.3.3-i386"
+ },
+ "20150422": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "ffe02ef2b49cb34881f96e2b4c69383c",
+ "sha256":
"5760cae9b9701dc09f495c3787f1da271800dcbc040eb793ddf4eb636689148a",
+ "size": 3210378,
+ "path": "0.3.4/cirros-0.3.4-i386-lxc.tar.gz"
+ },
+ "disk.img": {
+ "ftype": "disk.img",
+ "md5": "79b4436412283bb63c2cba4ac796bcd9",
+ "sha256":
"48c279ff502ea4c5e3e09d58c9e3a2ab615452dae2ed8fe347f68c136c6a5a0b",
+ "size": 12506112,
+ "path": "0.3.4/cirros-0.3.4-i386-disk.img"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "c1630b33986cc09df2e0cbca7f5c5346",
+ "sha256":
"f1cad519da6632b1d0ebad2f892534b732b5f9dd54d27f532d2963a0748f246e",
+ "size": 8241360,
+ "path": "0.3.4/cirros-0.3.4-i386-uec.tar.gz"
+ }
+ },
+ "version": "0.3.4",
+ "pubname": "cirros-0.3.4-i386"
+ },
+ "20140317": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "55023b89a6121b30603859bb80f5c8d3",
+ "sha256":
"136f8dfff85b8d509a0d0a0264aea79ae94d9b7c3ea5745fbd478ae600adeb20",
+ "size": 3201206,
+ "path": "0.3.2/cirros-0.3.2-i386-lxc.tar.gz"
+ },
+ "disk.img": {
+ "ftype": "disk.img",
+ "md5": "b0a256d40e078d66576f7ae91c296e2b",
+ "sha256":
"f0803c2d179c8a02d029239d35fc3e752cc81ad3436ea52b757e11685ca7c074",
+ "size": 12336128,
+ "path": "0.3.2/cirros-0.3.2-i386-disk.img"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "dcbcc559fc3bc468d9149bd7191aaa0c",
+ "sha256":
"74ba8b67e0dce67f16a6bc5942bee90cbe31381f932aac1ba51bbc774aad5046",
+ "size": 8221995,
+ "path": "0.3.2/cirros-0.3.2-i386-uec.tar.gz"
+ }
+ },
+ "version": "0.3.2",
+ "pubname": "cirros-0.3.2-i386"
+ },
+ "20111020": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "e760bf470841f57c2c1bb426d407d169",
+ "sha256":
"cac7887628527604b65a89e8caa34096d51c2dc1acfe405c15db2fc58495142a",
+ "size": 1845928,
+ "path": "0.3.0/cirros-0.3.0-i386-lxc.tar.gz"
+ },
+ "disk.img": {
+ "ftype": "disk.img",
+ "md5": "90169ba6f09b5906a7f0755bd00bf2c3",
+ "sha256":
"3309675d0d409128b1c2651d576bc8092ca9ab93e15f3d3aa458f40947569b61",
+ "size": 9159168,
+ "path": "0.3.0/cirros-0.3.0-i386-disk.img"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "115ca6afa47089dc083c0dc9f9b7ff03",
+ "sha256":
"b57e0acb32852f89734ff11a511ae0897e8cecb41882d03551649289b6854a1b",
+ "size": 6596586,
+ "path": "0.3.0/cirros-0.3.0-i386-uec.tar.gz"
+ }
+ },
+ "version": "0.3.0",
+ "pubname": "cirros-0.3.0-i386"
+ },
+ "20130207": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "fc404d9fc9dc5f0eb33ebaa03920a046",
+ "sha256":
"70a8c9c175589f7ac7054c6151cf2bb7eb9e210cefbe310446df2fb1a436b504",
+ "size": 3191593,
+ "path": "0.3.1/cirros-0.3.1-i386-lxc.tar.gz"
+ },
+ "disk.img": {
+ "ftype": "disk.img",
+ "md5": "6ba617eafc992e33e7c141c679225e53",
+ "sha256":
"b8aa1ce5d11939eaa01205fc31348532a31b82790921d45ceb397fbe76492787",
+ "size": 12251136,
+ "path": "0.3.1/cirros-0.3.1-i386-disk.img"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "52845de5142e58faf211e135d2b45721",
+ "sha256":
"88dda2e505b862a95d0e0044013addcaa3200e602150c9d73e32c2e29345d6f3",
+ "size": 8197543,
+ "path": "0.3.1/cirros-0.3.1-i386-uec.tar.gz"
+ }
+ },
+ "version": "0.3.1",
+ "pubname": "cirros-0.3.1-i386"
+ }
+ },
+ "stream": "released"
+ },
+ "net.cirros-cloud:standard:0.3:x86_64": {
+ "arch": "x86_64",
+ "versions": {
+ "20140908": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "600363faf89daa6adea87e2dd77263b4",
+ "sha256":
"66255c2f9404484996e646bb825fd2f1fd9d66583fecd3e9e0789376cf055fd4",
+ "size": 3544884,
+ "path": "0.3.3/cirros-0.3.3-x86_64-lxc.tar.gz"
+ },
+ "disk.img": {
+ "ftype": "disk.img",
+ "md5": "133eae9fb1c98f45894a4e60d8736619",
+ "sha256":
"f11286e2bd317ee1a1d0469a6b182b33bda4af6f35ba224ca49d75752c81e20a",
+ "size": 13200896,
+ "path": "0.3.3/cirros-0.3.3-x86_64-disk.img"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "4f3371e52d60e5d47a6fbdd7d6a33973",
+ "sha256":
"6bd27854862c30e25f0312defb9e86f9176b503751f040e323ab83322aa07dae",
+ "size": 8668951,
+ "path": "0.3.3/cirros-0.3.3-x86_64-uec.tar.gz"
+ }
+ },
+ "version": "0.3.3",
+ "pubname": "cirros-0.3.3-x86_64"
+ },
+ "20150422": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "6554ba2d15401c8caa90212ace985593",
+ "sha256":
"e8172c603fad47f4c95e67bd2751c2977e07164c9ebdfcf3f9c1d7ff598ed217",
+ "size": 3555536,
+ "path": "0.3.4/cirros-0.3.4-x86_64-lxc.tar.gz"
+ },
+ "disk.img": {
+ "ftype": "disk.img",
+ "md5": "ee1eca47dc88f4879d8a229cc70a07c6",
+ "sha256":
"34987d0d5702f8813f3ff9efe90e9e39e6926ec78658763580a79face67f3394",
+ "size": 13287936,
+ "path": "0.3.4/cirros-0.3.4-x86_64-disk.img"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "067d511efcc4acd034f7d64b716273bf",
+ "sha256":
"95e77c7deaf0f515f959ffe329918d5dd23e417503d1d45e926a888853c90710",
+ "size": 8683894,
+ "path": "0.3.4/cirros-0.3.4-x86_64-uec.tar.gz"
+ }
+ },
+ "version": "0.3.4",
+ "pubname": "cirros-0.3.4-x86_64"
+ },
+ "20140317": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "174a08e827f22b20ebd774f90f1c9181",
+ "sha256":
"03eff2a3603164fa02c00ca76fdcbd611b2ae8a6a80406753ec35eb275648d2e",
+ "size": 3538286,
+ "path": "0.3.2/cirros-0.3.2-x86_64-lxc.tar.gz"
+ },
+ "disk.img": {
+ "ftype": "disk.img",
+ "md5": "64d7c1cd2b6f60c92c14662941cb7913",
+ "sha256":
"a2ca56aeded5a5bcaa6104fb14ec07b1ceb65222e2890bef8a89b8d2da729ad5",
+ "size": 13167616,
+ "path": "0.3.2/cirros-0.3.2-x86_64-disk.img"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "b369559e3ffa9208b4eb2224c949f579",
+ "sha256":
"f462729fc2f071081dbc55932e07437e265263ef2e688306c353a1f152162b03",
+ "size": 8655821,
+ "path": "0.3.2/cirros-0.3.2-x86_64-uec.tar.gz"
+ }
+ },
+ "version": "0.3.2",
+ "pubname": "cirros-0.3.2-x86_64"
+ },
+ "20111020": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "1a480e5150db4d93be2aa3c9ced94fa1",
+ "sha256":
"0e78796a30641dd7184f752c302a87d66f1eba9985c876911e4f26b4d8ba4a88",
+ "size": 2115217,
+ "path": "0.3.0/cirros-0.3.0-x86_64-lxc.tar.gz"
+ },
+ "disk.img": {
+ "ftype": "disk.img",
+ "md5": "50bdc35edb03a38d91b1b071afb20a3c",
+ "sha256":
"648782e9287288630250d07531fed9944ecc3986764a6664f0bf6c050ec06afd",
+ "size": 9761280,
+ "path": "0.3.0/cirros-0.3.0-x86_64-disk.img"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "f56d3cffa47b7d209d2b6905628f07b9",
+ "sha256":
"043a3e090a5d76d23758a3919fcaff93f77ce7b97594d9d10fc8d00e85f83191",
+ "size": 6957349,
+ "path": "0.3.0/cirros-0.3.0-x86_64-uec.tar.gz"
+ }
+ },
+ "version": "0.3.0",
+ "pubname": "cirros-0.3.0-x86_64"
+ },
+ "20130207": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "38252f1a49fec0ebedebc820854497e0",
+ "sha256":
"a086fcf2758468972d45957dc78ec6317c06f356930dbbc6cad6a8d1855f135e",
+ "size": 3534564,
+ "path": "0.3.1/cirros-0.3.1-x86_64-lxc.tar.gz"
+ },
+ "disk.img": {
+ "ftype": "disk.img",
+ "md5": "d972013792949d0d3ba628fbe8685bce",
+ "sha256":
"e01302fb2d2b13ae65226a0300335172e4487bbe60bb1e5c8b0843a25f126d34",
+ "size": 13147648,
+ "path": "0.3.1/cirros-0.3.1-x86_64-disk.img"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "e1849016cb71a00808093b7bf986f36a",
+ "sha256":
"51eb03b83123a68d4f866c7c15b195204e62db9e33475509a38b79b3122cde38",
+ "size": 8633554,
+ "path": "0.3.1/cirros-0.3.1-x86_64-uec.tar.gz"
+ }
+ },
+ "version": "0.3.1",
+ "pubname": "cirros-0.3.1-x86_64"
+ }
+ },
+ "stream": "released"
+ },
+ "net.cirros-cloud:standard:0.3:powerpc": {
+ "arch": "powerpc",
+ "versions": {
+ "20150422": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "7e3a147b5665a1e14fe6d0ffef9ca410",
+ "sha256":
"b1ab58ebb2a3f253d15cfa13f0cd0de883ce6e80f42ce2e3889e880423e95462",
+ "size": 3603000,
+ "path": "0.3.4/cirros-0.3.4-powerpc-lxc.tar.gz"
+ },
+ "disk.img": {
+ "ftype": "disk.img",
+ "md5": "453b21916c47c6ff8c615f8a5f7b76d2",
+ "sha256":
"5445d77104d19ccdc2dbc943a3d0735c0dadd1227466a3f3e109c19671065f18",
+ "size": 17145856,
+ "path": "0.3.4/cirros-0.3.4-powerpc-disk.img"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "2f8a48928a6b0b2c9afbcb7255ff2aec",
+ "sha256":
"80444c3ac8277d87eed0963567206ea5b009ecf4fdbc71fe8c4df020b42e3215",
+ "size": 12032417,
+ "path": "0.3.4/cirros-0.3.4-powerpc-uec.tar.gz"
+ }
+ }
+ }
+ },
+ "version": "0.3.4",
+ "stream": "released",
+ "pubname": "cirros-0.3.4-powerpc"
+ },
+ "net.cirros-cloud:standard:0.3:arm": {
+ "arch": "arm",
+ "versions": {
+ "20140908": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "7f2fe450d9a0b1688f2a4df6748690f5",
+ "sha256":
"c839db36d5c96651d1dbcfc8a553678b010c7bb49416ac3099282858003fa021",
+ "size": 3482025,
+ "path": "0.3.3/cirros-0.3.3-arm-lxc.tar.gz"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "0437419d2371771b7406fade2d6db7d1",
+ "sha256":
"4a0987818f3a834d9907b93729beb79426e58be9d46b3c207241bc4b1ceec52f",
+ "size": 7351177,
+ "path": "0.3.3/cirros-0.3.3-arm-uec.tar.gz"
+ }
+ },
+ "version": "0.3.3",
+ "pubname": "cirros-0.3.3-arm"
+ },
+ "20150422": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "5fd856d158dc6787264a1b4236126aab",
+ "sha256":
"06c780e8c7166e16154bd0d3a6d1b0031e219269e990c5b8864a82925285486c",
+ "size": 3489736,
+ "path": "0.3.4/cirros-0.3.4-arm-lxc.tar.gz"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "1a2aea370f9f2d95d837f6b84bef658d",
+ "sha256":
"6dd3bad904671aee13317c187d933b3efb1ac39a0d81fd5ac9a1fc694e3cb7ff",
+ "size": 7357906,
+ "path": "0.3.4/cirros-0.3.4-arm-uec.tar.gz"
+ }
+ },
+ "version": "0.3.4",
+ "pubname": "cirros-0.3.4-arm"
+ },
+ "20140317": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "bfb2ecb203cf27f4786b43a558b1ffe8",
+ "sha256":
"a916b3d268793977001e2f09638e4a3e3953cc51d0d53d0bfb8c14cfa7105e86",
+ "size": 3474403,
+ "path": "0.3.2/cirros-0.3.2-arm-lxc.tar.gz"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "171719bfd4b3ec613f5fac321e4216de",
+ "sha256":
"7f74826638e153ec58230bae9eb21805f875ed12eab299140f978e45597cb5cd",
+ "size": 7340357,
+ "path": "0.3.2/cirros-0.3.2-arm-uec.tar.gz"
+ }
+ },
+ "version": "0.3.2",
+ "pubname": "cirros-0.3.2-arm"
+ },
+ "20111020": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "91add49e56cbe6b5004015a4d2f51dbc",
+ "sha256":
"fcd3723c956a1c232730dc28513b466657cbe984232ba2fcc30a4e1f55aa91e9",
+ "size": 2043822,
+ "path": "0.3.0/cirros-0.3.0-arm-lxc.tar.gz"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "c31e05f7829ad45f9d9995c35d232769",
+ "sha256":
"b871823406f818430f57744333b1bb17ce0047e551a316f316641f1bd70d9152",
+ "size": 5761642,
+ "path": "0.3.0/cirros-0.3.0-arm-uec.tar.gz"
+ }
+ },
+ "version": "0.3.0",
+ "pubname": "cirros-0.3.0-arm"
+ },
+ "20130207": {
+ "items": {
+ "lxc.tar.gz": {
+ "ftype": "lxc.tar.gz",
+ "md5": "7ddea367ecb7ecb91554e18bed7c71bd",
+ "sha256":
"2060e59e642b3b2bdf6e34aba3ed15f468bc6f9a8417fc196d01d29b2075493e",
+ "size": 3466149,
+ "path": "0.3.1/cirros-0.3.1-arm-lxc.tar.gz"
+ },
+ "uec.tar.gz": {
+ "ftype": "uec.tar.gz",
+ "md5": "d04e6f26aed123bba2c096581b269e7f",
+ "sha256":
"09dcd3ea6f1d48b3519232973e4dc00fc5e73cbea974cda6b5f7cfa380c6b428",
+ "size": 7314471,
+ "path": "0.3.1/cirros-0.3.1-arm-uec.tar.gz"
+ }
+ },
+ "version": "0.3.1",
+ "pubname": "cirros-0.3.1-arm"
+ }
+ },
+ "stream": "released"
+ }
+ },
+ "datatype": "image-downloads",
+ "format": "products:1.0",
+ "updated": "Fri, 08 May 2015 13:20:51 +0000",
+ "content_id": "net.cirros-cloud:released:download"
+}
diff --git a/builder/test-simplestreams/virt-builder/repos.d/cirros.conf.in
b/builder/test-simplestreams/virt-builder/repos.d/cirros.conf.in
new file mode 100644
index 0000000..a6f2765
--- /dev/null
+++ b/builder/test-simplestreams/virt-builder/repos.d/cirros.conf.in
@@ -0,0 +1,3 @@
+[test-cirros]
+uri=file://@abs_top_builddir@/builder/test-simplestreams
+format=simplestreams
diff --git a/builder/test-virt-builder-list-simplestreams.sh
b/builder/test-virt-builder-list-simplestreams.sh
new file mode 100755
index 0000000..24cf44c
--- /dev/null
+++ b/builder/test-virt-builder-list-simplestreams.sh
@@ -0,0 +1,108 @@
+#!/bin/bash -
+# libguestfs virt-builder test script
+# Copyright (C) 2015 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+export LANG=C
+set -e
+
+abs_builddir=$(pwd)
+
+export XDG_CONFIG_HOME+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
+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
+ echo "$0: unexpected --list output:"
+ echo "$short_list"
+ exit 1
+fi
+
+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:x86_64
+Full name: cirros-0.3.4-x86_64
+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
+ echo "$0: unexpected --list --long output:"
+ echo "$long_list"
+ exit 1
+fi
+
+json_list=$(virt-builder --no-check-signature --no-cache --list --list-format
json)
+
+if [ "$json_list" != "{
+ \"version\": 1,
+ \"sources\": [
+ {
+ \"uri\": \"file://$abs_builddir/test-simplestreams\"
+ }
+ ],
+ \"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\",
+ \"arch\": \"powerpc\",
+ \"size\": 17145856,
+ \"aliases\": [
+ \"cirros-0.3.4-powerpc\"
+ ],
+ \"hidden\": false
+ }
+ ]
+}" ]; then
+ echo "$0: unexpected --list --format json output:"
+ echo "$json_list"
+ exit 1
+fi
diff --git a/builder/virt-builder.pod b/builder/virt-builder.pod
index 710f006..67e017f 100644
--- a/builder/virt-builder.pod
+++ b/builder/virt-builder.pod
@@ -1183,6 +1183,13 @@ The possible values are:
The native format of the C<virt-builder> repository. See also
L</Creating and signing the index file> below.
+=item B<simplestreams>
+
+The URI represents the root of a Simple Streams v1.0 tree of metadata.
+
+For more information about Simple Streams, see also
+L<https://launchpad.net/simplestreams>.
+
=back
If not present, the assumed value is C<native>.
diff --git a/configure.ac b/configure.ac
index 2ce2456..e057660 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1724,6 +1724,7 @@ AC_CONFIG_FILES([Makefile
builder/Makefile
builder/libguestfs.conf
builder/test-config/virt-builder/repos.d/test-index.conf
+ builder/test-simplestreams/virt-builder/repos.d/cirros.conf
builder/test-website/virt-builder/repos.d/libguestfs.conf
builder/website/Makefile
cat/Makefile
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index ff08a53..3f0038e 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -12,6 +12,7 @@ builder/paths.ml
builder/pxzcat.ml
builder/setlocale.ml
builder/sigchecker.ml
+builder/simplestreams_parser.ml
builder/sources.ml
builder/utils.ml
builder/yajl.ml
--
2.1.0
Richard W.M. Jones
2015-Sep-07 16:57 UTC
Re: [Libguestfs] [PATCH 4/4] builder: support Simple Streams v1.0 as index metadata
Looks good, ACK series. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://people.redhat.com/~rjones/virt-df/
Possibly Parallel Threads
- [PATCH 0/4] mltools: JSON unification
- [PATCH 4/4] builder: support Simple Streams v1.0 as index metadata
- [PATCH 0/2 v2] RFC: builder: support for Simple Streams metadata
- [PATCH v2 0/2] mltools: JSON: unify JSON & JSON parser.
- [PATCH 00/10] RFC: builder: first support for Simple Streams metadata