From d7a15b381ec7d64af5d24a8922a79738ccb7840b Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 11 May 2012 16:23:28 -0400 Subject: [PATCH] core: Allow adding related objects to commits This will be used to store the set of components. --- src/libostree/ostree-core.h | 2 + src/libostree/ostree-repo.c | 4 +- src/libostree/ostree-repo.h | 1 + src/ostree/ostree-pull.c | 49 +++++++++++++++++++-- src/ostree/ot-builtin-commit.c | 79 +++++++++++++++++++++++++++++++++- 5 files changed, 128 insertions(+), 7 deletions(-) diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h index fd58ee3f..d3491e57 100644 --- a/src/libostree/ostree-core.h +++ b/src/libostree/ostree-core.h @@ -29,6 +29,8 @@ G_BEGIN_DECLS #define OSTREE_MAX_METADATA_SIZE (1 << 26) +#define OSTREE_MAX_RECURSION (256) + #define OSTREE_EMPTY_STRING_SHA256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; typedef enum { diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index bee08dca..fcb0a5c9 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -1691,6 +1691,7 @@ ostree_repo_stage_commit (OstreeRepo *self, const char *subject, const char *body, GVariant *metadata, + GVariant *related_objects, const char *root_contents_checksum, const char *root_metadata_checksum, char **out_commit, @@ -1712,8 +1713,7 @@ ostree_repo_stage_commit (OstreeRepo *self, commit = g_variant_new ("(@a{sv}@ay@a(say)sst@ay@ay)", 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), + related_objects ? related_objects : g_variant_new_array (G_VARIANT_TYPE ("(say)"), NULL, 0), subject, body ? body : "", GUINT64_TO_BE (g_date_time_to_unix (now)), ostree_checksum_to_bytes_v (root_contents_checksum), diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index 20154777..3cecffad 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -245,6 +245,7 @@ gboolean ostree_repo_stage_commit (OstreeRepo *self, const char *subject, const char *body, GVariant *metadata, + GVariant *related_objects, const char *content_checksum, const char *metadata_checksum, char **out_commit, diff --git a/src/ostree/ostree-pull.c b/src/ostree/ostree-pull.c index 766e1cba..652cff33 100644 --- a/src/ostree/ostree-pull.c +++ b/src/ostree/ostree-pull.c @@ -29,10 +29,12 @@ gboolean verbose; gboolean opt_prefer_loose; +gboolean opt_related; static GOptionEntry options[] = { { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Show more information", NULL }, { "prefer-loose", 0, 0, G_OPTION_ARG_NONE, &opt_prefer_loose, "Download loose objects by default", NULL }, + { "related", 0, 0, G_OPTION_ARG_NONE, &opt_related, "Download related commits", NULL }, { NULL }, }; @@ -666,6 +668,7 @@ fetch_and_store_metadata (OtPullData *pull_data, static gboolean fetch_and_store_tree_metadata_recurse (OtPullData *pull_data, + int depth, const char *rev, GCancellable *cancellable, GError **error) @@ -678,6 +681,13 @@ fetch_and_store_tree_metadata_recurse (OtPullData *pull_data, ot_lobj GFile *stored_path = NULL; ot_lfree char *pack_checksum = NULL; + if (depth > OSTREE_MAX_RECURSION) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Exceeded maximum recursion"); + goto out; + } + if (!fetch_and_store_metadata (pull_data, rev, OSTREE_OBJECT_TYPE_DIR_TREE, &tree, cancellable, error)) goto out; @@ -726,7 +736,7 @@ fetch_and_store_tree_metadata_recurse (OtPullData *pull_data, g_free (tmp_checksum); tmp_checksum = ostree_checksum_from_bytes_v (tree_csum); - if (!fetch_and_store_tree_metadata_recurse (pull_data, tmp_checksum, cancellable, error)) + if (!fetch_and_store_tree_metadata_recurse (pull_data, depth+1, tmp_checksum, cancellable, error)) goto out; } @@ -737,15 +747,18 @@ fetch_and_store_tree_metadata_recurse (OtPullData *pull_data, static gboolean fetch_and_store_commit_metadata_recurse (OtPullData *pull_data, + int depth, const char *rev, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; ot_lvariant GVariant *commit = NULL; + ot_lvariant GVariant *related_objects = NULL; ot_lvariant GVariant *tree_contents_csum = NULL; ot_lvariant GVariant *tree_meta_csum = NULL; ot_lfree char *tmp_checksum = NULL; + GVariantIter *iter = NULL; if (!fetch_and_store_metadata (pull_data, rev, OSTREE_OBJECT_TYPE_COMMIT, &commit, cancellable, error)) @@ -763,12 +776,39 @@ fetch_and_store_commit_metadata_recurse (OtPullData *pull_data, g_free (tmp_checksum); tmp_checksum = ostree_checksum_from_bytes_v (tree_contents_csum); - if (!fetch_and_store_tree_metadata_recurse (pull_data, tmp_checksum, + if (!fetch_and_store_tree_metadata_recurse (pull_data, depth, tmp_checksum, cancellable, error)) goto out; + if (opt_related) + { + const char *name; + ot_lvariant GVariant *csum_v = NULL; + + if (depth > OSTREE_MAX_RECURSION) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Exceeded maximum recursion"); + goto out; + } + + related_objects = g_variant_get_child_value (commit, 2); + iter = g_variant_iter_new (related_objects); + + while (g_variant_iter_loop (iter, "(&s@ay)", &name, &csum_v)) + { + ot_lfree char *checksum = ostree_checksum_from_bytes_v (csum_v); + + if (!fetch_and_store_commit_metadata_recurse (pull_data, depth+1, checksum, + cancellable, error)) + goto out; + } + } + ret = TRUE; out: + if (iter) + g_variant_iter_free (iter); return ret; } @@ -1258,7 +1298,8 @@ ostree_builtin_pull (int argc, char **argv, GFile *repo_path, GError **error) { const char *commit = value; - if (!fetch_and_store_commit_metadata_recurse (pull_data, commit, cancellable, error)) + if (!fetch_and_store_commit_metadata_recurse (pull_data, 0, commit, + cancellable, error)) goto out; } @@ -1286,7 +1327,7 @@ ostree_builtin_pull (int argc, char **argv, GFile *repo_path, GError **error) if (!ostree_validate_checksum_string (sha256, error)) goto out; - if (!fetch_and_store_commit_metadata_recurse (pull_data, sha256, cancellable, error)) + if (!fetch_and_store_commit_metadata_recurse (pull_data, 0, sha256, cancellable, error)) goto out; g_hash_table_insert (updated_refs, g_strdup (ref), g_strdup (sha256)); diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index add7aa2c..4fe36748 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -37,6 +37,7 @@ static char *parent; static char *branch; static char **metadata_strings; static char *statoverride_file; +static char *opt_related_objects_file; static gboolean skip_if_unchanged; static gboolean tar_autocreate_parents; static gboolean no_xattrs; @@ -59,6 +60,7 @@ static GOptionEntry options[] = { { "tar-autocreate-parents", 0, 0, G_OPTION_ARG_NONE, &tar_autocreate_parents, "When loading tar archives, automatically create parent directories as needed", NULL }, { "skip-if-unchanged", 0, 0, G_OPTION_ARG_NONE, &skip_if_unchanged, "If the contents are unchanged from previous commit, do nothing", NULL }, { "statoverride", 0, 0, G_OPTION_ARG_FILENAME, &statoverride_file, "File containing list of modifications to make to permissions", "path" }, + { "related-objects-file", 0, 0, G_OPTION_ARG_FILENAME, &opt_related_objects_file, "File containing newline-separated pairs of (checksum SPACE name) of related objects", "path" }, { NULL } }; @@ -115,6 +117,74 @@ parse_statoverride_file (GHashTable **out_mode_add, return ret; } +static gboolean +parse_related_objects_file (GVariant **out_related_objects, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + gsize len; + char **iter = NULL; /* nofree */ + ot_lhash GHashTable *ret_hash = NULL; + ot_lvariant GVariant *ret_related_objects = NULL; + ot_lobj GFile *path = NULL; + ot_lfree char *contents = NULL; + GVariantBuilder builder; + gboolean builder_initialized = FALSE; + char **lines = NULL; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(say)")); + builder_initialized = TRUE; + + path = ot_gfile_new_for_path (opt_related_objects_file); + + if (!g_file_load_contents (path, cancellable, &contents, &len, NULL, + error)) + goto out; + + lines = g_strsplit (contents, "\n", -1); + + for (iter = lines; iter && *iter; iter++) + { + const char *line = *iter; + const char *spc; + ot_lfree char *name = NULL; + + if (!*line) + break; + + spc = strchr (line, ' '); + if (!spc) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Malformed related objects file"); + goto out; + } + + name = g_strndup (line, spc - line); + + if (!ostree_validate_checksum_string (spc + 1, error)) + goto out; + + { + GVariant *csum_bytes_v = ostree_checksum_to_bytes_v (spc + 1); + g_variant_builder_add (&builder, "(s@ay)", name, csum_bytes_v); + } + } + + ret_related_objects = g_variant_builder_end (&builder); + g_variant_ref_sink (ret_related_objects); + builder_initialized = FALSE; + + ret = TRUE; + ot_transfer_out_value (out_related_objects, &ret_related_objects); + out: + if (builder_initialized) + g_variant_builder_clear (&builder); + g_strfreev (lines); + return ret; +} + static OstreeRepoCommitFilterResult commit_filter (OstreeRepo *self, const char *path, @@ -155,6 +225,7 @@ ostree_builtin_commit (int argc, char **argv, GFile *repo_path, GError **error) ot_lfree char *commit_checksum = NULL; ot_lvariant GVariant *parent_commit = NULL; ot_lvariant GVariant *metadata = NULL; + ot_lvariant GVariant *related_objects = NULL; ot_lobj GFile *metadata_f = NULL; ot_lfree char *contents_checksum = NULL; ot_lobj OstreeMutableTree *mtree = NULL; @@ -236,6 +307,12 @@ ostree_builtin_commit (int argc, char **argv, GFile *repo_path, GError **error) goto out; } + if (opt_related_objects_file) + { + if (!parse_related_objects_file (&related_objects, cancellable, error)) + goto out; + } + repo = ostree_repo_new (repo_path); if (!ostree_repo_check (repo, error)) goto out; @@ -390,7 +467,7 @@ ostree_builtin_commit (int argc, char **argv, GFile *repo_path, GError **error) } if (!ostree_repo_stage_commit (repo, branch, parent, subject, body, metadata, - contents_checksum, root_metadata, + related_objects, contents_checksum, root_metadata, &commit_checksum, cancellable, error)) goto out;