lib/repo-refs: Add ostree_repo_remote_list_collection_refs() API
authorPhilip Withnall <withnall@endlessm.com>
Mon, 7 Aug 2017 18:52:17 +0000 (19:52 +0100)
committerAtomic Bot <atomic-devel@projectatomic.io>
Tue, 8 Aug 2017 13:59:58 +0000 (13:59 +0000)
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

apidoc/ostree-experimental-sections.txt
src/libostree/libostree-experimental.sym
src/libostree/ostree-repo-finder-config.c
src/libostree/ostree-repo-refs.c
src/libostree/ostree-repo.h

index a2c2c29549571a6e672ae8a652c0d34fbe7d817a..23412dda09162e3ee1219335a5f3684a80e823d7 100644 (file)
@@ -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
 </SECTION>
index 32ba09292f4d72bfcf1eef019d6c57da3c434c35..f60d4e013966d1d79853f1c0d136868f6aa20f7d 100644 (file)
@@ -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;
index 79a63536e74ea9f851b45ff69bd24bde100aba61..2f9841dba0f2deca0f77c6f99cd6eb95843c7248 100644 (file)
@@ -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
index a180e40ba0629619013e7367446da9857428b341..6c113fb65c8b27862d42bd5f8939439a3a73c531 100644 (file)
@@ -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)
index decf9a4e4e01bc538d826ec532ee0a027b57967c..f01fee2abfc48efadcbe6aafb993e5396ec00ddc 100644 (file)
@@ -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,