repo_pull (OstreeRepo                           *self,
           FlatpakRemoteState                   *state,
           const char                          **dirs_to_pull,
           const char                           *ref_to_fetch,
           const char                           *rev_to_fetch, /* (nullable) */
           GFile                                *sideload_repo,
           const char                           *token,
           FlatpakPullFlags                      flatpak_flags,
           OstreeRepoPullFlags                   flags,
           FlatpakProgress                      *progress,
           GCancellable                         *cancellable,
           GError                              **error)
{
  gboolean force_disable_deltas = (flatpak_flags & FLATPAK_PULL_FLAGS_NO_STATIC_DELTAS) != 0;
  g_autofree char *current_checksum = NULL;
  g_autoptr(GVariant) old_commit = NULL;
  g_autoptr(GVariant) new_commit = NULL;
  const char *revs_to_fetch[2];
  g_autoptr(GError) dummy_error = NULL;
  GVariantBuilder builder;
  g_autoptr(GVariant) options = NULL;
  const char *refs_to_fetch[2];
  g_autofree char *sideload_url = NULL;

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

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

  if (!flatpak_repo_resolve_rev (self, NULL, state->remote_name, ref_to_fetch, TRUE,
                                 &current_checksum, cancellable, error))
    return FALSE;

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

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

  if (sideload_repo)
    {
      GVariantBuilder colref_builder;

      sideload_url = g_file_get_uri (sideload_repo);

      g_debug ("Sideloading %s from %s in pull", ref_to_fetch, sideload_url);

      g_assert (state->collection_id != NULL);

      g_variant_builder_init (&colref_builder, G_VARIANT_TYPE ("a(sss)"));
      g_variant_builder_add (&colref_builder, "(sss)", state->collection_id, ref_to_fetch, rev_to_fetch);

      g_variant_builder_add (&builder, "{s@v}", "collection-refs",
                             g_variant_new_variant (g_variant_builder_end (&colref_builder)));
      g_variant_builder_add (&builder, "{s@v}", "override-remote-name",
                             g_variant_new_variant (g_variant_new_string (state->remote_name)));
    }
  else
    {
      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)));


      if (state->sideload_repos->len > 0)
        {
          GVariantBuilder localcache_repos_builder;

          g_variant_builder_init (&localcache_repos_builder, G_VARIANT_TYPE ("as"));
          for (int i = 0; i < state->sideload_repos->len; i++)
            {
              FlatpakSideloadState *ss = g_ptr_array_index (state->sideload_repos, i);
              GFile *sideload_path = ostree_repo_get_path (ss->repo);

              g_variant_builder_add (&localcache_repos_builder, "s",
                                     flatpak_file_get_path_cached (sideload_path));
            }
          g_variant_builder_add (&builder, "{s@v}", "localcache-repos",
                                 g_variant_new_variant (g_variant_builder_end (&localcache_repos_builder)));
        }
    }

  options = g_variant_ref_sink (g_variant_builder_end (&builder));

  {
    g_auto(FlatpakMainContext) context = FLATKPAK_MAIN_CONTEXT_INIT;
    flatpak_progress_init_main_context (progress, &context);

    if (!ostree_repo_pull_with_options (self,
                                        sideload_url ? sideload_url : state->remote_name,
                                        options, context.ostree_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;
}
repo_pull (OstreeRepo                           *self,
           FlatpakRemoteState                   *state,
           const char                          **dirs_to_pull,
           const char                           *ref_to_fetch,
           const char                           *rev_to_fetch,  
           GFile                                *sideload_repo,
           const char                           *token,
           FlatpakPullFlags                      flatpak_flags,
           OstreeRepoPullFlags                   flags,
           FlatpakProgress                      *progress,
           GCancellable                         *cancellable,
           GError                              **error)
{
  gboolean force_disable_deltas = (flatpak_flags & FLATPAK_PULL_FLAGS_NO_STATIC_DELTAS) != 0;
  g_autofree char *current_checksum = NULL;
  g_autoptr(GVariant) old_commit = NULL;
  g_autoptr(GVariant) new_commit = NULL;
  const char *revs_to_fetch[2];
  g_autoptr(GError) dummy_error = NULL;
  GVariantBuilder builder;
  g_autoptr(GVariant) options = NULL;
  const char *refs_to_fetch[2];
  g_autofree char *sideload_url = NULL;

   
  if (error == NULL)
    error = &dummy_error;

   
  flags |= OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES;

  if (!flatpak_repo_resolve_rev (self, NULL, state->remote_name, ref_to_fetch, TRUE,
                                 &current_checksum, cancellable, error))
    return FALSE;

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

   
  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
  get_common_pull_options (&builder, state, ref_to_fetch, token, dirs_to_pull, current_checksum,
                           force_disable_deltas, flags, progress);

  if (sideload_repo)
    {
      GVariantBuilder colref_builder;

      sideload_url = g_file_get_uri (sideload_repo);

      g_debug ("Sideloading %s from %s in pull", ref_to_fetch, sideload_url);

      g_assert (state->collection_id != NULL);

      g_variant_builder_init (&colref_builder, G_VARIANT_TYPE ("a(sss)"));
      g_variant_builder_add (&colref_builder, "(sss)", state->collection_id, ref_to_fetch, rev_to_fetch);

      g_variant_builder_add (&builder, "{s@v}", "collection-refs",
                             g_variant_new_variant (g_variant_builder_end (&colref_builder)));
      g_variant_builder_add (&builder, "{s@v}", "override-remote-name",
                             g_variant_new_variant (g_variant_new_string (state->remote_name)));
    }
  else
    {
      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)));


      if (state->sideload_repos->len > 0)
        {
          GVariantBuilder localcache_repos_builder;

          g_variant_builder_init (&localcache_repos_builder, G_VARIANT_TYPE ("as"));
          for (int i = 0; i < state->sideload_repos->len; i++)
            {
              FlatpakSideloadState *ss = g_ptr_array_index (state->sideload_repos, i);
              GFile *sideload_path = ostree_repo_get_path (ss->repo);

              g_variant_builder_add (&localcache_repos_builder, "s",
                                     flatpak_file_get_path_cached (sideload_path));
            }
          g_variant_builder_add (&builder, "{s@v}", "localcache-repos",
                                 g_variant_new_variant (g_variant_builder_end (&localcache_repos_builder)));
        }
    }

  options = g_variant_ref_sink (g_variant_builder_end (&builder));

  {
    g_auto(FlatpakMainContext) context = FLATKPAK_MAIN_CONTEXT_INIT;
    flatpak_progress_init_main_context (progress, &context);

    if (!ostree_repo_pull_with_options (self,
                                        sideload_url ? sideload_url : state->remote_name,
                                        options, context.ostree_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;
}