[gnome-software: 10/21] gs-plugin-loader: Add D-Bus connection properties




commit 9316bb8ca8b7c71f12b72aba15860ea3a0c21eb5
Author: Philip Withnall <pwithnall endlessos org>
Date:   Wed Mar 30 15:55:24 2022 +0100

    gs-plugin-loader: Add D-Bus connection properties
    
    These will be set either at construction time of the `GsPluginLoader`,
    or (by default) when `setup_async()` is called.
    
    In a subsequent commit, they will be passed to the `GsPlugin` objects
    the plugin loader loads. The ultimate aim is to allow plugins to easily
    use a mock D-Bus connection provided by unit tests.
    
    Signed-off-by: Philip Withnall <pwithnall endlessos org>
    
    Helps: #1694

 lib/gs-plugin-loader.c | 188 +++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 165 insertions(+), 23 deletions(-)
---
diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c
index 1e0754ec7..e72f47766 100644
--- a/lib/gs-plugin-loader.c
+++ b/lib/gs-plugin-loader.c
@@ -80,6 +80,9 @@ struct _GsPluginLoader
 #ifdef HAVE_SYSPROF
        SysprofCaptureWriter    *sysprof_writer;  /* (owned) (nullable) */
 #endif
+
+       GDBusConnection         *session_bus_connection;  /* (owned); (not nullable) after setup */
+       GDBusConnection         *system_bus_connection;  /* (owned); (not nullable) after setup */
 };
 
 static void gs_plugin_loader_monitor_network (GsPluginLoader *plugin_loader);
@@ -112,9 +115,11 @@ typedef enum {
        PROP_ALLOW_UPDATES,
        PROP_NETWORK_AVAILABLE,
        PROP_NETWORK_METERED,
+       PROP_SESSION_BUS_CONNECTION,
+       PROP_SYSTEM_BUS_CONNECTION,
 } GsPluginLoaderProperty;
 
-static GParamSpec *obj_props[PROP_NETWORK_METERED + 1] = { NULL, };
+static GParamSpec *obj_props[PROP_SYSTEM_BUS_CONNECTION + 1] = { NULL, };
 
 typedef void            (*GsPluginFunc)                (GsPlugin       *plugin);
 typedef gboolean        (*GsPluginSetupFunc)           (GsPlugin       *plugin,
@@ -2142,6 +2147,8 @@ gs_plugin_loader_find_plugins (const gchar *path, GError **error)
 
 typedef struct {
        guint n_pending;
+       gchar **allowlist;
+       gchar **blocklist;
 #ifdef HAVE_SYSPROF
        gint64 setup_begin_time_nsec;
        gint64 plugins_begin_time_nsec;
@@ -2151,11 +2158,20 @@ typedef struct {
 static void
 setup_data_free (SetupData *data)
 {
+       g_clear_pointer (&data->allowlist, g_strfreev);
+       g_clear_pointer (&data->blocklist, g_strfreev);
        g_free (data);
 }
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (SetupData, setup_data_free)
 
+static void get_session_bus_cb (GObject      *object,
+                                GAsyncResult *result,
+                                gpointer      user_data);
+static void get_system_bus_cb (GObject      *object,
+                               GAsyncResult *result,
+                               gpointer      user_data);
+static void finish_setup_get_bus (GTask *task);
 static void plugin_setup_cb (GObject      *source_object,
                              GAsyncResult *result,
                              gpointer      user_data);
@@ -2196,19 +2212,8 @@ gs_plugin_loader_setup_async (GsPluginLoader      *plugin_loader,
                               GAsyncReadyCallback  callback,
                               gpointer             user_data)
 {
-       const gchar *plugin_name;
-       gboolean changes;
-       GPtrArray *deps;
-       GsPlugin *dep;
-       GsPlugin *plugin;
-       guint dep_loop_check = 0;
-       guint i;
-       guint j;
        SetupData *setup_data;
        g_autoptr(SetupData) setup_data_owned = NULL;
-       g_autoptr(GsPluginLoaderHelper) helper = NULL;
-       g_autoptr(GsPluginJob) plugin_job = NULL;
-       g_autoptr(GPtrArray) locations = NULL;
        g_autoptr(GTask) task = NULL;
        g_autoptr(GError) local_error = NULL;
 #ifdef HAVE_SYSPROF
@@ -2224,6 +2229,94 @@ gs_plugin_loader_setup_async (GsPluginLoader      *plugin_loader,
                return;
        }
 
+       /* Setup data closure. */
+       setup_data = setup_data_owned = g_new0 (SetupData, 1);
+       setup_data->allowlist = g_strdupv ((gchar **) allowlist);
+       setup_data->blocklist = g_strdupv ((gchar **) blocklist);
+#ifdef HAVE_SYSPROF
+       setup_data->setup_begin_time_nsec = begin_time_nsec;
+#endif
+
+       g_task_set_task_data (task, g_steal_pointer (&setup_data_owned), (GDestroyNotify) setup_data_free);
+
+       /* Connect to D-Bus if connections haven’t been provided at construction
+        * time. */
+       if (plugin_loader->session_bus_connection == NULL)
+               g_bus_get (G_BUS_TYPE_SESSION, cancellable, get_session_bus_cb, g_object_ref (task));
+       if (plugin_loader->system_bus_connection == NULL)
+               g_bus_get (G_BUS_TYPE_SYSTEM, cancellable, get_system_bus_cb, g_object_ref (task));
+
+       finish_setup_get_bus (task);
+}
+
+static void
+get_session_bus_cb (GObject      *object,
+                    GAsyncResult *result,
+                    gpointer      user_data)
+{
+       g_autoptr(GTask) task = g_steal_pointer (&user_data);
+       GsPluginLoader *plugin_loader = g_task_get_source_object (task);
+       g_autoptr(GError) local_error = NULL;
+
+       plugin_loader->session_bus_connection = g_bus_get_finish (result, &local_error);
+       if (plugin_loader->session_bus_connection == NULL) {
+               notify_setup_complete (plugin_loader);
+               g_prefix_error_literal (&local_error, "Error getting session bus: ");
+               g_task_return_error (task, g_steal_pointer (&local_error));
+               return;
+       }
+
+       g_object_notify_by_pspec (G_OBJECT (plugin_loader), obj_props[PROP_SESSION_BUS_CONNECTION]);
+
+       finish_setup_get_bus (task);
+}
+
+static void
+get_system_bus_cb (GObject      *object,
+                   GAsyncResult *result,
+                   gpointer      user_data)
+{
+       g_autoptr(GTask) task = g_steal_pointer (&user_data);
+       GsPluginLoader *plugin_loader = g_task_get_source_object (task);
+       g_autoptr(GError) local_error = NULL;
+
+       plugin_loader->system_bus_connection = g_bus_get_finish (result, &local_error);
+       if (plugin_loader->system_bus_connection == NULL) {
+               notify_setup_complete (plugin_loader);
+               g_prefix_error_literal (&local_error, "Error getting system bus: ");
+               g_task_return_error (task, g_steal_pointer (&local_error));
+               return;
+       }
+
+       g_object_notify_by_pspec (G_OBJECT (plugin_loader), obj_props[PROP_SYSTEM_BUS_CONNECTION]);
+
+       finish_setup_get_bus (task);
+}
+
+static void
+finish_setup_get_bus (GTask *task)
+{
+       SetupData *data = g_task_get_task_data (task);
+       GsPluginLoader *plugin_loader = g_task_get_source_object (task);
+       GCancellable *cancellable = g_task_get_cancellable (task);
+       const gchar *plugin_name;
+       gboolean changes;
+       GPtrArray *deps;
+       GsPlugin *dep;
+       GsPlugin *plugin;
+       guint dep_loop_check = 0;
+       guint i;
+       guint j;
+       g_autoptr(GsPluginLoaderHelper) helper = NULL;
+       g_autoptr(GsPluginJob) plugin_job = NULL;
+       g_autoptr(GPtrArray) locations = NULL;
+       g_autoptr(GError) local_error = NULL;
+
+       /* Wait until we’ve got all the buses we need. */
+       if (plugin_loader->session_bus_connection == NULL ||
+           plugin_loader->system_bus_connection == NULL)
+               return;
+
        /* use the default, but this requires a 'make install' */
        if (plugin_loader->locations->len == 0) {
                g_autofree gchar *filename = NULL;
@@ -2275,13 +2368,13 @@ gs_plugin_loader_setup_async (GsPluginLoader      *plugin_loader,
        }
 
        /* optional allowlist */
-       if (allowlist != NULL) {
+       if (data->allowlist != NULL) {
                for (i = 0; i < plugin_loader->plugins->len; i++) {
                        gboolean ret;
                        plugin = g_ptr_array_index (plugin_loader->plugins, i);
                        if (!gs_plugin_get_enabled (plugin))
                                continue;
-                       ret = g_strv_contains ((const gchar * const *) allowlist,
+                       ret = g_strv_contains ((const gchar * const *) data->allowlist,
                                               gs_plugin_get_name (plugin));
                        if (!ret) {
                                g_debug ("%s not in allowlist, disabling",
@@ -2292,13 +2385,13 @@ gs_plugin_loader_setup_async (GsPluginLoader      *plugin_loader,
        }
 
        /* optional blocklist */
-       if (blocklist != NULL) {
+       if (data->blocklist != NULL) {
                for (i = 0; i < plugin_loader->plugins->len; i++) {
                        gboolean ret;
                        plugin = g_ptr_array_index (plugin_loader->plugins, i);
                        if (!gs_plugin_get_enabled (plugin))
                                continue;
-                       ret = g_strv_contains ((const gchar * const *) blocklist,
+                       ret = g_strv_contains ((const gchar * const *) data->blocklist,
                                               gs_plugin_get_name (plugin));
                        if (ret)
                                gs_plugin_set_enabled (plugin, FALSE);
@@ -2427,15 +2520,11 @@ gs_plugin_loader_setup_async (GsPluginLoader      *plugin_loader,
        } while (changes);
 
        /* run setup */
-       setup_data = setup_data_owned = g_new0 (SetupData, 1);
-       setup_data->n_pending = 1;  /* incremented until all operations have been started */
+       data->n_pending = 1;  /* incremented until all operations have been started */
 #ifdef HAVE_SYSPROF
-       setup_data->setup_begin_time_nsec = begin_time_nsec;
-       setup_data->plugins_begin_time_nsec = SYSPROF_CAPTURE_CURRENT_TIME;
+       data->plugins_begin_time_nsec = SYSPROF_CAPTURE_CURRENT_TIME;
 #endif
 
-       g_task_set_task_data (task, g_steal_pointer (&setup_data_owned), (GDestroyNotify) setup_data_free);
-
        for (i = 0; i < plugin_loader->plugins->len; i++) {
                plugin = GS_PLUGIN (plugin_loader->plugins->pdata[i]);
 
@@ -2443,7 +2532,7 @@ gs_plugin_loader_setup_async (GsPluginLoader      *plugin_loader,
                        continue;
 
                if (GS_PLUGIN_GET_CLASS (plugin)->setup_async != NULL) {
-                       setup_data->n_pending++;
+                       data->n_pending++;
                        GS_PLUGIN_GET_CLASS (plugin)->setup_async (plugin, cancellable,
                                                                   plugin_setup_cb, g_object_ref (task));
                }
@@ -2628,6 +2717,12 @@ gs_plugin_loader_get_property (GObject *object, guint prop_id,
        case PROP_NETWORK_METERED:
                g_value_set_boolean (value, gs_plugin_loader_get_network_metered (plugin_loader));
                break;
+       case PROP_SESSION_BUS_CONNECTION:
+               g_value_set_object (value, plugin_loader->session_bus_connection);
+               break;
+       case PROP_SYSTEM_BUS_CONNECTION:
+               g_value_set_object (value, plugin_loader->system_bus_connection);
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -2638,6 +2733,8 @@ static void
 gs_plugin_loader_set_property (GObject *object, guint prop_id,
                               const GValue *value, GParamSpec *pspec)
 {
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
+
        switch ((GsPluginLoaderProperty) prop_id) {
        case PROP_EVENTS:
        case PROP_ALLOW_UPDATES:
@@ -2646,6 +2743,16 @@ gs_plugin_loader_set_property (GObject *object, guint prop_id,
                /* Read only */
                g_assert_not_reached ();
                break;
+       case PROP_SESSION_BUS_CONNECTION:
+               /* Construct only */
+               g_assert (plugin_loader->session_bus_connection == NULL);
+               plugin_loader->session_bus_connection = g_value_dup_object (value);
+               break;
+       case PROP_SYSTEM_BUS_CONNECTION:
+               /* Construct only */
+               g_assert (plugin_loader->system_bus_connection == NULL);
+               plugin_loader->system_bus_connection = g_value_dup_object (value);
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -2699,6 +2806,9 @@ gs_plugin_loader_dispose (GObject *object)
        g_clear_pointer (&plugin_loader->sysprof_writer, sysprof_capture_writer_unref);
 #endif
 
+       g_clear_object (&plugin_loader->session_bus_connection);
+       g_clear_object (&plugin_loader->system_bus_connection);
+
        G_OBJECT_CLASS (gs_plugin_loader_parent_class)->dispose (object);
 }
 
@@ -2778,6 +2888,38 @@ gs_plugin_loader_class_init (GsPluginLoaderClass *klass)
                                      FALSE,
                                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
 
+       /**
+        * GsPluginLoader:session-bus-connection: (nullable)
+        *
+        * A connection to the D-Bus session bus.
+        *
+        * This may be %NULL at construction time. If so, the default session
+        * bus connection will be used (and returned as the value of this
+        * property) after gs_plugin_loader_setup_async() is called.
+        *
+        * Since: 43
+        */
+       obj_props[PROP_SESSION_BUS_CONNECTION] =
+               g_param_spec_object ("session-bus-connection", NULL, NULL,
+                                    G_TYPE_DBUS_CONNECTION,
+                                    G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | 
G_PARAM_EXPLICIT_NOTIFY);
+
+       /**
+        * GsPluginLoader:system-bus-connection: (not nullable)
+        *
+        * A connection to the D-Bus system bus.
+        *
+        * This may be %NULL at construction time. If so, the default system
+        * bus connection will be used (and returned as the value of this
+        * property) after gs_plugin_loader_setup_async() is called.
+        *
+        * Since: 43
+        */
+       obj_props[PROP_SYSTEM_BUS_CONNECTION] =
+               g_param_spec_object ("system-bus-connection", NULL, NULL,
+                                    G_TYPE_DBUS_CONNECTION,
+                                    G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | 
G_PARAM_EXPLICIT_NOTIFY);
+
        g_object_class_install_properties (object_class, G_N_ELEMENTS (obj_props), obj_props);
 
        signals [SIGNAL_STATUS_CHANGED] =


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