[gnome-software/wip/packagekit-auto-prepare-update] packagekit: Auto-prepare update when the file is deleted
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/wip/packagekit-auto-prepare-update] packagekit: Auto-prepare update when the file is deleted
- Date: Wed, 2 Mar 2022 15:58:10 +0000 (UTC)
commit 3792dd9ea6cde5afdd97a903fc4a58199f8462bd
Author: Milan Crha <mcrha redhat com>
Date: Wed Mar 2 16:52:17 2022 +0100
packagekit: Auto-prepare update when the file is deleted
The PackageKit prepared update can be deleted in some cases, sometimes
as a side-effect of some actions done by the Software itself, like when
calling refresh after start of the application. Due to the PackageKit
can be used by other applications as well, listen for the changes
on the prepared update file and restore it in case it disappears.
The auto-prepare of the update is triggered only if the file was deleted
and the user has set to download updates. It's not triggered when
the Software is started and there is no prepared update. It's because
the file name is not exposed in the public PackageKit API.
plugins/packagekit/gs-plugin-packagekit.c | 161 +++++++++++++++++++++++++++---
1 file changed, 145 insertions(+), 16 deletions(-)
---
diff --git a/plugins/packagekit/gs-plugin-packagekit.c b/plugins/packagekit/gs-plugin-packagekit.c
index 76cd8041b..63a5f2089 100644
--- a/plugins/packagekit/gs-plugin-packagekit.c
+++ b/plugins/packagekit/gs-plugin-packagekit.c
@@ -46,6 +46,9 @@
#define GS_PLUGIN_PACKAGEKIT_HISTORY_TIMEOUT 5000 /* ms */
+/* Timeout to trigger auto-prepare update after the prepared update had been invalidated */
+#define PREPARE_UPDATE_TIMEOUT_SECS 30
+
struct _GsPluginPackagekit {
GsPlugin parent;
@@ -86,6 +89,7 @@ struct _GsPluginPackagekit {
gboolean is_triggered;
GHashTable *prepared_updates; /* (element-type utf8); set of package IDs for updates
which are already prepared */
GMutex prepared_updates_mutex;
+ guint prepare_update_timeout_id;
GCancellable *proxy_settings_cancellable; /* (nullable) (owned) */
};
@@ -215,6 +219,11 @@ gs_plugin_packagekit_dispose (GObject *object)
{
GsPluginPackagekit *self = GS_PLUGIN_PACKAGEKIT (object);
+ if (self->prepare_update_timeout_id) {
+ g_source_remove (self->prepare_update_timeout_id);
+ self->prepare_update_timeout_id = 0;
+ }
+
g_cancellable_cancel (self->proxy_settings_cancellable);
g_clear_object (&self->proxy_settings_cancellable);
@@ -806,11 +815,11 @@ gs_plugin_packagekit_build_update_app (GsPlugin *plugin, PkPackage *package)
return app;
}
-gboolean
-gs_plugin_add_updates (GsPlugin *plugin,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error)
+static gboolean
+gs_plugin_packagekit_add_updates (GsPlugin *plugin,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
{
GsPluginPackagekit *self = GS_PLUGIN_PACKAGEKIT (plugin);
g_autoptr(GsPackagekitHelper) helper = gs_packagekit_helper_new (plugin);
@@ -859,6 +868,15 @@ gs_plugin_add_updates (GsPlugin *plugin,
return TRUE;
}
+gboolean
+gs_plugin_add_updates (GsPlugin *plugin,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return gs_plugin_packagekit_add_updates (plugin, list, cancellable, error);
+}
+
gboolean
gs_plugin_add_search_files (GsPlugin *plugin,
gchar **search,
@@ -2140,16 +2158,118 @@ gs_plugin_packagekit_permission_cb (GPermission *permission,
gs_plugin_set_allow_updates (plugin, ret);
}
+static gboolean
+gs_plugin_packagekit_download (GsPlugin *plugin,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error);
+
+static void
+gs_plugin_packagekit_auto_prepare_update_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GsPlugin *plugin = source_object;
+ g_autoptr(GsAppList) list = NULL;
+ g_autoptr(GError) local_error = NULL;
+
+ g_return_if_fail (GS_IS_PLUGIN_PACKAGEKIT (plugin));
+
+ list = gs_app_list_new ();
+ if (!gs_plugin_packagekit_add_updates (plugin, list, cancellable, &local_error)) {
+ g_task_return_error (task, g_steal_pointer (&local_error));
+ return;
+ }
+
+ if (gs_app_list_length (list) > 0 &&
+ !gs_plugin_packagekit_download (plugin, list, cancellable, &local_error)) {
+ g_task_return_error (task, g_steal_pointer (&local_error));
+ return;
+ }
+
+ /* Ignore errors here */
+ gs_plugin_systemd_update_cache (GS_PLUGIN_PACKAGEKIT (source_object), NULL);
+
+ g_task_return_boolean (task, TRUE);
+}
+
+static void
+gs_plugin_packagekit_auto_prepare_update_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ g_autoptr(GError) local_error = NULL;
+
+ if (g_task_propagate_boolean (G_TASK (result), &local_error)) {
+ g_debug ("Successfully auto-prepared update");
+ gs_plugin_updates_changed (GS_PLUGIN (source_object));
+ } else {
+ g_debug ("Failed to auto-prepare update: %s", local_error->message);
+ }
+}
+
+static gboolean
+gs_plugin_packagekit_run_prepare_update_cb (gpointer user_data)
+{
+ GsPluginPackagekit *self = user_data;
+ g_autoptr(GTask) task = NULL;
+
+ self->prepare_update_timeout_id = 0;
+
+ g_debug ("Going to auto-prepare update");
+ task = g_task_new (self, self->proxy_settings_cancellable,
gs_plugin_packagekit_auto_prepare_update_cb, NULL);
+ g_task_set_source_tag (task, gs_plugin_packagekit_run_prepare_update_cb);
+ g_task_run_in_thread (task, gs_plugin_packagekit_auto_prepare_update_thread);
+ return G_SOURCE_REMOVE;
+}
+
/* Run in the main thread. */
static void
-gs_plugin_packagekit_changed_cb (GFileMonitor *monitor,
- GFile *file,
- GFile *other_file,
- GFileMonitorEvent event_type,
- gpointer user_data)
+gs_plugin_packagekit_prepared_update_changed_cb (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ gpointer user_data)
{
GsPluginPackagekit *self = GS_PLUGIN_PACKAGEKIT (user_data);
+ /* Interested only in these events. */
+ if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
+ event_type != G_FILE_MONITOR_EVENT_DELETED &&
+ event_type != G_FILE_MONITOR_EVENT_CREATED)
+ return;
+
+ /* This is going to break, if PackageKit renames the file, but it's unlikely to happen;
+ there is no API to get the file name from, sadly. */
+ if (g_file_peek_path (file) == NULL ||
+ !g_str_has_suffix (g_file_peek_path (file), "prepared-update"))
+ return;
+
+ if (event_type == G_FILE_MONITOR_EVENT_DELETED) {
+ g_autoptr(GSettings) settings = g_settings_new ("org.gnome.software");
+ if (g_settings_get_boolean (settings, "download-updates")) {
+ /* The prepared-update file had been removed, but the user has set
+ to have the updates downloaded, thus prepared, thus prepare
+ the update again. */
+ if (self->prepare_update_timeout_id)
+ g_source_remove (self->prepare_update_timeout_id);
+ g_debug ("Scheduled to auto-prepare update in %d s", PREPARE_UPDATE_TIMEOUT_SECS);
+ self->prepare_update_timeout_id = g_timeout_add_seconds (PREPARE_UPDATE_TIMEOUT_SECS,
+ gs_plugin_packagekit_run_prepare_update_cb, self);
+ } else {
+ if (self->prepare_update_timeout_id) {
+ g_source_remove (self->prepare_update_timeout_id);
+ self->prepare_update_timeout_id = 0;
+ g_debug ("Cancelled auto-prepare update");
+ }
+ }
+ } else if (self->prepare_update_timeout_id) {
+ g_source_remove (self->prepare_update_timeout_id);
+ self->prepare_update_timeout_id = 0;
+ g_debug ("Cancelled auto-prepare update");
+ }
+
/* update UI */
gs_plugin_systemd_update_cache (self, NULL);
gs_plugin_updates_changed (GS_PLUGIN (self));
@@ -2240,13 +2360,14 @@ setup_proxy_settings_cb (GObject *source_object,
/* watch the prepared file */
self->monitor = pk_offline_get_prepared_monitor (cancellable, &local_error);
if (self->monitor == NULL) {
+ g_debug ("Failed to get prepared update file monitor: %s", local_error->message);
gs_utils_error_convert_gio (&local_error);
g_task_return_error (task, g_steal_pointer (&local_error));
return;
}
g_signal_connect (self->monitor, "changed",
- G_CALLBACK (gs_plugin_packagekit_changed_cb),
+ G_CALLBACK (gs_plugin_packagekit_prepared_update_changed_cb),
self);
/* watch the trigger file */
@@ -3518,11 +3639,11 @@ _download_only (GsPluginPackagekit *self,
return TRUE;
}
-gboolean
-gs_plugin_download (GsPlugin *plugin,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error)
+static gboolean
+gs_plugin_packagekit_download (GsPlugin *plugin,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
{
GsPluginPackagekit *self = GS_PLUGIN_PACKAGEKIT (plugin);
g_autoptr(GsAppList) list_tmp = gs_app_list_new ();
@@ -3572,6 +3693,14 @@ gs_plugin_download (GsPlugin *plugin,
return retval;
}
+gboolean
+gs_plugin_download (GsPlugin *plugin,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return gs_plugin_packagekit_download (plugin, list, cancellable, error);
+}
gboolean
gs_plugin_refresh (GsPlugin *plugin,
guint cache_age,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]