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