ostree/summary: Add support for adding additional metadata
authorPhilip Withnall <withnall@endlessm.com>
Thu, 22 Jun 2017 14:16:53 +0000 (15:16 +0100)
committerAtomic Bot <atomic-devel@projectatomic.io>
Tue, 27 Jun 2017 19:19:32 +0000 (19:19 +0000)
When updating a summary file, parse additional arguments to the `ostree
summary` command as additional metadata to be put into the summary.

Add some tests for this.

Signed-off-by: Philip Withnall <withnall@endlessm.com>
Closes: #961
Approved by: cgwalters

Makefile-tests.am
man/ostree-summary.xml
src/ostree/ot-builtin-summary.c
tests/test-summary-update.sh [new file with mode: 0755]

index cb7753204e47a4192d9e105c43f422559984c2e3..2fe0a2350a322738210e4b9992d19a8d8146ac0c 100644 (file)
@@ -108,6 +108,7 @@ _installed_or_uninstalled_test_scripts = \
        tests/test-switchroot.sh \
        tests/test-pull-contenturl.sh \
        tests/test-pull-mirrorlist.sh \
+       tests/test-summary-update.sh \
        tests/test-summary-view.sh \
        $(NULL)
 
index 3fa287ebfe3c1a5dc2359e43162c47efaf4cac7b..4e897592c6ec62bf3716d17c4e79478af7da0060 100644 (file)
@@ -73,7 +73,16 @@ Boston, MA 02111-1307, USA.
                 <term><option>-u</option></term>
 
                 <listitem><para>
-                 Update the summary file.
+                  Update the summary file.
+                </para><para>
+                  Any additional arguments to the command
+                  are treated as additional key–value pairs to be added to the
+                  summary file as additional metadata. They must be in the format
+                  <command><replaceable>KEY</replaceable>=<replaceable>VALUE</replaceable></command>
+                  or as two separate arguments. The keys must be namespaced for
+                  your organisation or repository using a dot prefix. The values
+                  must be in GVariant text format. For example,
+                  <command>exampleos.end-of-life "@t 1445385600"</command>.
                 </para></listitem>
             </varlistentry>
 
index 9055d972ca298b88bd3ed57e475d841f70a2df51..f2e687ec0319e324a4e1926e410b1577109553df 100644 (file)
@@ -30,6 +30,7 @@
 static gboolean opt_update, opt_view, opt_raw;
 static char **opt_key_ids;
 static char *opt_gpg_homedir;
+static char **opt_metadata;
 
 static GOptionEntry options[] = {
   { "update", 'u', 0, G_OPTION_ARG_NONE, &opt_update, "Update the summary", NULL },
@@ -37,9 +38,44 @@ static GOptionEntry options[] = {
   { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "View the raw bytes of the summary file", NULL },
   { "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the summary with", "KEY-ID"},
   { "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
+  { "add-metadata", 'm', 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata, "Additional metadata field to add to the summary", "KEY=VALUE" },
   { NULL }
 };
 
+/* Take arguments of the form KEY=VALUE and put them into an a{sv} variant. The
+ * value arguments must be parsable using g_variant_parse(). */
+static GVariant *
+build_additional_metadata (const char * const  *args,
+                           GError             **error)
+{
+  g_autoptr(GVariantBuilder) builder = NULL;
+
+  builder = g_variant_builder_new (G_VARIANT_TYPE_VARDICT);
+
+  for (gsize i = 0; args[i] != NULL; i++)
+    {
+      const gchar *equals = strchr (args[i], '=');
+      g_autofree gchar *key = NULL;
+      const gchar *value_str;
+      g_autoptr(GVariant) value = NULL;
+
+      if (equals == NULL)
+        return glnx_null_throw (error,
+                                "Missing '=' in KEY=VALUE metadata '%s'", args[i]);
+
+      key = g_strndup (args[i], equals - args[i]);
+      value_str = equals + 1;
+
+      value = g_variant_parse (NULL, value_str, NULL, NULL, error);
+      if (value == NULL)
+        return glnx_prefix_error_null (error, "Error parsing variant ‘%s’: ", value_str);
+
+      g_variant_builder_add (builder, "{sv}", key, value);
+    }
+
+  return g_variant_ref_sink (g_variant_builder_end (builder));
+}
+
 gboolean
 ostree_builtin_summary (int argc, char **argv, GCancellable *cancellable, GError **error)
 {
@@ -55,10 +91,19 @@ ostree_builtin_summary (int argc, char **argv, GCancellable *cancellable, GError
 
   if (opt_update)
     {
+      g_autoptr(GVariant) additional_metadata = NULL;
+
       if (!ostree_ensure_repo_writable (repo, error))
         goto out;
 
-      if (!ostree_repo_regenerate_summary (repo, NULL, cancellable, error))
+      if (opt_metadata != NULL)
+        {
+          additional_metadata = build_additional_metadata ((const char * const *) opt_metadata, error);
+          if (additional_metadata == NULL)
+            goto out;
+        }
+
+      if (!ostree_repo_regenerate_summary (repo, additional_metadata, cancellable, error))
         goto out;
 
       if (opt_key_ids)
diff --git a/tests/test-summary-update.sh b/tests/test-summary-update.sh
new file mode 100755 (executable)
index 0000000..457debb
--- /dev/null
@@ -0,0 +1,94 @@
+#!/bin/bash
+#
+# Copyright © 2017 Endless Mobile, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+# Authors:
+#  - Philip Withnall <withnall@endlessm.com>
+
+set -euo pipefail
+
+. $(dirname $0)/libtest.sh
+
+echo "1..2"
+
+cd ${test_tmpdir}
+mkdir repo
+ostree_repo_init repo
+
+mkdir -p tree/root
+touch tree/root/a
+
+# Add a few commits
+seq 5 | while read i; do
+    echo a >> tree/root/a
+    ${CMD_PREFIX} ostree --repo=repo commit --branch=test-$i -m test -s test tree
+done
+
+# Generate a plain summary file.
+${CMD_PREFIX} ostree --repo=repo summary --update
+
+# Generate a signed summary file.
+${CMD_PREFIX} ostree --repo=repo summary --update --gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}
+
+# Try various ways of adding additional data.
+${CMD_PREFIX} ostree --repo=repo summary --update --add-metadata key="'value'" --add-metadata=key2=true
+${CMD_PREFIX} ostree --repo=repo summary --update -m some-int='@t 123'
+${CMD_PREFIX} ostree --repo=repo summary --update --add-metadata=map='@a{sv} {}'
+
+# Check the additional metadata turns up in the output.
+${CMD_PREFIX} ostree --repo=repo summary --view > summary
+assert_file_has_content summary "^map: {}$"
+
+echo "ok 1 update summary"
+
+# Test again, but with collections enabled in the repository (if supported).
+if ! ostree --version | grep -q -e '- experimental'; then
+    echo "ok 2 # skip No experimental API is compiled in"
+    exit 0
+fi
+
+cd ${test_tmpdir}
+rm -rf repo
+ostree_repo_init repo --collection-id org.example.Collection1
+
+mkdir -p tree/root
+touch tree/root/a
+
+# Add a few commits
+seq 5 | while read i; do
+    echo a >> tree/root/a
+    ${CMD_PREFIX} ostree --repo=repo commit --branch=test-$i -m test -s test tree
+    ${CMD_PREFIX} ostree --repo=repo refs --collections --create=org.example.Collection2:test-$i test-$i
+done
+
+# Generate a plain summary file.
+${CMD_PREFIX} ostree --repo=repo summary --update
+
+# Generate a signed summary file.
+${CMD_PREFIX} ostree --repo=repo summary --update --gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}
+
+# Try various ways of adding additional data.
+${CMD_PREFIX} ostree --repo=repo summary --update --add-metadata key="'value'" --add-metadata=key2=true
+${CMD_PREFIX} ostree --repo=repo summary --update -m some-int='@t 123'
+${CMD_PREFIX} ostree --repo=repo summary --update --add-metadata=map='@a{sv} {}'
+
+# Check the additional metadata turns up in the output.
+${CMD_PREFIX} ostree --repo=repo summary --view > summary
+assert_file_has_content summary "^map: {}$"
+
+echo "ok 2 update summary with collections"