[ostree] core: Add detached metadata, readd metadata to commits
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ostree] core: Add detached metadata, readd metadata to commits
- Date: Mon, 9 Sep 2013 21:12:09 +0000 (UTC)
commit ac2d61dd515e547df6e1fc9e9d438783a201848d
Author: Colin Walters <walters verbum org>
Date: Mon Sep 9 17:01:32 2013 -0400
core: Add detached metadata, readd metadata to commits
Previously I thought we'd have to ditch the current commit
format to avoid a{sv} due to
See https://bugzilla.gnome.org/show_bug.cgi?id=673012
But I realized that we don't really have to care about
unpacking/repacking commit objects, so let's just re-expose the
existing metadata a{sv} in commits in the API.
Also, add support for "detached" metadata that can be updated at any
time post-commit. This is specifically designed for GPG signatures.
https://bugzilla.gnome.org/show_bug.cgi?id=707379
src/libostree/ostree-repo-commit.c | 92 ++++++++++++++++++++++++++++++++++-
src/libostree/ostree-repo-private.h | 4 ++
src/libostree/ostree-repo-prune.c | 7 +++
src/libostree/ostree-repo.h | 13 +++++
src/ostree/ot-builtin-commit.c | 68 +++++++++++++++++++++++++-
src/ostree/ot-builtin-show.c | 38 +++++++++-----
tests/test-basic.sh | 11 ++++-
7 files changed, 217 insertions(+), 16 deletions(-)
---
diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c
index 0cfb216..3a80cde 100644
--- a/src/libostree/ostree-repo-commit.c
+++ b/src/libostree/ostree-repo-commit.c
@@ -1171,6 +1171,7 @@ create_empty_gvariant_dict (void)
* @parent: (allow-none): ASCII SHA256 checksum for parent, or %NULL for none
* @subject: Subject
* @body: (allow-none): Body
+ * @metadata: (allow-none): GVariant of type a{sv}, or %NULL for none
* @root_contents_checksum: ASCII SHA256 checksum for %OSTREE_OBJECT_TYPE_DIR_TREE
* @root_metadata_checksum: ASCII SHA256 checksum for %OSTREE_OBJECT_TYPE_DIR_META
* @out_commit: (out): Resulting ASCII SHA256 checksum for commit
@@ -1185,6 +1186,7 @@ ostree_repo_write_commit (OstreeRepo *self,
const char *parent,
const char *subject,
const char *body,
+ GVariant *metadata,
const char *root_contents_checksum,
const char *root_metadata_checksum,
char **out_commit,
@@ -1203,7 +1205,7 @@ ostree_repo_write_commit (OstreeRepo *self,
now = g_date_time_new_now_utc ();
commit = g_variant_new ("(@a{sv} ay@a(say)sst ay@ay)",
- create_empty_gvariant_dict (),
+ metadata ? metadata : create_empty_gvariant_dict (),
parent ? ostree_checksum_to_bytes_v (parent) : ot_gvariant_new_bytearray (NULL, 0),
g_variant_new_array (G_VARIANT_TYPE ("(say)"), NULL, 0),
subject, body ? body : "",
@@ -1226,6 +1228,94 @@ ostree_repo_write_commit (OstreeRepo *self,
return ret;
}
+GFile *
+_ostree_repo_get_commit_metadata_loose_path (OstreeRepo *self,
+ const char *checksum)
+{
+ gs_free char *commit_path = ostree_get_relative_object_path (checksum, OSTREE_OBJECT_TYPE_COMMIT, FALSE);
+ return ot_gfile_resolve_path_printf (self->repodir, "%smeta", commit_path);
+}
+
+/**
+ * ostree_repo_read_commit_detached_metadata:
+ * @self: Repo
+ * @checksum: ASCII SHA256 commit checksum
+ * @out_metadata: (out) (transfer full): Metadata associated with commit in with format "a{sv}", or %NULL if
none exists
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * OSTree commits can have arbitrary metadata associated; this
+ * function retrieves them. If none exists, @out_metadata will be set
+ * to %NULL.
+ */
+gboolean
+ostree_repo_read_commit_detached_metadata (OstreeRepo *self,
+ const char *checksum,
+ GVariant **out_metadata,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_unref_object GFile *metadata_path =
+ _ostree_repo_get_commit_metadata_loose_path (self, checksum);
+ gs_unref_variant GVariant *ret_metadata = NULL;
+ GError *temp_error = NULL;
+
+ if (!ot_util_variant_map (metadata_path, G_VARIANT_TYPE ("a{sv}"),
+ TRUE, &ret_metadata, &temp_error))
+ {
+ if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ {
+ g_clear_error (&temp_error);
+ }
+ else
+ {
+ g_propagate_error (error, temp_error);
+ goto out;
+ }
+ }
+
+ ret = TRUE;
+ ot_transfer_out_value (out_metadata, &ret_metadata);
+ out:
+ return ret;
+}
+
+/**
+ * ostree_repo_write_commit_detached_metadata:
+ * @self: Repo
+ * @checksum: ASCII SHA256 commit checksum
+ * @metadata: (allow-none): Metadata to associate with commit in with format "a{sv}", or %NULL to delete
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Replace any existing metadata associated with commit referred to by
+ * @checksum with @metadata. If @metadata is %NULL, then existing
+ * data will be deleted.
+ */
+gboolean
+ostree_repo_write_commit_detached_metadata (OstreeRepo *self,
+ const char *checksum,
+ GVariant *metadata,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_unref_object GFile *metadata_path =
+ _ostree_repo_get_commit_metadata_loose_path (self, checksum);
+
+ if (!g_file_replace_contents (metadata_path,
+ g_variant_get_data (metadata),
+ g_variant_get_size (metadata),
+ NULL, FALSE, 0, NULL,
+ cancellable, error))
+ goto out;
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
static GVariant *
create_tree_variant_from_hashes (GHashTable *file_checksums,
GHashTable *dir_contents_checksums,
diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h
index 6df7d0c..a3e8723 100644
--- a/src/libostree/ostree-repo-private.h
+++ b/src/libostree/ostree-repo-private.h
@@ -74,6 +74,10 @@ _ostree_repo_find_object (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
+GFile *
+_ostree_repo_get_commit_metadata_loose_path (OstreeRepo *self,
+ const char *checksum);
+
gboolean
_ostree_repo_has_loose_object (OstreeRepo *self,
const char *checksum,
diff --git a/src/libostree/ostree-repo-prune.c b/src/libostree/ostree-repo-prune.c
index caef29e..4f1db66 100644
--- a/src/libostree/ostree-repo-prune.c
+++ b/src/libostree/ostree-repo-prune.c
@@ -64,6 +64,13 @@ maybe_prune_loose_object (OtPruneData *data,
if (info)
{
+ if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
+ {
+ gs_unref_object GFile *detached_metadata =
+ _ostree_repo_get_commit_metadata_loose_path (data->repo, checksum);
+ if (!ot_gfile_ensure_unlinked (detached_metadata, cancellable, error))
+ goto out;
+ }
if (!gs_file_unlink (objf, cancellable, error))
goto out;
data->freed_bytes += g_file_info_get_size (info);
diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h
index ab4c4c7..ca24a76 100644
--- a/src/libostree/ostree-repo.h
+++ b/src/libostree/ostree-repo.h
@@ -318,12 +318,25 @@ gboolean ostree_repo_write_commit (OstreeRepo *self,
const char *parent,
const char *subject,
const char *body,
+ GVariant *metadata,
const char *root_contents_checksum,
const char *root_metadata_checksum,
char **out_commit,
GCancellable *cancellable,
GError **error);
+gboolean ostree_repo_read_commit_detached_metadata (OstreeRepo *self,
+ const char *checksum,
+ GVariant **out_metadata,
+ GCancellable *cancellable,
+ GError **error);
+
+gboolean ostree_repo_write_commit_detached_metadata (OstreeRepo *self,
+ const char *checksum,
+ GVariant *metadata,
+ GCancellable *cancellable,
+ GError **error);
+
/**
* OstreeRepoCheckoutMode:
* @OSTREE_REPO_CHECKOUT_MODE_NONE: No special options
diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c
index fd52a3e..e240204 100644
--- a/src/ostree/ot-builtin-commit.c
+++ b/src/ostree/ot-builtin-commit.c
@@ -31,6 +31,8 @@ static char *opt_subject;
static char *opt_body;
static char *opt_branch;
static char *opt_statoverride_file;
+static char **opt_metadata_strings;
+static char **opt_detached_metadata_strings;
static gboolean opt_link_checkout_speedup;
static gboolean opt_skip_if_unchanged;
static gboolean opt_tar_autocreate_parents;
@@ -45,6 +47,8 @@ static GOptionEntry options[] = {
{ "body", 'm', 0, G_OPTION_ARG_STRING, &opt_body, "Full description", "body" },
{ "branch", 'b', 0, G_OPTION_ARG_STRING, &opt_branch, "Branch", "branch" },
{ "tree", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_trees, "Overlay the given argument as a tree", "NAME" },
+ { "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-detached-metadata-string", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_detached_metadata_strings, "Append
given key and value (in string format) 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" },
{ "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Do not import extended attributes", NULL },
@@ -218,6 +222,45 @@ out:
return ret;
}
+static gboolean
+parse_keyvalue_strings (char **strings,
+ GVariant **out_metadata,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ char **iter;
+ gs_unref_variant_builder GVariantBuilder *builder = NULL;
+
+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
+
+ for (iter = strings; *iter; iter++)
+ {
+ const char *s;
+ const char *eq;
+ gs_free char *key = NULL;
+
+ s = *iter;
+
+ eq = strchr (s, '=');
+ if (!eq)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Missing '=' in KEY=VALUE metadata '%s'", s);
+ goto out;
+ }
+
+ key = g_strndup (s, eq - s);
+ g_variant_builder_add (builder, "{sv}", key,
+ g_variant_new_string (eq + 1));
+ }
+
+ ret = TRUE;
+ *out_metadata = g_variant_builder_end (builder);
+ g_variant_ref_sink (*out_metadata);
+ out:
+ return ret;
+}
+
gboolean
ostree_builtin_commit (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
{
@@ -228,6 +271,8 @@ ostree_builtin_commit (int argc, char **argv, OstreeRepo *repo, GCancellable *ca
gs_free char *parent = NULL;
gs_free char *commit_checksum = NULL;
gs_free char *contents_checksum = NULL;
+ gs_unref_variant GVariant *metadata = NULL;
+ gs_unref_variant GVariant *detached_metadata = NULL;
gs_unref_object OstreeMutableTree *mtree = NULL;
gs_free char *tree_type = NULL;
gs_unref_hashtable GHashTable *mode_adds = NULL;
@@ -246,6 +291,19 @@ ostree_builtin_commit (int argc, char **argv, OstreeRepo *repo, GCancellable *ca
goto out;
}
+ if (opt_metadata_strings)
+ {
+ if (!parse_keyvalue_strings (opt_metadata_strings,
+ &metadata, error))
+ goto out;
+ }
+ if (opt_detached_metadata_strings)
+ {
+ if (!parse_keyvalue_strings (opt_detached_metadata_strings,
+ &detached_metadata, error))
+ goto out;
+ }
+
if (!opt_branch)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
@@ -405,10 +463,18 @@ ostree_builtin_commit (int argc, char **argv, OstreeRepo *repo, GCancellable *ca
}
if (!ostree_repo_write_commit (repo, parent, opt_subject, opt_body,
- contents_checksum, root_metadata,
+ metadata, contents_checksum, root_metadata,
&commit_checksum, cancellable, error))
goto out;
+ if (detached_metadata)
+ {
+ if (!ostree_repo_write_commit_detached_metadata (repo, commit_checksum,
+ detached_metadata,
+ cancellable, error))
+ goto out;
+ }
+
ostree_repo_transaction_set_ref (repo, NULL, opt_branch, commit_checksum);
if (!ostree_repo_commit_transaction (repo, &stats, cancellable, error))
diff --git a/src/ostree/ot-builtin-show.c b/src/ostree/ot-builtin-show.c
index c98000b..09aaead 100644
--- a/src/ostree/ot-builtin-show.c
+++ b/src/ostree/ot-builtin-show.c
@@ -30,12 +30,14 @@
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_raw;
static GOptionEntry options[] = {
{ "print-related", 0, 0, G_OPTION_ARG_NONE, &opt_print_related, "If given, show the \"related\" commits",
NULL },
{ "print-variant-type", 0, 0, G_OPTION_ARG_STRING, &opt_print_variant_type, "If given, argument should be
a filename and it will be interpreted as this type", NULL },
{ "print-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_metadata_key, "Print string value of
metadata key KEY for given commit", "KEY" },
+ { "print-detached-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_detached_metadata_key, "Print
string value of detached metadata key KEY for given commit", "KEY" },
{ "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data" },
{ NULL }
};
@@ -98,22 +100,31 @@ do_print_related (OstreeRepo *repo,
}
static gboolean
-do_print_metadata_key (OstreeRepo *repo,
- const char *resolved_rev,
- const char *key,
- GError **error)
+do_print_metadata_key (OstreeRepo *repo,
+ const char *resolved_rev,
+ gboolean detached,
+ const char *key,
+ GError **error)
{
gboolean ret = FALSE;
const char *value;
gs_unref_variant GVariant *commit = NULL;
gs_unref_variant GVariant *metadata = NULL;
- if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT,
- resolved_rev, &commit, error))
- goto out;
-
- /* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */
- metadata = g_variant_get_child_value (commit, 1);
+ if (!detached)
+ {
+ if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT,
+ resolved_rev, &commit, error))
+ goto out;
+ /* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */
+ metadata = g_variant_get_child_value (commit, 0);
+ }
+ else
+ {
+ if (!ostree_repo_read_commit_detached_metadata (repo, resolved_rev, &metadata,
+ NULL, error))
+ goto out;
+ }
if (!g_variant_lookup (metadata, key, "&s", &value))
goto out;
@@ -125,7 +136,6 @@ do_print_metadata_key (OstreeRepo *repo,
return ret;
}
-
static gboolean
print_object (OstreeRepo *repo,
OstreeObjectType objtype,
@@ -198,12 +208,14 @@ ostree_builtin_show (int argc, char **argv, OstreeRepo *repo, GCancellable *canc
}
rev = argv[1];
- if (opt_print_metadata_key)
+ if (opt_print_metadata_key || opt_print_detached_metadata_key)
{
+ gboolean detached = opt_print_detached_metadata_key != NULL;
+ const char *key = detached ? opt_print_detached_metadata_key : opt_print_metadata_key;
if (!ostree_repo_resolve_rev (repo, rev, FALSE, &resolved_rev, error))
goto out;
- if (!do_print_metadata_key (repo, resolved_rev, opt_print_metadata_key, error))
+ if (!do_print_metadata_key (repo, resolved_rev, detached, key, error))
goto out;
}
else if (opt_print_related)
diff --git a/tests/test-basic.sh b/tests/test-basic.sh
index 0c17fc5..d5b9e5a 100755
--- a/tests/test-basic.sh
+++ b/tests/test-basic.sh
@@ -19,7 +19,7 @@
set -e
-echo "1..40"
+echo "1..41"
. $(dirname $0)/libtest.sh
@@ -282,3 +282,12 @@ $OSTREE checkout test2 checkout-test2
touch checkout-test2/sometestfile
$OSTREE commit -s sometest -b test2 checkout-test2
echo "ok commit with directory filename"
+
+$OSTREE commit -b test2 -s "Metadata string" --add-metadata-string=FOO=BAR
--add-metadata-string=KITTENS=CUTE --add-detached-metadata-string=SIGNATURE=HANCOCK --tree=ref=test2
+$OSTREE show --print-metadata-key=FOO test2 > test2-meta
+assert_file_has_content test2-meta "BAR"
+$OSTREE show --print-metadata-key=KITTENS test2 > test2-meta
+assert_file_has_content test2-meta "CUTE"
+$OSTREE show --print-detached-metadata-key=SIGNATURE test2 > test2-meta
+assert_file_has_content test2-meta "HANCOCK"
+echo "ok metadata commit with strings"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]