From eaee792f9f386eb90797895cb9f6637e2b0ff6bc Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Wed, 13 Aug 2025 18:32:50 +0200 Subject: [PATCH 01/12] dnf5-plugin: Auto-accept new RPM keys --- 0001-dnf5-plugin.patch | 12 +++++++----- gnome-software.spec | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/0001-dnf5-plugin.patch b/0001-dnf5-plugin.patch index 3e9a13f..0ba8881 100644 --- a/0001-dnf5-plugin.patch +++ b/0001-dnf5-plugin.patch @@ -1,5 +1,5 @@ -at commit 8a1f0ca6564157dd688c84ffd25af9747c1e038e -Date: Mon Aug 11 17:07:06 2025 +0200 +at commit d7f516e25742e1c0631194df5829bf73668f7df5 +Date: Wed Aug 13 18:23:59 2025 +0200 diff --git a/meson_options.txt b/meson_options.txt index cd49cf529..27fa15e8b 100644 @@ -610,10 +610,10 @@ index 000000000..5d522468c +G_END_DECLS diff --git a/plugins/dnf5/gs-plugin-dnf5.c b/plugins/dnf5/gs-plugin-dnf5.c new file mode 100644 -index 000000000..88d7e25d8 +index 000000000..36d10163a --- /dev/null +++ b/plugins/dnf5/gs-plugin-dnf5.c -@@ -0,0 +1,4275 @@ +@@ -0,0 +1,4277 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * vi:set noexpandtab tabstop=8 shiftwidth=8: + * @@ -1702,7 +1702,9 @@ index 000000000..88d7e25d8 + g_autoptr(GVariantBuilder) options_builder = NULL; + gboolean confirmed; + -+ confirmed = gs_plugin_ask_untrusted (GS_PLUGIN (data->self), data->title, data->msg, data->details, data->accept_label); ++ /* auto-accept new keys, just as PacakgeKit plugin used to do */ ++ confirmed = TRUE; ++ /* confirmed = gs_plugin_ask_untrusted (GS_PLUGIN (data->self), data->title, data->msg, data->details, data->accept_label); */ + + options_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (options_builder, "{sv}", "interactive", diff --git a/gnome-software.spec b/gnome-software.spec index 10c8d74..21466da 100644 --- a/gnome-software.spec +++ b/gnome-software.spec @@ -30,7 +30,7 @@ Name: gnome-software Version: 49~beta -Release: 3%{?dist} +Release: 4%{?dist} Summary: A software center for GNOME License: GPL-2.0-or-later From 446ce42aa8d01622a25810693ed527f115afddbe Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Mon, 25 Aug 2025 12:05:46 +0200 Subject: [PATCH 02/12] dnf5-plugin: Auto-accept new RPM keys only when installed from repos - dnf5-plugin: Download offline updates also by regular users --- 0001-dnf5-plugin.patch | 327 +++++++++++++++++++++++++++++++++++++++-- gnome-software.spec | 2 +- 2 files changed, 317 insertions(+), 12 deletions(-) diff --git a/0001-dnf5-plugin.patch b/0001-dnf5-plugin.patch index 0ba8881..088ad51 100644 --- a/0001-dnf5-plugin.patch +++ b/0001-dnf5-plugin.patch @@ -1,5 +1,5 @@ -at commit d7f516e25742e1c0631194df5829bf73668f7df5 -Date: Wed Aug 13 18:23:59 2025 +0200 +at commit 55ca6d4d49d5edd682b8ca15904ec556eb5d0874 +Date: Tue Aug 19 13:13:48 2025 +0200 diff --git a/meson_options.txt b/meson_options.txt index cd49cf529..27fa15e8b 100644 @@ -610,10 +610,10 @@ index 000000000..5d522468c +G_END_DECLS diff --git a/plugins/dnf5/gs-plugin-dnf5.c b/plugins/dnf5/gs-plugin-dnf5.c new file mode 100644 -index 000000000..36d10163a +index 000000000..c8d9ed83d --- /dev/null +++ b/plugins/dnf5/gs-plugin-dnf5.c -@@ -0,0 +1,4277 @@ +@@ -0,0 +1,4582 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * vi:set noexpandtab tabstop=8 shiftwidth=8: + * @@ -1671,9 +1671,13 @@ index 000000000..36d10163a + gchar *details; + gchar *accept_label; + gchar *key_id; ++ gchar *key_filename; ++ gchar *session_path; ++ GCancellable *cancellable; /* (owned) */ + GsPluginDnf5 *self; /* (owned) */ + GWeakRef repo_proxy_weakref; /* GsDnf5RpmRepo */ + gboolean interactive; ++ gboolean confirmed_by_repo; +} QuestionData; + +static void @@ -1685,6 +1689,9 @@ index 000000000..36d10163a + g_free (data->details); + g_free (data->accept_label); + g_free (data->key_id); ++ g_free (data->key_filename); ++ g_free (data->session_path); ++ g_clear_object (&data->cancellable); + g_clear_object (&data->self); + g_weak_ref_clear (&data->repo_proxy_weakref); + g_free (data); @@ -1703,8 +1710,9 @@ index 000000000..36d10163a + gboolean confirmed; + + /* auto-accept new keys, just as PacakgeKit plugin used to do */ -+ confirmed = TRUE; -+ /* confirmed = gs_plugin_ask_untrusted (GS_PLUGIN (data->self), data->title, data->msg, data->details, data->accept_label); */ ++ confirmed = data->confirmed_by_repo; ++ if (!confirmed) ++ confirmed = gs_plugin_ask_untrusted (GS_PLUGIN (data->self), data->title, data->msg, data->details, data->accept_label); + + options_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (options_builder, "{sv}", "interactive", @@ -1714,7 +1722,7 @@ index 000000000..36d10163a + data->key_id, + confirmed, + g_variant_builder_end (options_builder), -+ NULL, ++ data->cancellable, + gs_dnf5_confirm_key_response_cb, + NULL); + } @@ -1722,10 +1730,184 @@ index 000000000..36d10163a + return G_SOURCE_REMOVE; +} + ++static gboolean ++gs_dnf5_read_package_repo_ids_cb (GsPluginDnf5 *self, ++ GVariant *package_array, ++ gpointer user_data, ++ GCancellable *cancellable, ++ GError **error) ++{ ++ GPtrArray **out_repo_ids = user_data; ++ g_autoptr(GVariantDict) dict = NULL; ++ g_autoptr(GVariant) value = NULL; ++ ++ dict = g_variant_dict_new (package_array); ++ ++ value = g_variant_dict_lookup_value (dict, "from_repo_id", G_VARIANT_TYPE_STRING); ++ if (value != NULL) { ++ const gchar *repo_id_const = g_variant_get_string (value, NULL); ++ if (repo_id_const != NULL && *repo_id_const != '\0') { ++ if (*out_repo_ids == NULL) ++ *out_repo_ids = g_ptr_array_new_with_free_func (g_free); ++ g_ptr_array_add (*out_repo_ids, g_strdup (repo_id_const)); ++ } ++ } ++ ++ return TRUE; ++} ++ ++static gboolean ++gs_dnf5_read_repo_gpg_info_cb (GsPluginDnf5 *self, ++ GVariant *package_array, ++ gpointer user_data, ++ GCancellable *cancellable, ++ GError **error) ++{ ++ guint *out_n_good = user_data; ++ g_autoptr(GVariantDict) dict = NULL; ++ g_autoptr(GVariant) id_value = NULL; ++ g_autoptr(GVariant) gpgcheck_value = NULL; ++ ++ dict = g_variant_dict_new (package_array); ++ ++ id_value = g_variant_dict_lookup_value (dict, "id", G_VARIANT_TYPE_STRING); ++ gpgcheck_value = g_variant_dict_lookup_value (dict, "gpgcheck", G_VARIANT_TYPE_BOOLEAN); ++ ++ if (id_value != NULL && gpgcheck_value != NULL) { ++ gboolean gpgcheck = g_variant_get_boolean (gpgcheck_value); ++ ++ if (gpgcheck) ++ *out_n_good = (*out_n_good) + 1; ++ } ++ ++ return TRUE; ++} ++ ++static gpointer ++gs_dnf5_check_key_source_thread (gpointer user_data) ++{ ++ QuestionData *data = user_data; ++ g_autoptr(GsDnf5RpmRpm) rpm_proxy = NULL; ++ g_autoptr(GPtrArray) repo_ids = NULL; ++ g_autoptr(GError) local_error = NULL; ++ gboolean success; ++ ++ rpm_proxy = gs_dnf5_rpm_rpm_proxy_new_sync (data->self->connection, ++ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, ++ GS_DNF5_INTERFACE_RPM_DNF, ++ data->session_path, ++ data->cancellable, ++ &local_error); ++ success = rpm_proxy != NULL; ++ if (!success) { ++ gs_dnf5_convert_error (&local_error); ++ g_prefix_error_literal (&local_error, "Failed to create Rpm proxy: "); ++ } ++ ++ /* try to get whether the key comes from any package */ ++ if (success) { ++ g_autoptr(GVariantBuilder) options_builder = NULL; ++ g_autoptr(GVariantBuilder) package_attrs_builder = NULL; ++ g_autoptr(GVariantBuilder) whatprovides_builder = NULL; ++ g_autoptr(GVariant) result = NULL; ++ ++ g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (rpm_proxy), G_MAXINT); ++ ++ package_attrs_builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); ++ g_variant_builder_add (package_attrs_builder, "s", "from_repo_id"); ++ ++ whatprovides_builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); ++ g_variant_builder_add (whatprovides_builder, "s", data->key_filename); ++ ++ options_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); ++ g_variant_builder_add (options_builder, "{sv}", "package_attrs", ++ g_variant_builder_end (package_attrs_builder)); ++ g_variant_builder_add (options_builder, "{sv}", "whatprovides", ++ g_variant_builder_end (whatprovides_builder)); ++ g_variant_builder_add (options_builder, "{sv}", "scope", ++ g_variant_new_string ("installed")); ++ ++ success = gs_dnf5_rpm_rpm_call_list_sync (rpm_proxy, ++ g_variant_builder_end (options_builder), ++ &result, ++ data->cancellable, ++ &local_error); ++ ++ if (success) { ++ success = gs_dnf5_foreach_item (data->self, result, gs_dnf5_read_package_repo_ids_cb, &repo_ids, data->cancellable, &local_error); ++ } else { ++ gs_dnf5_convert_error (&local_error); ++ g_prefix_error_literal (&local_error, "Failed to call rpm::list: "); ++ } ++ } ++ ++ if (success && repo_ids != NULL) { ++ g_autoptr(GVariantBuilder) patterns_builder = NULL; ++ guint n_verify = 0; ++ ++ for (guint i = 0; i < repo_ids->len; i++) { ++ const gchar *repo_id = g_ptr_array_index (repo_ids, i); ++ /* those are special repos, like `@commandline` */ ++ if (*repo_id != '@') { ++ if (patterns_builder == NULL) ++ patterns_builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); ++ g_variant_builder_add (patterns_builder, "s", repo_id); ++ n_verify++; ++ } ++ } ++ ++ if (patterns_builder != NULL) { ++ g_autoptr(GsDnf5RpmRepo) repo_proxy = NULL; ++ ++ repo_proxy = g_weak_ref_get (&data->repo_proxy_weakref); ++ if (repo_proxy != NULL) { ++ g_autoptr(GVariantBuilder) repo_attrs_builder = NULL; ++ g_autoptr(GVariantBuilder) options_builder = NULL; ++ g_autoptr(GVariant) result = NULL; ++ ++ repo_attrs_builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); ++ g_variant_builder_add (repo_attrs_builder, "s", "id"); ++ g_variant_builder_add (repo_attrs_builder, "s", "gpgcheck"); ++ ++ options_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); ++ g_variant_builder_add (options_builder, "{sv}", "patterns", ++ g_variant_builder_end (patterns_builder)); ++ g_variant_builder_add (options_builder, "{sv}", "repo_attrs", ++ g_variant_builder_end (repo_attrs_builder)); ++ ++ success = gs_dnf5_rpm_repo_call_list_sync (repo_proxy, ++ g_variant_builder_end (options_builder), ++ &result, ++ data->cancellable, ++ &local_error); ++ ++ if (success) { ++ guint n_good = 0; ++ ++ success = gs_dnf5_foreach_item (data->self, result, gs_dnf5_read_repo_gpg_info_cb, &n_good, data->cancellable, &local_error); ++ ++ data->confirmed_by_repo = success && n_verify == n_good; ++ } else { ++ gs_dnf5_convert_error (&local_error); ++ g_prefix_error_literal (&local_error, "Failed to call repo::list: "); ++ } ++ } else { ++ success = FALSE; ++ g_set_error_literal (&local_error, G_IO_ERROR, G_IO_ERROR_FAILED, "Repo proxy vanished"); ++ } ++ } ++ } ++ ++ g_idle_add_full (G_PRIORITY_HIGH_IDLE, gs_dnf5_ask_question_idle_cb, data, (GDestroyNotify) question_data_free); ++ ++ return NULL; ++} ++ +typedef struct { + GsPluginDnf5 *self; /* (not owned) */ + const gchar *session_path; /* (not owned) */ + GsDnf5RpmRepo *repo_proxy; /* (not owned) */ ++ GCancellable *cancellable; /* (not owned) */ + gboolean interactive; +} RepoKeyImportData; + @@ -1800,11 +1982,18 @@ index 000000000..36d10163a + data->details = g_string_free (details, FALSE); + data->accept_label = g_strdup (_("_Import Key")); + data->key_id = g_strdup (arg_key_id); ++ data->key_filename = g_steal_pointer (&key_filename); ++ data->session_path = g_strdup (repo_key_import_data->session_path); + data->self = g_object_ref (repo_key_import_data->self); + data->interactive = repo_key_import_data->interactive; ++ data->confirmed_by_repo = FALSE; ++ g_set_object (&data->cancellable, repo_key_import_data->cancellable); + g_weak_ref_init (&data->repo_proxy_weakref, repo_key_import_data->repo_proxy); + -+ g_idle_add_full (G_PRIORITY_HIGH_IDLE, gs_dnf5_ask_question_idle_cb, data, (GDestroyNotify) question_data_free); ++ if (data->key_filename != NULL) ++ g_thread_unref (g_thread_new ("gs-dnf5-check-key-source_thread", gs_dnf5_check_key_source_thread, data)); ++ else ++ g_idle_add_full (G_PRIORITY_HIGH_IDLE, gs_dnf5_ask_question_idle_cb, data, (GDestroyNotify) question_data_free); +} + +static void @@ -1886,7 +2075,8 @@ index 000000000..36d10163a + GS_DNF5_TRANSACTION_FLAG_OFFLINE = 1 << 0, + GS_DNF5_TRANSACTION_FLAG_RESOLVE_ONLY = 1 << 1, + GS_DNF5_TRANSACTION_FLAG_DISALLOW_ERASING = 1 << 2, /* negative flag, to not have it everywhere */ -+ GS_DNF5_TRANSACTION_FLAG_INTERACTIVE = 1 << 3 ++ GS_DNF5_TRANSACTION_FLAG_INTERACTIVE = 1 << 3, ++ GS_DNF5_TRANSACTION_FLAG_DOWNLOAD_ONLY = 1 << 4 +} GsDnf5TransactionFlags; + +static gboolean @@ -1965,6 +2155,7 @@ index 000000000..36d10163a + repo_key_import_data.session_path = session_path; + repo_key_import_data.repo_proxy = repo_proxy; + repo_key_import_data.interactive = interactive; ++ repo_key_import_data.cancellable = cancellable; + repo_key_import_id = g_signal_connect (base_proxy, "repo_key_import_request", + G_CALLBACK (gs_dnf5_repo_key_import_request_cb), &repo_key_import_data); + @@ -2017,6 +2208,10 @@ index 000000000..36d10163a + g_variant_builder_add (options_builder, "{sv}", "offline", + g_variant_new_boolean (TRUE)); + } ++ if ((flags & GS_DNF5_TRANSACTION_FLAG_DOWNLOAD_ONLY) != 0) { ++ g_variant_builder_add (options_builder, "{sv}", "downloadonly", ++ g_variant_new_boolean (TRUE)); ++ } + g_variant_builder_add (options_builder, "{sv}", "interactive", + g_variant_new_boolean (interactive)); + @@ -3576,6 +3771,7 @@ index 000000000..36d10163a + GsAppList *list, + gboolean is_install, + gboolean interactive, ++ gboolean can_apply, + GsPluginEventCallback event_callback, + void *event_user_data, + GCancellable *cancellable, @@ -3700,7 +3896,8 @@ index 000000000..36d10163a + success = rpm_proxy != NULL; + if (success) { + g_autoptr(GVariantBuilder) options_builder = NULL; -+ GsDnf5TransactionFlags flags = interactive ? GS_DNF5_TRANSACTION_FLAG_INTERACTIVE : GS_DNF5_TRANSACTION_FLAG_NONE; ++ GsDnf5TransactionFlags flags = (interactive ? GS_DNF5_TRANSACTION_FLAG_INTERACTIVE : GS_DNF5_TRANSACTION_FLAG_NONE) | ++ (!can_apply ? GS_DNF5_TRANSACTION_FLAG_DOWNLOAD_ONLY : GS_DNF5_TRANSACTION_FLAG_NONE); + + g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (rpm_proxy), G_MAXINT); + @@ -3732,7 +3929,7 @@ index 000000000..36d10163a + success = success && gs_dnf5_run_transaction (self, session_path, rpm_proxy, progress_app, progress_list, + flags | (is_install ? 0 : GS_DNF5_TRANSACTION_FLAG_OFFLINE), + NULL, cancellable, error); -+ if (success && !is_install) { ++ if (success && !is_install && can_apply) { + /* ensure the update is finished with the 'reboot' action */ + g_autoptr(GsDnf5Offline) offline_proxy = NULL; + @@ -3852,6 +4049,7 @@ index 000000000..36d10163a + + success = gs_dnf5_install_update (plugin, data->apps, TRUE, + (data->flags & GS_PLUGIN_INSTALL_APPS_FLAGS_INTERACTIVE) != 0, ++ (data->flags & GS_PLUGIN_INSTALL_APPS_FLAGS_NO_APPLY) == 0, + data->event_callback, data->event_user_data, + cancellable, &local_error); + @@ -4095,6 +4293,7 @@ index 000000000..36d10163a + + success = gs_dnf5_install_update (plugin, data->apps, FALSE, + (data->flags & GS_PLUGIN_UPDATE_APPS_FLAGS_INTERACTIVE) != 0, ++ (data->flags & GS_PLUGIN_UPDATE_APPS_FLAGS_NO_APPLY) == 0, + data->event_callback, data->event_user_data, + cancellable, &local_error); + @@ -4780,6 +4979,110 @@ index 000000000..36d10163a + return g_task_propagate_boolean (G_TASK (result), error); +} + ++/* Run in @worker. */ ++static void ++gs_dnf5_cancel_offline_update_thread_cb (GTask *task, ++ gpointer source_object, ++ gpointer task_data, ++ GCancellable *cancellable) ++{ ++ GsPluginDnf5 *self = GS_PLUGIN_DNF5 (source_object); ++ GsPluginCancelOfflineUpdateData *data = task_data; ++ g_autofree gchar *session_path = NULL; ++ g_autoptr(GsAppList) list = NULL; ++ g_autoptr(GsDnf5SessionManager) session_manager = NULL; ++ g_autoptr(GsDnf5Offline) offline_proxy = NULL; ++ gboolean success; ++ g_autoptr(GError) local_error = NULL; ++ ++ assert_in_worker (self); ++ ++ session_path = gs_dnf5_open_session (self, GS_DNF5_RELEASEVER_DEFAULT, &session_manager, cancellable, &local_error); ++ if (session_path == NULL) { ++ gs_dnf5_convert_error (&local_error); ++ g_task_return_error (task, g_steal_pointer (&local_error)); ++ return; ++ } ++ ++ offline_proxy = gs_dnf5_offline_proxy_new_sync (self->connection, ++ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, ++ GS_DNF5_INTERFACE_RPM_DNF, ++ session_path, ++ cancellable, ++ &local_error); ++ success = offline_proxy != NULL; ++ if (!success) { ++ gs_dnf5_convert_error (&local_error); ++ g_prefix_error_literal (&local_error, "Failed to create Offline proxy: "); ++ } ++ ++ if (success) { ++ gboolean pending = FALSE; ++ g_autoptr(GVariant) transaction_status = NULL; ++ ++ if (gs_dnf5_offline_call_get_status_sync (offline_proxy, &pending, &transaction_status, cancellable, &local_error) && ++ pending && transaction_status != NULL) { ++ g_autoptr(GVariantBuilder) options_builder = NULL; ++ g_autofree gchar *op_error_msg = NULL; ++ gboolean op_success = FALSE; ++ ++ options_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); ++ g_variant_builder_add (options_builder, "{sv}", "interactive", ++ g_variant_new_boolean ((data->flags & GS_PLUGIN_CANCEL_OFFLINE_UPDATE_FLAGS_INTERACTIVE) != 0)); ++ ++ success = gs_dnf5_offline_call_cancel_with_options_sync (offline_proxy, g_variant_builder_end (options_builder), ++ &op_success, &op_error_msg, cancellable, &local_error); ++ if (!success) { ++ gs_dnf5_convert_error (&local_error); ++ g_prefix_error_literal (&local_error, "Failed to call OfflineProxy::cancel: "); ++ } else if (!op_success) { ++ success = FALSE; ++ if (op_error_msg != NULL) { ++ g_set_error_literal (&local_error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, op_error_msg); ++ g_prefix_error_literal (&local_error, "Failed to call OfflineProxy::cancel op: "); ++ } else { ++ g_set_error_literal (&local_error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Failed to call OfflineProxy::cancel op"); ++ } ++ } ++ } ++ } ++ ++ gs_dnf5_close_session (self, session_manager, session_path); ++ ++ if (success) { ++ g_task_return_boolean (task, TRUE); ++ } else { ++ gs_dnf5_convert_error (&local_error); ++ g_task_return_error (task, g_steal_pointer (&local_error)); ++ } ++} ++ ++static void ++gs_plugin_dnf5_cancel_offline_update_async (GsPlugin *plugin, ++ GsPluginCancelOfflineUpdateFlags flags, ++ GCancellable *cancellable, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ GsPluginDnf5 *self = GS_PLUGIN_DNF5 (plugin); ++ g_autoptr(GTask) task = NULL; ++ gboolean interactive = (flags & GS_PLUGIN_CANCEL_OFFLINE_UPDATE_FLAGS_INTERACTIVE) != 0; ++ ++ task = gs_plugin_cancel_offline_update_data_new_task (plugin, flags, cancellable, callback, user_data); ++ g_task_set_source_tag (task, gs_plugin_dnf5_cancel_offline_update_async); ++ ++ gs_worker_thread_queue (self->worker, gs_dnf5_get_priority_for_interactivity (interactive), ++ gs_dnf5_cancel_offline_update_thread_cb, g_steal_pointer (&task)); ++} ++ ++static gboolean ++gs_plugin_dnf5_cancel_offline_update_finish (GsPlugin *plugin, ++ GAsyncResult *result, ++ GError **error) ++{ ++ return g_task_propagate_boolean (G_TASK (result), error); ++} ++ +static void +gs_plugin_dnf5_dispose (GObject *object) +{ @@ -4865,6 +5168,8 @@ index 000000000..36d10163a + plugin_class->download_upgrade_finish = gs_plugin_dnf5_download_upgrade_finish; + plugin_class->trigger_upgrade_async = gs_plugin_dnf5_trigger_upgrade_async; + plugin_class->trigger_upgrade_finish = gs_plugin_dnf5_trigger_upgrade_finish; ++ plugin_class->cancel_offline_update_async = gs_plugin_dnf5_cancel_offline_update_async; ++ plugin_class->cancel_offline_update_finish = gs_plugin_dnf5_cancel_offline_update_finish; +} + +static void diff --git a/gnome-software.spec b/gnome-software.spec index 21466da..2cce046 100644 --- a/gnome-software.spec +++ b/gnome-software.spec @@ -30,7 +30,7 @@ Name: gnome-software Version: 49~beta -Release: 4%{?dist} +Release: 5%{?dist} Summary: A software center for GNOME License: GPL-2.0-or-later From e95633c7038667767acefda20b67d7f50d928c98 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Tue, 26 Aug 2025 19:02:10 +0200 Subject: [PATCH 03/12] dnf5-plugin: Skip historical updates search when no last date is set --- 0001-dnf5-plugin.patch | 97 ++++++++++++++++++++++-------------------- gnome-software.spec | 2 +- 2 files changed, 53 insertions(+), 46 deletions(-) diff --git a/0001-dnf5-plugin.patch b/0001-dnf5-plugin.patch index 088ad51..43864c1 100644 --- a/0001-dnf5-plugin.patch +++ b/0001-dnf5-plugin.patch @@ -1,5 +1,5 @@ -at commit 55ca6d4d49d5edd682b8ca15904ec556eb5d0874 -Date: Tue Aug 19 13:13:48 2025 +0200 +at commit 73640bc9127fb2200189433f935445208bf0b472 +Date: Tue Aug 26 18:59:16 2025 +0200 diff --git a/meson_options.txt b/meson_options.txt index cd49cf529..27fa15e8b 100644 @@ -610,10 +610,10 @@ index 000000000..5d522468c +G_END_DECLS diff --git a/plugins/dnf5/gs-plugin-dnf5.c b/plugins/dnf5/gs-plugin-dnf5.c new file mode 100644 -index 000000000..c8d9ed83d +index 000000000..b9b698a81 --- /dev/null +++ b/plugins/dnf5/gs-plugin-dnf5.c -@@ -0,0 +1,4582 @@ +@@ -0,0 +1,4589 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * vi:set noexpandtab tabstop=8 shiftwidth=8: + * @@ -2767,55 +2767,62 @@ index 000000000..c8d9ed83d + g_prefix_error_literal (&local_error, "Failed to call Rpm::list: "); + } + } else if (is_historical_update == GS_APP_QUERY_TRISTATE_TRUE) { -+ g_autoptr(GsDnf5History) history_proxy = NULL; ++ g_autoptr(GSettings) settings = NULL; ++ gint64 timestamp; ++ gboolean interactive = (data->flags & GS_PLUGIN_LIST_APPS_FLAGS_INTERACTIVE) != 0; + -+ history_proxy = gs_dnf5_history_proxy_new_sync (self->connection, -+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, -+ GS_DNF5_INTERFACE_RPM_DNF, -+ session_path, -+ cancellable, -+ &local_error); -+ success = history_proxy != NULL; -+ if (!success) { -+ gs_dnf5_convert_error (&local_error); -+ g_prefix_error_literal (&local_error, "Failed to create History proxy: "); -+ } ++ /* use the option the GUI part uses */ ++ settings = g_settings_new ("org.gnome.software"); ++ timestamp = g_settings_get_int64 (settings, "install-timestamp"); + -+ if (success) { -+ g_autoptr(GVariantBuilder) options_builder = NULL; -+ g_autoptr(GVariant) result = NULL; -+ g_autoptr(GSettings) settings; -+ gint64 timestamp; ++ if (timestamp > 0 || interactive) { ++ g_autoptr(GsDnf5History) history_proxy = NULL; + -+ /* use the option the GUI part uses */ -+ settings = g_settings_new ("org.gnome.software"); -+ timestamp = g_settings_get_int64 (settings, "install-timestamp"); -+ -+ options_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); -+ g_variant_builder_add (options_builder, "{sv}", "since", -+ g_variant_new_int64 (timestamp)); -+ g_variant_builder_add (options_builder, "{sv}", "package_attrs", -+ gs_dnf5_dup_package_attrs ()); -+ -+ success = gs_dnf5_history_call_recent_changes_sync (history_proxy, -+ g_variant_builder_end (options_builder), -+ &result, -+ cancellable, -+ &local_error); ++ history_proxy = gs_dnf5_history_proxy_new_sync (self->connection, ++ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, ++ GS_DNF5_INTERFACE_RPM_DNF, ++ session_path, ++ cancellable, ++ &local_error); ++ success = history_proxy != NULL; ++ if (!success) { ++ gs_dnf5_convert_error (&local_error); ++ g_prefix_error_literal (&local_error, "Failed to create History proxy: "); ++ } + + if (success) { -+ ReadPackageData rpd = { 0, }; ++ g_autoptr(GVariantBuilder) options_builder = NULL; ++ g_autoptr(GVariant) result = NULL; + -+ rpd.list = list; -+ rpd.set_state = GS_APP_STATE_UNKNOWN; -+ rpd.nevra_to_app = NULL; -+ rpd.timestamp = timestamp; ++ options_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); ++ g_variant_builder_add (options_builder, "{sv}", "since", ++ g_variant_new_int64 (timestamp)); ++ g_variant_builder_add (options_builder, "{sv}", "package_attrs", ++ gs_dnf5_dup_package_attrs ()); + -+ success = gs_dnf5_foreach_item (self, result, gs_dnf5_read_history_items_cb, &rpd, cancellable, &local_error); -+ } else { -+ gs_dnf5_convert_error (&local_error); -+ g_prefix_error_literal (&local_error, "Failed to call recent_changes: "); ++ success = gs_dnf5_history_call_recent_changes_sync (history_proxy, ++ g_variant_builder_end (options_builder), ++ &result, ++ cancellable, ++ &local_error); ++ ++ if (success) { ++ ReadPackageData rpd = { 0, }; ++ ++ rpd.list = list; ++ rpd.set_state = GS_APP_STATE_UNKNOWN; ++ rpd.nevra_to_app = NULL; ++ rpd.timestamp = timestamp; ++ ++ success = gs_dnf5_foreach_item (self, result, gs_dnf5_read_history_items_cb, &rpd, cancellable, &local_error); ++ } else { ++ gs_dnf5_convert_error (&local_error); ++ g_prefix_error_literal (&local_error, "Failed to call recent_changes: "); ++ } + } ++ } else { ++ /* initialize the value to today */ ++ g_settings_set (settings, "install-timestamp", "x", g_get_real_time () / G_USEC_PER_SEC); + } + } else if (gs_component_kind_array_contains (component_kinds, AS_COMPONENT_KIND_REPOSITORY)) { + g_autoptr(GsDnf5RpmRepo) repo_proxy = NULL; diff --git a/gnome-software.spec b/gnome-software.spec index 2cce046..ad7833b 100644 --- a/gnome-software.spec +++ b/gnome-software.spec @@ -30,7 +30,7 @@ Name: gnome-software Version: 49~beta -Release: 5%{?dist} +Release: 6%{?dist} Summary: A software center for GNOME License: GPL-2.0-or-later From 4a71393113c82fe2afd330153fd30851504aa0da Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Fri, 29 Aug 2025 09:11:51 +0200 Subject: [PATCH 04/12] Update to 49.rc --- gnome-software.spec | 4 ++-- sources | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gnome-software.spec b/gnome-software.spec index ad7833b..c6f4ac8 100644 --- a/gnome-software.spec +++ b/gnome-software.spec @@ -29,8 +29,8 @@ %global __provides_exclude_from ^%{_libdir}/%{name}/plugins-%{gs_plugin_version}/.*\\.so.*$ Name: gnome-software -Version: 49~beta -Release: 6%{?dist} +Version: 49~rc +Release: 1%{?dist} Summary: A software center for GNOME License: GPL-2.0-or-later diff --git a/sources b/sources index f212fbd..c3ec757 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (gnome-software-49.beta.tar.xz) = 9cb6d67216193840b2661871ef43da5e726a284d1164781f13423ee8dd86359334f199efc29f4b3a0b3eddfa8a3811d7dd38cd412fa53aaebb2e1c35ddc1f9df +SHA512 (gnome-software-49.rc.tar.xz) = cecebbff1163f0179c5699ecc8325e2c4f68c811ec7633e6cf32e18ad2f03592b55daa16b9b5497a117cbfbf63f3d9162dd8e8191e6a6213d35261fa1bad15a5 From 90da5737b3044a752d2f4d7ebc5513123b46113d Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Mon, 1 Sep 2025 18:28:21 +0200 Subject: [PATCH 05/12] Resolves: #2392057 (dnf5-pugin: No update notifications shown) --- 0001-dnf5-plugin.patch | 18 +++++++++--------- gnome-software.spec | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/0001-dnf5-plugin.patch b/0001-dnf5-plugin.patch index 43864c1..3b4b355 100644 --- a/0001-dnf5-plugin.patch +++ b/0001-dnf5-plugin.patch @@ -1,5 +1,5 @@ -at commit 73640bc9127fb2200189433f935445208bf0b472 -Date: Tue Aug 26 18:59:16 2025 +0200 +at commit 786bab5f1928920251ee9e93d51953ff9dd9faa4 +Date: Mon Sep 1 18:23:09 2025 +0200 diff --git a/meson_options.txt b/meson_options.txt index cd49cf529..27fa15e8b 100644 @@ -610,7 +610,7 @@ index 000000000..5d522468c +G_END_DECLS diff --git a/plugins/dnf5/gs-plugin-dnf5.c b/plugins/dnf5/gs-plugin-dnf5.c new file mode 100644 -index 000000000..b9b698a81 +index 000000000..82f3e19a8 --- /dev/null +++ b/plugins/dnf5/gs-plugin-dnf5.c @@ -0,0 +1,4589 @@ @@ -2769,13 +2769,12 @@ index 000000000..b9b698a81 + } else if (is_historical_update == GS_APP_QUERY_TRISTATE_TRUE) { + g_autoptr(GSettings) settings = NULL; + gint64 timestamp; -+ gboolean interactive = (data->flags & GS_PLUGIN_LIST_APPS_FLAGS_INTERACTIVE) != 0; + + /* use the option the GUI part uses */ + settings = g_settings_new ("org.gnome.software"); -+ timestamp = g_settings_get_int64 (settings, "install-timestamp"); ++ timestamp = (gint64) g_settings_get_uint64 (settings, "packagekit-historical-updates-timestamp"); + -+ if (timestamp > 0 || interactive) { ++ if (timestamp > 0) { + g_autoptr(GsDnf5History) history_proxy = NULL; + + history_proxy = gs_dnf5_history_proxy_new_sync (self->connection, @@ -2820,9 +2819,6 @@ index 000000000..b9b698a81 + g_prefix_error_literal (&local_error, "Failed to call recent_changes: "); + } + } -+ } else { -+ /* initialize the value to today */ -+ g_settings_set (settings, "install-timestamp", "x", g_get_real_time () / G_USEC_PER_SEC); + } + } else if (gs_component_kind_array_contains (component_kinds, AS_COMPONENT_KIND_REPOSITORY)) { + g_autoptr(GsDnf5RpmRepo) repo_proxy = NULL; @@ -3973,6 +3969,10 @@ index 000000000..b9b698a81 + } else if (!success) { + gs_dnf5_convert_error (error); + g_prefix_error_literal (error, "Failed to set finish action: "); ++ } else { ++ g_autoptr(GSettings) settings = g_settings_new ("org.gnome.software"); ++ /* to check anything installed/updated after today */ ++ g_settings_set (settings, "packagekit-historical-updates-timestamp", "t", g_get_real_time () / G_USEC_PER_SEC); + } + } else { + gs_dnf5_convert_error (error); diff --git a/gnome-software.spec b/gnome-software.spec index c6f4ac8..09c8546 100644 --- a/gnome-software.spec +++ b/gnome-software.spec @@ -30,7 +30,7 @@ Name: gnome-software Version: 49~rc -Release: 1%{?dist} +Release: 2%{?dist} Summary: A software center for GNOME License: GPL-2.0-or-later From ac8dbc92e832cb6c72963e90cd49f7d92a6b05ee Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Fri, 12 Sep 2025 10:01:34 +0200 Subject: [PATCH 06/12] Update to 49.0 --- gnome-software.spec | 8 ++++---- sources | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gnome-software.spec b/gnome-software.spec index 09c8546..34328cf 100644 --- a/gnome-software.spec +++ b/gnome-software.spec @@ -29,17 +29,19 @@ %global __provides_exclude_from ^%{_libdir}/%{name}/plugins-%{gs_plugin_version}/.*\\.so.*$ Name: gnome-software -Version: 49~rc -Release: 2%{?dist} +Version: 49.0 +Release: 1%{?dist} Summary: A software center for GNOME License: GPL-2.0-or-later URL: https://apps.gnome.org/Software Source0: https://download.gnome.org/sources/gnome-software/49/%{name}-%{tarball_version}.tar.xz +%if %{with dnf5} # to update the patch enter the ./dnf5-plugin/ directory and run from # it the ./update-patch.sh script Patch: 0001-dnf5-plugin.patch +%endif # ostree and flatpak not on i686 for Fedora and RHEL 10 # https://github.com/containers/composefs/pull/229#issuecomment-1838735764 @@ -177,8 +179,6 @@ This package includes the rpm-ostree backend. %endif %if %{with dnf5} -Ddnf5=true \ -%else - -Ddnf5=false \ %endif -Dexternal_appstream=false \ %if %{with rpmostree} diff --git a/sources b/sources index c3ec757..469fb06 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (gnome-software-49.rc.tar.xz) = cecebbff1163f0179c5699ecc8325e2c4f68c811ec7633e6cf32e18ad2f03592b55daa16b9b5497a117cbfbf63f3d9162dd8e8191e6a6213d35261fa1bad15a5 +SHA512 (gnome-software-49.0.tar.xz) = 7c63b0bd59e6ebe7ef526b438c6d0b234897edacfa72ab4846358ffa9e3d63ced2945f52a4d3111307e349b846be80cb4039b4cec25f7bc5ceba135d0a4fe343 From 2c29600426d9ef7d1ef04b90d8b3af73ba1c07c1 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Fri, 19 Sep 2025 13:25:37 +0200 Subject: [PATCH 07/12] Resolves: #2395811 (Packages not found for "what-provides" searches) --- ...ackages-not-found-for-what-provides-.patch | 28 +++++++++++++++++++ gnome-software.spec | 4 ++- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 0002-gs-extras-page-Packages-not-found-for-what-provides-.patch diff --git a/0002-gs-extras-page-Packages-not-found-for-what-provides-.patch b/0002-gs-extras-page-Packages-not-found-for-what-provides-.patch new file mode 100644 index 0000000..5d14caf --- /dev/null +++ b/0002-gs-extras-page-Packages-not-found-for-what-provides-.patch @@ -0,0 +1,28 @@ +From 272cdf10b69a84f773ce203a4d1fa9e7be9cd225 Mon Sep 17 00:00:00 2001 +Date: Fri, 19 Sep 2025 12:52:43 +0200 +Subject: [PATCH] gs-extras-page: Packages not found for "what-provides" + searches + +This is a regression after commit 22926c20b3f062082f689379b0d7b2946c35c958, +accidentally removed "allow-packages" flag for the app listing for one branch. + +Reported downstream at: https://bugzilla.redhat.com/show_bug.cgi?id=2395811 +--- + src/gs-extras-page.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/gs-extras-page.c b/src/gs-extras-page.c +index 9d16c0eb9..0d8d786c1 100644 +--- a/src/gs-extras-page.c ++++ b/src/gs-extras-page.c +@@ -853,6 +853,7 @@ gs_extras_page_load (GsExtrasPage *self, GPtrArray *array_search_data) + + query = gs_app_query_new ("provides-tag", search_data->search, + "provides-type", search_data->search_provides_type, ++ "refine-flags", GS_PLUGIN_REFINE_FLAGS_ALLOW_PACKAGES, + "refine-require-flags", require_flags, + "license-type", gs_page_get_query_license_type (GS_PAGE (self)), + "developer-verified-type", gs_page_get_query_developer_verified_type (GS_PAGE (self)), +-- +2.49.0 + diff --git a/gnome-software.spec b/gnome-software.spec index 34328cf..91e0bd4 100644 --- a/gnome-software.spec +++ b/gnome-software.spec @@ -30,7 +30,7 @@ Name: gnome-software Version: 49.0 -Release: 1%{?dist} +Release: 2%{?dist} Summary: A software center for GNOME License: GPL-2.0-or-later @@ -43,6 +43,8 @@ Source0: https://download.gnome.org/sources/gnome-software/49/%{name}-%{tarbal Patch: 0001-dnf5-plugin.patch %endif +Patch: 0002-gs-extras-page-Packages-not-found-for-what-provides-.patch + # ostree and flatpak not on i686 for Fedora and RHEL 10 # https://github.com/containers/composefs/pull/229#issuecomment-1838735764 %if 0%{?fedora} || 0%{?rhel} >= 10 From 3364ed6d8c4f5b3536689bb260aac812ad3c6134 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Fri, 10 Oct 2025 08:47:16 +0200 Subject: [PATCH 08/12] Update to 49.1 --- ...ackages-not-found-for-what-provides-.patch | 28 ------------------- gnome-software.spec | 8 ++---- sources | 2 +- 3 files changed, 4 insertions(+), 34 deletions(-) delete mode 100644 0002-gs-extras-page-Packages-not-found-for-what-provides-.patch diff --git a/0002-gs-extras-page-Packages-not-found-for-what-provides-.patch b/0002-gs-extras-page-Packages-not-found-for-what-provides-.patch deleted file mode 100644 index 5d14caf..0000000 --- a/0002-gs-extras-page-Packages-not-found-for-what-provides-.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 272cdf10b69a84f773ce203a4d1fa9e7be9cd225 Mon Sep 17 00:00:00 2001 -Date: Fri, 19 Sep 2025 12:52:43 +0200 -Subject: [PATCH] gs-extras-page: Packages not found for "what-provides" - searches - -This is a regression after commit 22926c20b3f062082f689379b0d7b2946c35c958, -accidentally removed "allow-packages" flag for the app listing for one branch. - -Reported downstream at: https://bugzilla.redhat.com/show_bug.cgi?id=2395811 ---- - src/gs-extras-page.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/gs-extras-page.c b/src/gs-extras-page.c -index 9d16c0eb9..0d8d786c1 100644 ---- a/src/gs-extras-page.c -+++ b/src/gs-extras-page.c -@@ -853,6 +853,7 @@ gs_extras_page_load (GsExtrasPage *self, GPtrArray *array_search_data) - - query = gs_app_query_new ("provides-tag", search_data->search, - "provides-type", search_data->search_provides_type, -+ "refine-flags", GS_PLUGIN_REFINE_FLAGS_ALLOW_PACKAGES, - "refine-require-flags", require_flags, - "license-type", gs_page_get_query_license_type (GS_PAGE (self)), - "developer-verified-type", gs_page_get_query_developer_verified_type (GS_PAGE (self)), --- -2.49.0 - diff --git a/gnome-software.spec b/gnome-software.spec index 91e0bd4..e62923e 100644 --- a/gnome-software.spec +++ b/gnome-software.spec @@ -29,8 +29,8 @@ %global __provides_exclude_from ^%{_libdir}/%{name}/plugins-%{gs_plugin_version}/.*\\.so.*$ Name: gnome-software -Version: 49.0 -Release: 2%{?dist} +Version: 49.1 +Release: 1%{?dist} Summary: A software center for GNOME License: GPL-2.0-or-later @@ -43,8 +43,6 @@ Source0: https://download.gnome.org/sources/gnome-software/49/%{name}-%{tarbal Patch: 0001-dnf5-plugin.patch %endif -Patch: 0002-gs-extras-page-Packages-not-found-for-what-provides-.patch - # ostree and flatpak not on i686 for Fedora and RHEL 10 # https://github.com/containers/composefs/pull/229#issuecomment-1838735764 %if 0%{?fedora} || 0%{?rhel} >= 10 @@ -162,7 +160,7 @@ This package includes the rpm-ostree backend. %endif %prep -%autosetup -p1 -S git -n %{name}-%{tarball_version} +%autosetup -p1 -S gendiff -n %{name}-%{tarball_version} %build %meson \ diff --git a/sources b/sources index 469fb06..f738461 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (gnome-software-49.0.tar.xz) = 7c63b0bd59e6ebe7ef526b438c6d0b234897edacfa72ab4846358ffa9e3d63ced2945f52a4d3111307e349b846be80cb4039b4cec25f7bc5ceba135d0a4fe343 +SHA512 (gnome-software-49.1.tar.xz) = 3475ea7d7062679192d4317a6ae278601acd5316d20eb6db9512407058e3b39bf6804443a272016d206cd97d12c8c9fdd883db96297e6b5866d80300ff48503a From 93f854207d7f0b44f2019701a3c1a2b854319f8f Mon Sep 17 00:00:00 2001 From: Yanko Kaneti Date: Fri, 10 Oct 2025 10:04:05 +0300 Subject: [PATCH 09/12] Add NEWS to docs --- gnome-software.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnome-software.spec b/gnome-software.spec index e62923e..78d502f 100644 --- a/gnome-software.spec +++ b/gnome-software.spec @@ -232,7 +232,7 @@ FOE desktop-file-validate %{buildroot}%{_datadir}/applications/*.desktop %files -f %{name}.lang -%doc AUTHORS README.md +%doc AUTHORS NEWS README.md %license COPYING %{_bindir}/gnome-software %{_datadir}/applications/gnome-software-local-file-flatpak.desktop From 2a31982d3e20fec1a199d87dbb4013d39de293a9 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Fri, 21 Nov 2025 11:10:15 +0100 Subject: [PATCH 10/12] Update to 49.2 --- gnome-software.spec | 2 +- sources | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gnome-software.spec b/gnome-software.spec index 78d502f..3552763 100644 --- a/gnome-software.spec +++ b/gnome-software.spec @@ -29,7 +29,7 @@ %global __provides_exclude_from ^%{_libdir}/%{name}/plugins-%{gs_plugin_version}/.*\\.so.*$ Name: gnome-software -Version: 49.1 +Version: 49.2 Release: 1%{?dist} Summary: A software center for GNOME diff --git a/sources b/sources index f738461..0e06aac 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (gnome-software-49.1.tar.xz) = 3475ea7d7062679192d4317a6ae278601acd5316d20eb6db9512407058e3b39bf6804443a272016d206cd97d12c8c9fdd883db96297e6b5866d80300ff48503a +SHA512 (gnome-software-49.2.tar.xz) = 9ce33e2046b776f2a56c96d17eec85817e04bada9af9590125530c84bcc529f278bcba0c0ccdabcb459f92b326e0837cd63a9e316551ec313ac2f8720bf69835 From 095b81906e30c01f354627060e7229af28eafb36 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Mon, 24 Nov 2025 16:20:33 +0100 Subject: [PATCH 11/12] Add patch for bug #2416542 (Crash under gs_flatpak_refine_wildcard()) --- ...ash-under-gs_flatpak_refine_wildcard.patch | 155 ++++++++++++++++++ gnome-software.spec | 5 +- 2 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 0002-rhbug2416542-crash-under-gs_flatpak_refine_wildcard.patch diff --git a/0002-rhbug2416542-crash-under-gs_flatpak_refine_wildcard.patch b/0002-rhbug2416542-crash-under-gs_flatpak_refine_wildcard.patch new file mode 100644 index 0000000..0150264 --- /dev/null +++ b/0002-rhbug2416542-crash-under-gs_flatpak_refine_wildcard.patch @@ -0,0 +1,155 @@ +diff --git a/plugins/flatpak/gs-flatpak.c b/plugins/flatpak/gs-flatpak.c +index b409475c7..a40ab54fb 100644 +--- a/plugins/flatpak/gs-flatpak.c ++++ b/plugins/flatpak/gs-flatpak.c +@@ -3748,16 +3748,19 @@ gboolean + gs_flatpak_refine_wildcard (GsFlatpak *self, GsApp *app, + GsAppList *list, GsPluginRefineRequireFlags require_flags, + gboolean interactive, ++ XbSilo **inout_silo, ++ gchar **inout_silo_filename, ++ GHashTable **inout_installed_by_desktopid, + GHashTable **inout_components_by_id, + GHashTable **inout_components_by_bundle, + GCancellable *cancellable, GError **error) + { + const gchar *id; + GPtrArray* components = NULL; ++ XbSilo *silo; ++ GHashTable *silo_installed_by_desktopid; ++ const gchar *silo_filename; + g_autoptr(GError) error_local = NULL; +- g_autoptr(XbSilo) silo = NULL; +- g_autoptr(GHashTable) silo_installed_by_desktopid = NULL; +- g_autofree gchar *silo_filename = NULL; + + GS_PROFILER_BEGIN_SCOPED (FlatpakRefineWildcard, "Flatpak (refine wildcard)", NULL); + +@@ -3766,10 +3769,15 @@ gs_flatpak_refine_wildcard (GsFlatpak *self, GsApp *app, + if (id == NULL) + return TRUE; + +- silo = gs_flatpak_ref_silo (self, interactive, &silo_filename, &silo_installed_by_desktopid, cancellable, error); +- if (silo == NULL) ++ if (*inout_silo == NULL) ++ *inout_silo = gs_flatpak_ref_silo (self, interactive, inout_silo_filename, inout_installed_by_desktopid, cancellable, error); ++ if (*inout_silo == NULL) + return FALSE; + ++ silo = *inout_silo; ++ silo_filename = *inout_silo_filename; ++ silo_installed_by_desktopid = *inout_installed_by_desktopid; ++ + GS_PROFILER_BEGIN_SCOPED (FlatpakRefineWildcardQuerySilo, "Flatpak (query silo)", NULL); + + if (*inout_components_by_id != NULL) { +diff --git a/plugins/flatpak/gs-flatpak.h b/plugins/flatpak/gs-flatpak.h +index 66ff59967..34e1416b5 100644 +--- a/plugins/flatpak/gs-flatpak.h ++++ b/plugins/flatpak/gs-flatpak.h +@@ -11,6 +11,7 @@ + + #include + #include ++#include + + G_BEGIN_DECLS + +@@ -108,6 +109,9 @@ gboolean gs_flatpak_refine_wildcard (GsFlatpak *self, + GsAppList *list, + GsPluginRefineRequireFlags require_flags, + gboolean interactive, ++ XbSilo **inout_silo, ++ gchar **inout_silo_filename, ++ GHashTable **inout_installed_by_desktopid, + GHashTable **inout_components_by_id, + GHashTable **inout_components_by_bundle, + GCancellable *cancellable, +diff --git a/plugins/flatpak/gs-plugin-flatpak.c b/plugins/flatpak/gs-plugin-flatpak.c +index 3d0503d46..f5d4a1d67 100644 +--- a/plugins/flatpak/gs-plugin-flatpak.c ++++ b/plugins/flatpak/gs-plugin-flatpak.c +@@ -667,12 +667,29 @@ gs_plugin_flatpak_refine_app (GsPluginFlatpak *self, + return gs_flatpak_refine_app (flatpak, app, require_flags, interactive, FALSE, event_callback, event_user_data, cancellable, error); + } + ++typedef struct { ++ XbSilo *silo; ++ gchar *silo_filename; ++ GHashTable *installed_by_desktopid; ++ GHashTable *components_by_id; ++ GHashTable *components_by_bundle; ++} RefineInstallationData; ++ + static void +-unref_nonnull_hash_table (gpointer ptr) ++refine_installation_data_free (gpointer ptr) + { +- GHashTable *hash_table = ptr; +- if (hash_table != NULL) +- g_hash_table_unref (hash_table); ++ RefineInstallationData *data = ptr; ++ ++ if (data == NULL) ++ return; ++ ++ g_clear_pointer (&data->silo_filename, g_free); ++ g_clear_pointer (&data->installed_by_desktopid, g_hash_table_unref); ++ g_clear_pointer (&data->components_by_id, g_hash_table_unref); ++ g_clear_pointer (&data->components_by_bundle, g_hash_table_unref); ++ /* free the silo as the last, just in case, because the data from it is in the above hash tables */ ++ g_clear_object (&data->silo); ++ g_free (data); + } + + static gboolean +@@ -761,8 +778,7 @@ refine_thread_cb (GTask *task, + gboolean interactive = (data->job_flags & GS_PLUGIN_REFINE_FLAGS_INTERACTIVE) != 0; + GsPluginEventCallback event_callback = data->event_callback; + void *event_user_data = data->event_user_data; +- g_autoptr(GPtrArray) array_components_by_id = NULL; /* (element-type GHashTable) */ +- g_autoptr(GPtrArray) array_components_by_bundle = NULL; /* (element-type GHashTable) */ ++ g_autoptr(GPtrArray) installation_data = NULL; /* (element-type RefineInstallationData) */ + g_autoptr(GsAppList) app_list = NULL; + g_autoptr(GError) local_error = NULL; + +@@ -783,10 +799,9 @@ refine_thread_cb (GTask *task, + * (e.g. inserting an app in the list on every call results in + * an infinite loop) */ + app_list = gs_app_list_copy (list); +- array_components_by_id = g_ptr_array_new_full (self->installations->len, unref_nonnull_hash_table); +- g_ptr_array_set_size (array_components_by_id, self->installations->len); +- array_components_by_bundle = g_ptr_array_new_full (self->installations->len, unref_nonnull_hash_table); +- g_ptr_array_set_size (array_components_by_bundle, self->installations->len); ++ ++ installation_data = g_ptr_array_new_full (self->installations->len, refine_installation_data_free); ++ g_ptr_array_set_size (installation_data, self->installations->len); + + for (guint j = 0; j < gs_app_list_length (app_list); j++) { + GsApp *app = gs_app_list_index (app_list, j); +@@ -796,16 +811,20 @@ refine_thread_cb (GTask *task, + + for (guint i = 0; i < self->installations->len; i++) { + GsFlatpak *flatpak = g_ptr_array_index (self->installations, i); +- GHashTable *components_by_id = array_components_by_id->pdata[i]; +- GHashTable *components_by_bundle = array_components_by_bundle->pdata[i]; ++ RefineInstallationData *inst_data = g_ptr_array_index (installation_data, i); ++ ++ if (inst_data == NULL) { ++ inst_data = g_new0 (RefineInstallationData, 1); ++ installation_data->pdata[i] = inst_data; ++ } + +- if (!gs_flatpak_refine_wildcard (flatpak, app, list, require_flags, interactive, &components_by_id, &components_by_bundle, ++ if (!gs_flatpak_refine_wildcard (flatpak, app, list, require_flags, interactive, &inst_data->silo, ++ &inst_data->silo_filename, &inst_data->installed_by_desktopid, ++ &inst_data->components_by_id, &inst_data->components_by_bundle, + cancellable, &local_error)) { + g_task_return_error (task, g_steal_pointer (&local_error)); + return; + } +- array_components_by_id->pdata[i] = components_by_id; +- array_components_by_bundle->pdata[i] = components_by_bundle; + } + } + diff --git a/gnome-software.spec b/gnome-software.spec index 3552763..6830ae0 100644 --- a/gnome-software.spec +++ b/gnome-software.spec @@ -30,7 +30,7 @@ Name: gnome-software Version: 49.2 -Release: 1%{?dist} +Release: 2%{?dist} Summary: A software center for GNOME License: GPL-2.0-or-later @@ -43,6 +43,9 @@ Source0: https://download.gnome.org/sources/gnome-software/49/%{name}-%{tarbal Patch: 0001-dnf5-plugin.patch %endif +# https://bugzilla.redhat.com/show_bug.cgi?id=2416542 +Patch: 0002-rhbug2416542-crash-under-gs_flatpak_refine_wildcard.patch + # ostree and flatpak not on i686 for Fedora and RHEL 10 # https://github.com/containers/composefs/pull/229#issuecomment-1838735764 %if 0%{?fedora} || 0%{?rhel} >= 10 From a10b3cf10fff31405ee2087b87c1a7d8d139fd29 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Mon, 12 Jan 2026 17:23:11 +0100 Subject: [PATCH 12/12] Update to 49.3 --- ...ash-under-gs_flatpak_refine_wildcard.patch | 531 ++++++++++++++++++ gnome-software.spec | 4 +- sources | 2 +- 3 files changed, 534 insertions(+), 3 deletions(-) diff --git a/0002-rhbug2416542-crash-under-gs_flatpak_refine_wildcard.patch b/0002-rhbug2416542-crash-under-gs_flatpak_refine_wildcard.patch index 0150264..33140df 100644 --- a/0002-rhbug2416542-crash-under-gs_flatpak_refine_wildcard.patch +++ b/0002-rhbug2416542-crash-under-gs_flatpak_refine_wildcard.patch @@ -1,3 +1,26 @@ +From 0c79d9fb08a348a45a18f15427c945a63b44982e Mon Sep 17 00:00:00 2001 +Date: Mon, 24 Nov 2025 16:06:51 +0100 +Subject: [PATCH 1/3] flatpak: Fix XbSilo lifetime in + gs_flatpak_refine_wildcard() + +The function uses pre-cached data in the hash tables, consisting of XbNode-s +from an XbSilo. The nodes are referenced, but the silos the node belongs to +is not referenced (by the XbNode). + +This change keeps the XbSilo alive as long as it's needed for the nodes +in the pre-cached data. It also does not call gs_flatpak_ref_silo() multiple +times for the same GsFlatpak instance, which could invalidate the XbNode-s +in the pre-cached data when a change in the silo or in the installation +had been received while the function was still processing the apps. + +Related downstream bug https://bugzilla.redhat.com/show_bug.cgi?id=2416542 +Closes https://gitlab.gnome.org/GNOME/gnome-software/-/issues/2900 +--- + plugins/flatpak/gs-flatpak.c | 18 ++++++++--- + plugins/flatpak/gs-flatpak.h | 4 +++ + plugins/flatpak/gs-plugin-flatpak.c | 49 ++++++++++++++++++++--------- + 3 files changed, 51 insertions(+), 20 deletions(-) + diff --git a/plugins/flatpak/gs-flatpak.c b/plugins/flatpak/gs-flatpak.c index b409475c7..a40ab54fb 100644 --- a/plugins/flatpak/gs-flatpak.c @@ -153,3 +176,511 @@ index 3d0503d46..f5d4a1d67 100644 } } +-- +GitLab + + +From 546c6ee17b5959d2a696a6cb346a1f8b94aba303 Mon Sep 17 00:00:00 2001 +Date: Wed, 7 Jan 2026 18:37:52 +0100 +Subject: [PATCH 2/3] flatpak: Simplify wildcard app lookup function + +By flipping the order of traversing app and installation the code +can be simplified to not have too many in/out arguments. + +Suggested by Philip Withnall +--- + plugins/flatpak/gs-flatpak.c | 251 ++++++++++++++-------------- + plugins/flatpak/gs-flatpak.h | 9 +- + plugins/flatpak/gs-plugin-flatpak.c | 61 +------ + 3 files changed, 130 insertions(+), 191 deletions(-) + +diff --git a/plugins/flatpak/gs-flatpak.c b/plugins/flatpak/gs-flatpak.c +index a40ab54fb..782b0bb48 100644 +--- a/plugins/flatpak/gs-flatpak.c ++++ b/plugins/flatpak/gs-flatpak.c +@@ -3745,167 +3745,158 @@ gs_flatpak_refine_app (GsFlatpak *self, + } + + gboolean +-gs_flatpak_refine_wildcard (GsFlatpak *self, GsApp *app, +- GsAppList *list, GsPluginRefineRequireFlags require_flags, +- gboolean interactive, +- XbSilo **inout_silo, +- gchar **inout_silo_filename, +- GHashTable **inout_installed_by_desktopid, +- GHashTable **inout_components_by_id, +- GHashTable **inout_components_by_bundle, +- GCancellable *cancellable, GError **error) ++gs_flatpak_refine_wildcards (GsFlatpak *self, ++ GPtrArray *wildcard_apps, ++ GsAppList *list, ++ GsPluginRefineRequireFlags require_flags, ++ gboolean interactive, ++ GCancellable *cancellable, ++ GError **error) + { +- const gchar *id; +- GPtrArray* components = NULL; +- XbSilo *silo; +- GHashTable *silo_installed_by_desktopid; +- const gchar *silo_filename; + g_autoptr(GError) error_local = NULL; ++ g_autoptr(XbSilo) silo = NULL; ++ g_autoptr(GHashTable) silo_installed_by_desktopid = NULL; ++ g_autoptr(GHashTable) components_by_id = NULL; ++ g_autoptr(GHashTable) components_by_bundle = NULL; ++ g_autoptr(GPtrArray) components_with_id = NULL; ++ g_autoptr(GPtrArray) bundles = NULL; ++ g_autofree gchar *silo_filename = NULL; + + GS_PROFILER_BEGIN_SCOPED (FlatpakRefineWildcard, "Flatpak (refine wildcard)", NULL); + +- /* not enough info to find */ +- id = gs_app_get_id (app); +- if (id == NULL) +- return TRUE; +- +- if (*inout_silo == NULL) +- *inout_silo = gs_flatpak_ref_silo (self, interactive, inout_silo_filename, inout_installed_by_desktopid, cancellable, error); +- if (*inout_silo == NULL) ++ silo = gs_flatpak_ref_silo (self, interactive, &silo_filename, &silo_installed_by_desktopid, cancellable, error); ++ if (silo == NULL) + return FALSE; + +- silo = *inout_silo; +- silo_filename = *inout_silo_filename; +- silo_installed_by_desktopid = *inout_installed_by_desktopid; +- + GS_PROFILER_BEGIN_SCOPED (FlatpakRefineWildcardQuerySilo, "Flatpak (query silo)", NULL); + +- if (*inout_components_by_id != NULL) { +- components = g_hash_table_lookup (*inout_components_by_id, gs_app_get_id (app)); +- } else { +- g_autoptr(GPtrArray) components_with_id = NULL; +- *inout_components_by_id = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_ptr_array_unref); +- components_with_id = xb_silo_query (silo, "components/component/id", 0, &error_local); +- if (components_with_id == NULL) { +- if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) +- return TRUE; +- g_propagate_error (error, g_steal_pointer (&error_local)); +- return FALSE; ++ components_by_id = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_ptr_array_unref); ++ components_with_id = xb_silo_query (silo, "components/component/id", 0, &error_local); ++ if (components_with_id == NULL) { ++ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) ++ return TRUE; ++ g_propagate_error (error, g_steal_pointer (&error_local)); ++ return FALSE; ++ } ++ ++ for (guint i = 0; i < components_with_id->len; i++) { ++ XbNode *node = g_ptr_array_index (components_with_id, i); ++ XbNode *comp_node = xb_node_get_parent (node); ++ const gchar *comp_id = xb_node_get_text (node); ++ GPtrArray *comps = g_hash_table_lookup (components_by_id, comp_id); ++ if (comps == NULL) { ++ comps = g_ptr_array_new_with_free_func (g_object_unref); ++ g_hash_table_insert (components_by_id, g_strdup (comp_id), comps); + } +- for (guint i = 0; i < components_with_id->len; i++) { +- XbNode *node = g_ptr_array_index (components_with_id, i); +- XbNode *comp_node = xb_node_get_parent (node); +- const gchar *comp_id = xb_node_get_text (node); +- GPtrArray *comps = g_hash_table_lookup (*inout_components_by_id, comp_id); +- if (comps == NULL) { +- comps = g_ptr_array_new_with_free_func (g_object_unref); +- g_hash_table_insert (*inout_components_by_id, g_strdup (comp_id), comps); ++ g_ptr_array_add (comps, comp_node); ++ } ++ ++ components_by_bundle = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); ++ bundles = xb_silo_query (silo, "/components/component/bundle[@type='flatpak']", 0, NULL); ++ for (guint b = 0; bundles != NULL && b < bundles->len; b++) { ++ XbNode *bundle_node = g_ptr_array_index (bundles, b); ++ g_autoptr(XbNode) component_node = xb_node_get_parent (bundle_node); ++ g_autoptr(XbNode) components_node = xb_node_get_parent (component_node); ++ const gchar *origin = xb_node_get_attr (components_node, "origin"); ++ if (origin != NULL) { ++ const gchar *bundle = xb_node_get_text (bundle_node); ++ if (bundle != NULL) { ++ g_autofree gchar *key = g_strconcat (origin, "\n", bundle, NULL); ++ g_hash_table_insert (components_by_bundle, g_steal_pointer (&key), g_steal_pointer (&component_node)); + } +- g_ptr_array_add (comps, comp_node); +- if (components == NULL && g_strcmp0 (id, comp_id) == 0) +- components = comps; + } + } + + GS_PROFILER_END_SCOPED (FlatpakRefineWildcardQuerySilo); + +- if (components == NULL) +- return TRUE; +- + gs_flatpak_ensure_remote_title (self, interactive, cancellable); + +- if (*inout_components_by_bundle == NULL) { +- g_autoptr(GPtrArray) bundles = NULL; +- +- *inout_components_by_bundle = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); +- bundles = xb_silo_query (silo, "/components/component/bundle[@type='flatpak']", 0, NULL); +- for (guint b = 0; bundles != NULL && b < bundles->len; b++) { +- XbNode *bundle_node = g_ptr_array_index (bundles, b); +- g_autoptr(XbNode) component_node = xb_node_get_parent (bundle_node); +- g_autoptr(XbNode) components_node = xb_node_get_parent (component_node); +- const gchar *origin = xb_node_get_attr (components_node, "origin"); +- if (origin != NULL) { +- const gchar *bundle = xb_node_get_text (bundle_node); +- if (bundle != NULL) { +- g_autofree gchar *key = g_strconcat (origin, "\n", bundle, NULL); +- g_hash_table_insert (*inout_components_by_bundle, g_steal_pointer (&key), g_steal_pointer (&component_node)); +- } +- } +- } +- } ++ for (guint j = 0; j < wildcard_apps->len; j++) { ++ GsApp *app = g_ptr_array_index (wildcard_apps, j); ++ GPtrArray *components = NULL; ++ const gchar *id; + ++ /* not enough info to find */ ++ id = gs_app_get_id (app); ++ if (id == NULL) ++ continue; + +- GS_PROFILER_BEGIN_SCOPED (FlatpakRefineWildcardGenerateApps, "Flatpak (create app)", NULL); +- for (guint i = 0; i < components->len; i++) { +- XbNode *component = g_ptr_array_index (components, i); +- g_autoptr(GsApp) new = NULL; ++ components = g_hash_table_lookup (components_by_id, id); ++ if (components == NULL) ++ continue; + +- GS_PROFILER_BEGIN_SCOPED (FlatpakRefineWildcardCreateAppstreamApp, "Flatpak (create Appstream app)", NULL); +- new = gs_appstream_create_app (self->plugin, silo, component, silo_filename ? silo_filename : "", +- self->scope, error); +- GS_PROFILER_END_SCOPED (FlatpakRefineWildcardCreateAppstreamApp); ++ GS_PROFILER_BEGIN_SCOPED (FlatpakRefineWildcardGenerateApps, "Flatpak (create app)", NULL); ++ for (guint i = 0; i < components->len; i++) { ++ XbNode *component = g_ptr_array_index (components, i); ++ g_autoptr(GsApp) new = NULL; + +- if (new == NULL) +- return FALSE; ++ GS_PROFILER_BEGIN_SCOPED (FlatpakRefineWildcardCreateAppstreamApp, "Flatpak (create Appstream app)", NULL); ++ new = gs_appstream_create_app (self->plugin, silo, component, silo_filename ? silo_filename : "", ++ self->scope, error); ++ GS_PROFILER_END_SCOPED (FlatpakRefineWildcardCreateAppstreamApp); + +- gs_flatpak_claim_app (self, new); +- +- /* The appstream plugin did not find the component in the plugin's cache, +- thus read the required info from the 'bundle' element. */ +- if (gs_flatpak_app_get_ref_name (new) == NULL || +- gs_flatpak_app_get_ref_arch (new) == NULL) { +- const gchar *xref_str = NULL; +- g_autoptr(XbNode) child = NULL; +- g_autoptr(XbNode) next = NULL; +- for (child = xb_node_get_child (component); child != NULL && xref_str == NULL; +- g_object_unref (child), child = g_steal_pointer (&next)) { +- next = xb_node_get_next (child); +- if (g_strcmp0 (xb_node_get_element (child), "bundle") == 0 && +- g_strcmp0 (xb_node_get_attr (child, "type"), "flatpak") == 0) { +- xref_str = xb_node_get_text (child); +- break; ++ if (new == NULL) ++ return FALSE; ++ ++ gs_flatpak_claim_app (self, new); ++ ++ /* The appstream plugin did not find the component in the plugin's cache, ++ thus read the required info from the 'bundle' element. */ ++ if (gs_flatpak_app_get_ref_name (new) == NULL || ++ gs_flatpak_app_get_ref_arch (new) == NULL) { ++ const gchar *xref_str = NULL; ++ g_autoptr(XbNode) child = NULL; ++ g_autoptr(XbNode) next = NULL; ++ for (child = xb_node_get_child (component); child != NULL && xref_str == NULL; ++ g_object_unref (child), child = g_steal_pointer (&next)) { ++ next = xb_node_get_next (child); ++ if (g_strcmp0 (xb_node_get_element (child), "bundle") == 0 && ++ g_strcmp0 (xb_node_get_attr (child, "type"), "flatpak") == 0) { ++ xref_str = xb_node_get_text (child); ++ break; ++ } + } +- } +- if (xref_str != NULL) { +- g_auto(GStrv) split = NULL; +- +- /* get the kind/name/arch/branch */ +- split = g_strsplit (xref_str, "/", -1); +- if (g_strv_length (split) == 4) { +- const gchar *comp_type = xb_node_get_attr (component, "type"); +- AsComponentKind kind = as_component_kind_from_string (comp_type); +- if (kind != AS_COMPONENT_KIND_UNKNOWN) +- gs_app_set_kind (new, kind); +- else if (g_ascii_strcasecmp (split[0], "app") == 0) +- gs_app_set_kind (new, AS_COMPONENT_KIND_DESKTOP_APP); +- else if (g_ascii_strcasecmp (split[0], "runtime") == 0) +- gs_flatpak_set_runtime_kind_from_id (new); +- gs_flatpak_app_set_ref_name (new, split[1]); +- gs_flatpak_app_set_ref_arch (new, split[2]); +- gs_app_set_branch (new, split[3]); +- gs_app_set_metadata (new, "GnomeSoftware::packagename-value", xref_str); ++ if (xref_str != NULL) { ++ g_auto(GStrv) split = NULL; ++ ++ /* get the kind/name/arch/branch */ ++ split = g_strsplit (xref_str, "/", -1); ++ if (g_strv_length (split) == 4) { ++ const gchar *comp_type = xb_node_get_attr (component, "type"); ++ AsComponentKind kind = as_component_kind_from_string (comp_type); ++ if (kind != AS_COMPONENT_KIND_UNKNOWN) ++ gs_app_set_kind (new, kind); ++ else if (g_ascii_strcasecmp (split[0], "app") == 0) ++ gs_app_set_kind (new, AS_COMPONENT_KIND_DESKTOP_APP); ++ else if (g_ascii_strcasecmp (split[0], "runtime") == 0) ++ gs_flatpak_set_runtime_kind_from_id (new); ++ gs_flatpak_app_set_ref_name (new, split[1]); ++ gs_flatpak_app_set_ref_arch (new, split[2]); ++ gs_app_set_branch (new, split[3]); ++ gs_app_set_metadata (new, "GnomeSoftware::packagename-value", xref_str); ++ } + } + } +- } + +- if (gs_flatpak_app_get_ref_name (new) == NULL || +- gs_flatpak_app_get_ref_arch (new) == NULL) { +- g_debug ("Failed to get ref info for '%s' from wildcard '%s', skipping it...", gs_app_get_id (new), id); +- } else { +- GS_PROFILER_BEGIN_SCOPED (FlatpakRefineWildcardRefineNewApp, "Flatpak (refine new app)", NULL); +- if (!gs_flatpak_refine_app_internal (self, new, require_flags, interactive, FALSE, *inout_components_by_bundle, +- silo, silo_filename, silo_installed_by_desktopid, cancellable, error)) +- return FALSE; +- GS_PROFILER_END_SCOPED (FlatpakRefineWildcardRefineNewApp); ++ if (gs_flatpak_app_get_ref_name (new) == NULL || ++ gs_flatpak_app_get_ref_arch (new) == NULL) { ++ g_debug ("Failed to get ref info for '%s' from wildcard '%s', skipping it...", gs_app_get_id (new), id); ++ } else { ++ GS_PROFILER_BEGIN_SCOPED (FlatpakRefineWildcardRefineNewApp, "Flatpak (refine new app)", NULL); ++ if (!gs_flatpak_refine_app_internal (self, new, require_flags, interactive, FALSE, components_by_bundle, ++ silo, silo_filename, silo_installed_by_desktopid, cancellable, error)) ++ return FALSE; ++ GS_PROFILER_END_SCOPED (FlatpakRefineWildcardRefineNewApp); + +- GS_PROFILER_BEGIN_SCOPED (FlatpakRefineWildcardSubsumeMetadata, "Flatpak (subsume metadata)", NULL); +- gs_app_subsume_metadata (new, app); +- GS_PROFILER_END_SCOPED (FlatpakRefineWildcardSubsumeMetadata); ++ GS_PROFILER_BEGIN_SCOPED (FlatpakRefineWildcardSubsumeMetadata, "Flatpak (subsume metadata)", NULL); ++ gs_app_subsume_metadata (new, app); ++ GS_PROFILER_END_SCOPED (FlatpakRefineWildcardSubsumeMetadata); + +- gs_app_list_add (list, new); ++ gs_app_list_add (list, new); ++ } + } ++ GS_PROFILER_END_SCOPED (FlatpakRefineWildcardGenerateApps); + } +- GS_PROFILER_END_SCOPED (FlatpakRefineWildcardGenerateApps); + + GS_PROFILER_END_SCOPED (FlatpakRefineWildcard); + +diff --git a/plugins/flatpak/gs-flatpak.h b/plugins/flatpak/gs-flatpak.h +index 34e1416b5..1f7d35a8f 100644 +--- a/plugins/flatpak/gs-flatpak.h ++++ b/plugins/flatpak/gs-flatpak.h +@@ -104,16 +104,11 @@ gboolean gs_flatpak_refine_app_state (GsFlatpak *self, + void *event_user_data, + GCancellable *cancellable, + GError **error); +-gboolean gs_flatpak_refine_wildcard (GsFlatpak *self, +- GsApp *app, ++gboolean gs_flatpak_refine_wildcards (GsFlatpak *self, ++ GPtrArray *wildcard_apps, + GsAppList *list, + GsPluginRefineRequireFlags require_flags, + gboolean interactive, +- XbSilo **inout_silo, +- gchar **inout_silo_filename, +- GHashTable **inout_installed_by_desktopid, +- GHashTable **inout_components_by_id, +- GHashTable **inout_components_by_bundle, + GCancellable *cancellable, + GError **error); + gboolean gs_flatpak_launch (GsFlatpak *self, +diff --git a/plugins/flatpak/gs-plugin-flatpak.c b/plugins/flatpak/gs-plugin-flatpak.c +index f5d4a1d67..c06b1fb5f 100644 +--- a/plugins/flatpak/gs-plugin-flatpak.c ++++ b/plugins/flatpak/gs-plugin-flatpak.c +@@ -667,31 +667,6 @@ gs_plugin_flatpak_refine_app (GsPluginFlatpak *self, + return gs_flatpak_refine_app (flatpak, app, require_flags, interactive, FALSE, event_callback, event_user_data, cancellable, error); + } + +-typedef struct { +- XbSilo *silo; +- gchar *silo_filename; +- GHashTable *installed_by_desktopid; +- GHashTable *components_by_id; +- GHashTable *components_by_bundle; +-} RefineInstallationData; +- +-static void +-refine_installation_data_free (gpointer ptr) +-{ +- RefineInstallationData *data = ptr; +- +- if (data == NULL) +- return; +- +- g_clear_pointer (&data->silo_filename, g_free); +- g_clear_pointer (&data->installed_by_desktopid, g_hash_table_unref); +- g_clear_pointer (&data->components_by_id, g_hash_table_unref); +- g_clear_pointer (&data->components_by_bundle, g_hash_table_unref); +- /* free the silo as the last, just in case, because the data from it is in the above hash tables */ +- g_clear_object (&data->silo); +- g_free (data); +-} +- + static gboolean + refine_app (GsPluginFlatpak *self, + GsApp *app, +@@ -778,8 +753,7 @@ refine_thread_cb (GTask *task, + gboolean interactive = (data->job_flags & GS_PLUGIN_REFINE_FLAGS_INTERACTIVE) != 0; + GsPluginEventCallback event_callback = data->event_callback; + void *event_user_data = data->event_user_data; +- g_autoptr(GPtrArray) installation_data = NULL; /* (element-type RefineInstallationData) */ +- g_autoptr(GsAppList) app_list = NULL; ++ g_autoptr(GPtrArray) wildcard_apps = g_ptr_array_new_with_free_func (g_object_unref); /* (element-type GsApp) (owned) */ + g_autoptr(GError) local_error = NULL; + + assert_in_worker (self); +@@ -790,38 +764,17 @@ refine_thread_cb (GTask *task, + g_task_return_error (task, g_steal_pointer (&local_error)); + return; + } +- } +- +- /* Refine wildcards. +- * +- * Use a copy of the list for the loop because a function called +- * on the plugin may affect the list which can lead to problems +- * (e.g. inserting an app in the list on every call results in +- * an infinite loop) */ +- app_list = gs_app_list_copy (list); +- +- installation_data = g_ptr_array_new_full (self->installations->len, refine_installation_data_free); +- g_ptr_array_set_size (installation_data, self->installations->len); +- +- for (guint j = 0; j < gs_app_list_length (app_list); j++) { +- GsApp *app = gs_app_list_index (app_list, j); + +- if (!gs_app_has_quirk (app, GS_APP_QUIRK_IS_WILDCARD)) +- continue; ++ if (gs_app_has_quirk (app, GS_APP_QUIRK_IS_WILDCARD) && gs_app_get_id (app) != NULL) ++ g_ptr_array_add (wildcard_apps, g_object_ref (app)); ++ } + ++ /* Refine wildcards. */ ++ if (wildcard_apps->len > 0) { + for (guint i = 0; i < self->installations->len; i++) { + GsFlatpak *flatpak = g_ptr_array_index (self->installations, i); +- RefineInstallationData *inst_data = g_ptr_array_index (installation_data, i); +- +- if (inst_data == NULL) { +- inst_data = g_new0 (RefineInstallationData, 1); +- installation_data->pdata[i] = inst_data; +- } + +- if (!gs_flatpak_refine_wildcard (flatpak, app, list, require_flags, interactive, &inst_data->silo, +- &inst_data->silo_filename, &inst_data->installed_by_desktopid, +- &inst_data->components_by_id, &inst_data->components_by_bundle, +- cancellable, &local_error)) { ++ if (!gs_flatpak_refine_wildcards (flatpak, wildcard_apps, list, require_flags, interactive, cancellable, &local_error)) { + g_task_return_error (task, g_steal_pointer (&local_error)); + return; + } +-- +GitLab + + +From 8472d717356a801e6c0171156738ea48480fa695 Mon Sep 17 00:00:00 2001 +Date: Wed, 7 Jan 2026 18:45:47 +0100 +Subject: [PATCH 3/3] flatpak: Hold silo lock when refining wildcard apps + +The refine can take a long time, thus hold the silo lock to not have +it invalidated from another thread. Object reference is not enough +for the XbSilo, it breaks as soon as the underlying file changes. +--- + plugins/flatpak/gs-flatpak.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/plugins/flatpak/gs-flatpak.c b/plugins/flatpak/gs-flatpak.c +index 782b0bb48..c5437125d 100644 +--- a/plugins/flatpak/gs-flatpak.c ++++ b/plugins/flatpak/gs-flatpak.c +@@ -59,7 +59,7 @@ struct _GsFlatpak { + AsComponentScope scope; + GsPlugin *plugin; + XbSilo *silo; +- GMutex silo_lock; ++ GRecMutex silo_lock; + gchar *silo_filename; + GHashTable *silo_installed_by_desktopid; + gint silo_change_stamp; +@@ -1187,11 +1187,11 @@ gs_flatpak_ref_silo (GsFlatpak *self, + g_autoptr(GFile) file = NULL; + g_autoptr(GPtrArray) xremotes = NULL; + g_autoptr(GPtrArray) desktop_paths = NULL; +- g_autoptr(GMutexLocker) locker = NULL; ++ g_autoptr(GRecMutexLocker) locker = NULL; + g_autoptr(XbBuilder) builder = NULL; + g_autoptr(GMainContext) old_thread_default = NULL; + +- locker = g_mutex_locker_new (&self->silo_lock); ++ locker = g_rec_mutex_locker_new (&self->silo_lock); + /* everything is okay */ + if (self->silo != NULL && xb_silo_is_valid (self->silo) && + g_atomic_int_get (&self->silo_change_stamp_current) == g_atomic_int_get (&self->silo_change_stamp)) { +@@ -3754,6 +3754,7 @@ gs_flatpak_refine_wildcards (GsFlatpak *self, + GError **error) + { + g_autoptr(GError) error_local = NULL; ++ g_autoptr(GRecMutexLocker) silo_locker = NULL; + g_autoptr(XbSilo) silo = NULL; + g_autoptr(GHashTable) silo_installed_by_desktopid = NULL; + g_autoptr(GHashTable) components_by_id = NULL; +@@ -3764,6 +3765,11 @@ gs_flatpak_refine_wildcards (GsFlatpak *self, + + GS_PROFILER_BEGIN_SCOPED (FlatpakRefineWildcard, "Flatpak (refine wildcard)", NULL); + ++ /* the refine can take a long time, thus hold the silo lock to not have ++ it invalidated from another thread; object reference is not enough ++ for the XbSilo, it breaks as soon as the underlying file changes */ ++ silo_locker = g_rec_mutex_locker_new (&self->silo_lock); ++ + silo = gs_flatpak_ref_silo (self, interactive, &silo_filename, &silo_installed_by_desktopid, cancellable, error); + if (silo == NULL) + return FALSE; +@@ -4810,7 +4816,7 @@ gs_flatpak_finalize (GObject *object) + g_object_unref (self->plugin); + g_hash_table_unref (self->broken_remotes); + g_mutex_clear (&self->broken_remotes_mutex); +- g_mutex_clear (&self->silo_lock); ++ g_rec_mutex_clear (&self->silo_lock); + g_hash_table_unref (self->app_silos); + g_mutex_clear (&self->app_silos_mutex); + g_clear_pointer (&self->remote_title, g_hash_table_unref); +@@ -4831,7 +4837,7 @@ gs_flatpak_init (GsFlatpak *self) + { + /* XbSilo needs external locking as we destroy the silo and build a new + * one when something changes */ +- g_mutex_init (&self->silo_lock); ++ g_rec_mutex_init (&self->silo_lock); + + g_mutex_init (&self->installed_refs_mutex); + self->installed_refs = NULL; +-- +GitLab + diff --git a/gnome-software.spec b/gnome-software.spec index 6830ae0..c080ede 100644 --- a/gnome-software.spec +++ b/gnome-software.spec @@ -29,8 +29,8 @@ %global __provides_exclude_from ^%{_libdir}/%{name}/plugins-%{gs_plugin_version}/.*\\.so.*$ Name: gnome-software -Version: 49.2 -Release: 2%{?dist} +Version: 49.3 +Release: 1%{?dist} Summary: A software center for GNOME License: GPL-2.0-or-later diff --git a/sources b/sources index 0e06aac..c24e704 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (gnome-software-49.2.tar.xz) = 9ce33e2046b776f2a56c96d17eec85817e04bada9af9590125530c84bcc529f278bcba0c0ccdabcb459f92b326e0837cd63a9e316551ec313ac2f8720bf69835 +SHA512 (gnome-software-49.3.tar.xz) = 0414ea55ad3b83bcd50514985e3d2026207801c040934805bb26d162e88f0619a9d70aa6ba324a29acfab02573490b928c83594b54f57ec2a8ad00e6c127f657