repo_pull (OstreeRepo                           *self,
           const char                           *remote_name,
           const char                          **dirs_to_pull,
           const char                           *ref_to_fetch,
           const char                           *rev_to_fetch,
           const OstreeRepoFinderResult * const *results_to_fetch,
           FlatpakPullFlags                      flatpak_flags,
           OstreeRepoPullFlags                   flags,
           OstreeAsyncProgress                  *progress,
           GCancellable                         *cancellable,
           GError                              **error)
{
  gboolean force_disable_deltas = (flatpak_flags & FLATPAK_PULL_FLAGS_NO_STATIC_DELTAS) != 0;
  g_autofree char *remote_and_branch = NULL;
  g_autofree char *current_checksum = NULL;

  g_autoptr(GVariant) old_commit = NULL;
  g_autoptr(GVariant) new_commit = NULL;
  const char *revs_to_fetch[2];
  gboolean res = FALSE;
  g_autofree gchar *collection_id = NULL;
  g_autoptr(GError) dummy_error = NULL;

  /* The ostree fetcher asserts if error is NULL */
  if (error == NULL)
    error = &dummy_error;

  /* If @results_to_fetch is set, @rev_to_fetch must be. */
  g_assert (results_to_fetch == NULL || rev_to_fetch != NULL);

  /* We always want this on for every type of pull */
  flags |= OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES;

  remote_and_branch = g_strdup_printf ("%s:%s", remote_name, ref_to_fetch);
  if (!ostree_repo_resolve_rev (self, remote_and_branch, TRUE, &current_checksum, error))
    return FALSE;

  if (current_checksum != NULL &&
      !ostree_repo_load_commit (self, current_checksum, &old_commit, NULL, error))
    return FALSE;

  if (!repo_get_remote_collection_id (self, remote_name, &collection_id, NULL))
    g_clear_pointer (&collection_id, g_free);

  if (collection_id != NULL)
    {
      GVariantBuilder find_builder, pull_builder;
      g_autoptr(GVariant) find_options = NULL, pull_options = NULL;
      g_autoptr(GAsyncResult) find_result = NULL, pull_result = NULL;
      g_auto(OstreeRepoFinderResultv) results = NULL;
      OstreeCollectionRef collection_ref;
      OstreeCollectionRef *collection_refs_to_fetch[2];
      guint32 update_freq = 0;
      g_autoptr(GMainContextPopDefault) context = NULL;

      /* Find options */
      g_variant_builder_init (&find_builder, G_VARIANT_TYPE ("a{sv}"));

      if (force_disable_deltas)
        {
          g_variant_builder_add (&find_builder, "{s@v}", "disable-static-deltas",
                                 g_variant_new_variant (g_variant_new_boolean (TRUE)));
        }

      collection_ref.collection_id = collection_id;
      collection_ref.ref_name = (char *) ref_to_fetch;

      collection_refs_to_fetch[0] = &collection_ref;
      collection_refs_to_fetch[1] = NULL;

      if (progress != NULL)
        update_freq = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (progress), "update-frequency"));
      if (update_freq == 0)
        update_freq = FLATPAK_DEFAULT_UPDATE_FREQUENCY;

      g_variant_builder_add (&find_builder, "{s@v}", "update-frequency",
                             g_variant_new_variant (g_variant_new_uint32 (update_freq)));

      if (rev_to_fetch != NULL)
        {
          g_variant_builder_add (&find_builder, "{s@v}", "override-commit-ids",
                                 g_variant_new_variant (g_variant_new_strv (&rev_to_fetch, 1)));
        }

      find_options = g_variant_ref_sink (g_variant_builder_end (&find_builder));

      /* Pull options */
      g_variant_builder_init (&pull_builder, G_VARIANT_TYPE ("a{sv}"));
      get_common_pull_options (&pull_builder, ref_to_fetch, dirs_to_pull, current_checksum,
                               force_disable_deltas, flags, progress);
      pull_options = g_variant_ref_sink (g_variant_builder_end (&pull_builder));

      context = flatpak_main_context_new_default ();

      if (results_to_fetch == NULL)
        {
          ostree_repo_find_remotes_async (self, (const OstreeCollectionRef * const *) collection_refs_to_fetch,
                                          find_options,
                                          NULL /* default finders */, progress, cancellable,
                                          async_result_cb, &find_result);

          while (find_result == NULL)
            g_main_context_iteration (context, TRUE);

          results = ostree_repo_find_remotes_finish (self, find_result, error);
          results_to_fetch = (const OstreeRepoFinderResult * const *) results;
        }

      if (results_to_fetch != NULL)
        {
          ostree_repo_pull_from_remotes_async (self, results_to_fetch,
                                               pull_options, progress,
                                               cancellable, async_result_cb,
                                               &pull_result);

          while (pull_result == NULL)
            g_main_context_iteration (context, TRUE);

          res = ostree_repo_pull_from_remotes_finish (self, pull_result, error);
        }
      else
        res = FALSE;
    }
  else
    res = FALSE;

  if (!res)
    {
      if (error != NULL && *error != NULL)
        g_debug ("Failed to pull using find-remotes; falling back to normal pull: %s", (*error)->message);
      g_clear_error (error);
    }

  if (!res)
    {
      GVariantBuilder builder;
      g_autoptr(GVariant) options = NULL;
      const char *refs_to_fetch[2];

      /* Pull options */
      g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
      get_common_pull_options (&builder, ref_to_fetch, dirs_to_pull, current_checksum,
                               force_disable_deltas, flags, progress);

      refs_to_fetch[0] = ref_to_fetch;
      refs_to_fetch[1] = NULL;
      g_variant_builder_add (&builder, "{s@v}", "refs",
                             g_variant_new_variant (g_variant_new_strv ((const char * const *) refs_to_fetch, -1)));

      revs_to_fetch[0] = rev_to_fetch;
      revs_to_fetch[1] = NULL;
      g_variant_builder_add (&builder, "{s@v}", "override-commit-ids",
                             g_variant_new_variant (g_variant_new_strv ((const char * const *) revs_to_fetch, -1)));

      options = g_variant_ref_sink (g_variant_builder_end (&builder));

      if (!ostree_repo_pull_with_options (self, remote_name, options,
                                          progress, cancellable, error))
        return translate_ostree_repo_pull_errors (error);
    }

  if (old_commit &&
      (flatpak_flags & FLATPAK_PULL_FLAGS_ALLOW_DOWNGRADE) == 0)
    {
      guint64 old_timestamp;
      guint64 new_timestamp;

      if (!ostree_repo_load_commit (self, rev_to_fetch, &new_commit, NULL, error))
        return FALSE;

      old_timestamp = ostree_commit_get_timestamp (old_commit);
      new_timestamp = ostree_commit_get_timestamp (new_commit);

      if (new_timestamp < old_timestamp)
        return flatpak_fail_error (error, FLATPAK_ERROR_DOWNGRADE, "Update is older than current version");
    }

  return TRUE;
}