[gnome-software/961-gsapp-state-not-updated-after-repository-enable-disable: 101/101] GsApp: State not updated after repository enable/disable




commit 41c26e1f550eac581256a59af3e9be6a868b69d3
Author: Milan Crha <mcrha redhat com>
Date:   Tue Feb 2 07:51:28 2021 +0100

    GsApp: State not updated after repository enable/disable
    
    Let the other plugins know that a repository was enabled/disabled,
    thus they can refresh their cache accordingly.
    
    Closes https://gitlab.gnome.org/GNOME/gnome-software/-/issues/961

 lib/gs-plugin-loader.c                    | 18 ++++++
 lib/gs-plugin.c                           | 99 +++++++++++++++++++++++++++++++
 lib/gs-plugin.h                           |  9 ++-
 lib/gs-self-test.c                        |  2 +
 plugins/core/gs-plugin-appstream.c        |  7 +++
 plugins/core/gs-self-test.c               |  1 +
 plugins/dpkg/gs-self-test.c               |  1 +
 plugins/dummy/gs-self-test.c              |  1 +
 plugins/fedora-langpacks/gs-self-test.c   |  1 +
 plugins/flatpak/gs-flatpak.c              |  6 ++
 plugins/flatpak/gs-self-test.c            |  1 +
 plugins/fwupd/gs-plugin-fwupd.c           |  3 +
 plugins/fwupd/gs-self-test.c              |  1 +
 plugins/modalias/gs-self-test.c           |  1 +
 plugins/packagekit/gs-plugin-packagekit.c | 10 ++++
 plugins/packagekit/gs-self-test.c         |  1 +
 plugins/repos/gs-self-test.c              |  1 +
 plugins/rpm-ostree/gs-plugin-rpm-ostree.c |  2 +
 plugins/snap/gs-self-test.c               |  1 +
 src/gs-application.c                      | 19 ++++++
 src/gs-self-test.c                        |  1 +
 21 files changed, 185 insertions(+), 1 deletion(-)
---
diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c
index 2dad71f86..8d7be842a 100644
--- a/lib/gs-plugin-loader.c
+++ b/lib/gs-plugin-loader.c
@@ -2125,6 +2125,21 @@ gs_plugin_loader_reload_cb (GsPlugin *plugin,
                                       g_object_ref (plugin_loader));
 }
 
+static void
+gs_plugin_loader_repository_changed_cb (GsPlugin *plugin,
+                                       GsApp *repository,
+                                       GsPluginLoader *plugin_loader)
+{
+       GApplication *application = g_application_get_default ();
+
+       /* Can be NULL when running the self tests */
+       if (application) {
+               g_signal_emit_by_name (application,
+                       "repository-changed",
+                       repository);
+       }
+}
+
 static void
 gs_plugin_loader_open_plugin (GsPluginLoader *plugin_loader,
                              const gchar *filename)
@@ -2156,6 +2171,9 @@ gs_plugin_loader_open_plugin (GsPluginLoader *plugin_loader,
        g_signal_connect (plugin, "allow-updates",
                          G_CALLBACK (gs_plugin_loader_allow_updates_cb),
                          plugin_loader);
+       g_signal_connect (plugin, "repository-changed",
+                         G_CALLBACK (gs_plugin_loader_repository_changed_cb),
+                         plugin_loader);
        gs_plugin_set_soup_session (plugin, plugin_loader->soup_session);
        gs_plugin_set_locale (plugin, plugin_loader->locale);
        gs_plugin_set_language (plugin, plugin_loader->language);
diff --git a/lib/gs-plugin.c b/lib/gs-plugin.c
index d91cd496b..69d1e5733 100644
--- a/lib/gs-plugin.c
+++ b/lib/gs-plugin.c
@@ -90,6 +90,7 @@ enum {
        SIGNAL_REPORT_EVENT,
        SIGNAL_ALLOW_UPDATES,
        SIGNAL_BASIC_AUTH_START,
+       SIGNAL_REPOSITORY_CHANGED,
        SIGNAL_LAST
 };
 
@@ -2024,6 +2025,13 @@ gs_plugin_class_init (GsPluginClass *klass)
                              G_STRUCT_OFFSET (GsPluginClass, basic_auth_start),
                              NULL, NULL, g_cclosure_marshal_generic,
                              G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER);
+
+       signals [SIGNAL_REPOSITORY_CHANGED] =
+               g_signal_new ("repository-changed",
+                             G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET (GsPluginClass, repository_changed),
+                             NULL, NULL, g_cclosure_marshal_generic,
+                             G_TYPE_NONE, 1, GS_TYPE_APP);
 }
 
 static void
@@ -2065,3 +2073,94 @@ gs_plugin_new (void)
        plugin = g_object_new (GS_TYPE_PLUGIN, NULL);
        return plugin;
 }
+
+typedef struct {
+       GsPlugin *plugin;
+       GsApp    *repository;
+} GsPluginRepositoryChangedHelper;
+
+static gboolean
+gs_plugin_repository_changed_cb (gpointer user_data)
+{
+       GsPluginRepositoryChangedHelper *helper = user_data;
+       g_signal_emit (helper->plugin,
+                      signals[SIGNAL_REPOSITORY_CHANGED], 0,
+                      helper->repository);
+       g_clear_object (&helper->repository);
+       g_clear_object (&helper->plugin);
+       g_slice_free (GsPluginRepositoryChangedHelper, helper);
+       return FALSE;
+}
+
+/**
+ * gs_plugin_repository_changed:
+ * @plugin: a #GsPlugin
+ * @repository: a #GsApp representing the repository
+ *
+ * Emit the "repository-changed" signal in the main thread.
+ *
+ * Since: 40
+ **/
+void
+gs_plugin_repository_changed (GsPlugin *plugin,
+                             GsApp *repository)
+{
+       GsPluginRepositoryChangedHelper *helper;
+       g_autoptr(GSource) idle_source = NULL;
+
+       g_return_if_fail (GS_IS_PLUGIN (plugin));
+       g_return_if_fail (GS_IS_APP (repository));
+
+       helper = g_slice_new0 (GsPluginRepositoryChangedHelper);
+       helper->plugin = g_object_ref (plugin);
+       helper->repository = g_object_ref (repository);
+
+       idle_source = g_idle_source_new ();
+       g_source_set_callback (idle_source, gs_plugin_repository_changed_cb, helper, NULL);
+       g_source_attach (idle_source, NULL);
+}
+
+/**
+ * gs_plugin_update_cache_state_for_repository:
+ * @plugin: a #GsPlugin
+ * @repository: a #GsApp representing a repository, which changed
+ *
+ * Update state of the all cached #GsApp instances related
+ * to the @repository.
+ *
+ * Since: 40
+ **/
+void
+gs_plugin_update_cache_state_for_repository (GsPlugin *plugin,
+                                            GsApp *repository)
+{
+       GsPluginPrivate *priv;
+       GHashTableIter iter;
+       g_autoptr(GMutexLocker) locker = NULL;
+       gpointer value;
+       const gchar *repo_id;
+       GsAppState repo_state;
+
+       g_return_if_fail (GS_IS_PLUGIN (plugin));
+       g_return_if_fail (GS_IS_APP (repository));
+
+       priv = gs_plugin_get_instance_private (plugin);
+       repo_id = gs_app_get_id (repository);
+       repo_state = gs_app_get_state (repository);
+
+       locker = g_mutex_locker_new (&priv->cache_mutex);
+
+       g_hash_table_iter_init (&iter, priv->cache);
+       while (g_hash_table_iter_next (&iter, NULL, &value)) {
+               GsApp *app = value;
+               GsAppState app_state = gs_app_get_state (app);
+
+               if (((app_state == GS_APP_STATE_AVAILABLE &&
+                   repo_state != GS_APP_STATE_INSTALLED) ||
+                   (app_state == GS_APP_STATE_UNAVAILABLE &&
+                   repo_state == GS_APP_STATE_INSTALLED)) &&
+                   g_strcmp0 (gs_app_get_origin (app), repo_id) == 0) {
+                       gs_app_set_state (app, repo_state == GS_APP_STATE_INSTALLED ? GS_APP_STATE_AVAILABLE 
: GS_APP_STATE_UNAVAILABLE);
+               }
+       }
+}
diff --git a/lib/gs-plugin.h b/lib/gs-plugin.h
index 175b30612..d66ec3190 100644
--- a/lib/gs-plugin.h
+++ b/lib/gs-plugin.h
@@ -43,7 +43,9 @@ struct _GsPluginClass
                                                         const gchar    *realm,
                                                         GCallback       callback,
                                                         gpointer        user_data);
-       gpointer                 padding[25];
+       void                    (*repository_changed)   (GsPlugin       *plugin,
+                                                        GsApp          *repository);
+       gpointer                 padding[24];
 };
 
 typedef struct GsPluginData    GsPluginData;
@@ -127,5 +129,10 @@ void                gs_plugin_basic_auth_start             (GsPlugin       *plugin,
                                                         const gchar    *realm,
                                                         GCallback       callback,
                                                         gpointer        user_data);
+void           gs_plugin_repository_changed            (GsPlugin       *plugin,
+                                                        GsApp          *repository);
+void           gs_plugin_update_cache_state_for_repository
+                                                       (GsPlugin *plugin,
+                                                        GsApp *repository);
 
 G_END_DECLS
diff --git a/lib/gs-self-test.c b/lib/gs-self-test.c
index af862b047..fc5bf3999 100644
--- a/lib/gs-self-test.c
+++ b/lib/gs-self-test.c
@@ -823,6 +823,8 @@ main (int argc, char **argv)
 #endif
                     NULL);
 
+       g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
+
        /* only critical and error are fatal */
        g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
 
diff --git a/plugins/core/gs-plugin-appstream.c b/plugins/core/gs-plugin-appstream.c
index 5effadd73..2f8e3e592 100644
--- a/plugins/core/gs-plugin-appstream.c
+++ b/plugins/core/gs-plugin-appstream.c
@@ -36,6 +36,7 @@ void
 gs_plugin_initialize (GsPlugin *plugin)
 {
        GsPluginData *priv = gs_plugin_alloc_data (plugin, sizeof(GsPluginData));
+       GApplication *application = g_application_get_default ();
 
        /* XbSilo needs external locking as we destroy the silo and build a new
         * one when something changes */
@@ -46,6 +47,12 @@ gs_plugin_initialize (GsPlugin *plugin)
 
        /* require settings */
        priv->settings = g_settings_new ("org.gnome.software");
+
+       /* Can be NULL when running the self tests */
+       if (application) {
+               g_signal_connect_object (application, "repository-changed",
+                       G_CALLBACK (gs_plugin_update_cache_state_for_repository), plugin, G_CONNECT_SWAPPED);
+       }
 }
 
 void
diff --git a/plugins/core/gs-self-test.c b/plugins/core/gs-self-test.c
index 53be465a9..2e5cdc55f 100644
--- a/plugins/core/gs-self-test.c
+++ b/plugins/core/gs-self-test.c
@@ -213,6 +213,7 @@ main (int argc, char **argv)
 #endif
                     NULL);
        g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+       g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
 
        /* Use a common cache directory for all tests, since the appstream
         * plugin uses it and cannot be reinitialised for each test. */
diff --git a/plugins/dpkg/gs-self-test.c b/plugins/dpkg/gs-self-test.c
index e3a76b230..811015175 100644
--- a/plugins/dpkg/gs-self-test.c
+++ b/plugins/dpkg/gs-self-test.c
@@ -73,6 +73,7 @@ main (int argc, char **argv)
 #endif
                     NULL);
        g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+       g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
 
        /* only critical and error are fatal */
        g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
diff --git a/plugins/dummy/gs-self-test.c b/plugins/dummy/gs-self-test.c
index cdadfc6da..8634b99e0 100644
--- a/plugins/dummy/gs-self-test.c
+++ b/plugins/dummy/gs-self-test.c
@@ -751,6 +751,7 @@ main (int argc, char **argv)
 #endif
                     NULL);
        g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+       g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
        g_setenv ("GS_XMLB_VERBOSE", "1", TRUE);
 
        /* set all the things required as a dummy test harness */
diff --git a/plugins/fedora-langpacks/gs-self-test.c b/plugins/fedora-langpacks/gs-self-test.c
index df15e33d5..d4ead59b5 100644
--- a/plugins/fedora-langpacks/gs-self-test.c
+++ b/plugins/fedora-langpacks/gs-self-test.c
@@ -72,6 +72,7 @@ main (int argc, char **argv)
 #endif
                     NULL);
        g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+       g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
 
        /* only critical and error are fatal */
        g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
diff --git a/plugins/flatpak/gs-flatpak.c b/plugins/flatpak/gs-flatpak.c
index 07f29c08b..4828921a7 100644
--- a/plugins/flatpak/gs-flatpak.c
+++ b/plugins/flatpak/gs-flatpak.c
@@ -1484,6 +1484,9 @@ gs_flatpak_app_install_source (GsFlatpak *self, GsApp *app,
 
        /* success */
        gs_app_set_state (app, GS_APP_STATE_INSTALLED);
+
+       gs_plugin_repository_changed (self->plugin, app);
+
        return TRUE;
 }
 
@@ -2938,6 +2941,9 @@ gs_flatpak_app_remove_source (GsFlatpak *self,
        g_rw_lock_reader_unlock (&self->silo_lock);
 
        gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
+
+       gs_plugin_repository_changed (self->plugin, app);
+
        return TRUE;
 }
 
diff --git a/plugins/flatpak/gs-self-test.c b/plugins/flatpak/gs-self-test.c
index 9408d14d8..441be11ff 100644
--- a/plugins/flatpak/gs-self-test.c
+++ b/plugins/flatpak/gs-self-test.c
@@ -1859,6 +1859,7 @@ main (int argc, char **argv)
 #endif
                     NULL);
        g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+       g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
        g_setenv ("GS_XMLB_VERBOSE", "1", TRUE);
        g_setenv ("GS_SELF_TEST_PLUGIN_ERROR_FAIL_HARD", "1", TRUE);
 
diff --git a/plugins/fwupd/gs-plugin-fwupd.c b/plugins/fwupd/gs-plugin-fwupd.c
index b46f572ba..eab12dda1 100644
--- a/plugins/fwupd/gs-plugin-fwupd.c
+++ b/plugins/fwupd/gs-plugin-fwupd.c
@@ -944,6 +944,9 @@ gs_plugin_fwupd_modify_source (GsPlugin *plugin, GsApp *app, gboolean enabled,
        }
        gs_app_set_state (app, enabled ?
                          GS_APP_STATE_INSTALLED : GS_APP_STATE_AVAILABLE);
+
+       gs_plugin_repository_changed (plugin, app);
+
        return TRUE;
 }
 
diff --git a/plugins/fwupd/gs-self-test.c b/plugins/fwupd/gs-self-test.c
index 2c0bf10b2..625afb7e9 100644
--- a/plugins/fwupd/gs-self-test.c
+++ b/plugins/fwupd/gs-self-test.c
@@ -81,6 +81,7 @@ main (int argc, char **argv)
 #endif
                     NULL);
        g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+       g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
 
        /* only critical and error are fatal */
        g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
diff --git a/plugins/modalias/gs-self-test.c b/plugins/modalias/gs-self-test.c
index 92bf88f00..d566c5a27 100644
--- a/plugins/modalias/gs-self-test.c
+++ b/plugins/modalias/gs-self-test.c
@@ -61,6 +61,7 @@ main (int argc, char **argv)
 #endif
                     NULL);
        g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+       g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
        g_setenv ("GS_SELF_TEST_DUMMY_ENABLE", "1", TRUE);
 
        xml = g_strdup_printf ("<?xml version=\"1.0\"?>\n"
diff --git a/plugins/packagekit/gs-plugin-packagekit.c b/plugins/packagekit/gs-plugin-packagekit.c
index 0c7309c88..013fddac4 100644
--- a/plugins/packagekit/gs-plugin-packagekit.c
+++ b/plugins/packagekit/gs-plugin-packagekit.c
@@ -181,6 +181,7 @@ gs_plugin_app_origin_repo_enable (GsPlugin *plugin,
 {
        GsPluginData *priv = gs_plugin_get_data (plugin);
        g_autoptr(GsPackagekitHelper) helper = gs_packagekit_helper_new (plugin);
+       g_autoptr(GsApp) repo_app = NULL;
        g_autoptr(PkResults) results = NULL;
        g_autoptr(PkError) error_code = NULL;
        const gchar *repo_id;
@@ -219,6 +220,11 @@ gs_plugin_app_origin_repo_enable (GsPlugin *plugin,
         * UNAVAILABLE state to AVAILABLE */
        gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
 
+       /* Construct a simple fake GsApp for the repository, used only by the signal handler */
+       repo_app = gs_app_new (repo_id);
+       gs_app_set_state (repo_app, GS_APP_STATE_INSTALLED);
+       gs_plugin_repository_changed (plugin, repo_app);
+
        return TRUE;
 }
 
@@ -260,6 +266,8 @@ gs_plugin_repo_enable (GsPlugin *plugin,
        /* state is known */
        gs_app_set_state (app, GS_APP_STATE_INSTALLED);
 
+       gs_plugin_repository_changed (plugin, app);
+
        return TRUE;
 }
 
@@ -499,6 +507,8 @@ gs_plugin_repo_disable (GsPlugin *plugin,
        /* state is known */
        gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
 
+       gs_plugin_repository_changed (plugin, app);
+
        return TRUE;
 }
 
diff --git a/plugins/packagekit/gs-self-test.c b/plugins/packagekit/gs-self-test.c
index 5dbaf0a7b..8bc86e6e4 100644
--- a/plugins/packagekit/gs-self-test.c
+++ b/plugins/packagekit/gs-self-test.c
@@ -250,6 +250,7 @@ main (int argc, char **argv)
 #endif
                     NULL);
        g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+       g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
 
        /* only critical and error are fatal */
        g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
diff --git a/plugins/repos/gs-self-test.c b/plugins/repos/gs-self-test.c
index ff5b3e726..9b7675b66 100644
--- a/plugins/repos/gs-self-test.c
+++ b/plugins/repos/gs-self-test.c
@@ -53,6 +53,7 @@ main (int argc, char **argv)
 #endif
                     NULL);
        g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+       g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
 
        /* dummy data */
        reposdir = gs_test_get_filename (TESTDATADIR, "yum.repos.d");
diff --git a/plugins/rpm-ostree/gs-plugin-rpm-ostree.c b/plugins/rpm-ostree/gs-plugin-rpm-ostree.c
index a3117aeae..b3d7754dc 100644
--- a/plugins/rpm-ostree/gs-plugin-rpm-ostree.c
+++ b/plugins/rpm-ostree/gs-plugin-rpm-ostree.c
@@ -1112,6 +1112,8 @@ gs_plugin_repo_enable (GsPlugin *plugin,
        else
                gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
 
+       gs_plugin_repository_changed (plugin, app);
+
        return TRUE;
 }
 
diff --git a/plugins/snap/gs-self-test.c b/plugins/snap/gs-self-test.c
index 41696c114..7d3661c59 100644
--- a/plugins/snap/gs-self-test.c
+++ b/plugins/snap/gs-self-test.c
@@ -351,6 +351,7 @@ main (int argc, char **argv)
 #endif
                     NULL);
        g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+       g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
 
        /* only critical and error are fatal */
        g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
diff --git a/src/gs-application.c b/src/gs-application.c
index 0117a4e0d..a5f151040 100644
--- a/src/gs-application.c
+++ b/src/gs-application.c
@@ -67,6 +67,7 @@ static GParamSpec *obj_props[PROP_DEBUG + 1] = { NULL, };
 
 enum {
        INSTALL_RESOURCES_DONE,
+       REPOSITORY_CHANGED,
        LAST_SIGNAL
 };
 
@@ -1274,6 +1275,24 @@ gs_application_class_init (GsApplicationClass *klass)
                NULL,
                G_TYPE_NONE, 2,
                G_TYPE_STRING, G_TYPE_ERROR);
+
+       /**
+        * GsApplication::repository-changed:
+        * @repository: a #GsApp of the repository
+        *
+        * Emitted when the repository changed, usually when it is enabled or disabled.
+        *
+        * Since: 40
+        */
+       signals[REPOSITORY_CHANGED] = g_signal_new (
+               "repository-changed",
+               G_TYPE_FROM_CLASS (klass),
+               G_SIGNAL_ACTION | G_SIGNAL_NO_RECURSE,
+               0,
+               NULL, NULL,
+               NULL,
+               G_TYPE_NONE, 1,
+               GS_TYPE_APP);
 }
 
 /**
diff --git a/src/gs-self-test.c b/src/gs-self-test.c
index b664656c0..b52a47d84 100644
--- a/src/gs-self-test.c
+++ b/src/gs-self-test.c
@@ -49,6 +49,7 @@ main (int argc, char **argv)
 #endif
                     NULL);
        g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+       g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
 
        /* only critical and error are fatal */
        g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);


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