compose: Add --write-composejson-to

For higher level tools driving rpm-ostree, the command line arguments
are mostly OK as inputs, but the addition of `--write-commitid-to`
shows that we really want structured data that these tools can parse.
JSON is a good enough interchange format, let's use that.

Most notably this does a pkgdiff in the JSON which several higher
level tools do too.

Closes: #1529
Approved by: jlebon
This commit is contained in:
Colin Walters 2018-09-06 11:22:39 -04:00 committed by Atomic Bot
parent d2aee36f8f
commit 6f6728b992
2 changed files with 114 additions and 11 deletions

View File

@ -43,6 +43,7 @@
#include "rpmostree-rojig-build.h"
#include "rpmostree-postprocess.h"
#include "rpmostree-passwd-util.h"
#include "rpmostree-package-variants.h"
#include "rpmostree-libbuiltin.h"
#include "rpmostree-rpm-util.h"
#include "rpmostree-rust.h"
@ -67,6 +68,7 @@ static char *opt_touch_if_changed;
static gboolean opt_dry_run;
static gboolean opt_print_only;
static char *opt_write_commitid_to;
static char *opt_write_composejson_to;
/* shared by both install & commit */
static GOptionEntry common_option_entries[] = {
@ -103,6 +105,7 @@ static GOptionEntry commit_option_entries[] = {
{ "add-metadata-string", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_strings, "Append given key and value (in string format) to metadata", "KEY=VALUE" },
{ "add-metadata-from-json", 0, 0, G_OPTION_ARG_STRING, &opt_metadata_json, "Parse the given JSON file as object, convert to GVariant, append to OSTree commit", "JSON" },
{ "write-commitid-to", 0, 0, G_OPTION_ARG_STRING, &opt_write_commitid_to, "File to write the composed commitid to instead of updating the ref", "FILE" },
{ "write-composejson-to", 0, 0, G_OPTION_ARG_STRING, &opt_write_composejson_to, "Write JSON to FILE containing information about the compose run", "FILE" },
{ NULL }
};
@ -417,6 +420,24 @@ treespec_bind_bool (JsonObject *treedata,
return TRUE;
}
static gboolean
inputhash_from_commit (OstreeRepo *repo,
const char *sha256,
char **out_value, /* inout Option<String> */
GError **error)
{
g_autoptr(GVariant) commit_v = NULL;
if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT,
sha256, &commit_v, error))
return FALSE;
g_autoptr(GVariant) commit_metadata = g_variant_get_child_value (commit_v, 0);
g_assert (out_value);
*out_value = NULL;
g_variant_lookup (commit_metadata, "rpmostree.inputhash", "s", out_value);
return TRUE;
}
static gboolean
install_packages_in_root (RpmOstreeTreeComposeContext *self,
JsonObject *treedata,
@ -561,17 +582,12 @@ install_packages_in_root (RpmOstreeTreeComposeContext *self,
/* Only look for previous checksum if caller has passed *out_unmodified */
if (self->previous_checksum && out_unmodified != NULL)
{
g_autoptr(GVariant) commit_v = NULL;
g_autoptr(GVariant) commit_metadata = NULL;
const char *previous_inputhash = NULL;
if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_COMMIT,
self->previous_checksum,
&commit_v, error))
g_autofree char *previous_inputhash = NULL;
if (!inputhash_from_commit (self->repo, self->previous_checksum,
&previous_inputhash, error))
return FALSE;
commit_metadata = g_variant_get_child_value (commit_v, 0);
if (g_variant_lookup (commit_metadata, "rpmostree.inputhash", "&s", &previous_inputhash))
if (previous_inputhash)
{
if (strcmp (previous_inputhash, ret_new_inputhash) == 0)
{
@ -1283,6 +1299,9 @@ impl_commit_tree (RpmOstreeTreeComposeContext *self,
GCancellable *cancellable,
GError **error)
{
g_auto(GVariantBuilder) composemeta_builder;
g_variant_builder_init (&composemeta_builder, G_VARIANT_TYPE ("a{sv}"));
const char *gpgkey = NULL;
if (!_rpmostree_jsonutil_object_get_optional_string_member (self->treefile, "gpg_key", &gpgkey, error))
return FALSE;
@ -1369,6 +1388,12 @@ impl_commit_tree (RpmOstreeTreeComposeContext *self,
&new_revision, cancellable, error))
return FALSE;
g_autoptr(GVariant) new_commit = NULL;
if (!ostree_repo_load_commit (self->repo, new_revision, &new_commit,
NULL, error))
return FALSE;
g_autoptr(GVariant) new_commit_inline_meta = g_variant_get_child_value (new_commit, 0);
const char *rojig_outputdir = opt_ex_jigdo_output_rpm ?: opt_ex_jigdo_output_set;
if (rojig_outputdir)
{
@ -1402,13 +1427,40 @@ impl_commit_tree (RpmOstreeTreeComposeContext *self,
if (!ostree_repo_commit_transaction (self->repo, &stats, cancellable, error))
return glnx_prefix_error (error, "Commit");
g_variant_builder_add (&composemeta_builder, "{sv}", "ostree-n-metadata-total",
g_variant_new_uint32 (stats.metadata_objects_total));
g_print ("Metadata Total: %u\n", stats.metadata_objects_total);
g_variant_builder_add (&composemeta_builder, "{sv}", "ostree-n-metadata-written",
g_variant_new_uint32 (stats.metadata_objects_written));
g_print ("Metadata Written: %u\n", stats.metadata_objects_written);
g_variant_builder_add (&composemeta_builder, "{sv}", "ostree-n-content-total",
g_variant_new_uint32 (stats.content_objects_total));
g_print ("Content Total: %u\n", stats.content_objects_total);
g_print ("Content Written: %u\n", stats.content_objects_written);
g_variant_builder_add (&composemeta_builder, "{sv}", "ostree-n-content-written",
g_variant_new_uint32 (stats.content_objects_written));
g_print ("Content Bytes Written: %" G_GUINT64_FORMAT "\n", stats.content_bytes_written);
g_variant_builder_add (&composemeta_builder, "{sv}", "ostree-content-bytes-written",
g_variant_new_uint64 (stats.content_bytes_written));
}
g_print ("Wrote commit: %s\n", new_revision);
g_variant_builder_add (&composemeta_builder, "{sv}", "ostree-commit", g_variant_new_string (new_revision));
const char *commit_version = NULL;
(void)g_variant_lookup (new_commit_inline_meta, OSTREE_COMMIT_META_KEY_VERSION, "&s", &commit_version);
if (commit_version)
g_variant_builder_add (&composemeta_builder, "{sv}", "ostree-version", g_variant_new_string (commit_version));
const char *inputhash = NULL;
(void)g_variant_lookup (new_commit_inline_meta, "rpmostree.inputhash", "&s", &inputhash);
/* We may not have the inputhash in the split-up installroot case */
if (inputhash)
g_variant_builder_add (&composemeta_builder, "{sv}", "rpm-ostree-inputhash", g_variant_new_string (inputhash));
if (parent_revision)
g_variant_builder_add (&composemeta_builder, "{sv}", "ostree-parent-commit", g_variant_new_string (parent_revision));
if (opt_write_commitid_to)
{
@ -1416,7 +1468,47 @@ impl_commit_tree (RpmOstreeTreeComposeContext *self,
return glnx_prefix_error (error, "While writing to '%s'", opt_write_commitid_to);
}
else if (self->ref)
g_print ("%s => %s\n", self->ref, new_revision);
{
g_print ("%s => %s\n", self->ref, new_revision);
g_variant_builder_add (&composemeta_builder, "{sv}", "ref", g_variant_new_string (self->ref));
}
if (opt_write_composejson_to && parent_revision)
{
g_autoptr(GVariant) diffv = NULL;
if (!rpm_ostree_db_diff_variant (self->repo, parent_revision, new_revision,
FALSE, &diffv, cancellable, error))
return FALSE;
g_variant_builder_add (&composemeta_builder, "{sv}", "pkgdiff", diffv);
}
if (opt_write_composejson_to)
{
g_autoptr(GVariant) composemeta_v = g_variant_builder_end (&composemeta_builder);
JsonNode *composemeta_node = json_gvariant_serialize (composemeta_v);
glnx_unref_object JsonGenerator *generator = json_generator_new ();
json_generator_set_root (generator, composemeta_node);
char *dnbuf = strdupa (opt_write_composejson_to);
const char *dn = dirname (dnbuf);
g_auto(GLnxTmpfile) tmpf = { 0, };
if (!glnx_open_tmpfile_linkable_at (AT_FDCWD, dn, O_WRONLY | O_CLOEXEC,
&tmpf, error))
return FALSE;
g_autoptr(GOutputStream) out = g_unix_output_stream_new (tmpf.fd, FALSE);
/* See also similar code in status.c */
if (json_generator_to_stream (generator, out, NULL, error) <= 0
|| (error != NULL && *error != NULL))
return FALSE;
/* World readable to match --write-commitid-to which uses umask */
if (!glnx_fchmod (tmpf.fd, 0644, error))
return FALSE;
if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_REPLACE,
AT_FDCWD, opt_write_composejson_to, error))
return FALSE;
}
return TRUE;
}

View File

@ -6,7 +6,8 @@ dn=$(cd $(dirname $0) && pwd)
. ${dn}/libcomposetest.sh
prepare_compose_test "write-commitid"
runcompose --write-commitid-to $(pwd)/commitid.txt
runcompose --write-commitid-to $(pwd)/commitid.txt \
--write-composejson-to $(pwd)/composemeta.json
wc -c < commitid.txt > wc.txt
assert_file_has_content_literal wc.txt 64
echo "ok compose"
@ -16,3 +17,13 @@ if ostree --repo=${repobuild} rev-parse ${treeref}; then
fatal "Found ${treeref} ?"
fi
echo "ok ref not written"
commitid_txt=$(cat commitid.txt)
json_commit=$(jq -r '.["ostree-commit"]' composemeta.json)
assert_streq "${json_commit}" "${commitid_txt}"
# And verify we have other keys
for key in ostree-version rpm-ostree-inputhash ostree-content-bytes-written; do
jq -r '.["'${key}'"]' composemeta.json >/dev/null
done
echo "ok composejson"