lib/repo-refs: Add ostree_repo_remote_list_collection_refs() API

This parallels ostree_repo_remote_list_refs(), but returns a map of
OstreeCollectionRef → checksum, and includes refs from collection IDs
other than the remote repository’s main collection ID.

Use this in OstreeRepoFinderConfig to ensure that refs are matched
against even if they’re stored in the repository summary file’s
collection map, rather than its main ref map. This fixes false negatives
when searching for refs in some situations.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Closes: #1058
Approved by: cgwalters
This commit is contained in:
Philip Withnall 2017-08-07 19:52:17 +01:00 committed by Atomic Bot
parent 11e165b154
commit f35b409077
5 changed files with 136 additions and 4 deletions

View File

@ -82,6 +82,7 @@ ostree_repo_get_collection_id
ostree_repo_set_collection_id ostree_repo_set_collection_id
ostree_validate_collection_id ostree_validate_collection_id
ostree_repo_list_collection_refs ostree_repo_list_collection_refs
ostree_repo_remote_list_collection_refs
ostree_repo_set_collection_ref_immediate ostree_repo_set_collection_ref_immediate
ostree_repo_transaction_set_collection_ref ostree_repo_transaction_set_collection_ref
</SECTION> </SECTION>

View File

@ -70,6 +70,7 @@ global:
ostree_repo_list_collection_refs; ostree_repo_list_collection_refs;
ostree_repo_pull_from_remotes_async; ostree_repo_pull_from_remotes_async;
ostree_repo_pull_from_remotes_finish; ostree_repo_pull_from_remotes_finish;
ostree_repo_remote_list_collection_refs;
ostree_repo_resolve_keyring_for_collection; ostree_repo_resolve_keyring_for_collection;
ostree_repo_set_collection_id; ostree_repo_set_collection_id;
ostree_repo_set_collection_ref_immediate; ostree_repo_set_collection_ref_immediate;

View File

@ -111,7 +111,7 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find
for (i = 0; i < n_remotes; i++) for (i = 0; i < n_remotes; i++)
{ {
g_autoptr(GError) local_error = NULL; 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; const gchar *checksum;
g_autofree gchar *remote_collection_id = NULL; g_autofree gchar *remote_collection_id = NULL;
@ -127,8 +127,9 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find
continue; continue;
} }
if (!ostree_repo_remote_list_refs (parent_repo, remote_name, &remote_refs, if (!ostree_repo_remote_list_collection_refs (parent_repo, remote_name,
cancellable, &local_error)) &remote_refs, cancellable,
&local_error))
{ {
g_debug ("Ignoring remote %s due to error loading its refs: %s", g_debug ("Ignoring remote %s due to error loading its refs: %s",
remote_name, local_error->message); remote_name, local_error->message);
@ -139,7 +140,7 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find
for (j = 0; refs[j] != NULL; j++) for (j = 0; refs[j] != NULL; j++)
{ {
if (g_strcmp0 (refs[j]->collection_id, remote_collection_id) == 0 && 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 requested ref is listed in the refs for this remote. Add
* the remote to the results, and the ref to its * the remote to the results, and the ref to its

View File

@ -779,6 +779,126 @@ ostree_repo_remote_list_refs (OstreeRepo *self,
return TRUE; 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 collectionref 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 * static char *
relative_symlink_to (const char *relpath, relative_symlink_to (const char *relpath,
const char *target) const char *target)

View File

@ -482,6 +482,15 @@ gboolean ostree_repo_remote_list_refs (OstreeRepo *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); 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 _OSTREE_PUBLIC
gboolean ostree_repo_load_variant (OstreeRepo *self, gboolean ostree_repo_load_variant (OstreeRepo *self,
OstreeObjectType objtype, OstreeObjectType objtype,