bin/commit: add --keep-metadata option
authorJonathan Lebon <jlebon@redhat.com>
Tue, 9 Jan 2018 20:29:22 +0000 (20:29 +0000)
committerAtomic Bot <atomic-devel@projectatomic.io>
Wed, 10 Jan 2018 01:42:56 +0000 (01:42 +0000)
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
src/ostree/ot-builtin-commit.c
tests/basic-test.sh

index 0ba135e71a4fe654aeac996949fcec6268e65392..a6eb56defdda68eadb4323f865d61d9c6c00916d 100644 (file)
@@ -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
index 842d07d1f7a6540fede8a8060067907a060f742b..5e5cddd1457f55fd20f725d4853f4079a773b52b 100644 (file)
@@ -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));
     }
 
index c4eb9cadda4f1d2c9bb32c65e0511f3014e300db..9c8771e51d33b6cacf5d381e61752479dbd87c1b 100644 (file)
@@ -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'