flatpak_dir_update_appstream (FlatpakDir          *self,
                              const char          *remote,
                              const char          *arch,
                              gboolean            *out_changed,
                              OstreeAsyncProgress *progress,
                              GCancellable        *cancellable,
                              GError             **error)
{
  g_autofree char *new_branch = NULL;
  g_autofree char *old_branch = NULL;
  const char *used_branch = NULL;
  g_autofree char *remote_and_branch = NULL;
  g_autofree char *new_checksum = NULL;

  g_autoptr(GError) first_error = NULL;
  g_autoptr(GError) second_error = NULL;
  g_autoptr(FlatpakRemoteState) state = NULL;
  const char *installation;
  gboolean is_oci;

  if (out_changed)
    *out_changed = FALSE;

  if (arch == NULL)
    arch = flatpak_get_arch ();

  new_branch = g_strdup_printf ("appstream2/%s", arch);
  old_branch = g_strdup_printf ("appstream/%s", arch);

  is_oci = flatpak_dir_get_remote_oci (self, remote);

  state = flatpak_dir_get_remote_state_optional (self, remote, cancellable, error);
  if (state == NULL)
    return FALSE;

  if (flatpak_dir_use_system_helper (self, NULL))
    {
      g_auto(GLnxLockFile) child_repo_lock = { 0, };
      g_autofree char *url = NULL;
      g_autoptr(GFile) child_repo_file = NULL;
      g_autofree char *child_repo_path = NULL;
      gboolean gpg_verify_summary;
      gboolean gpg_verify;

      if (!ostree_repo_remote_get_url (self->repo,
                                       state->remote_name,
                                       &url,
                                       error))
        return FALSE;

      if (!ostree_repo_remote_get_gpg_verify_summary (self->repo, state->remote_name,
                                                      &gpg_verify_summary, error))
        return FALSE;

      if (!ostree_repo_remote_get_gpg_verify (self->repo, state->remote_name,
                                              &gpg_verify, error))
        return FALSE;

      if (is_oci)
        {
          /* In the OCI case, we just ask the system helper do the network i/o, since
           * there is no way to verify the index validity without actually downloading it.
           * While we try to avoid network i/o as root, there's no hard line where doing
           * network i/o as root is much worse than parsing the results of network i/o
           * as root. A trusted, but unprivileged helper could be used to do the download
           * if necessary.
           */
        }
      else if ((!gpg_verify_summary && state->collection_id == NULL) || !gpg_verify)
        {
          /* The remote is not gpg verified, so we don't want to allow installation via
             a download in the home directory, as there is no way to verify you're not
             injecting anything into the remote. However, in the case of a remote
             configured to a local filesystem we can just let the system helper do
             the installation, as it can then avoid network i/o and be certain the
             data comes from the right place.

             If @collection_id is non-%NULL, we can verify the refs in commit
             metadata, so don’t need to verify the summary. */
          if (!g_str_has_prefix (url, "file:"))
            return flatpak_fail_error (error, FLATPAK_ERROR_UNTRUSTED, _("Can't pull from untrusted non-gpg verified remote"));
        }
      else
        {
          g_autoptr(OstreeRepo) child_repo = flatpak_dir_create_system_child_repo (self, &child_repo_lock, NULL, error);
          if (child_repo == NULL)
            return FALSE;

          /* No need to use an existing OstreeRepoFinderResult array, since
           * appstream updates do not need to be atomic wrt other updates. */
          used_branch = new_branch;
          if (!flatpak_dir_pull (self, state, used_branch, NULL, NULL, NULL,
                                 child_repo, FLATPAK_PULL_FLAGS_NONE, OSTREE_REPO_PULL_FLAGS_MIRROR,
                                 progress, cancellable, &first_error))
            {
              used_branch = old_branch;
              if (!flatpak_dir_pull (self, state, used_branch, NULL, NULL, NULL,
                                     child_repo, FLATPAK_PULL_FLAGS_NONE, OSTREE_REPO_PULL_FLAGS_MIRROR,
                                     progress, cancellable, &second_error))
                {
                  g_prefix_error (&first_error, "Error updating appstream2: ");
                  g_prefix_error (&second_error, "Error updating appstream: ");
                  g_propagate_prefixed_error (error, g_steal_pointer (&second_error), "%s; ", first_error->message);
                  return FALSE;
                }
            }

          if (!child_repo_ensure_summary (child_repo, state, cancellable, error))
            return FALSE;

          remote_and_branch = g_strdup_printf ("%s:%s", remote, used_branch);

          if (!ostree_repo_resolve_rev (child_repo, remote_and_branch, TRUE, &new_checksum, error))
            return FALSE;

          child_repo_file = g_object_ref (ostree_repo_get_path (child_repo));
        }

      if (child_repo_file)
        child_repo_path = g_file_get_path (child_repo_file);

      installation = flatpak_dir_get_id (self);

      if (!flatpak_dir_system_helper_call_deploy_appstream (self,
                                                            child_repo_path ? child_repo_path : "",
                                                            FLATPAK_HELPER_DEPLOY_APPSTREAM_FLAGS_NONE,
                                                            remote,
                                                            arch,
                                                            installation ? installation : "",
                                                            cancellable,
                                                            error))
        return FALSE;

      if (child_repo_file)
        (void) flatpak_rm_rf (child_repo_file, NULL, NULL);

      return TRUE;
    }

  if (is_oci)
    {
      return flatpak_dir_update_appstream_oci (self, remote, arch,
                                               out_changed, progress, cancellable,
                                               error);
    }

  /* No need to use an existing OstreeRepoFinderResult array, since
   * appstream updates do not need to be atomic wrt other updates. */
  used_branch = new_branch;
  if (!flatpak_dir_pull (self, state, used_branch, NULL, NULL, NULL, NULL,
                         FLATPAK_PULL_FLAGS_NONE, OSTREE_REPO_PULL_FLAGS_NONE, progress,
                         cancellable, &first_error))
    {
      used_branch = old_branch;
      if (!flatpak_dir_pull (self, state, used_branch, NULL, NULL, NULL, NULL,
                             FLATPAK_PULL_FLAGS_NONE, OSTREE_REPO_PULL_FLAGS_NONE, progress,
                             cancellable, &second_error))
        {
          g_prefix_error (&first_error, "Error updating appstream2: ");
          g_prefix_error (&second_error, "Error updating appstream: ");
          g_propagate_prefixed_error (error, g_steal_pointer (&second_error), "%s; ", first_error->message);
          return FALSE;
        }
    }

  remote_and_branch = g_strdup_printf ("%s:%s", remote, used_branch);

  if (!ostree_repo_resolve_rev (self->repo, remote_and_branch, TRUE, &new_checksum, error))
    return FALSE;

  return flatpak_dir_deploy_appstream (self,
                                       remote,
                                       arch,
                                       out_changed,
                                       cancellable,
                                       error);
}