From 939791b4fa528bd69d25ecb9354b0a3013c45be8 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Tue, 9 Jan 2018 20:29:22 +0000 Subject: [PATCH] bin/commit: add --keep-metadata option Clients of libostree such as rpm-ostree make extensive use of the `ostree commit -b foo --tree=ref=foo` pattern in their tests, e.g. to simulate an update. What I'm trying to solve here is that it's often the case that we want to keep metadata from the previous commit without having to be too verbose (i.e. reading from the parent, then passing it as an argument). The new `--keep-metadata` switch makes this really easy. I intend to use this in the rpm-ostree testsuite to make sure we always carry over the `source-title` metadata as well as during set up for tests that require `rpmostree.rpmdb.pkglist` metadata. I initially implemented this in a small wrapper script that uses the API directly, though we make use of so many other `ostree commit` functions that it'd require re-implementing a lot of it. Closes: #1402 Approved by: cgwalters --- bash/ostree | 1 + src/ostree/ot-builtin-commit.c | 37 +++++++++++++++++++++++++++++++++- tests/basic-test.sh | 14 ++++++++++++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/bash/ostree b/bash/ostree index 0ba135e7..a6eb56de 100644 --- a/bash/ostree +++ b/bash/ostree @@ -783,6 +783,7 @@ _ostree_commit() { local options_with_args=" --add-detached-metadata-string --add-metadata-string + --keep-metadata --bind-ref --body -m --body-file -F diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index 842d07d1..5e5cddd1 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -45,6 +45,7 @@ static char *opt_skiplist_file; static char **opt_metadata_strings; static char **opt_metadata_variants; static char **opt_detached_metadata_strings; +static char **opt_metadata_keep; static gboolean opt_link_checkout_speedup; static gboolean opt_skip_if_unchanged; static gboolean opt_tar_autocreate_parents; @@ -96,6 +97,7 @@ static GOptionEntry options[] = { { "tree", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_trees, "Overlay the given argument as a tree", "dir=PATH or tar=TARFILE or ref=COMMIT" }, { "add-metadata-string", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_strings, "Add a key/value pair to metadata", "KEY=VALUE" }, { "add-metadata", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_variants, "Add a key/value pair to metadata, where the KEY is a string, an VALUE is g_variant_parse() formatted", "KEY=VALUE" }, + { "keep-metadata", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_keep, "Keep metadata KEY and its associated VALUE from parent", "KEY" }, { "add-detached-metadata-string", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_detached_metadata_strings, "Add a key/value pair to detached metadata", "KEY=VALUE" }, { "owner-uid", 0, 0, G_OPTION_ARG_INT, &opt_owner_uid, "Set file ownership user id", "UID" }, { "owner-gid", 0, 0, G_OPTION_ARG_INT, &opt_owner_gid, "Set file ownership group id", "GID" }, @@ -498,7 +500,15 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio } } - if (opt_metadata_strings || opt_metadata_variants) + if (!parent && opt_metadata_keep) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Either --branch or --parent must be specified when using " + "--keep-metadata"); + goto out; + } + + if (opt_metadata_strings || opt_metadata_variants || opt_metadata_keep) { g_autoptr(GVariantBuilder) builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); @@ -511,6 +521,31 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio !parse_keyvalue_strings (builder, opt_metadata_variants, TRUE, error)) goto out; + if (opt_metadata_keep) + { + g_assert (parent); + + g_autoptr(GVariant) parent_commit = NULL; + if (!ostree_repo_load_commit (repo, parent, &parent_commit, NULL, error)) + goto out; + + g_auto(GVariantDict) dict; + g_variant_dict_init (&dict, g_variant_get_child_value (parent_commit, 0)); + for (char **keyp = opt_metadata_keep; keyp && *keyp; keyp++) + { + const char *key = *keyp; + g_autoptr(GVariant) val = g_variant_dict_lookup_value (&dict, key, NULL); + if (!val) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Missing metadata key '%s' from commit '%s'", key, parent); + goto out; + } + + g_variant_builder_add (builder, "{sv}", key, val); + } + } + metadata = g_variant_ref_sink (g_variant_builder_end (builder)); } diff --git a/tests/basic-test.sh b/tests/basic-test.sh index c4eb9cad..9c8771e5 100644 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -19,7 +19,7 @@ set -euo pipefail -echo "1..$((78 + ${extra_basic_tests:-0}))" +echo "1..$((79 + ${extra_basic_tests:-0}))" CHECKOUT_U_ARG="" CHECKOUT_H_ARGS="-H" @@ -779,6 +779,18 @@ $OSTREE show --print-detached-metadata-key=SIGNATURE test2 > test2-meta assert_file_has_content test2-meta "HANCOCK" echo "ok metadata commit with strings" +$OSTREE commit ${COMMIT_ARGS} -b test2 --tree=ref=test2 \ + --add-detached-metadata-string=SIGNATURE=HANCOCK \ + --keep-metadata=KITTENS --keep-metadata=SOMENUM +if $OSTREE show --print-metadata-key=FOO test2; then + assert_not_reached "FOO was kept without explicit --keep-metadata?" +fi +$OSTREE show --print-metadata-key=KITTENS test2 > test2-meta +assert_file_has_content test2-meta "CUTE" +$OSTREE show -B --print-metadata-key=SOMENUM test2 > test2-meta +assert_file_has_content test2-meta "uint64 42" +echo "ok keep metadata from parent" + cd ${test_tmpdir} $OSTREE show --print-metadata-key=ostree.ref-binding test2 > test2-ref-binding assert_file_has_content test2-ref-binding 'test2'