Compare commits

...
Sign in to create a new pull request.

12 commits

Author SHA1 Message Date
Milan Crha
f0b0c23ce0 Update to 49.3 2026-01-12 17:24:02 +01:00
Milan Crha
ab5e4457e4 Add patch for bug #2416542 (Crash under gs_flatpak_refine_wildcard()) 2025-11-24 16:21:45 +01:00
Milan Crha
5f0a66c87b Update to 49.2 2025-11-21 11:11:08 +01:00
Milan Crha
3025fb5ba5 Update to 49.1 2025-10-10 08:49:17 +02:00
Milan Crha
9094b1656e Resolves: #2395811 (Packages not found for "what-provides" searches) 2025-09-19 13:27:11 +02:00
Milan Crha
975a1e4c06 Update to 49.0 2025-09-12 10:03:10 +02:00
Milan Crha
43d8246f4b Resolves: #2392645 (Use PackageKit plugin instead of dnf5 plugin) 2025-09-05 11:18:19 +02:00
Milan Crha
b60b90e758 Resolves: #2392057 (dnf5-pugin: No update notifications shown) 2025-09-01 18:32:05 +02:00
Milan Crha
33a8261ad0 Update to 49.rc 2025-08-29 09:12:41 +02:00
Milan Crha
ba25bafa5f dnf5-plugin: Skip historical updates search when no last date is set 2025-08-26 19:04:54 +02:00
Milan Crha
e7d886350b dnf5-plugin: Auto-accept new RPM keys only when installed from repos
- dnf5-plugin: Download offline updates also by regular users
2025-08-25 12:08:32 +02:00
Milan Crha
73ce07b97a dnf5-plugin: Auto-accept new RPM keys 2025-08-13 18:35:53 +02:00
4 changed files with 1062 additions and 59 deletions

View file

@ -1,5 +1,5 @@
at commit 8a1f0ca6564157dd688c84ffd25af9747c1e038e
Date: Mon Aug 11 17:07:06 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,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..82f3e19a8
--- /dev/null
+++ b/plugins/dnf5/gs-plugin-dnf5.c
@@ -0,0 +1,4275 @@
@@ -0,0 +1,4589 @@
+/* -*- 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..88d7e25d8
+ 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..88d7e25d8
+ 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);
@ -1702,7 +1709,10 @@ 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 = 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",
@ -1712,7 +1722,7 @@ index 000000000..88d7e25d8
+ data->key_id,
+ confirmed,
+ g_variant_builder_end (options_builder),
+ NULL,
+ data->cancellable,
+ gs_dnf5_confirm_key_response_cb,
+ NULL);
+ }
@ -1720,10 +1730,184 @@ index 000000000..88d7e25d8
+ 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;
+
@ -1798,11 +1982,18 @@ index 000000000..88d7e25d8
+ 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
@ -1884,7 +2075,8 @@ index 000000000..88d7e25d8
+ 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
@ -1963,6 +2155,7 @@ index 000000000..88d7e25d8
+ 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);
+
@ -2015,6 +2208,10 @@ index 000000000..88d7e25d8
+ 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));
+
@ -2570,54 +2767,57 @@ index 000000000..88d7e25d8
+ 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;
+
+ 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 = (gint64) g_settings_get_uint64 (settings, "packagekit-historical-updates-timestamp");
+
+ if (success) {
+ g_autoptr(GVariantBuilder) options_builder = NULL;
+ g_autoptr(GVariant) result = NULL;
+ g_autoptr(GSettings) settings;
+ gint64 timestamp;
+ if (timestamp > 0) {
+ 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 if (gs_component_kind_array_contains (component_kinds, AS_COMPONENT_KIND_REPOSITORY)) {
@ -3574,6 +3774,7 @@ index 000000000..88d7e25d8
+ GsAppList *list,
+ gboolean is_install,
+ gboolean interactive,
+ gboolean can_apply,
+ GsPluginEventCallback event_callback,
+ void *event_user_data,
+ GCancellable *cancellable,
@ -3698,7 +3899,8 @@ index 000000000..88d7e25d8
+ 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);
+
@ -3730,7 +3932,7 @@ index 000000000..88d7e25d8
+ 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;
+
@ -3767,6 +3969,10 @@ index 000000000..88d7e25d8
+ } 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);
@ -3850,6 +4056,7 @@ index 000000000..88d7e25d8
+
+ 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);
+
@ -4093,6 +4300,7 @@ index 000000000..88d7e25d8
+
+ 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);
+
@ -4778,6 +4986,110 @@ index 000000000..88d7e25d8
+ 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)
+{
@ -4863,6 +5175,8 @@ index 000000000..88d7e25d8
+ 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

View file

@ -0,0 +1,686 @@
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
+++ 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 <gnome-software.h>
#include <flatpak.h>
+#include <xmlb.h>
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;
}
}
--
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

View file

@ -18,8 +18,8 @@
# Disable DKMS/akmods support for RHEL builds
%bcond dkms %[!0%{?rhel}]
%bcond packagekit 0
%bcond dnf5 1
%bcond packagekit 1
%bcond dnf5 0
# this is not a library version
%define gs_plugin_version 23
@ -29,17 +29,22 @@
%global __provides_exclude_from ^%{_libdir}/%{name}/plugins-%{gs_plugin_version}/.*\\.so.*$
Name: gnome-software
Version: 49~beta
Release: 3%{?dist}
Version: 49.3
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
# 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
@ -158,7 +163,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 \
@ -177,8 +182,6 @@ This package includes the rpm-ostree backend.
%endif
%if %{with dnf5}
-Ddnf5=true \
%else
-Ddnf5=false \
%endif
-Dexternal_appstream=false \
%if %{with rpmostree}

View file

@ -1 +1 @@
SHA512 (gnome-software-49.beta.tar.xz) = 9cb6d67216193840b2661871ef43da5e726a284d1164781f13423ee8dd86359334f199efc29f4b3a0b3eddfa8a3811d7dd38cd412fa53aaebb2e1c35ddc1f9df
SHA512 (gnome-software-49.3.tar.xz) = 0414ea55ad3b83bcd50514985e3d2026207801c040934805bb26d162e88f0619a9d70aa6ba324a29acfab02573490b928c83594b54f57ec2a8ad00e6c127f657