From 2b8707b010b0e81f8f95cdbb6558572cea04e7d9 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Sun, 29 Jan 2023 09:28:31 -0700 Subject: [PATCH 1/8] bin: Cleanup documentation of --cache-dir option In all cases documentation was missing from the manual and the bash completion was incorrectly assigning it as a boolean option. --- bash/ostree | 12 ++++++------ man/ostree-find-remotes.xml | 8 ++++++++ man/ostree-pull.xml | 8 ++++++++ man/ostree-remote.xml | 22 ++++++++++++++++++++++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/bash/ostree b/bash/ostree index 6f3b86ea13..5958176f46 100644 --- a/bash/ostree +++ b/bash/ostree @@ -900,7 +900,6 @@ _ostree_pull() { local boolean_options=" $main_boolean_options --commit-metadata-only - --cache-dir --disable-fsync --disable-static-deltas --require-static-deltas @@ -912,6 +911,7 @@ _ostree_pull() { " local options_with_args=" + --cache-dir --depth --http-header --localcache-repo -L @@ -925,7 +925,7 @@ _ostree_pull() { local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) case "$prev" in - --localcache-repo|-L|--repo|--subpath) + --cache-dir|--localcache-repo|-L|--repo|--subpath) __ostree_compreply_dirs_only return 0 ;; @@ -1274,17 +1274,17 @@ _ostree_remote_list_gpg_keys() { _ostree_remote_refs() { local boolean_options=" $main_boolean_options - --cache-dir " local options_with_args=" + --cache-dir --repo " local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) case "$prev" in - --repo) + --cache-dir|--repo) __ostree_compreply_dirs_only return 0 ;; @@ -1343,18 +1343,18 @@ _ostree_remote_show_url() { _ostree_remote_summary() { local boolean_options=" $main_boolean_options - --cache-dir --raw " local options_with_args=" + --cache-dir --repo " local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) case "$prev" in - --repo) + --cache-dir|--repo) __ostree_compreply_dirs_only return 0 ;; diff --git a/man/ostree-find-remotes.xml b/man/ostree-find-remotes.xml index 5c5b2412e9..eee0d123c8 100644 --- a/man/ostree-find-remotes.xml +++ b/man/ostree-find-remotes.xml @@ -86,6 +86,14 @@ License along with this library. If not, see . Options + + =DIR + + + Use an alternate cache directory in DIR. + + + diff --git a/man/ostree-pull.xml b/man/ostree-pull.xml index 0915dd2781..b86987ba53 100644 --- a/man/ostree-pull.xml +++ b/man/ostree-pull.xml @@ -65,6 +65,14 @@ License along with this library. If not, see . + + =DIR + + + Use an alternate cache directory in DIR. + + + diff --git a/man/ostree-remote.xml b/man/ostree-remote.xml index b14fc6d409..5b537a9fca 100644 --- a/man/ostree-remote.xml +++ b/man/ostree-remote.xml @@ -194,6 +194,20 @@ License along with this library. If not, see . + + 'Refs' Options + + + + =DIR + + + Use an alternate cache directory in DIR. + + + + + 'GPG-Import' Options @@ -226,6 +240,14 @@ License along with this library. If not, see . 'Summary' Options + + =DIR + + + Use an alternate cache directory in DIR. + + + From 6b0f42ae376ff7e953241fc98d6f3735225f0d3e Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Sun, 29 Jan 2023 06:49:18 -0700 Subject: [PATCH 2/8] bin/refs: Sort listing The output is much more readable sorted. I can't think of any reason you'd want it unsorted (which is essentially dentry order). --- src/ostree/ot-builtin-refs.c | 34 ++++++++++++++++++++++++++++------ tests/test-refs.sh | 4 ++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/ostree/ot-builtin-refs.c b/src/ostree/ot-builtin-refs.c index c687a5ffc7..0233b8f801 100644 --- a/src/ostree/ot-builtin-refs.c +++ b/src/ostree/ot-builtin-refs.c @@ -47,6 +47,16 @@ static GOptionEntry options[] = { { NULL } }; +static int +collection_ref_cmp (OstreeCollectionRef *a, + OstreeCollectionRef *b) +{ + int ret = g_strcmp0 (a->collection_id, b->collection_id); + if (ret == 0) + ret = g_strcmp0 (a->ref_name, b->ref_name); + return ret; +} + static gboolean do_ref_with_collections (OstreeRepo *repo, const char *refspec_prefix, @@ -66,10 +76,12 @@ do_ref_with_collections (OstreeRepo *repo, if (!opt_delete && !opt_create) { - g_hash_table_iter_init (&hashiter, refs); - while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) + g_autoptr(GList) ordered_keys = g_hash_table_get_keys (refs); + ordered_keys = g_list_sort (ordered_keys, (GCompareFunc) collection_ref_cmp); + + for (GList *iter = ordered_keys; iter != NULL; iter = iter->next) { - const OstreeCollectionRef *ref = hashkey; + OstreeCollectionRef *ref = iter->data; g_print ("(%s, %s)\n", ref->collection_id, ref->ref_name); } } @@ -179,12 +191,22 @@ static gboolean do_ref (OstreeRepo *repo, const char *refspec_prefix, GCancellab if (is_list) { - GLNX_HASH_TABLE_FOREACH_KV (refs, const char *, ref, const char *, value) + g_autoptr(GList) ordered_keys = g_hash_table_get_keys (refs); + ordered_keys = g_list_sort (ordered_keys, (GCompareFunc) g_strcmp0); + + for (GList *iter = ordered_keys; iter != NULL; iter = iter->next) { + const char *ref = iter->data; + if (opt_alias) - g_print ("%s -> %s\n", ref, value); + { + const char *alias = g_hash_table_lookup (refs, ref); + g_print ("%s -> %s\n", ref, alias); + } else - g_print ("%s\n", ref); + { + g_print ("%s\n", ref); + } } } else if (opt_create) diff --git a/tests/test-refs.sh b/tests/test-refs.sh index 3653d035a6..1ddb3a21e4 100755 --- a/tests/test-refs.sh +++ b/tests/test-refs.sh @@ -42,6 +42,10 @@ done ${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount assert_file_has_content refscount "^10$" +${CMD_PREFIX} ostree --repo=repo refs > refs +sort refs > refs-sorted +assert_files_equal refs refs-sorted + ${CMD_PREFIX} ostree --repo=repo refs foo > refs assert_not_file_has_content refs foo From 90dd45fb27594be7fec346987506d08f22a2a37a Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Sun, 29 Jan 2023 09:23:13 -0700 Subject: [PATCH 3/8] bin/refs: Add option to print revisions Allow printing the revision along with the ref. This is very convenient for looping over the refs in a shell as well as for quickly seeing which refs are pointed to the same commit. --- bash/ostree | 1 + man/ostree-refs.xml | 9 +++++++++ src/ostree/ot-builtin-refs.c | 18 +++++++++++++++++- tests/test-refs.sh | 8 ++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/bash/ostree b/bash/ostree index 5958176f46..ea915b4bb4 100644 --- a/bash/ostree +++ b/bash/ostree @@ -953,6 +953,7 @@ _ostree_pull() { _ostree_refs() { local boolean_options=" $main_boolean_options + --revision -r --alias -A --collections -c --delete diff --git a/man/ostree-refs.xml b/man/ostree-refs.xml index 97d69fd768..b54039a38f 100644 --- a/man/ostree-refs.xml +++ b/man/ostree-refs.xml @@ -98,6 +98,15 @@ License along with this library. If not, see . + + , + + + When listing refs, also print their revisions. The revisions + will be separated by a tab character. + + + , diff --git a/src/ostree/ot-builtin-refs.c b/src/ostree/ot-builtin-refs.c index 0233b8f801..c49d7507bd 100644 --- a/src/ostree/ot-builtin-refs.c +++ b/src/ostree/ot-builtin-refs.c @@ -27,6 +27,7 @@ static gboolean opt_delete; static gboolean opt_list; +static gboolean opt_revision; static gboolean opt_alias; static char *opt_create; static gboolean opt_collections; @@ -40,6 +41,7 @@ static gboolean opt_force; static GOptionEntry options[] = { { "delete", 0, 0, G_OPTION_ARG_NONE, &opt_delete, "Delete refs which match PREFIX, rather than listing them", NULL }, { "list", 0, 0, G_OPTION_ARG_NONE, &opt_list, "Do not remove the prefix from the refs", NULL }, + { "revision", 'r', 0, G_OPTION_ARG_NONE, &opt_revision, "Show revisions in listing", NULL }, { "alias", 'A', 0, G_OPTION_ARG_NONE, &opt_alias, "If used with --create, create an alias, otherwise just list aliases", NULL }, { "create", 0, 0, G_OPTION_ARG_STRING, &opt_create, "Create a new ref for an existing commit", "NEWREF" }, { "collections", 'c', 0, G_OPTION_ARG_NONE, &opt_collections, "Enable listing collection IDs for refs", NULL }, @@ -82,7 +84,16 @@ do_ref_with_collections (OstreeRepo *repo, for (GList *iter = ordered_keys; iter != NULL; iter = iter->next) { OstreeCollectionRef *ref = iter->data; - g_print ("(%s, %s)\n", ref->collection_id, ref->ref_name); + + if (opt_revision) + { + const char *rev = g_hash_table_lookup (refs, ref); + g_print ("(%s, %s)\t%s\n", ref->collection_id, ref->ref_name, rev); + } + else + { + g_print ("(%s, %s)\n", ref->collection_id, ref->ref_name); + } } } else if (opt_create) @@ -203,6 +214,11 @@ static gboolean do_ref (OstreeRepo *repo, const char *refspec_prefix, GCancellab const char *alias = g_hash_table_lookup (refs, ref); g_print ("%s -> %s\n", ref, alias); } + else if (opt_revision) + { + const char *rev = g_hash_table_lookup (refs, ref); + g_print ("%s\t%s\n", ref, rev); + } else { g_print ("%s\n", ref); diff --git a/tests/test-refs.sh b/tests/test-refs.sh index 1ddb3a21e4..53b36f6bbc 100755 --- a/tests/test-refs.sh +++ b/tests/test-refs.sh @@ -55,6 +55,14 @@ assert_file_has_content refs foo ${CMD_PREFIX} ostree --repo=repo refs foo | wc -l > refscount.foo assert_file_has_content refscount.foo "^5$" +rm -f expected-refs-revs +for ref in foo/test-{1..5}; do + rev=$(${CMD_PREFIX} ostree --repo=repo rev-parse $ref) + echo -e "${ref}\t${rev}" >> expected-refs-revs +done +${CMD_PREFIX} ostree --repo=repo refs --list --revision foo > refs-revs +assert_files_equal refs-revs expected-refs-revs + ${CMD_PREFIX} ostree --repo=repo refs --delete 2>/dev/null || true ${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.delete1 assert_file_has_content refscount.delete1 "^10$" From 008c5a95404cb670590394227e41a03ce1d1c437 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Sun, 29 Jan 2023 09:37:03 -0700 Subject: [PATCH 4/8] bin/remote-refs: Add option to print revisions The only other way to get the remote ref revision from the CLI is to scrape the output of `ostree remote summary` or pull the commit. The revision is already there in the summary's ref map, so might as well add an option to show it. --- Makefile-tests.am | 1 + bash/ostree | 1 + man/ostree-remote.xml | 11 +++++++ src/ostree/ot-remote-builtin-refs.c | 14 ++++++++- tests/test-remote-refs.sh | 49 +++++++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 1 deletion(-) create mode 100755 tests/test-remote-refs.sh diff --git a/Makefile-tests.am b/Makefile-tests.am index 470eec2551..01ed0bd564 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -68,6 +68,7 @@ _installed_or_uninstalled_test_scripts = \ tests/test-archivez.sh \ tests/test-remote-add.sh \ tests/test-remote-headers.sh \ + tests/test-remote-refs.sh \ tests/test-commit-sign.sh \ tests/test-commit-timestamp.sh \ tests/test-export.sh \ diff --git a/bash/ostree b/bash/ostree index ea915b4bb4..2b7c552f06 100644 --- a/bash/ostree +++ b/bash/ostree @@ -1275,6 +1275,7 @@ _ostree_remote_list_gpg_keys() { _ostree_remote_refs() { local boolean_options=" $main_boolean_options + --revision -r " local options_with_args=" diff --git a/man/ostree-remote.xml b/man/ostree-remote.xml index 5b537a9fca..d107ce919a 100644 --- a/man/ostree-remote.xml +++ b/man/ostree-remote.xml @@ -197,6 +197,17 @@ License along with this library. If not, see . 'Refs' Options + + + , + + + Also print the revisions for each ref. The revisions will + be separated by a tab character. + + + + =DIR diff --git a/src/ostree/ot-remote-builtin-refs.c b/src/ostree/ot-remote-builtin-refs.c index 29c39328b1..24ad0776fe 100644 --- a/src/ostree/ot-remote-builtin-refs.c +++ b/src/ostree/ot-remote-builtin-refs.c @@ -24,6 +24,7 @@ #include "ot-main.h" #include "ot-remote-builtins.h" +static gboolean opt_revision; static char* opt_cache_dir; /* ATTENTION: @@ -32,6 +33,7 @@ static char* opt_cache_dir; */ static GOptionEntry option_entries[] = { + { "revision", 'r', 0, G_OPTION_ARG_NONE, &opt_revision, "Show revisions in listing", NULL }, { "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL }, { NULL } }; @@ -73,7 +75,17 @@ ot_remote_builtin_refs (int argc, char **argv, OstreeCommandInvocation *invocati for (iter = ordered_keys; iter; iter = iter->next) { - g_print ("%s:%s\n", remote_name, (const char *) iter->data); + const char *ref = iter->data; + + if (opt_revision) + { + const char *rev = g_hash_table_lookup (refs, ref); + g_print ("%s:%s\t%s\n", remote_name, ref, rev); + } + else + { + g_print ("%s:%s\n", remote_name, ref); + } } } diff --git a/tests/test-remote-refs.sh b/tests/test-remote-refs.sh new file mode 100755 index 0000000000..b92fb20e4e --- /dev/null +++ b/tests/test-remote-refs.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# +# Copyright © 2023 Endless OS Foundation LLC +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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, see . +# +# Authors: +# - Dan Nicholson + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..2" + +setup_fake_remote_repo2 "archive" +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/repo summary -u +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/repo refs > origin-refs +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/repo refs --revision > origin-refs-revs + +cd ${test_tmpdir} +rm -rf repo +ostree_repo_init repo --mode=archive +${OSTREE} remote add --no-sign-verify origin $(cat httpd-address)/ostree/repo + +${OSTREE} remote refs origin > refs +sed 's/^/origin:/' origin-refs > expected-refs +assert_files_equal refs expected-refs + +echo "ok remote refs listing" + +${OSTREE} remote refs origin --revision > refs-revs +sed 's/^/origin:/' origin-refs-revs > expected-refs-revs +assert_files_equal refs-revs expected-refs-revs + +echo "ok remote refs revisions" From 86701f0f848dde51352d760872d4e0d821a9fc21 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Sun, 29 Jan 2023 14:13:05 -0700 Subject: [PATCH 5/8] bin/show: Add options to list metadata keys While `--print-metadata-key` is very useful, it's not that helpful if you don't know what the keys are. --- bash/ostree | 2 + man/ostree-show.xml | 16 ++++++++ src/ostree/ot-builtin-show.c | 77 +++++++++++++++++++++++++++++++++--- tests/basic-test.sh | 7 ++++ 4 files changed, 96 insertions(+), 6 deletions(-) diff --git a/bash/ostree b/bash/ostree index 2b7c552f06..76a62c594a 100644 --- a/bash/ostree +++ b/bash/ostree @@ -1486,6 +1486,8 @@ _ostree_rev_parse() { _ostree_show() { local boolean_options=" $main_boolean_options + --list-detached-metadata-keys + --list-metadata-keys --print-related --print-sizes --raw diff --git a/man/ostree-show.xml b/man/ostree-show.xml index 4495b1e69e..8d134cc43e 100644 --- a/man/ostree-show.xml +++ b/man/ostree-show.xml @@ -81,6 +81,14 @@ License along with this library. If not, see . + + + + + List the available metadata keys. + + + ="KEY" @@ -89,6 +97,14 @@ License along with this library. If not, see . + + + + + List the available detached metadata keys. + + + ="KEY" diff --git a/src/ostree/ot-builtin-show.c b/src/ostree/ot-builtin-show.c index 55f2b47e21..9346a7b35e 100644 --- a/src/ostree/ot-builtin-show.c +++ b/src/ostree/ot-builtin-show.c @@ -31,6 +31,8 @@ static gboolean opt_print_related; static char* opt_print_variant_type; static char* opt_print_metadata_key; static char* opt_print_detached_metadata_key; +static gboolean opt_list_metadata_keys; +static gboolean opt_list_detached_metadata_keys; static gboolean opt_print_sizes; static gboolean opt_raw; static gboolean opt_no_byteswap; @@ -45,7 +47,9 @@ static char *opt_gpg_verify_remote; static GOptionEntry options[] = { { "print-related", 0, 0, G_OPTION_ARG_NONE, &opt_print_related, "Show the \"related\" commits", NULL }, { "print-variant-type", 0, 0, G_OPTION_ARG_STRING, &opt_print_variant_type, "Memory map OBJECT (in this case a filename) to the GVariant type string", "TYPE" }, + { "list-metadata-keys", 0, 0, G_OPTION_ARG_NONE, &opt_list_metadata_keys, "List the available metadata keys", NULL }, { "print-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_metadata_key, "Print string value of metadata key", "KEY" }, + { "list-detached-metadata-keys", 0, 0, G_OPTION_ARG_NONE, &opt_list_detached_metadata_keys, "List the available detached metadata keys", NULL }, { "print-detached-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_detached_metadata_key, "Print string value of detached metadata key", "KEY" }, { "print-sizes", 0, 0, G_OPTION_ARG_NONE, &opt_print_sizes, "Show the commit size metadata", NULL }, { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data" }, @@ -98,12 +102,14 @@ do_print_related (OstreeRepo *repo, } static gboolean -do_print_metadata_key (OstreeRepo *repo, - const char *resolved_rev, - gboolean detached, - const char *key, - GError **error) +get_metadata (OstreeRepo *repo, + const char *resolved_rev, + gboolean detached, + GVariant **out_metadata, + GError **error) { + g_assert (out_metadata != NULL); + g_autoptr(GVariant) commit = NULL; g_autoptr(GVariant) metadata = NULL; @@ -128,6 +134,59 @@ do_print_metadata_key (OstreeRepo *repo, } } + *out_metadata = g_steal_pointer (&metadata); + + return TRUE; +} + +static gint +strptr_cmp (gconstpointer a, + gconstpointer b) +{ + const char *a_str = *((const char **) a); + const char *b_str = *((const char **) b); + + return g_strcmp0 (a_str, b_str); +} + +static gboolean +do_list_metadata_keys (OstreeRepo *repo, + const char *resolved_rev, + gboolean detached, + GError **error) +{ + g_autoptr(GVariant) metadata = NULL; + if (!get_metadata (repo, resolved_rev, detached, &metadata, error)) + return FALSE; + + GVariantIter iter; + const char *key = NULL; + g_autoptr(GPtrArray) keys = g_ptr_array_new (); + g_variant_iter_init (&iter, metadata); + while (g_variant_iter_loop (&iter, "{&s@v}", &key, NULL)) + g_ptr_array_add (keys, (gpointer) key); + + g_ptr_array_sort (keys, strptr_cmp); + for (guint i = 0; i < keys-> len; i++) + { + key = keys->pdata[i]; + g_print ("%s\n", key); + } + + return TRUE; +} + +static gboolean +do_print_metadata_key (OstreeRepo *repo, + const char *resolved_rev, + gboolean detached, + const char *key, + GError **error) +{ + g_autoptr(GVariant) metadata = NULL; + if (!get_metadata (repo, resolved_rev, detached, &metadata, error)) + return FALSE; + g_autoptr(GVariant) value = g_variant_lookup_value (metadata, key, NULL); if (!value) { @@ -321,10 +380,16 @@ ostree_builtin_show (int argc, char **argv, OstreeCommandInvocation *invocation, const char *key = detached ? opt_print_detached_metadata_key : opt_print_metadata_key; if (!ostree_repo_resolve_rev (repo, rev, FALSE, &resolved_rev, error)) return FALSE; - if (!do_print_metadata_key (repo, resolved_rev, detached, key, error)) return FALSE; } + else if (opt_list_metadata_keys || opt_list_detached_metadata_keys) + { + if (!ostree_repo_resolve_rev (repo, rev, FALSE, &resolved_rev, error)) + return FALSE; + if (!do_list_metadata_keys (repo, resolved_rev, opt_list_detached_metadata_keys, error)) + return FALSE; + } else if (opt_print_related) { if (!ostree_repo_resolve_rev (repo, rev, FALSE, &resolved_rev, error)) diff --git a/tests/basic-test.sh b/tests/basic-test.sh index f97f6fc376..e2a7d70c14 100644 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -1006,6 +1006,13 @@ $OSTREE show -B --print-metadata-key=SOMENUM test2 > test2-meta assert_file_has_content test2-meta "uint64 42" $OSTREE show --print-detached-metadata-key=SIGNATURE test2 > test2-meta assert_file_has_content test2-meta "HANCOCK" + +$OSTREE show --list-metadata-keys test2 > test2-meta +assert_file_has_content test2-meta "FOO" +assert_file_has_content test2-meta "KITTENS" +assert_file_has_content test2-meta "SOMENUM" +$OSTREE show --list-detached-metadata-keys test2 > test2-meta +assert_file_has_content test2-meta "SIGNATURE" echo "ok metadata commit with strings" $OSTREE commit ${COMMIT_ARGS} -b test2 --tree=ref=test2 \ From d0f2c5d36105256ba7749da0a5abc04cbb4915f2 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Sun, 29 Jan 2023 22:41:52 -0700 Subject: [PATCH 6/8] ostree/dump: Add support for summary metadata keys Like with commit metadata, it's useful to list and print metadata keys are in a summary file. This adds helpers to do that. --- src/ostree/ot-dump.c | 60 ++++++++++++++++++++++++++++++++++++++++++++ src/ostree/ot-dump.h | 6 +++++ 2 files changed, 66 insertions(+) diff --git a/src/ostree/ot-dump.c b/src/ostree/ot-dump.c index 509eb792d1..4cfac81135 100644 --- a/src/ostree/ot-dump.c +++ b/src/ostree/ot-dump.c @@ -407,6 +407,66 @@ ot_dump_summary_bytes (GBytes *summary_bytes, } } +static gint +strptr_cmp (gconstpointer a, + gconstpointer b) +{ + const char *a_str = *((const char **) a); + const char *b_str = *((const char **) b); + + return g_strcmp0 (a_str, b_str); +} + +void +ot_dump_summary_metadata_keys (GBytes *summary_bytes) +{ + g_autoptr(GVariant) summary = NULL; + g_autoptr(GVariant) metadata = NULL; + + summary = g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, + summary_bytes, FALSE); + metadata = g_variant_get_child_value (summary, 1); + + GVariantIter iter; + const char *key = NULL; + g_autoptr(GPtrArray) keys = g_ptr_array_new (); + g_variant_iter_init (&iter, metadata); + while (g_variant_iter_loop (&iter, "{&s@v}", &key, NULL)) + g_ptr_array_add (keys, (gpointer) key); + + g_ptr_array_sort (keys, strptr_cmp); + for (guint i = 0; i < keys-> len; i++) + { + key = keys->pdata[i]; + g_print ("%s\n", key); + } +} + +gboolean +ot_dump_summary_metadata_key (GBytes *summary_bytes, + const char *key, + GError **error) +{ + g_autoptr(GVariant) summary = NULL; + g_autoptr(GVariant) metadata = NULL; + g_autoptr(GVariant) value = NULL; + + summary = g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, + summary_bytes, FALSE); + metadata = g_variant_get_child_value (summary, 1); + value = g_variant_lookup_value (metadata, key, NULL); + if (!value) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No such metadata key '%s'", key); + return FALSE; + } + + ot_dump_variant (value); + + return TRUE; +} + static gboolean dump_gpg_subkey (GVariant *subkey, gboolean primary, diff --git a/src/ostree/ot-dump.h b/src/ostree/ot-dump.h index 217a3964b6..da1a2cb2f7 100644 --- a/src/ostree/ot-dump.h +++ b/src/ostree/ot-dump.h @@ -41,5 +41,11 @@ void ot_dump_object (OstreeObjectType objtype, void ot_dump_summary_bytes (GBytes *summary_bytes, OstreeDumpFlags flags); +void ot_dump_summary_metadata_keys (GBytes *summary_bytes); + +gboolean ot_dump_summary_metadata_key (GBytes *summary_bytes, + const char *key, + GError **error); + gboolean ot_dump_gpg_key (GVariant *key, GError **error); From b49f93aa951c5a168ccd32908425c670f319a65f Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Sun, 29 Jan 2023 22:45:29 -0700 Subject: [PATCH 7/8] bin/summary: Add options to show metadata --- bash/ostree | 2 ++ src/ostree/ot-builtin-summary.c | 49 +++++++++++++++++++++++++++++---- tests/test-summary-update.sh | 4 +++ 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/bash/ostree b/bash/ostree index 76a62c594a..0415e225ae 100644 --- a/bash/ostree +++ b/bash/ostree @@ -1816,6 +1816,7 @@ _ostree_static_delta() { _ostree_summary() { local boolean_options=" $main_boolean_options + --list-metadata-keys --raw --update -u --view -v @@ -1825,6 +1826,7 @@ _ostree_summary() { --add-metadata -m --gpg-homedir --gpg-sign + --print-metadata-key --repo " diff --git a/src/ostree/ot-builtin-summary.c b/src/ostree/ot-builtin-summary.c index 2d6306a4a8..cdfc11e699 100644 --- a/src/ostree/ot-builtin-summary.c +++ b/src/ostree/ot-builtin-summary.c @@ -28,6 +28,8 @@ #include "ostree-sign.h" static gboolean opt_update, opt_view, opt_raw; +static gboolean opt_list_metadata_keys; +static char *opt_print_metadata_key; static char **opt_gpg_key_ids; static char *opt_gpg_homedir; static char **opt_key_ids; @@ -43,6 +45,8 @@ static GOptionEntry options[] = { { "update", 'u', 0, G_OPTION_ARG_NONE, &opt_update, "Update the summary", NULL }, { "view", 'v', 0, G_OPTION_ARG_NONE, &opt_view, "View the local summary file", NULL }, { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "View the raw bytes of the summary file", NULL }, + { "list-metadata-keys", 0, 0, G_OPTION_ARG_NONE, &opt_list_metadata_keys, "List the available metadata keys", NULL }, + { "print-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_metadata_key, "Print string value of metadata key", "KEY" }, { "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_gpg_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"}, { "sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "Key ID to sign the summary with", "KEY-ID"}, @@ -85,6 +89,26 @@ build_additional_metadata (const char * const *args, return g_variant_ref_sink (g_variant_builder_end (builder)); } +static gboolean +get_summary_data (OstreeRepo *repo, + GBytes **out_summary_data, + GError **error) +{ + g_assert (out_summary_data != NULL); + + g_autoptr(GBytes) summary_data = NULL; + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (repo->repo_dir_fd, "summary", TRUE, &fd, error)) + return FALSE; + summary_data = ot_fd_readall_or_mmap (fd, 0, error); + if (!summary_data) + return FALSE; + + *out_summary_data = g_steal_pointer (&summary_data); + + return TRUE; +} + gboolean ostree_builtin_summary (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) { @@ -275,15 +299,30 @@ ostree_builtin_summary (int argc, char **argv, OstreeCommandInvocation *invocati if (opt_raw) flags |= OSTREE_DUMP_RAW; - glnx_autofd int fd = -1; - if (!glnx_openat_rdonly (repo->repo_dir_fd, "summary", TRUE, &fd, error)) - return FALSE; - summary_data = ot_fd_readall_or_mmap (fd, 0, error); - if (!summary_data) + if (!get_summary_data (repo, &summary_data, error)) return FALSE; ot_dump_summary_bytes (summary_data, flags); } + else if (opt_list_metadata_keys) + { + g_autoptr(GBytes) summary_data = NULL; + + if (!get_summary_data (repo, &summary_data, error)) + return FALSE; + + ot_dump_summary_metadata_keys (summary_data); + } + else if (opt_print_metadata_key) + { + g_autoptr(GBytes) summary_data = NULL; + + if (!get_summary_data (repo, &summary_data, error)) + return FALSE; + + if (!ot_dump_summary_metadata_key (summary_data, opt_print_metadata_key, error)) + return FALSE; + } else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, diff --git a/tests/test-summary-update.sh b/tests/test-summary-update.sh index 74c42d10d1..d85e9c4b39 100755 --- a/tests/test-summary-update.sh +++ b/tests/test-summary-update.sh @@ -59,6 +59,10 @@ ${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: {}$" +${CMD_PREFIX} ostree --repo=repo summary --list-metadata-keys > metadata +assert_file_has_content metadata "^map$" +${CMD_PREFIX} ostree --repo=repo summary --print-metadata-key=map > metadata +assert_file_has_content metadata "^@a{sv} {}$" echo "ok 1 update summary" From 70ec92e1cdc3ad882ac569a3655857fb1241a449 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Sun, 29 Jan 2023 22:45:29 -0700 Subject: [PATCH 8/8] bin/remote-summary: Add options to show metadata --- bash/ostree | 2 + src/ostree/ot-remote-builtin-summary.c | 78 ++++++++++++++++---------- tests/test-pull-summary-sigs.sh | 10 ++++ tests/test-signed-pull-summary.sh | 10 ++++ 4 files changed, 69 insertions(+), 31 deletions(-) diff --git a/bash/ostree b/bash/ostree index 0415e225ae..875b34ff13 100644 --- a/bash/ostree +++ b/bash/ostree @@ -1345,11 +1345,13 @@ _ostree_remote_show_url() { _ostree_remote_summary() { local boolean_options=" $main_boolean_options + --list-metadata-keys --raw " local options_with_args=" --cache-dir + --print-metadata-key --repo " diff --git a/src/ostree/ot-remote-builtin-summary.c b/src/ostree/ot-remote-builtin-summary.c index fb2c45a379..55ccc396b2 100644 --- a/src/ostree/ot-remote-builtin-summary.c +++ b/src/ostree/ot-remote-builtin-summary.c @@ -25,8 +25,10 @@ #include "ot-dump.h" #include "ot-remote-builtins.h" +static gboolean opt_list_metadata_keys; static gboolean opt_raw; +static char *opt_print_metadata_key; static char* opt_cache_dir; /* ATTENTION: @@ -35,6 +37,8 @@ static char* opt_cache_dir; */ static GOptionEntry option_entries[] = { + { "list-metadata-keys", 0, 0, G_OPTION_ARG_NONE, &opt_list_metadata_keys, "List the available metadata keys", NULL }, + { "print-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_metadata_key, "Print string value of metadata key", "KEY" }, { "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL }, { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data", NULL }, { NULL } @@ -90,42 +94,54 @@ ot_remote_builtin_summary (int argc, char **argv, OstreeCommandInvocation *invoc goto out; } - ot_dump_summary_bytes (summary_bytes, flags); + if (opt_list_metadata_keys) + { + ot_dump_summary_metadata_keys (summary_bytes); + } + else if (opt_print_metadata_key) + { + if (!ot_dump_summary_metadata_key (summary_bytes, opt_print_metadata_key, error)) + goto out; + } + else + { + ot_dump_summary_bytes (summary_bytes, flags); #ifndef OSTREE_DISABLE_GPGME - if (!ostree_repo_remote_get_gpg_verify_summary (repo, remote_name, - &gpg_verify_summary, - error)) - goto out; - - if (!gpg_verify_summary) - g_clear_pointer (&signature_bytes, g_bytes_unref); - - /* XXX Note we don't show signatures for "--raw". My intuition is - * if someone needs to see or parse raw summary data, including - * signatures in the output would probably just interfere. - * If there's demand for it I suppose we could introduce a new - * option for raw signature data like "--raw-signatures". */ - if (signature_bytes != NULL && !opt_raw) - { - g_autoptr(OstreeGpgVerifyResult) result = NULL; - - /* The actual signed summary verification happens above in - * ostree_repo_remote_fetch_summary(). Here we just parse - * the signatures again for the purpose of printing. */ - result = ostree_repo_verify_summary (repo, - remote_name, - summary_bytes, - signature_bytes, - cancellable, - error); - if (result == NULL) + if (!ostree_repo_remote_get_gpg_verify_summary (repo, remote_name, + &gpg_verify_summary, + error)) goto out; - g_print ("\n"); - ostree_print_gpg_verify_result (result); - } + if (!gpg_verify_summary) + g_clear_pointer (&signature_bytes, g_bytes_unref); + + /* XXX Note we don't show signatures for "--raw". My intuition is + * if someone needs to see or parse raw summary data, including + * signatures in the output would probably just interfere. + * If there's demand for it I suppose we could introduce a new + * option for raw signature data like "--raw-signatures". */ + if (signature_bytes != NULL && !opt_raw) + { + g_autoptr(OstreeGpgVerifyResult) result = NULL; + + /* The actual signed summary verification happens above in + * ostree_repo_remote_fetch_summary(). Here we just parse + * the signatures again for the purpose of printing. */ + result = ostree_repo_verify_summary (repo, + remote_name, + summary_bytes, + signature_bytes, + cancellable, + error); + if (result == NULL) + goto out; + + g_print ("\n"); + ostree_print_gpg_verify_result (result); + } #endif /* OSTREE_DISABLE_GPGME */ + } ret = TRUE; out: diff --git a/tests/test-pull-summary-sigs.sh b/tests/test-pull-summary-sigs.sh index 03a40e4630..e1b0412e68 100755 --- a/tests/test-pull-summary-sigs.sh +++ b/tests/test-pull-summary-sigs.sh @@ -157,6 +157,16 @@ assert_file_has_content summary.txt "Good signature from \"Ostree Tester static-deltas.txt assert_file_has_content static-deltas.txt \ $(${OSTREE} --repo=repo rev-parse origin:main) +${OSTREE} --repo=repo remote summary origin --list-metadata-keys > metadata +assert_file_has_content metadata "^ostree.static-deltas$" +assert_file_has_content metadata "^ostree.summary.indexed-deltas$" +assert_file_has_content metadata "^ostree.summary.last-modified$" +assert_file_has_content metadata "^ostree.summary.mode$" +assert_file_has_content metadata "^ostree.summary.tombstone-commits$" +${OSTREE} --repo=repo remote summary origin --print-metadata-key=ostree.summary.indexed-deltas > metadata +assert_file_has_content metadata "^true$" +${OSTREE} --repo=repo remote summary origin --print-metadata-key=ostree.summary.mode > metadata +assert_file_has_content metadata "^'archive-z2'$" ## Tests for handling of cached summaries while racing with remote summary updates diff --git a/tests/test-signed-pull-summary.sh b/tests/test-signed-pull-summary.sh index 2d6b25527c..d28738947e 100755 --- a/tests/test-signed-pull-summary.sh +++ b/tests/test-signed-pull-summary.sh @@ -194,6 +194,16 @@ assert_file_has_content summary.txt "* yet-another" grep static-deltas summary.txt > static-deltas.txt assert_file_has_content static-deltas.txt \ $(${OSTREE} --repo=repo rev-parse origin:main) +${OSTREE} --repo=repo remote summary origin --list-metadata-keys > metadata +assert_file_has_content metadata "^ostree.static-deltas$" +assert_file_has_content metadata "^ostree.summary.indexed-deltas$" +assert_file_has_content metadata "^ostree.summary.last-modified$" +assert_file_has_content metadata "^ostree.summary.mode$" +assert_file_has_content metadata "^ostree.summary.tombstone-commits$" +${OSTREE} --repo=repo remote summary origin --print-metadata-key=ostree.summary.indexed-deltas > metadata +assert_file_has_content metadata "^true$" +${OSTREE} --repo=repo remote summary origin --print-metadata-key=ostree.summary.mode > metadata +assert_file_has_content metadata "^'archive-z2'$" ## Tests for handling of cached summaries while racing with remote summary updates