diff --git a/src/app/rpmostree-db-builtin-diff.c b/src/app/rpmostree-db-builtin-diff.c index e513cf21..942b36b5 100644 --- a/src/app/rpmostree-db-builtin-diff.c +++ b/src/app/rpmostree-db-builtin-diff.c @@ -20,10 +20,15 @@ #include "config.h" +#include +#include +#include + #include "rpmostree.h" #include "rpmostree-db-builtins.h" #include "rpmostree-libbuiltin.h" #include "rpmostree-rpm-util.h" +#include "rpmostree-package-variants.h" static char *opt_format = "block"; static gboolean opt_changelogs; @@ -31,7 +36,7 @@ static char *opt_sysroot; static gboolean opt_base; static GOptionEntry option_entries[] = { - { "format", 'F', 0, G_OPTION_ARG_STRING, &opt_format, "Output format: \"diff\" or (default) \"block\"", "FORMAT" }, + { "format", 'F', 0, G_OPTION_ARG_STRING, &opt_format, "Output format: \"diff\" or \"json\" or (default) \"block\"", "FORMAT" }, { "changelogs", 'c', 0, G_OPTION_ARG_NONE, &opt_changelogs, "Also output RPM changelogs", NULL }, { "sysroot", 0, 0, G_OPTION_ARG_STRING, &opt_sysroot, "Use system root SYSROOT (default: /)", "SYSROOT" }, { "base", 0, 0, G_OPTION_ARG_NONE, &opt_base, "Diff against deployments' base, not layered commits", NULL }, @@ -157,6 +162,12 @@ rpmostree_db_builtin_diff (int argc, char **argv, return FALSE; } + if (g_str_equal (opt_format, "json") && opt_changelogs) + { + rpmostree_usage_error (context, "json format and --changelogs not supported", error); + return FALSE; + } + const char *old_desc = NULL; g_autofree char *old_checksum = NULL; const char *new_desc = NULL; @@ -221,6 +232,36 @@ rpmostree_db_builtin_diff (int argc, char **argv, } + if (g_str_equal (opt_format, "json")) + { + g_auto(GVariantBuilder) builder; + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&builder, "{sv}", "ostree-commit-from", + g_variant_new_string (old_checksum)); + g_variant_builder_add (&builder, "{sv}", "ostree-commit-to", + g_variant_new_string (new_checksum)); + + g_autoptr(GVariant) diffv = NULL; + if (!rpm_ostree_db_diff_variant (repo, old_checksum, new_checksum, + FALSE, &diffv, cancellable, error)) + return FALSE; + g_variant_builder_add (&builder, "{sv}", "pkgdiff", diffv); + g_autoptr(GVariant) metadata = g_variant_builder_end (&builder); + + JsonNode *node = json_gvariant_serialize (metadata); + glnx_unref_object JsonGenerator *generator = json_generator_new (); + json_generator_set_pretty (generator, TRUE); + json_generator_set_root (generator, node); + + glnx_unref_object GOutputStream *stdout_gio = g_unix_output_stream_new (1, FALSE); + /* NB: watch out for the misleading API docs */ + if (json_generator_to_stream (generator, stdout_gio, cancellable, error) <= 0 + || (error != NULL && *error != NULL)) + return FALSE; + + return TRUE; + } + return print_diff (repo, old_desc, old_checksum, new_desc, new_checksum, cancellable, error); } diff --git a/tests/vmcheck/test-db.sh b/tests/vmcheck/test-db.sh index 4e03e1f5..5d762c3f 100755 --- a/tests/vmcheck/test-db.sh +++ b/tests/vmcheck/test-db.sh @@ -73,6 +73,15 @@ check_diff $booted_csum $pending_csum \ +pkg-to-replace \ +pkg-to-replace-archtrans +# also check the diff using json +vm_rpmostree db diff --format=json $booted_csum $pending_csum > diff.json +# See assert_replaced_local_pkg() for some syntax explanation. The .[1] == 0 bit +# is what filters by "pkgs added". +assert_jq diff.json \ + '[.pkgdiff|map(select(.[1] == 0))[][0]]|index("pkg-to-remove") >= 0' \ + '[.pkgdiff|map(select(.[1] == 0))[][0]]|index("pkg-to-replace") >= 0' \ + '[.pkgdiff|map(select(.[1] == 0))[][0]]|index("pkg-to-replace-archtrans") >= 0' + # check that it's the default behaviour without both args check_diff "" "" \ +pkg-to-remove \