[gnome-software/mwleeds/hardcoded-pwa-list: 10/18] epiphany: Bring some harmony to the different app IDs




commit 38fd4332882bacf0a5696670b3a00afbb098b502
Author: Phaedrus Leeds <mwleeds protonmail com>
Date:   Wed Mar 16 16:14:15 2022 -0700

    epiphany: Bring some harmony to the different app IDs
    
    For most plugins, an app always has a certain app ID regardless of
    whether it's installed or not and the app ID never changes (aside from
    when apps are renamed in a Flatpak update). But for web apps, the app ID
    in the appstream metainfo file can't be the final installed app ID,
    which has to have the parent app as a prefix, and there's no way to
    predict the parent app ID. Even if we could assume that webapps would
    only be installed by Epiphany (and we can't) we couldn't assume which
    variant ("org.gnome.Epiphany" vs "org.gnome.Epiphany.Devel"). So the app
    ID in the appstream data will be something like
    "org.gnome.Software.WebApp_${checksum}.desktop" whereas the installed
    app ID would resemble "org.gnome.Epiphany.WebApp_${checksum}.desktop".
    
    This could cause issues, because in gnome-software generally we assume
    that there's a one-to-one mapping between the app ID and the GsApp
    object (except when a duplicate GsApp is created and then later filtered
    out). For example, after an app is installed we don't want to create a
    new GsApp object for it in list_installed_apps_thread_cb(); we want to
    use the GsApp object that was created by the appstream plugin and used
    for the details page.
    
    So try to solve such issues by using the AppStream app ID to create
    GsApp objects, storing the installed app ID on the object, and using one
    or the other as needed.

 plugins/epiphany/gs-plugin-epiphany.c | 69 ++++++++++++++++++++++++++++-------
 1 file changed, 56 insertions(+), 13 deletions(-)
---
diff --git a/plugins/epiphany/gs-plugin-epiphany.c b/plugins/epiphany/gs-plugin-epiphany.c
index 725357a76..fcc4bf652 100644
--- a/plugins/epiphany/gs-plugin-epiphany.c
+++ b/plugins/epiphany/gs-plugin-epiphany.c
@@ -40,6 +40,7 @@ struct _GsPluginEpiphany
        GDBusConnection *connection; /* (owned) */
        guint changed_id;
        GMutex installed_apps_mutex;
+       GHashTable *url_id_map; /* (owned) */
 };
 
 G_DEFINE_TYPE (GsPluginEpiphany, gs_plugin_epiphany, GS_TYPE_PLUGIN)
@@ -93,6 +94,8 @@ gs_plugin_epiphany_changed_cb (GFileMonitor      *monitor,
 {
        GsPluginEpiphany *self = GS_PLUGIN_EPIPHANY (user_data);
 
+       gs_plugin_cache_invalidate (GS_PLUGIN (self));
+
        /* With the current API this is the only way to reload the list of
         * installed apps.
         */
@@ -125,6 +128,13 @@ gs_plugin_epiphany_setup_async (GsPlugin            *plugin,
        if (connection)
                self->connection = g_object_ref (connection);
 
+       /* This is a mapping from URL to app ID, where the app ID comes from an
+        * appstream file. This allows us to use the AppStream app ID rather
+        * than the one provided by Epiphany for GsApp objects of installed
+        * apps.
+        */
+       self->url_id_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
        /* Watch for changes to the set of installed apps in the main thread.
         * This will also trigger when other apps' dynamic launchers are
         * installed or removed but that is expected to be infrequent.
@@ -331,6 +341,7 @@ gs_plugin_epiphany_dispose (GObject *object)
        g_clear_object (&self->monitor);
        g_clear_object (&self->worker);
        g_clear_object (&self->connection);
+       g_clear_pointer (&self->url_id_map, g_hash_table_unref);
 
        G_OBJECT_CLASS (gs_plugin_epiphany_parent_class)->dispose (object);
 }
@@ -478,6 +489,8 @@ gs_epiphany_create_app (GsPluginEpiphany *self,
        app = gs_app_new (id);
        gs_app_set_management_plugin (app, GS_PLUGIN (self));
        gs_app_set_kind (app, AS_COMPONENT_KIND_WEB_APP);
+       gs_app_set_metadata (app, "GnomeSoftware::Creator",
+                            gs_plugin_get_name (GS_PLUGIN (self)));
 
        gs_plugin_cache_add (GS_PLUGIN (self), id, app);
        return g_steal_pointer (&app);
@@ -517,6 +530,7 @@ list_installed_apps_thread_cb (GTask        *task,
                const gchar *desktop_path;
                const gchar *name;
                const gchar *url = NULL;
+               const gchar *metainfo_app_id;
                g_autofree char *icon_path = NULL;
                const gchar *exec;
                int argc;
@@ -568,7 +582,14 @@ list_installed_apps_thread_cb (GTask        *task,
                        desktop_size = g_file_info_get_size (file_info);
                }
 
-               app = gs_epiphany_create_app (self, desktop_file_id);
+               /* Create the GsApp using the app id from the appstream
+                * metainfo, but store the app id provided by epiphany for
+                * later use
+                */
+               metainfo_app_id = g_hash_table_lookup (self->url_id_map, url);
+               app = gs_epiphany_create_app (self, metainfo_app_id ? metainfo_app_id : desktop_file_id);
+               gs_app_set_metadata (app, "epiphany::installed-app-id", desktop_file_id);
+
                gs_app_set_state (app, GS_APP_STATE_INSTALLED);
                gs_app_set_name (app, GS_APP_QUALITY_NORMAL, name);
                gs_app_set_launchable (app, AS_LAUNCHABLE_KIND_URL, url);
@@ -623,14 +644,18 @@ list_installed_apps_thread_cb (GTask        *task,
        gs_plugin_cache_lookup_by_state (GS_PLUGIN (self), installed_cache, GS_APP_STATE_INSTALLED);
        for (guint i = 0; i < gs_app_list_length (installed_cache); i++) {
                GsApp *app = gs_app_list_index (installed_cache, i);
-               const char *app_id = gs_app_get_id (app);
                g_autoptr(GsApp) app_cached = NULL;
+               const char *installed_app_id;
+               const char *app_id;
+
+               installed_app_id = gs_app_get_metadata_item (app, "epiphany::installed-app-id");
+               app_id = installed_app_id ? installed_app_id : gs_app_get_id (app);
 
                if (g_strv_contains ((const char * const *)webapps, app_id))
                        continue;
 
                gs_app_set_state (app, GS_APP_STATE_UNKNOWN);
-               gs_plugin_cache_remove (GS_PLUGIN (self), app_id);
+               gs_plugin_cache_remove (GS_PLUGIN (self), gs_app_get_id (app));
        }
 
        g_task_return_pointer (task, g_steal_pointer (&list), g_object_unref);
@@ -646,17 +671,14 @@ gs_plugin_epiphany_list_installed_apps_finish (GsPlugin      *plugin,
 }
 
 static void
-gs_epiphany_refine_app (GsApp *app)
+gs_epiphany_refine_app (GsApp      *app,
+                       const char *url)
 {
-       const char *url;
        g_autoptr(GUri) uri = NULL;
 
-       url = gs_app_get_launchable (app, AS_LAUNCHABLE_KIND_URL);
-       if (url == NULL || *url == '\0') {
-               /* A launchable URL is required by the AppStream spec */
-               g_warning ("Web app %s missing launchable url", gs_app_get_id (app));
-               return;
-       } else if (!(uri = g_uri_parse (url, G_URI_FLAGS_NONE, NULL))) {
+       g_return_if_fail (url != NULL && *url != '\0');
+
+       if (!(uri = g_uri_parse (url, G_URI_FLAGS_NONE, NULL))) {
                g_warning ("Failed to parse URL for web app %s: %s", gs_app_get_id (app), url);
                return;
        }
@@ -704,13 +726,28 @@ refine_thread_cb (GTask        *task,
 
        for (guint i = 0; i < gs_app_list_length (list); i++) {
                GsApp *app = gs_app_list_index (list, i);
+               const char *url;
+               const char *source_plugin;
 
                /* not us */
                if (gs_app_get_kind (app) != AS_COMPONENT_KIND_WEB_APP ||
                    gs_app_get_bundle_kind (app) == AS_BUNDLE_KIND_PACKAGE)
                        continue;
 
-               gs_epiphany_refine_app (app);
+               url = gs_app_get_launchable (app, AS_LAUNCHABLE_KIND_URL);
+               if (url == NULL || *url == '\0') {
+                       /* A launchable URL is required by the AppStream spec */
+                       g_warning ("Web app %s missing launchable url", gs_app_get_id (app));
+                       continue;
+               }
+
+               source_plugin = gs_app_get_metadata_item (app, "GnomeSoftware::Creator");
+               if (g_strcmp0 (source_plugin, "appstream") == 0) {
+                       g_hash_table_insert (self->url_id_map, g_strdup (url),
+                                            g_strdup (gs_app_get_id (app)));
+               }
+
+               gs_epiphany_refine_app (app, url);
                gs_epiphany_refine_app_state (GS_PLUGIN (self), app);
 
                /* Usually the way to refine wildcard apps is to create a new
@@ -723,6 +760,7 @@ refine_thread_cb (GTask        *task,
                if (gs_app_has_quirk (app, GS_APP_QUIRK_IS_WILDCARD)) {
                        gs_app_remove_quirk (app, GS_APP_QUIRK_IS_WILDCARD);
                        gs_app_set_management_plugin (app, GS_PLUGIN (self));
+                       gs_plugin_cache_add (GS_PLUGIN (self), gs_app_get_id (app), app);
                }
        }
 
@@ -879,13 +917,18 @@ gs_plugin_app_remove (GsPlugin      *plugin,
                      GError       **error)
 {
        GsPluginEpiphany *self = GS_PLUGIN_EPIPHANY (plugin);
+       const char *installed_app_id;
+       const char *app_id;
 
        if (!gs_app_has_management_plugin (app, plugin))
                return TRUE;
 
+       installed_app_id = gs_app_get_metadata_item (app, "epiphany::installed-app-id");
+       app_id = installed_app_id ? installed_app_id : gs_app_get_id (app);
+
        gs_app_set_state (app, GS_APP_STATE_REMOVING);
        if (!gs_ephy_web_app_provider_call_uninstall_sync (self->epiphany_proxy,
-                                                          gs_app_get_id (app),
+                                                          app_id,
                                                           cancellable,
                                                           error)) {
                gs_epiphany_error_convert (error);


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