Blob Blame History Raw
From e3774822abcfd5be655cf7459c518beb3dc82b90 Mon Sep 17 00:00:00 2001
From: "Owen W. Taylor" <otaylor@fishsoup.net>
Date: Fri, 22 Oct 2021 14:20:56 -0400
Subject: [PATCH] dnf: Update appstream xml files if dnf_sack_add_repos() does
 the download

We were copying appstream xml files into /var/cache/app-info/xmls when we did
the repository download directly by calling dnf_repo_update(), but
dnf_repo_update() can also be implicitly called by dnf_sack_add_repos().

Check before calling dnf_sack_add_repos() which repos look out-of-date
and copy over their appstream info afterwards.
---
 backends/dnf/pk-backend-dnf.c | 134 ++++++++++++++++++++++------------
 1 file changed, 89 insertions(+), 45 deletions(-)

diff --git a/backends/dnf/pk-backend-dnf.c b/backends/dnf/pk-backend-dnf.c
index e62f40ff4..42ae19602 100644
--- a/backends/dnf/pk-backend-dnf.c
+++ b/backends/dnf/pk-backend-dnf.c
@@ -70,6 +70,12 @@ typedef struct {
 	HyGoal		 goal;
 } PkBackendDnfJobData;
 
+static GPtrArray * pk_backend_find_refresh_repos (PkBackendJob *job,
+						  DnfState     *state,
+						  GPtrArray    *repos,
+						  gboolean      force,
+						  GError      **error);
+
 const gchar *
 pk_backend_get_description (PkBackend *backend)
 {
@@ -555,11 +561,13 @@ dnf_utils_add_remote (PkBackendJob *job,
 	gboolean ret;
 	DnfState *state_local;
 	g_autoptr(GPtrArray) repos = NULL;
+	g_autoptr(GPtrArray) refresh_repos = NULL;
 
 	/* set state */
 	ret = dnf_state_set_steps (state, error,
 				   2, /* load files */
-				   98, /* add repos */
+				   1, /* count */
+				   97, /* add repos */
 				   -1);
 	if (!ret)
 		return FALSE;
@@ -573,6 +581,20 @@ dnf_utils_add_remote (PkBackendJob *job,
 	if (!dnf_state_done (state, error))
 		return FALSE;
 
+	/* Find out what repositories potentially will get downloaded - we might need to update
+	 * the appstream data for these repositories. Note that there is a small chance that the
+	 * repo metadata could expire between the call to dnf_repo_check() at this point, and
+	 * the call to dnf_repo_check() inside dnf_sack_add_repos() - in this case we'll end up
+	 * with stale appstream data until the next metadata refresh.
+	 */
+	refresh_repos = pk_backend_find_refresh_repos (job,
+						       state,
+						       repos,
+						       FALSE /* !force */,
+						       error);
+	if (refresh_repos == NULL)
+		return FALSE;
+
 	/* add each repo */
 	state_local = dnf_state_get_child (state);
 	ret = dnf_sack_add_repos (sack,
@@ -584,6 +606,12 @@ dnf_utils_add_remote (PkBackendJob *job,
 	if (!ret)
 		return FALSE;
 
+	for (guint i = 0; i < refresh_repos->len; i++) {
+		DnfRepo *repo = g_ptr_array_index (refresh_repos, i);
+		if (!dnf_utils_refresh_repo_appstream (repo, error))
+			return FALSE;
+	}
+
 	/* done */
 	if (!dnf_state_done (state, error))
 		return FALSE;
@@ -1655,49 +1683,22 @@ pk_backend_refresh_subman (PkBackendJob *job)
 	pk_backend_repo_list_changed (backend);
 }
 
-static void
-pk_backend_refresh_cache_thread (PkBackendJob *job,
-				 GVariant *params,
-				 gpointer user_data)
+static GPtrArray *
+pk_backend_find_refresh_repos (PkBackendJob *job,
+			       DnfState     *state,
+			       GPtrArray    *repos,
+			       gboolean      force,
+			       GError      **error)
 {
-	PkBackendDnfJobData *job_data = pk_backend_job_get_user_data (job);
-	PkBackend *backend = pk_backend_job_get_backend (job);
-	DnfRepo *repo;
+	g_autoptr(GPtrArray) refresh_repos = NULL;
 	DnfState *state_local;
 	DnfState *state_loop;
-	gboolean force;
-	gboolean ret;
 	guint cnt = 0;
 	guint i;
-	g_autoptr(DnfSack) sack = NULL;
-	g_autoptr(GError) error = NULL;
-	g_autoptr(GPtrArray) refresh_repos = NULL;
-	g_autoptr(GPtrArray) repos = NULL;
-
-	/* set state */
-	dnf_state_set_steps (job_data->state, NULL,
-			     1, /* count */
-			     95, /* download */
-			     4, /* rebuild SAT */
-			     -1);
-
-	g_variant_get (params, "(b)", &force);
-
-	/* kick subscription-manager if it exists */
-	pk_backend_refresh_subman (job);
-
-	/* ask the context's repo loader for new repos, forcing it to reload them */
-	repos = dnf_repo_loader_get_repos (dnf_context_get_repo_loader (job_data->context), &error);
-	if (repos == NULL) {
-		pk_backend_job_error_code (job,
-		                           error->code,
-		                           "failed to load repos: %s", error->message);
-		return;
-	}
 
 	/* count the enabled repos */
 	for (i = 0; i < repos->len; i++) {
-		repo = g_ptr_array_index (repos, i);
+		DnfRepo *repo = g_ptr_array_index (repos, i);
 		if (dnf_repo_get_enabled (repo) == DNF_REPO_ENABLED_NONE)
 			continue;
 		if (dnf_repo_get_kind (repo) == DNF_REPO_KIND_MEDIA)
@@ -1709,12 +1710,12 @@ pk_backend_refresh_cache_thread (PkBackendJob *job,
 
 	/* figure out which repos need refreshing */
 	refresh_repos = g_ptr_array_new ();
-	state_local = dnf_state_get_child (job_data->state);
+	state_local = dnf_state_get_child (state);
 	dnf_state_set_number_steps (state_local, cnt);
 	for (i = 0; i < repos->len; i++) {
+		DnfRepo *repo = g_ptr_array_index (repos, i);
 		gboolean repo_okay;
 
-		repo = g_ptr_array_index (repos, i);
 		if (dnf_repo_get_enabled (repo) == DNF_REPO_ENABLED_NONE)
 			continue;
 		if (dnf_repo_get_kind (repo) == DNF_REPO_KIND_MEDIA)
@@ -1733,16 +1734,59 @@ pk_backend_refresh_cache_thread (PkBackendJob *job,
 			                 g_ptr_array_index (repos, i));
 
 		/* done */
-		ret = dnf_state_done (state_local, &error);
-		if (!ret) {
-			pk_backend_job_error_code (job, error->code, "%s", error->message);
-			return;
-		}
+		if (!dnf_state_done (state_local, error))
+			return NULL;
 	}
 
 	/* done */
-	ret = dnf_state_done (job_data->state, &error);
-	if (!ret) {
+	if (!dnf_state_done (state, error))
+		return NULL;
+
+	return g_steal_pointer (&refresh_repos);
+}
+
+static void
+pk_backend_refresh_cache_thread (PkBackendJob *job,
+				 GVariant *params,
+				 gpointer user_data)
+{
+	PkBackendDnfJobData *job_data = pk_backend_job_get_user_data (job);
+	PkBackend *backend = pk_backend_job_get_backend (job);
+	DnfRepo *repo;
+	DnfState *state_local;
+	DnfState *state_loop;
+	gboolean force;
+	gboolean ret;
+	guint i;
+	g_autoptr(DnfSack) sack = NULL;
+	g_autoptr(GError) error = NULL;
+	g_autoptr(GPtrArray) refresh_repos = NULL;
+	g_autoptr(GPtrArray) repos = NULL;
+
+	/* set state */
+	dnf_state_set_steps (job_data->state, NULL,
+			     1, /* count */
+			     95, /* download */
+			     4, /* rebuild SAT */
+			     -1);
+
+	g_variant_get (params, "(b)", &force);
+
+	/* kick subscription-manager if it exists */
+	pk_backend_refresh_subman (job);
+
+	/* ask the context's repo loader for new repos, forcing it to reload them */
+	repos = dnf_repo_loader_get_repos (dnf_context_get_repo_loader (job_data->context), &error);
+	if (repos == NULL) {
+		pk_backend_job_error_code (job,
+		                           error->code,
+		                           "failed to load repos: %s", error->message);
+		return;
+	}
+
+	/* figure out which repos need refreshing */
+	refresh_repos = pk_backend_find_refresh_repos (job, job_data->state, repos, force, &error);
+	if (refresh_repos == NULL) {
 		pk_backend_job_error_code (job, error->code, "%s", error->message);
 		return;
 	}
-- 
2.29.2