[gnome-software/gnome-40: 2/4] gs-plugin-loader: Add option to propagate error to the caller




commit 59b5aaa611dae442d44b18295e37a21b69c8f48b
Author: Milan Crha <mcrha redhat com>
Date:   Tue May 18 12:13:14 2021 +0200

    gs-plugin-loader: Add option to propagate error to the caller
    
    This is required on installation of the apps, when they are invoked
    through D-Bus and the caller is awaiting a response. Without it
    the plugin loaded hides the real error and the callers receives
    success, even if the install failed or had been cancelled.
    
    Closes https://gitlab.gnome.org/GNOME/gnome-software/-/issues/1235

 lib/gs-plugin-job-private.h |  1 +
 lib/gs-plugin-job.c         | 29 +++++++++++++++++++++++++++++
 lib/gs-plugin-job.h         |  2 ++
 lib/gs-plugin-loader.c      | 15 +++++++++++----
 lib/gs-plugin-loader.h      |  2 ++
 src/gs-page.c               | 30 +++++++++++++++++++++++-------
 6 files changed, 68 insertions(+), 11 deletions(-)
---
diff --git a/lib/gs-plugin-job-private.h b/lib/gs-plugin-job-private.h
index 863d89014..997cc8353 100644
--- a/lib/gs-plugin-job-private.h
+++ b/lib/gs-plugin-job-private.h
@@ -25,6 +25,7 @@ void                   gs_plugin_job_add_refine_flags         (GsPluginJob    *self,
 void                    gs_plugin_job_remove_refine_flags      (GsPluginJob    *self,
                                                                 GsPluginRefineFlags refine_flags);
 gboolean                gs_plugin_job_get_interactive          (GsPluginJob    *self);
+gboolean                gs_plugin_job_get_propagate_error      (GsPluginJob    *self);
 guint                   gs_plugin_job_get_max_results          (GsPluginJob    *self);
 guint                   gs_plugin_job_get_timeout              (GsPluginJob    *self);
 guint64                         gs_plugin_job_get_age                  (GsPluginJob    *self);
diff --git a/lib/gs-plugin-job.c b/lib/gs-plugin-job.c
index 4e00e4f48..7625f2c5a 100644
--- a/lib/gs-plugin-job.c
+++ b/lib/gs-plugin-job.c
@@ -22,6 +22,7 @@ struct _GsPluginJob
        GsPluginRefineFlags      filter_flags;
        GsAppListFilterFlags     dedupe_flags;
        gboolean                 interactive;
+       gboolean                 propagate_error;
        guint                    max_results;
        guint                    timeout;
        guint64                  age;
@@ -54,6 +55,7 @@ enum {
        PROP_REVIEW,
        PROP_MAX_RESULTS,
        PROP_TIMEOUT,
+       PROP_PROPAGATE_ERROR,
        PROP_LAST
 };
 
@@ -82,6 +84,8 @@ gs_plugin_job_to_string (GsPluginJob *self)
        }
        if (self->interactive)
                g_string_append_printf (str, " with interactive=True");
+       if (self->propagate_error)
+               g_string_append_printf (str, " with propagate-error=True");
        if (self->timeout > 0)
                g_string_append_printf (str, " with timeout=%u", self->timeout);
        if (self->max_results > 0)
@@ -212,6 +216,20 @@ gs_plugin_job_get_interactive (GsPluginJob *self)
        return self->interactive;
 }
 
+void
+gs_plugin_job_set_propagate_error (GsPluginJob *self, gboolean propagate_error)
+{
+       g_return_if_fail (GS_IS_PLUGIN_JOB (self));
+       self->propagate_error = propagate_error;
+}
+
+gboolean
+gs_plugin_job_get_propagate_error (GsPluginJob *self)
+{
+       g_return_val_if_fail (GS_IS_PLUGIN_JOB (self), FALSE);
+       return self->propagate_error;
+}
+
 void
 gs_plugin_job_set_max_results (GsPluginJob *self, guint max_results)
 {
@@ -449,6 +467,9 @@ gs_plugin_job_get_property (GObject *obj, guint prop_id, GValue *value, GParamSp
        case PROP_TIMEOUT:
                g_value_set_uint (value, self->timeout);
                break;
+       case PROP_PROPAGATE_ERROR:
+               g_value_set_boolean (value, self->propagate_error);
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
                break;
@@ -503,6 +524,9 @@ gs_plugin_job_set_property (GObject *obj, guint prop_id, const GValue *value, GP
        case PROP_TIMEOUT:
                gs_plugin_job_set_timeout (self, g_value_get_uint (value));
                break;
+       case PROP_PROPAGATE_ERROR:
+               gs_plugin_job_set_propagate_error (self, g_value_get_boolean (value));
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
                break;
@@ -602,6 +626,11 @@ gs_plugin_job_class_init (GsPluginJobClass *klass)
                                   0, G_MAXUINT, 60,
                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
        g_object_class_install_property (object_class, PROP_TIMEOUT, pspec);
+
+       pspec = g_param_spec_boolean ("propagate-error", NULL, NULL,
+                                     FALSE,
+                                     G_PARAM_READWRITE);
+       g_object_class_install_property (object_class, PROP_PROPAGATE_ERROR, pspec);
 }
 
 static void
diff --git a/lib/gs-plugin-job.h b/lib/gs-plugin-job.h
index 885be1c8c..4bd7b6249 100644
--- a/lib/gs-plugin-job.h
+++ b/lib/gs-plugin-job.h
@@ -28,6 +28,8 @@ void           gs_plugin_job_set_dedupe_flags         (GsPluginJob    *self,
                                                         GsAppListFilterFlags dedupe_flags);
 void            gs_plugin_job_set_interactive          (GsPluginJob    *self,
                                                         gboolean        interactive);
+void            gs_plugin_job_set_propagate_error      (GsPluginJob    *self,
+                                                        gboolean        propagate_error);
 void            gs_plugin_job_set_max_results          (GsPluginJob    *self,
                                                         guint           max_results);
 void            gs_plugin_job_set_timeout              (GsPluginJob    *self,
diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c
index 0543f40d9..20f9ab440 100644
--- a/lib/gs-plugin-loader.c
+++ b/lib/gs-plugin-loader.c
@@ -316,7 +316,7 @@ gs_plugin_loader_notify_idle_cb (gpointer user_data)
        return FALSE;
 }
 
-static void
+void
 gs_plugin_loader_add_event (GsPluginLoader *plugin_loader, GsPluginEvent *event)
 {
        g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&plugin_loader->events_by_id_mutex);
@@ -400,6 +400,11 @@ gs_plugin_error_handle_failure (GsPluginLoaderHelper *helper,
                return TRUE;
        }
 
+       if (gs_plugin_job_get_propagate_error (helper->plugin_job)) {
+               g_propagate_error (error, g_error_copy (error_local));
+               return FALSE;
+       }
+
        /* this is only ever informational */
        if (g_error_matches (error_local, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_CANCELLED) ||
            g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
@@ -3421,13 +3426,15 @@ gs_plugin_loader_process_thread_cb (GTask *task,
                if (gs_app_list_length (list) == 0) {
                        g_autofree gchar *str = gs_plugin_job_to_string (helper->plugin_job);
                        g_autoptr(GError) error_local = NULL;
-                       g_autoptr(GsPluginEvent) event = NULL;
                        g_set_error (&error_local,
                                     GS_PLUGIN_ERROR,
                                     GS_PLUGIN_ERROR_NOT_SUPPORTED,
                                     "no application was created for %s", str);
-                       event = gs_plugin_job_to_failed_event (helper->plugin_job, error_local);
-                       gs_plugin_loader_add_event (plugin_loader, event);
+                       if (!gs_plugin_job_get_propagate_error (helper->plugin_job)) {
+                               g_autoptr(GsPluginEvent) event = NULL;
+                               event = gs_plugin_job_to_failed_event (helper->plugin_job, error_local);
+                               gs_plugin_loader_add_event (plugin_loader, event);
+                       }
                        g_task_return_error (task, g_steal_pointer (&error_local));
                        return;
                }
diff --git a/lib/gs-plugin-loader.h b/lib/gs-plugin-loader.h
index 056067bd8..4b76d9ebb 100644
--- a/lib/gs-plugin-loader.h
+++ b/lib/gs-plugin-loader.h
@@ -63,6 +63,8 @@ gboolean       gs_plugin_loader_get_network_metered   (GsPluginLoader *plugin_loader);
 gboolean        gs_plugin_loader_get_plugin_supported  (GsPluginLoader *plugin_loader,
                                                         const gchar    *function_name);
 
+void            gs_plugin_loader_add_event             (GsPluginLoader *plugin_loader,
+                                                        GsPluginEvent  *event);
 GPtrArray      *gs_plugin_loader_get_events            (GsPluginLoader *plugin_loader);
 GsPluginEvent  *gs_plugin_loader_get_event_default     (GsPluginLoader *plugin_loader);
 void            gs_plugin_loader_remove_events         (GsPluginLoader *plugin_loader);
diff --git a/src/gs-page.c b/src/gs-page.c
index 87effb97f..678da7798 100644
--- a/src/gs-page.c
+++ b/src/gs-page.c
@@ -43,6 +43,7 @@ typedef struct {
        GtkWidget       *button_install;
        GsPluginAction   action;
        GsShellInteraction interaction;
+       gboolean         propagate_error;
 } GsPageHelper;
 
 static void
@@ -131,16 +132,29 @@ gs_page_app_installed_cb (GObject *source,
 
        gs_application_emit_install_resources_done (GS_APPLICATION (g_application_get_default ()), NULL, 
error);
 
-       if (g_error_matches (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_CANCELLED)) {
-               g_debug ("%s", error->message);
+       if (g_error_matches (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_CANCELLED) ||
+           g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               g_debug ("App install cancelled with error: %s", error->message);
                return;
        }
        if (!ret) {
-               g_warning ("failed to install %s: %s",
-                          gs_app_get_id (helper->app),
-                          error->message);
+               if (helper->propagate_error) {
+                       g_autoptr(GsPluginEvent) event = NULL;
+
+                       /* create event which is handled by the GsShell */
+                       event = gs_plugin_event_new ();
+                       gs_plugin_event_set_error (event, error);
+                       gs_plugin_event_set_action (event, helper->action);
+                       gs_plugin_event_set_app (event, helper->app);
+                       if (helper->interaction == GS_SHELL_INTERACTION_FULL)
+                               gs_plugin_event_add_flag (event, GS_PLUGIN_EVENT_FLAG_INTERACTIVE);
+                       gs_plugin_event_add_flag (event, GS_PLUGIN_EVENT_FLAG_WARNING);
+
+                       /* add event to queue */
+                       gs_plugin_loader_add_event (plugin_loader, event);
+               } else {
+                       g_warning ("failed to install %s: %s", gs_app_get_id (helper->app), error->message);
+               }
                return;
        }
 
@@ -260,9 +274,11 @@ gs_page_install_app (GsPage *page,
        helper->page = g_object_ref (page);
        helper->cancellable = g_object_ref (cancellable);
        helper->interaction = interaction;
+       helper->propagate_error = TRUE;
 
        plugin_job = gs_plugin_job_newv (helper->action,
                                         "interactive", (interaction == GS_SHELL_INTERACTION_FULL),
+                                        "propagate-error", helper->propagate_error,
                                         "app", helper->app,
                                         NULL);
        gs_plugin_loader_job_process_async (priv->plugin_loader,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]