diff --git a/apidoc/ostree-experimental-sections.txt b/apidoc/ostree-experimental-sections.txt index a2c2c295..23412dda 100644 --- a/apidoc/ostree-experimental-sections.txt +++ b/apidoc/ostree-experimental-sections.txt @@ -82,6 +82,7 @@ ostree_repo_get_collection_id ostree_repo_set_collection_id ostree_validate_collection_id ostree_repo_list_collection_refs +ostree_repo_remote_list_collection_refs ostree_repo_set_collection_ref_immediate ostree_repo_transaction_set_collection_ref diff --git a/src/libostree/libostree-experimental.sym b/src/libostree/libostree-experimental.sym index 32ba0929..f60d4e01 100644 --- a/src/libostree/libostree-experimental.sym +++ b/src/libostree/libostree-experimental.sym @@ -70,6 +70,7 @@ global: ostree_repo_list_collection_refs; ostree_repo_pull_from_remotes_async; ostree_repo_pull_from_remotes_finish; + ostree_repo_remote_list_collection_refs; ostree_repo_resolve_keyring_for_collection; ostree_repo_set_collection_id; ostree_repo_set_collection_ref_immediate; diff --git a/src/libostree/ostree-repo-finder-config.c b/src/libostree/ostree-repo-finder-config.c index 79a63536..2f9841db 100644 --- a/src/libostree/ostree-repo-finder-config.c +++ b/src/libostree/ostree-repo-finder-config.c @@ -111,7 +111,7 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find for (i = 0; i < n_remotes; i++) { g_autoptr(GError) local_error = NULL; - g_autoptr(GHashTable) remote_refs = NULL; /* (element-type utf8 utf8) */ + g_autoptr(GHashTable) remote_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ const gchar *checksum; g_autofree gchar *remote_collection_id = NULL; @@ -127,8 +127,9 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find continue; } - if (!ostree_repo_remote_list_refs (parent_repo, remote_name, &remote_refs, - cancellable, &local_error)) + if (!ostree_repo_remote_list_collection_refs (parent_repo, remote_name, + &remote_refs, cancellable, + &local_error)) { g_debug ("Ignoring remote ‘%s’ due to error loading its refs: %s", remote_name, local_error->message); @@ -139,7 +140,7 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find for (j = 0; refs[j] != NULL; j++) { if (g_strcmp0 (refs[j]->collection_id, remote_collection_id) == 0 && - g_hash_table_lookup_extended (remote_refs, refs[j]->ref_name, NULL, (gpointer *) &checksum)) + g_hash_table_lookup_extended (remote_refs, refs[j], NULL, (gpointer *) &checksum)) { /* The requested ref is listed in the refs for this remote. Add * the remote to the results, and the ref to its diff --git a/src/libostree/ostree-repo-refs.c b/src/libostree/ostree-repo-refs.c index a180e40b..6c113fb6 100644 --- a/src/libostree/ostree-repo-refs.c +++ b/src/libostree/ostree-repo-refs.c @@ -779,6 +779,126 @@ ostree_repo_remote_list_refs (OstreeRepo *self, return TRUE; } +#ifdef OSTREE_ENABLE_EXPERIMENTAL_API +static gboolean +remote_list_collection_refs_process_refs (OstreeRepo *self, + const gchar *remote_name, + const gchar *summary_collection_id, + GVariant *summary_refs, + GHashTable *ret_all_refs, + GError **error) +{ + gsize j, n; + + for (j = 0, n = g_variant_n_children (summary_refs); j < n; j++) + { + const guchar *csum_bytes; + g_autoptr(GVariant) ref_v = NULL, csum_v = NULL; + gchar tmp_checksum[OSTREE_SHA256_STRING_LEN + 1]; + const gchar *ref_name; + + /* Check the ref name. */ + ref_v = g_variant_get_child_value (summary_refs, j); + g_variant_get_child (ref_v, 0, "&s", &ref_name); + + if (!ostree_validate_rev (ref_name, error)) + return FALSE; + + /* Check the commit checksum. */ + g_variant_get_child (ref_v, 1, "(t@ay@a{sv})", NULL, &csum_v, NULL); + + csum_bytes = ostree_checksum_bytes_peek_validate (csum_v, error); + if (csum_bytes == NULL) + return FALSE; + + ostree_checksum_inplace_from_bytes (csum_bytes, tmp_checksum); + + g_hash_table_insert (ret_all_refs, + ostree_collection_ref_new (summary_collection_id, ref_name), + g_strdup (tmp_checksum)); + } + + return TRUE; +} + +/** + * ostree_repo_remote_list_collection_refs: + * @self: Repo + * @remote_name: Name of the remote. + * @out_all_refs: (out) (element-type OstreeCollectionRef utf8): Mapping from collection–ref to checksum + * @cancellable: Cancellable + * @error: Error + * + * List refs advertised by @remote_name, including refs which are part of + * collections. If the repository at @remote_name has a collection ID set, its + * refs will be returned with that collection ID; otherwise, they will be returned + * with a %NULL collection ID in each #OstreeCollectionRef key in @out_all_refs. + * Any refs for other collections stored in the repository will also be returned. + * No filtering is performed. + * + * Since: 2017.10 + */ +gboolean +ostree_repo_remote_list_collection_refs (OstreeRepo *self, + const char *remote_name, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GBytes) summary_bytes = NULL; + g_autoptr(GHashTable) ret_all_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ + g_autoptr(GVariant) summary_v = NULL; + g_autoptr(GVariant) additional_metadata_v = NULL; + g_autoptr(GVariant) summary_refs = NULL; + const char *summary_collection_id; + g_autoptr(GVariantIter) summary_collection_map = NULL; + + if (!ostree_repo_remote_fetch_summary (self, remote_name, + &summary_bytes, NULL, + cancellable, error)) + return FALSE; + + if (summary_bytes == NULL) + return glnx_throw (error, "Remote refs not available; server has no summary file"); + + ret_all_refs = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, + (GDestroyNotify) ostree_collection_ref_free, + g_free); + + summary_v = g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, + summary_bytes, FALSE); + additional_metadata_v = g_variant_get_child_value (summary_v, 1); + + /* List the refs in the main map. */ + if (!g_variant_lookup (additional_metadata_v, OSTREE_SUMMARY_COLLECTION_ID, "&s", &summary_collection_id)) + summary_collection_id = NULL; + + summary_refs = g_variant_get_child_value (summary_v, 0); + + if (!remote_list_collection_refs_process_refs (self, remote_name, + summary_collection_id, summary_refs, + ret_all_refs, error)) + return FALSE; + + /* List the refs in the collection map. */ + if (!g_variant_lookup (additional_metadata_v, OSTREE_SUMMARY_COLLECTION_MAP, "a{sa(s(taya{sv}))}", &summary_collection_map)) + summary_collection_map = NULL; + + while (summary_collection_map != NULL && + g_variant_iter_loop (summary_collection_map, "{s@a(s(taya{sv}))}", &summary_collection_id, &summary_refs)) + { + if (!remote_list_collection_refs_process_refs (self, remote_name, + summary_collection_id, summary_refs, + ret_all_refs, error)) + return FALSE; + } + + ot_transfer_out_value (out_all_refs, &ret_all_refs); + return TRUE; +} +#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ + static char * relative_symlink_to (const char *relpath, const char *target) diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index decf9a4e..f01fee2a 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -482,6 +482,15 @@ gboolean ostree_repo_remote_list_refs (OstreeRepo *self, GCancellable *cancellable, GError **error); +#ifdef OSTREE_ENABLE_EXPERIMENTAL_API +_OSTREE_PUBLIC +gboolean ostree_repo_remote_list_collection_refs (OstreeRepo *self, + const char *remote_name, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error); +#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ + _OSTREE_PUBLIC gboolean ostree_repo_load_variant (OstreeRepo *self, OstreeObjectType objtype,