Pino Toscano
2014-Jan-16 14:04 UTC
[Libguestfs] [PATCH 0/3] Add JSON output for virt-builder
Hi, This small patch serie adds a JSON output for virt-builder. This way it is possible to parse the list of available templates, with no need to parse the unstructured and possibly changing short and long outputs of virt-builder. Pino Toscano (3): builder: small refactor of the list output builder: add --list-format builder: add a JSON output for --list builder/builder.ml | 4 +- builder/cmdline.ml | 19 +++-- builder/list_entries.ml | 142 ++++++++++++++++++++++++++++---------- builder/list_entries.mli | 2 +- builder/test-virt-builder-list.sh | 67 ++++++++++++++++++ builder/virt-builder.pod | 34 ++++++++- 6 files changed, 222 insertions(+), 46 deletions(-) -- 1.8.3.1
Pino Toscano
2014-Jan-16 14:04 UTC
[Libguestfs] [PATCH 1/3] builder: small refactor of the list output
Switch from a boolean for the short/long list output to labels for the actual format. Also, split the output of each list format to an own function for easier maintaineance. --- builder/builder.ml | 4 +-- builder/cmdline.ml | 9 +++--- builder/list_entries.ml | 82 +++++++++++++++++++++++++++--------------------- builder/list_entries.mli | 2 +- 4 files changed, 54 insertions(+), 43 deletions(-) diff --git a/builder/builder.ml b/builder/builder.ml index 861e029..bb0b108 100644 --- a/builder/builder.ml +++ b/builder/builder.ml @@ -37,7 +37,7 @@ let main () (* Command line argument parsing - see cmdline.ml. *) let mode, arg, attach, cache, check_signature, curl, debug, delete, delete_on_failure, - edit, firstboot, run, format, gpg, hostname, install, list_long, links, + edit, firstboot, run, format, gpg, hostname, install, list_format, links, memsize, mkdirs, network, output, password_crypto, quiet, root_password, scrub, scrub_logfile, size, smp, sources, sync, timezone, update, upload, @@ -148,7 +148,7 @@ let main () let mode match mode with | `List -> (* --list *) - List_entries.list_entries ~list_long ~sources index; + List_entries.list_entries ~list_format ~sources index; exit 0 | `Print_cache -> (* --print-cache *) diff --git a/builder/cmdline.ml b/builder/cmdline.ml index 67b142a..f199f03 100644 --- a/builder/cmdline.ml +++ b/builder/cmdline.ml @@ -130,7 +130,8 @@ let parse_cmdline () links := (target, lns) :: !links in - let list_long = ref false in + let list_format = ref `Short in + let list_set_long () = list_format := `Long in let memsize = ref None in let set_memsize arg = memsize := Some arg in @@ -255,7 +256,7 @@ let parse_cmdline () "--link", Arg.String add_link, "target:link.." ^ " " ^ s_"Create symbolic links"; "-l", Arg.Unit list_mode, " " ^ s_"List available templates"; "--list", Arg.Unit list_mode, ditto; - "--long", Arg.Set list_long, ditto; + "--long", Arg.Unit list_set_long, " " ^ s_"List available templates, in long textual form"; "--no-logfile", Arg.Set scrub_logfile, " " ^ s_"Scrub build log file"; "--long-options", Arg.Unit display_long_options, " " ^ s_"List long options"; "-m", Arg.Int set_memsize, "mb" ^ " " ^ s_"Set memory size"; @@ -329,7 +330,7 @@ read the man page virt-builder(1). let gpg = !gpg in let hostname = !hostname in let install = List.rev !install in - let list_long = !list_long in + let list_format = !list_format in let links = List.rev !links in let memsize = !memsize in let mkdirs = List.rev !mkdirs in @@ -443,7 +444,7 @@ read the man page virt-builder(1). mode, arg, attach, cache, check_signature, curl, debug, delete, delete_on_failure, - edit, firstboot, run, format, gpg, hostname, install, list_long, links, + edit, firstboot, run, format, gpg, hostname, install, list_format, links, memsize, mkdirs, network, output, password_crypto, quiet, root_password, scrub, scrub_logfile, size, smp, sources, sync, timezone, update, upload, diff --git a/builder/list_entries.ml b/builder/list_entries.ml index 87001c0..97ab201 100644 --- a/builder/list_entries.ml +++ b/builder/list_entries.ml @@ -21,15 +21,35 @@ open Common_utils open Printf -let list_entries ?(list_long = false) ~sources index - if list_long then ( - List.iter ( - fun (source, fingerprint) -> - printf (f_"Source URI: %s\n") source; - printf (f_"Fingerprint: %s\n") fingerprint; +let rec list_entries ~list_format ~sources index + match list_format with + | `Short -> list_entries_short index + | `Long -> list_entries_long ~sources index + +and list_entries_short index + List.iter ( + fun (name, { Index_parser.printable_name = printable_name; + size = size; + compressed_size = compressed_size; + notes = notes; + hidden = hidden }) -> + if not hidden then ( + printf "%-24s" name; + (match printable_name with + | None -> () + | Some s -> printf " %s" s + ); printf "\n" - ) sources - ); + ) + ) index + +and list_entries_long ~sources index + List.iter ( + fun (source, fingerprint) -> + printf (f_"Source URI: %s\n") source; + printf (f_"Fingerprint: %s\n") fingerprint; + printf "\n" + ) sources; List.iter ( fun (name, { Index_parser.printable_name = printable_name; @@ -38,33 +58,23 @@ let list_entries ?(list_long = false) ~sources index notes = notes; hidden = hidden }) -> if not hidden then ( - if not list_long then ( (* Short *) - printf "%-24s" name; - (match printable_name with - | None -> () - | Some s -> printf " %s" s - ); - printf "\n" - ) - else ( (* Long *) - printf "%-24s %s\n" "os-version:" name; - (match printable_name with - | None -> () - | Some name -> printf "%-24s %s\n" (s_"Full name:") name; - ); - printf "%-24s %s\n" (s_"Minimum/default size:") (human_size size); - (match compressed_size with - | None -> () - | Some size -> - printf "%-24s %s\n" (s_"Download size:") (human_size size); - ); - (match notes with - | None -> () - | Some notes -> - printf "\n"; - printf (f_"Notes:\n\n%s\n") notes - ); - printf "\n" - ) + printf "%-24s %s\n" "os-version:" name; + (match printable_name with + | None -> () + | Some name -> printf "%-24s %s\n" (s_"Full name:") name; + ); + printf "%-24s %s\n" (s_"Minimum/default size:") (human_size size); + (match compressed_size with + | None -> () + | Some size -> + printf "%-24s %s\n" (s_"Download size:") (human_size size); + ); + (match notes with + | None -> () + | Some notes -> + printf "\n"; + printf (f_"Notes:\n\n%s\n") notes + ); + printf "\n" ) ) index diff --git a/builder/list_entries.mli b/builder/list_entries.mli index d9486b0..41d0bff 100644 --- a/builder/list_entries.mli +++ b/builder/list_entries.mli @@ -16,4 +16,4 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *) -val list_entries : ?list_long:bool -> sources:(string * string) list -> Index_parser.index -> unit +val list_entries : list_format:([ `Short | `Long ]) -> sources:(string * string) list -> Index_parser.index -> unit -- 1.8.3.1
Add a --list-format which allows to choose which in format should be the output of --list. --- builder/cmdline.ml | 11 ++++++++++- builder/virt-builder.pod | 24 +++++++++++++++++++++--- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/builder/cmdline.ml b/builder/cmdline.ml index f199f03..6d6439f 100644 --- a/builder/cmdline.ml +++ b/builder/cmdline.ml @@ -132,6 +132,13 @@ let parse_cmdline () let list_format = ref `Short in let list_set_long () = list_format := `Long in + let list_set_format arg + list_format := match arg with + | "short" -> `Short + | "long" -> `Long + | fmt -> + eprintf (f_"%s: invalid --list-format type '%s', see the man page.\n") prog fmt; + exit 1 in let memsize = ref None in let set_memsize arg = memsize := Some arg in @@ -256,7 +263,9 @@ let parse_cmdline () "--link", Arg.String add_link, "target:link.." ^ " " ^ s_"Create symbolic links"; "-l", Arg.Unit list_mode, " " ^ s_"List available templates"; "--list", Arg.Unit list_mode, ditto; - "--long", Arg.Unit list_set_long, " " ^ s_"List available templates, in long textual form"; + "--long", Arg.Unit list_set_long, " " ^ s_"Shortcut for --list-format short"; + "--list-format", Arg.String list_set_format, + "short|long" ^ " " ^ s_"Set the format for --list (default: short)"; "--no-logfile", Arg.Set scrub_logfile, " " ^ s_"Scrub build log file"; "--long-options", Arg.Unit display_long_options, " " ^ s_"List long options"; "-m", Arg.Int set_memsize, "mb" ^ " " ^ s_"Set memory size"; diff --git a/builder/virt-builder.pod b/builder/virt-builder.pod index 9cbfbab..05abcc6 100644 --- a/builder/virt-builder.pod +++ b/builder/virt-builder.pod @@ -31,7 +31,7 @@ virt-builder - Build virtual machine images quickly [--firstboot SCRIPT] [--firstboot-command 'CMD ARGS ...'] [--firstboot-install PKG,[PKG...]] - virt-builder -l|--list [--long] + virt-builder -l|--list [--long] [--list-format short|long] virt-builder --notes os-version @@ -374,12 +374,30 @@ pointing at C<TARGET>. =item B<--list> +=item B<--list --format> format + =item B<--list --long> List available templates. -The alternative I<--list --long> form shows lots more details about -each operating system option. +It is possible to choose with I<--format> the output format for the list +templates: + +=over 4 + +=item B<short> + +The default format, prints only the template identifier and, next to it, +its short description. + +=item B<long> + +Prints a textual list with the details of the available sources, followed +by the details of the available templates. + +=back + +I<--long> is a shorthand for the C<long> format. See also: I<--source>, I<--notes>, L</CREATING YOUR OWN TEMPLATES>. -- 1.8.3.1
Pino Toscano
2014-Jan-16 14:04 UTC
[Libguestfs] [PATCH 3/3] builder: add a JSON output for --list
Simple JSON output for sources and templates, to be able to query them with no need to parse unstructured outputs like the "--list-format long" one. --- builder/cmdline.ml | 3 +- builder/list_entries.ml | 60 +++++++++++++++++++++++++++++++++++ builder/list_entries.mli | 2 +- builder/test-virt-builder-list.sh | 67 +++++++++++++++++++++++++++++++++++++++ builder/virt-builder.pod | 12 ++++++- 5 files changed, 141 insertions(+), 3 deletions(-) diff --git a/builder/cmdline.ml b/builder/cmdline.ml index 6d6439f..e3b1484 100644 --- a/builder/cmdline.ml +++ b/builder/cmdline.ml @@ -136,6 +136,7 @@ let parse_cmdline () list_format := match arg with | "short" -> `Short | "long" -> `Long + | "json" -> `Json | fmt -> eprintf (f_"%s: invalid --list-format type '%s', see the man page.\n") prog fmt; exit 1 in @@ -265,7 +266,7 @@ let parse_cmdline () "--list", Arg.Unit list_mode, ditto; "--long", Arg.Unit list_set_long, " " ^ s_"Shortcut for --list-format short"; "--list-format", Arg.String list_set_format, - "short|long" ^ " " ^ s_"Set the format for --list (default: short)"; + "short|long|json" ^ " " ^ s_"Set the format for --list (default: short)"; "--no-logfile", Arg.Set scrub_logfile, " " ^ s_"Scrub build log file"; "--long-options", Arg.Unit display_long_options, " " ^ s_"List long options"; "-m", Arg.Int set_memsize, "mb" ^ " " ^ s_"Set memory size"; diff --git a/builder/list_entries.ml b/builder/list_entries.ml index 97ab201..7369e6c 100644 --- a/builder/list_entries.ml +++ b/builder/list_entries.ml @@ -25,6 +25,7 @@ let rec list_entries ~list_format ~sources index match list_format with | `Short -> list_entries_short index | `Long -> list_entries_long ~sources index + | `Json -> list_entries_json ~sources index and list_entries_short index List.iter ( @@ -78,3 +79,62 @@ and list_entries_long ~sources index printf "\n" ) ) index + +and list_entries_json ~sources index + let trailing_comma index size + if index = size - 1 then "" else "," in + let json_string_of_bool b + if b then "true" else "false" in + let json_string_escape str + let res = ref "" in + for i = 0 to String.length str - 1 do + res := !res ^ (match str.[i] with + | '"' -> "\\\"" + | '\\' -> "\\\\" + | '\b' -> "\\b" + | '\n' -> "\\n" + | '\r' -> "\\r" + | '\t' -> "\\t" + | c -> String.make 1 c) + done; + !res in + let json_optional_printf_string key value + match value with + | None -> () + | Some str -> + printf " \"%s\": \"%s\",\n" key (json_string_escape str) in + let json_optional_printf_int64 key value + match value with + | None -> () + | Some n -> + printf " \"%s\": \"%Ld\",\n" key n in + + printf "{\n"; + printf " \"version\": %d,\n" 1; + printf " \"sources\": [\n"; + iteri ( + fun i (source, fingerprint) -> + printf " {\n"; + printf " \"uri\": \"%s\",\n" source; + printf " \"fingerprint\": \"%s\"\n" fingerprint; + printf " }%s\n" (trailing_comma i (List.length sources)) + ) sources; + printf " ],\n"; + printf " \"templates\": [\n"; + iteri ( + fun i (name, { Index_parser.printable_name = printable_name; + size = size; + compressed_size = compressed_size; + notes = notes; + hidden = hidden }) -> + printf " {\n"; + printf " \"os-version\": \"%s\",\n" name; + json_optional_printf_string "full-name" printable_name; + printf " \"size\": %Ld,\n" size; + json_optional_printf_int64 "compressed-size" compressed_size; + json_optional_printf_string "notes" notes; + printf " \"hidden\": %s\n" (json_string_of_bool hidden); + printf " }%s\n" (trailing_comma i (List.length index)) + ) index; + printf " ]\n"; + printf "}\n" diff --git a/builder/list_entries.mli b/builder/list_entries.mli index 41d0bff..e7c32f1 100644 --- a/builder/list_entries.mli +++ b/builder/list_entries.mli @@ -16,4 +16,4 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *) -val list_entries : list_format:([ `Short | `Long ]) -> sources:(string * string) list -> Index_parser.index -> unit +val list_entries : list_format:([ `Short | `Long | `Json ]) -> sources:(string * string) list -> Index_parser.index -> unit diff --git a/builder/test-virt-builder-list.sh b/builder/test-virt-builder-list.sh index 083c035..c3b791f 100755 --- a/builder/test-virt-builder-list.sh +++ b/builder/test-virt-builder-list.sh @@ -103,3 +103,70 @@ Phony Windows look-alike used for testing." ]; then 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\": \"$VIRT_BUILDER_SOURCE\", + \"fingerprint\": \"F777 4FB1 AD07 4A7E 8C87 67EA 9173 8F73 E1B7 68A0\" + } + ], + \"templates\": [ + { + \"os-version\": \"phony-debian\", + \"full-name\": \"Phony Debian\", + \"size\": 536870912, + \"notes\": \"Phony Debian look-alike used for testing.\", + \"hidden\": false + }, + { + \"os-version\": \"phony-fedora\", + \"full-name\": \"Phony Fedora\", + \"size\": 1073741824, + \"notes\": \"Phony Fedora look-alike used for testing.\", + \"hidden\": false + }, + { + \"os-version\": \"phony-fedora-qcow2\", + \"full-name\": \"Phony Fedora qcow2\", + \"size\": 1073741824, + \"notes\": \"Phony Fedora look-alike used for testing.\", + \"hidden\": false + }, + { + \"os-version\": \"phony-fedora-qcow2-uncompressed\", + \"full-name\": \"Phony Fedora qcow2 uncompressed\", + \"size\": 1073741824, + \"notes\": \"Phony Fedora look-alike used for testing.\", + \"hidden\": false + }, + { + \"os-version\": \"phony-fedora-no-format\", + \"full-name\": \"Phony Fedora\", + \"size\": 1073741824, + \"notes\": \"Phony Fedora look-alike used for testing.\", + \"hidden\": false + }, + { + \"os-version\": \"phony-ubuntu\", + \"full-name\": \"Phony Ubuntu\", + \"size\": 536870912, + \"notes\": \"Phony Ubuntu look-alike used for testing.\", + \"hidden\": false + }, + { + \"os-version\": \"phony-windows\", + \"full-name\": \"Phony Windows\", + \"size\": 536870912, + \"notes\": \"Phony Windows look-alike used for testing.\", + \"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 05abcc6..ded045b 100644 --- a/builder/virt-builder.pod +++ b/builder/virt-builder.pod @@ -31,7 +31,7 @@ virt-builder - Build virtual machine images quickly [--firstboot SCRIPT] [--firstboot-command 'CMD ARGS ...'] [--firstboot-install PKG,[PKG...]] - virt-builder -l|--list [--long] [--list-format short|long] + virt-builder -l|--list [--long] [--list-format short|long|json] virt-builder --notes os-version @@ -395,6 +395,16 @@ its short description. Prints a textual list with the details of the available sources, followed by the details of the available templates. +=item B<json> + +Prints a JSON object with the details of the available sources and +the details of the available templates. + +The C<version> key in the main object represents the "compatibility version", +and it is bumped every time the resulting JSON output is incompatible with +the previous versions (for example the structure has changed, or non-optional +keys are no more present). + =back I<--long> is a shorthand for the C<long> format. -- 1.8.3.1
Richard W.M. Jones
2014-Jan-16 15:44 UTC
Re: [Libguestfs] [PATCH 2/3] builder: add --list-format
On Thu, Jan 16, 2014 at 03:04:31PM +0100, Pino Toscano wrote:> Add a --list-format which allows to choose which in format should be the > output of --list. > --- > builder/cmdline.ml | 11 ++++++++++- > builder/virt-builder.pod | 24 +++++++++++++++++++++--- > 2 files changed, 31 insertions(+), 4 deletions(-) > > diff --git a/builder/cmdline.ml b/builder/cmdline.ml > index f199f03..6d6439f 100644 > --- a/builder/cmdline.ml > +++ b/builder/cmdline.ml > @@ -132,6 +132,13 @@ let parse_cmdline () > > let list_format = ref `Short in > let list_set_long () = list_format := `Long in > + let list_set_format arg > + list_format := match arg with > + | "short" -> `Short > + | "long" -> `Long > + | fmt -> > + eprintf (f_"%s: invalid --list-format type '%s', see the man page.\n") prog fmt; > + exit 1 inIt's possible to write this as: let list_set_format = function | "short" -> list_format := `Short etc. Not sure if it will make any difference here. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://people.redhat.com/~rjones/virt-top
Richard W.M. Jones
2014-Jan-16 15:58 UTC
Re: [Libguestfs] [PATCH 3/3] builder: add a JSON output for --list
On Thu, Jan 16, 2014 at 03:04:32PM +0100, Pino Toscano wrote:> + let json_optional_printf_string key value > + match value with > + | None -> () > + | Some str -> > + printf " \"%s\": \"%s\",\n" key (json_string_escape str) in > + let json_optional_printf_int64 key value > + match value with > + | None -> () > + | Some n -> > + printf " \"%s\": \"%Ld\",\n" key n inAgain you can shorten these slightly by: let json_optional_printf_string key = function | None -> () | Some str -> ... Anyway, *ACK* to this patch series. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-p2v converts physical machines to virtual machines. Boot with a live CD or over the network (PXE) and turn machines into KVM guests. http://libguestfs.org/virt-v2v