[gnome-software/wip/hughsie/unique_id: 2/2] Add gs_app_get_unique_id() and use it for de-duplication



commit f3f63d31e191cb04918e6f7b1b99f1e8d9c79f67
Author: Richard Hughes <richard hughsie com>
Date:   Thu Jul 28 16:30:06 2016 +0100

    Add gs_app_get_unique_id() and use it for de-duplication
    
    This allows us to finally support more than one version of application,
    and also more than one distribution system without hacks like an ID prefix.
    
    This requires a new appstream-glib as well.

 configure.ac                               |    2 +-
 src/gs-app-list.c                          |   14 ++--
 src/gs-app.c                               |   78 ++++++++++++++++++--------
 src/gs-app.h                               |    4 +-
 src/gs-plugin-loader.c                     |   14 ++--
 src/gs-plugin.c                            |    2 +-
 src/gs-self-test.c                         |   17 +++---
 src/gs-shell-search.c                      |    4 +-
 src/plugins/gs-appstream.c                 |   13 +++--
 src/plugins/gs-flatpak.c                   |   83 +++++++++++++++++++---------
 src/plugins/gs-plugin-appstream.c          |   60 ++++++++++++++------
 src/plugins/gs-plugin-dummy.c              |    9 ++-
 src/plugins/gs-plugin-epiphany.c           |    6 +-
 src/plugins/gs-plugin-flatpak-system.c     |    4 +-
 src/plugins/gs-plugin-flatpak-user.c       |    4 +-
 src/plugins/gs-plugin-hardcoded-featured.c |    2 +-
 src/plugins/gs-plugin-key-colors.c         |    4 +-
 src/plugins/gs-plugin-odrs.c               |   12 ++--
 src/plugins/gs-plugin-shell-extensions.c   |    7 +-
 19 files changed, 217 insertions(+), 122 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index ecb6513..8a13731 100644
--- a/configure.ac
+++ b/configure.ac
@@ -63,7 +63,7 @@ dnl ---------------------------------------------------------------------------
 dnl - Check library dependencies
 dnl ---------------------------------------------------------------------------
 PKG_CHECK_MODULES(GTK, gtk+-3.0 >= 3.18.2 gio-unix-2.0)
-PKG_CHECK_MODULES(APPSTREAM, appstream-glib >= 0.5.18)
+PKG_CHECK_MODULES(APPSTREAM, appstream-glib >= 0.6.1)
 PKG_CHECK_MODULES(GDK_PIXBUF, gdk-pixbuf-2.0 >= 2.31.5)
 PKG_CHECK_MODULES(JSON_GLIB, json-glib-1.0 >= 1.1.1)
 PKG_CHECK_MODULES(SQLITE, sqlite3)
diff --git a/src/gs-app-list.c b/src/gs-app-list.c
index da3d851..ce0bfcc 100644
--- a/src/gs-app-list.c
+++ b/src/gs-app-list.c
@@ -67,7 +67,7 @@ gs_app_list_add (GsAppList *list, GsApp *app)
        g_return_if_fail (GS_IS_APP (app));
 
        /* if we're lazy-loading the ID then we can't filter for duplicates */
-       id = gs_app_get_id (app);
+       id = gs_app_get_unique_id (app);
        if (id == NULL) {
                g_ptr_array_add (list->array, g_object_ref (app));
                return;
@@ -266,9 +266,9 @@ gs_app_list_filter_duplicates (GsAppList *list, GsAppListFilterFlags flags)
                                      g_free, (GDestroyNotify) g_object_unref);
        for (i = 0; i < list->array->len; i++) {
                app = gs_app_list_index (list, i);
-               id = gs_app_get_id (app);
+               id = gs_app_get_unique_id (app);
                if (flags & GS_APP_LIST_FILTER_FLAG_PRIORITY)
-                       id = gs_app_get_id_no_prefix (app);
+                       id = gs_app_get_id (app);
                if (id == NULL) {
                        g_autofree gchar *str = gs_app_to_string (app);
                        g_debug ("ignoring as no application id for: %s", str);
@@ -276,7 +276,7 @@ gs_app_list_filter_duplicates (GsAppList *list, GsAppListFilterFlags flags)
                }
                found = g_hash_table_lookup (hash, id);
                if (found == NULL) {
-                       g_debug ("found new %s", gs_app_get_id (app));
+                       g_debug ("found new %s", id);
                        g_hash_table_insert (hash,
                                             g_strdup (id),
                                             g_object_ref (app));
@@ -288,7 +288,7 @@ gs_app_list_filter_duplicates (GsAppList *list, GsAppListFilterFlags flags)
                        if (gs_app_get_priority (app) >
                            gs_app_get_priority (found)) {
                                g_debug ("using better %s (priority %u > %u)",
-                                        gs_app_get_id (app),
+                                        id,
                                         gs_app_get_priority (app),
                                         gs_app_get_priority (found));
                                g_hash_table_insert (hash,
@@ -297,12 +297,12 @@ gs_app_list_filter_duplicates (GsAppList *list, GsAppListFilterFlags flags)
                                continue;
                        }
                        g_debug ("ignoring worse duplicate %s (priority %u > %u)",
-                                gs_app_get_id (app),
+                                id,
                                 gs_app_get_priority (app),
                                 gs_app_get_priority (found));
                        continue;
                }
-               g_debug ("ignoring duplicate %s", gs_app_get_id (app));
+               g_debug ("ignoring duplicate %s", id);
                continue;
        }
 
diff --git a/src/gs-app.c b/src/gs-app.c
index 253b62b..ffda463 100644
--- a/src/gs-app.c
+++ b/src/gs-app.c
@@ -59,6 +59,7 @@ struct _GsApp
        GObject                  parent_instance;
 
        gchar                   *id;
+       gchar                   *unique_id;
        gchar                   *name;
        GsAppQuality             name_quality;
        GPtrArray               *icons;
@@ -254,6 +255,8 @@ gs_app_to_string (GsApp *app)
                gs_app_kv_printf (str, "progress", "%u%%", app->progress);
        if (app->id != NULL)
                gs_app_kv_lpad (str, "id", app->id);
+       if (app->unique_id != NULL)
+               gs_app_kv_lpad (str, "unique-id", app->unique_id);
        if ((app->kudos & GS_APP_KUDO_MY_LANGUAGE) > 0)
                gs_app_kv_lpad (str, "kudo", "my-language");
        if ((app->kudos & GS_APP_KUDO_RECENT_RELEASE) > 0)
@@ -486,7 +489,7 @@ gs_app_queue_notify (GsApp *app, const gchar *property_name)
  *
  * Gets the application ID.
  *
- * Returns: The whole ID, e.g. "gimp.desktop" or "flatpak:org.gnome.Gimp.desktop"
+ * Returns: The whole ID, e.g. "gimp.desktop"
  **/
 const gchar *
 gs_app_get_id (GsApp *app)
@@ -496,27 +499,6 @@ gs_app_get_id (GsApp *app)
 }
 
 /**
- * gs_app_get_id_no_prefix:
- * @app: a #GsApp
- *
- * Gets the application ID without any prefix set.
- *
- * Returns: The whole ID, e.g. gimp.desktop" or "org.gnome.Gimp.desktop"
- **/
-const gchar *
-gs_app_get_id_no_prefix (GsApp *app)
-{
-       gchar *tmp;
-       g_return_val_if_fail (GS_IS_APP (app), NULL);
-       if (app->id == NULL)
-               return NULL;
-       tmp = g_strrstr (app->id, ":");
-       if (tmp != NULL)
-               return tmp + 1;
-       return app->id;
-}
-
-/**
  * gs_app_set_id:
  * @app: a #GsApp
  * @id: a application ID, e.g. "gimp.desktop"
@@ -527,6 +509,15 @@ void
 gs_app_set_id (GsApp *app, const gchar *id)
 {
        g_return_if_fail (GS_IS_APP (app));
+
+       /* check for old-style prefix */
+       if (id != NULL && g_strstr_len (id, -1, ":") != NULL) {
+               g_warning ("Invalid ID of %s -- use "
+                          "gs_app_set_unique_id() and use the actual "
+                          "desktop-style ID here instead!", id);
+               return;
+       }
+
        g_free (app->id);
        app->id = g_strdup (id);
 }
@@ -829,6 +820,46 @@ gs_app_set_kind (GsApp *app, AsAppKind kind)
 }
 
 /**
+ * gs_app_get_unique_id:
+ * @app: a #GsApp
+ *
+ * Gets the unique application ID used for de-duplication.
+ * If nothing has been set the value from gs_app_get_id() will be used.
+ *
+ * Returns: The unique ID, e.g. "flatpak:gimp.desktop:3.22", or %NULL
+ **/
+const gchar *
+gs_app_get_unique_id (GsApp *app)
+{
+       g_return_val_if_fail (GS_IS_APP (app), NULL);
+       if (app->unique_id == NULL)
+               return app->id;
+       return app->unique_id;
+}
+
+/**
+ * gs_app_set_unique_id:
+ * @app: a #GsApp
+ * @unique_id: a unique application ID, e.g. "flatpak:gimp.desktop:3.22"
+ *
+ * Sets the unique application ID. Any #GsApp using the same ID will be
+ * deduplicated. This means that applications that can exist from more than
+ * one plugin should use this method.
+ */
+void
+gs_app_set_unique_id (GsApp *app, const gchar *unique_id)
+{
+       g_return_if_fail (GS_IS_APP (app));
+
+       /* check for validity */
+       if (!as_utils_unique_id_valid (unique_id))
+               g_warning ("unique ID %s is not valid!", unique_id);
+
+       g_free (app->unique_id);
+       app->unique_id = g_strdup (unique_id);
+}
+
+/**
  * gs_app_get_name:
  * @app: a #GsApp
  *
@@ -2844,6 +2875,7 @@ gs_app_finalize (GObject *object)
        GsApp *app = GS_APP (object);
 
        g_free (app->id);
+       g_free (app->unique_id);
        g_free (app->name);
        g_hash_table_unref (app->urls);
        g_free (app->license);
@@ -3013,7 +3045,7 @@ gs_app_init (GsApp *app)
 
 /**
  * gs_app_new:
- * @id: an application ID, or %NULL, e.g. "flatpak:org.gnome.Software.desktop"
+ * @id: an application ID, or %NULL, e.g. "org.gnome.Software.desktop"
  *
  * Creates a new application object.
  *
diff --git a/src/gs-app.h b/src/gs-app.h
index d7dacc6..f6e1672 100644
--- a/src/gs-app.h
+++ b/src/gs-app.h
@@ -103,7 +103,6 @@ gchar               *gs_app_to_string               (GsApp          *app);
 const gchar    *gs_app_get_id                  (GsApp          *app);
 void            gs_app_set_id                  (GsApp          *app,
                                                 const gchar    *id);
-const gchar    *gs_app_get_id_no_prefix        (GsApp          *app);
 AsAppKind       gs_app_get_kind                (GsApp          *app);
 void            gs_app_set_kind                (GsApp          *app,
                                                 AsAppKind       kind);
@@ -114,6 +113,9 @@ void                 gs_app_set_state_recover       (GsApp          *app);
 guint           gs_app_get_progress            (GsApp          *app);
 void            gs_app_set_progress            (GsApp          *app,
                                                 guint           percentage);
+const gchar    *gs_app_get_unique_id           (GsApp          *app);
+void            gs_app_set_unique_id           (GsApp          *app,
+                                                const gchar    *unique_id);
 const gchar    *gs_app_get_name                (GsApp          *app);
 void            gs_app_set_name                (GsApp          *app,
                                                 GsAppQuality    quality,
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index d808bce..25c3ba0 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -260,7 +260,7 @@ gs_plugin_loader_run_adopt (GsPluginLoader *plugin_loader, GsAppList *list)
                        if (gs_app_get_management_plugin (app) != NULL) {
                                g_debug ("%s adopted %s",
                                         gs_plugin_get_name (plugin),
-                                        gs_app_get_id (app));
+                                        gs_app_get_unique_id (app));
                        }
                }
        }
@@ -665,7 +665,7 @@ gs_plugin_loader_get_app_str (GsApp *app)
        const gchar *id;
 
        /* first try the actual id */
-       id = gs_app_get_id (app);
+       id = gs_app_get_unique_id (app);
        if (id != NULL)
                return id;
 
@@ -883,12 +883,12 @@ gs_plugin_loader_set_app_error (GsApp *app, GError *error)
        /* random, non-plugin error domains are never shown to the user */
        if (error->domain == GS_PLUGIN_ERROR) {
                g_debug ("saving error for %s: %s",
-                        gs_app_get_id (app),
+                        gs_app_get_unique_id (app),
                         error->message);
                gs_app_set_last_error (app, error);
        } else {
                g_warning ("not saving error for %s: %s",
-                          gs_app_get_id (app),
+                          gs_app_get_unique_id (app),
                           error->message);
        }
 }
@@ -2727,7 +2727,7 @@ gs_plugin_loader_app_action_thread_cb (GTask *task,
        case AS_APP_STATE_INSTALLING:
        case AS_APP_STATE_REMOVING:
                g_warning ("application %s left in %s state",
-                          gs_app_get_id (state->app),
+                          gs_app_get_unique_id (state->app),
                           as_app_state_to_string (gs_app_get_state (state->app)));
                gs_app_set_state (state->app, AS_APP_STATE_UNKNOWN);
                break;
@@ -2867,7 +2867,7 @@ load_install_queue (GsPluginLoader *plugin_loader, GError **error)
                                 g_object_ref (app));
                g_mutex_unlock (&priv->pending_apps_mutex);
 
-               g_debug ("adding pending app %s", gs_app_get_id (app));
+               g_debug ("adding pending app %s", gs_app_get_unique_id (app));
                gs_app_list_add (list, app);
        }
 
@@ -3970,7 +3970,7 @@ gs_plugin_loader_app_installed_cb (GObject *source,
        if (!ret) {
                remove_app_from_install_queue (plugin_loader, app);
                g_warning ("failed to install %s: %s",
-                          gs_app_get_id (app), error->message);
+                          gs_app_get_unique_id (app), error->message);
        }
 }
 
diff --git a/src/gs-plugin.c b/src/gs-plugin.c
index a596089..d6f9b52 100644
--- a/src/gs-plugin.c
+++ b/src/gs-plugin.c
@@ -801,7 +801,7 @@ gs_plugin_app_launch (GsPlugin *plugin, GsApp *app, GError **error)
        const gchar *desktop_id;
        g_autoptr(GAppInfo) appinfo = NULL;
 
-       desktop_id = gs_app_get_id_no_prefix (app);
+       desktop_id = gs_app_get_id (app);
        if (desktop_id == NULL) {
                g_set_error (error,
                             GS_PLUGIN_ERROR,
diff --git a/src/gs-self-test.c b/src/gs-self-test.c
index 7def349..e0e72ec 100644
--- a/src/gs-self-test.c
+++ b/src/gs-self-test.c
@@ -154,22 +154,25 @@ gs_plugin_func (void)
 
        /* respect priority when deduplicating */
        list = gs_app_list_new ();
-       app = gs_app_new ("foo:e");
+       app = gs_app_new ("e");
+       gs_app_set_unique_id (app, "user/foo/*/*/e/*/*");
        gs_app_list_add (list, app);
        gs_app_set_priority (app, 0);
        g_object_unref (app);
-       app = gs_app_new ("bar:e");
+       app = gs_app_new ("e");
+       gs_app_set_unique_id (app, "user/bar/*/*/e/*/*");
        gs_app_list_add (list, app);
        gs_app_set_priority (app, 99);
        g_object_unref (app);
-       app = gs_app_new ("baz:e");
+       app = gs_app_new ("e");
+       gs_app_set_unique_id (app, "user/baz/*/*/e/*/*");
        gs_app_list_add (list, app);
        gs_app_set_priority (app, 50);
        g_object_unref (app);
        g_assert_cmpint (gs_app_list_length (list), ==, 3);
        gs_app_list_filter_duplicates (list, GS_APP_LIST_FILTER_FLAG_PRIORITY);
        g_assert_cmpint (gs_app_list_length (list), ==, 1);
-       g_assert_cmpstr (gs_app_get_id (gs_app_list_index (list, 0)), ==, "bar:e");
+       g_assert_cmpstr (gs_app_get_unique_id (gs_app_list_index (list, 0)), ==, "user/bar/*/*/e/*/*");
        g_object_unref (list);
 }
 
@@ -178,11 +181,9 @@ gs_app_func (void)
 {
        g_autoptr(GsApp) app = NULL;
 
-       app = gs_app_new ("flatpak:gnome-software");
+       app = gs_app_new ("gnome-software.desktop");
        g_assert (GS_IS_APP (app));
-
-       g_assert_cmpstr (gs_app_get_id (app), ==, "flatpak:gnome-software");
-       g_assert_cmpstr (gs_app_get_id_no_prefix (app), ==, "gnome-software");
+       g_assert_cmpstr (gs_app_get_id (app), ==, "gnome-software.desktop");
 
        /* check we clean up the version, but not at the expense of having
         * the same string as the update version */
diff --git a/src/gs-shell-search.c b/src/gs-shell-search.c
index 995782f..6fb9bfb 100644
--- a/src/gs-shell-search.c
+++ b/src/gs-shell-search.c
@@ -111,8 +111,8 @@ _gs_app_list_is_duplicate (GsAppList *list, GsApp *app)
                }
 
                /* same D-Bus ID */
-               if (g_strcmp0 (gs_app_get_id_no_prefix (tmp),
-                              gs_app_get_id_no_prefix (app)) == 0) {
+               if (g_strcmp0 (gs_app_get_id (tmp),
+                              gs_app_get_id (app)) == 0) {
                        return TRUE;
                }
 
diff --git a/src/plugins/gs-appstream.c b/src/plugins/gs-appstream.c
index 937decf..6673b56 100644
--- a/src/plugins/gs-appstream.c
+++ b/src/plugins/gs-appstream.c
@@ -511,6 +511,10 @@ gs_appstream_refine_app (GsPlugin *plugin,
        if (as_app_get_id (item) != NULL && gs_app_get_id (app) == NULL)
                gs_app_set_id (app, as_app_get_id (item));
 
+       /* set unique-id */
+       if (as_app_get_unique_id (item) != NULL && gs_app_get_unique_id (app) == NULL)
+               gs_app_set_unique_id (app, as_app_get_unique_id (item));
+
        /* set source */
        gs_app_set_metadata (app, "appstream::source-file", as_app_get_source_file (item));
 
@@ -555,11 +559,10 @@ gs_appstream_refine_app (GsPlugin *plugin,
        /* set origin */
        if (as_app_get_origin (item) != NULL &&
            gs_app_get_origin (app) == NULL ) {
-               tmp = as_app_get_origin (item);
-               if (g_str_has_prefix (tmp, "flatpak:"))
-                       gs_app_set_origin (app, tmp + 8);
-               if (g_str_has_prefix (tmp, "user-flatpak:"))
-                       gs_app_set_origin (app, tmp + 13);
+               tmp = as_app_get_unique_id (item);
+               if (g_str_has_prefix (tmp, "user/flatpak/") ||
+                   g_str_has_prefix (tmp, "system/flatpak/"))
+                       gs_app_set_origin (app, as_app_get_origin (item));
        }
 
        /* set description */
diff --git a/src/plugins/gs-flatpak.c b/src/plugins/gs-flatpak.c
index 94e4824..cc82a35 100644
--- a/src/plugins/gs-flatpak.c
+++ b/src/plugins/gs-flatpak.c
@@ -218,15 +218,21 @@ gs_flatpak_refresh_appstream (GsFlatpak *self, guint cache_age,
        return TRUE;
 }
 
+static const gchar *
+_flatpak_ref_kind_to_string (FlatpakRefKind kind)
+{
+       if (kind == FLATPAK_REF_KIND_APP)
+               return "app";
+       if (kind == FLATPAK_REF_KIND_RUNTIME)
+               return "runtime";
+       return NULL;
+}
+
 static void
 gs_app_set_flatpak_kind (GsApp *app, FlatpakRefKind kind)
 {
-       if (kind == FLATPAK_REF_KIND_APP)
-               gs_app_set_metadata (app, "flatpak::kind", "app");
-       else if (kind == FLATPAK_REF_KIND_RUNTIME)
-               gs_app_set_metadata (app, "flatpak::kind", "runtime");
-       else
-               g_assert_not_reached ();
+       gs_app_set_metadata (app, "flatpak::kind",
+                            _flatpak_ref_kind_to_string (kind));
 }
 
 static void
@@ -283,23 +289,35 @@ gs_flatpak_set_metadata_installed (GsFlatpak *self, GsApp *app,
 }
 
 static gchar *
-gs_flatpak_build_id (FlatpakInstallation *installation, FlatpakRef *xref)
+gs_flatpak_build_id (FlatpakRef *xref)
 {
-       const gchar *prefix = GS_FLATPAK_SYSTEM_PREFIX;
+       if (flatpak_ref_get_kind (xref) == FLATPAK_REF_KIND_APP) {
+               return g_strdup_printf ("%s.desktop",
+                                       flatpak_ref_get_name (xref));
+       }
+       return g_strdup_printf ("%s.runtime",
+                               flatpak_ref_get_name (xref));
+}
+
+static gchar *
+gs_flatpak_build_unique_id (FlatpakInstallation *installation, FlatpakRef *xref)
+{
+       const gchar *scope = "system";
+       g_autofree gchar *id = NULL;
 
        /* use a different prefix if we're somehow running this as per-user */
        if (flatpak_installation_get_is_user (installation))
-               prefix = GS_FLATPAK_USER_PREFIX;
+               scope = "user";
 
        /* flatpak doesn't use a suffix; AppStream does */
-       if (flatpak_ref_get_kind (xref) == FLATPAK_REF_KIND_APP) {
-               return g_strdup_printf ("%s:%s.desktop",
-                                       prefix,
-                                       flatpak_ref_get_name (xref));
-       }
-       return g_strdup_printf ("%s:%s.runtime",
-                               prefix,
-                               flatpak_ref_get_name (xref));
+       id = gs_flatpak_build_id (xref);
+       return as_utils_unique_id_build (scope,
+                                        "flatpak",
+                                        NULL, /* origin */
+                                        _flatpak_ref_kind_to_string (flatpak_ref_get_kind (xref)),
+                                        id,
+                                        flatpak_ref_get_arch (xref),
+                                        flatpak_ref_get_branch (xref));
 }
 
 static GsApp *
@@ -307,7 +325,7 @@ gs_flatpak_create_installed (GsFlatpak *self,
                             FlatpakInstalledRef *xref,
                             GError **error)
 {
-       g_autofree gchar *id = NULL;
+       g_autofree gchar *unique_id = NULL;
        g_autoptr(AsIcon) icon = NULL;
        g_autoptr(GsApp) app = NULL;
 
@@ -332,11 +350,14 @@ gs_flatpak_create_installed (GsFlatpak *self,
        }
 
        /* create new object */
-       id = gs_flatpak_build_id (self->installation, FLATPAK_REF (xref));
-       app = gs_plugin_cache_lookup (self->plugin, id);
+       unique_id = gs_flatpak_build_unique_id (self->installation,
+                                               FLATPAK_REF (xref));
+       app = gs_plugin_cache_lookup (self->plugin, unique_id);
        if (app == NULL) {
+               g_autofree gchar *id = gs_flatpak_build_id (FLATPAK_REF (xref));
                app = gs_app_new (id);
-               gs_plugin_cache_add (self->plugin, id, app);
+               gs_app_set_unique_id (app, unique_id);
+               gs_plugin_cache_add (self->plugin, unique_id, app);
        }
        gs_flatpak_set_metadata_installed (self, app, xref);
 
@@ -931,8 +952,8 @@ gs_flatpak_app_matches_xref (GsFlatpak *self, GsApp *app, FlatpakRef *xref)
        g_autofree gchar *id = NULL;
 
        /* check ID */
-       id = gs_flatpak_build_id (self->installation, xref);
-       if (g_strcmp0 (id, gs_app_get_id (app)) == 0)
+       id = gs_flatpak_build_unique_id (self->installation, xref);
+       if (g_strcmp0 (id, gs_app_get_unique_id (app)) == 0)
                return TRUE;
 
        /* do all the metadata items match? */
@@ -944,6 +965,8 @@ gs_flatpak_app_matches_xref (GsFlatpak *self, GsApp *app, FlatpakRef *xref)
                       flatpak_ref_get_branch (xref)) == 0)
                return TRUE;
 
+g_debug ("no match for %s == %s", id, gs_app_get_unique_id (app));
+
        /* sad panda */
        return FALSE;
 }
@@ -1576,7 +1599,7 @@ gs_flatpak_file_to_app_bundle (GsFlatpak *self,
 {
        gint size;
        g_autofree gchar *content_type = NULL;
-       g_autofree gchar *id_prefixed = NULL;
+       g_autofree gchar *unique_id = NULL;
        g_autoptr(GBytes) appstream_gz = NULL;
        g_autoptr(GBytes) icon_data = NULL;
        g_autoptr(GBytes) metadata = NULL;
@@ -1591,11 +1614,17 @@ gs_flatpak_file_to_app_bundle (GsFlatpak *self,
        }
 
        /* create a virtual ID */
-       id_prefixed = gs_flatpak_build_id (self->installation,
-                                          FLATPAK_REF (xref_bundle));
+       unique_id = gs_flatpak_build_unique_id (self->installation,
+                                               FLATPAK_REF (xref_bundle));
+       app = gs_plugin_cache_lookup (self->plugin, unique_id);
+       if (app == NULL) {
+               g_autofree gchar *id = gs_flatpak_build_id (FLATPAK_REF (xref_bundle));
+               app = gs_app_new (id);
+               gs_app_set_unique_id (app, unique_id);
+               gs_plugin_cache_add (self->plugin, unique_id, app);
+       }
 
        /* load metadata */
-       app = gs_app_new (id_prefixed);
        gs_app_set_kind (app, AS_APP_KIND_DESKTOP);
        gs_app_set_state (app, AS_APP_STATE_AVAILABLE_LOCAL);
        gs_app_set_size_installed (app, flatpak_bundle_ref_get_installed_size (xref_bundle));
diff --git a/src/plugins/gs-plugin-appstream.c b/src/plugins/gs-plugin-appstream.c
index ac91f96..28708a6 100644
--- a/src/plugins/gs-plugin-appstream.c
+++ b/src/plugins/gs-plugin-appstream.c
@@ -274,6 +274,22 @@ gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
                }
        }
 
+       /* add keyword for non-package sources */
+       for (i = 0; i < items->len; i++) {
+               g_auto(GStrv) split = NULL;
+               app = g_ptr_array_index (items, i);
+               split = as_utils_unique_id_split (as_app_get_unique_id (app));
+               if (split == NULL)
+                       continue;
+               if (g_strcmp0 (split[1], "package") == 0)
+                       continue;
+               if (g_strcmp0 (split[1], "*") == 0)
+                       continue;
+               g_debug ("Adding keyword '%s' to %s",
+                        split[1], as_app_get_id (app));
+               as_app_add_keyword (app, NULL, split[1]);
+       }
+
        /* fix up these */
        for (i = 0; i < items->len; i++) {
                app = g_ptr_array_index (items, i);
@@ -305,21 +321,29 @@ gs_plugin_refine_from_id (GsPlugin *plugin,
                          GError **error)
 {
        GsPluginData *priv = gs_plugin_get_data (plugin);
-       const gchar *id;
+       const gchar *unique_id;
        AsApp *item;
 
        /* unfound */
        *found = FALSE;
 
        /* find anything that matches the ID */
-       id = gs_app_get_id (app);
-       if (id == NULL)
+       unique_id = gs_app_get_unique_id (app);
+       if (unique_id == NULL)
                return TRUE;
 
        /* nothing found */
-       item = as_store_get_app_by_id (priv->store, id);
-       if (item == NULL)
+       g_debug ("searching appstream for %s", unique_id);
+       item = as_store_get_app_by_unique_id (priv->store, unique_id);
+       if (item == NULL) {
+               const gchar *id = gs_app_get_id (app);
+               g_debug ("looking for fallback of %s", id);
+               item = as_store_get_app_by_id (priv->store, id);
+       }
+       if (item == NULL) {
+               g_debug ("no app with ID %s found in appstream", unique_id);
                return TRUE;
+       }
 
        /* set new properties */
        if (!gs_appstream_refine_app (plugin, app, item, error))
@@ -359,14 +383,16 @@ gs_plugin_refine_from_pkgname (GsPlugin *plugin,
 }
 
 static GsApp *
-gs_plugin_appstream_create_app (GsPlugin *plugin, const gchar *id)
+gs_plugin_appstream_create_app (GsPlugin *plugin, AsApp *item)
 {
-       GsApp *app = gs_plugin_cache_lookup (plugin, id);
+       const gchar *unique_id = as_app_get_unique_id (item);
+       GsApp *app = gs_plugin_cache_lookup (plugin, unique_id);
        if (app == NULL) {
-               app = gs_app_new (id);
+               app = gs_app_new (as_app_get_id (item));
+               gs_app_set_unique_id (app, unique_id);
                gs_app_set_metadata (app, "GnomeSoftware::Creator",
                                     gs_plugin_get_name (plugin));
-               gs_plugin_cache_add (plugin, id, app);
+               gs_plugin_cache_add (plugin, unique_id, app);
        }
        return app;
 }
@@ -391,7 +417,7 @@ gs_plugin_add_distro_upgrades (GsPlugin *plugin,
                        continue;
 
                /* create */
-               app = gs_plugin_appstream_create_app (plugin, as_app_get_id (item));
+               app = gs_plugin_appstream_create_app (plugin, item);
                gs_app_set_kind (app, AS_APP_KIND_OS_UPGRADE);
                gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
                if (!gs_appstream_refine_app (plugin, app, item, error))
@@ -460,8 +486,7 @@ gs_plugin_appstream_add_wildcards (GsPlugin *plugin,
                /* new app */
                g_debug ("found %s for wildcard %s",
                         as_app_get_id (item), id);
-               new = gs_plugin_appstream_create_app (plugin,
-                                                     as_app_get_id (item));
+               new = gs_plugin_appstream_create_app (plugin, item);
                if (!gs_appstream_refine_app (plugin, new, item, error))
                        return FALSE;
                gs_app_list_add (list, new);
@@ -554,8 +579,7 @@ gs_plugin_add_category_apps (GsPlugin *plugin,
                                continue;
 
                        /* add all the data we can */
-                       app = gs_plugin_appstream_create_app (plugin,
-                                                             as_app_get_id (item));
+                       app = gs_plugin_appstream_create_app (plugin, item);
                        if (!gs_appstream_refine_app (plugin, app, item, error))
                                return FALSE;
                        gs_app_list_add (list, app);
@@ -591,7 +615,7 @@ gs_plugin_add_search_item (GsPlugin *plugin,
                return TRUE;
 
        /* create app */
-       app = gs_plugin_appstream_create_app (plugin, as_app_get_id (item));
+       app = gs_plugin_appstream_create_app (plugin, item);
        if (!gs_appstream_refine_app (plugin, app, item, error))
                return FALSE;
        gs_app_set_match_value (app, match_value);
@@ -651,7 +675,7 @@ gs_plugin_add_installed (GsPlugin *plugin,
                item = g_ptr_array_index (array, i);
                if (as_app_get_state (item) == AS_APP_STATE_INSTALLED) {
                        g_autoptr(GsApp) app = NULL;
-                       app = gs_plugin_appstream_create_app (plugin, as_app_get_id (item));
+                       app = gs_plugin_appstream_create_app (plugin, item);
                        if (!gs_appstream_refine_app (plugin, app, item, error))
                                return FALSE;
                        gs_app_list_add (list, app);
@@ -746,7 +770,7 @@ gs_plugin_add_popular (GsPlugin *plugin,
                        continue;
                if (!as_app_has_kudo (item, "GnomeSoftware::popular"))
                        continue;
-               app = gs_plugin_appstream_create_app (plugin, as_app_get_id_no_prefix (item));
+               app = gs_plugin_appstream_create_app (plugin, item);
                gs_app_add_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX);
                gs_app_list_add (list, app);
        }
@@ -777,7 +801,7 @@ gs_plugin_add_featured (GsPlugin *plugin,
                        continue;
                if (as_app_get_metadata_item (item, "GnomeSoftware::FeatureTile-css") == NULL)
                        continue;
-               app = gs_plugin_appstream_create_app (plugin, as_app_get_id_no_prefix (item));
+               app = gs_plugin_appstream_create_app (plugin, item);
                if (!gs_appstream_refine_app (plugin, app, item, error))
                        return FALSE;
                gs_app_add_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX);
diff --git a/src/plugins/gs-plugin-dummy.c b/src/plugins/gs-plugin-dummy.c
index 84b49e1..b17abd4 100644
--- a/src/plugins/gs-plugin-dummy.c
+++ b/src/plugins/gs-plugin-dummy.c
@@ -304,7 +304,8 @@ gs_plugin_add_popular (GsPlugin *plugin,
        gs_app_list_add (list, app1);
 
        /* add again, this time with a prefix so it gets deduplicated */
-       app2 = gs_app_new ("dummy:zeus.desktop");
+       app2 = gs_app_new ("zeus.desktop");
+       gs_app_set_unique_id (app2, "user/dummy/*/*/zeus.desktop/*/*");
        gs_app_set_metadata (app2, "GnomeSoftware::Creator",
                             gs_plugin_get_name (plugin));
        gs_app_list_add (list, app2);
@@ -384,9 +385,9 @@ gs_plugin_refine_app (GsPlugin *plugin,
                      GError **error)
 {
        /* default */
-       if (g_strcmp0 (gs_app_get_id_no_prefix (app), "chiron.desktop") == 0 ||
-           g_strcmp0 (gs_app_get_id_no_prefix (app), "mate-spell.desktop") == 0 ||
-           g_strcmp0 (gs_app_get_id_no_prefix (app), "zeus.desktop") == 0) {
+       if (g_strcmp0 (gs_app_get_id (app), "chiron.desktop") == 0 ||
+           g_strcmp0 (gs_app_get_id (app), "mate-spell.desktop") == 0 ||
+           g_strcmp0 (gs_app_get_id (app), "zeus.desktop") == 0) {
                if (gs_app_get_state (app) == AS_APP_STATE_UNKNOWN)
                        gs_app_set_state (app, AS_APP_STATE_INSTALLED);
                if (gs_app_get_kind (app) == AS_APP_KIND_UNKNOWN)
diff --git a/src/plugins/gs-plugin-epiphany.c b/src/plugins/gs-plugin-epiphany.c
index 0c8ffaf..a64bb18 100644
--- a/src/plugins/gs-plugin-epiphany.c
+++ b/src/plugins/gs-plugin-epiphany.c
@@ -63,7 +63,7 @@ _gs_app_get_id_nonfull (GsApp *app)
        gchar *id;
        gchar *tmp;
 
-       id = g_strdup (gs_app_get_id_no_prefix (app));
+       id = g_strdup (gs_app_get_id (app));
        tmp = g_strrstr (id, ".desktop");
        if (tmp != NULL)
                *tmp = '\0';
@@ -191,7 +191,7 @@ gs_plugin_app_install (GsPlugin *plugin, GsApp *app,
        /* symlink it to somewhere the shell will notice */
        app_desktop = g_build_filename (g_get_user_data_dir (),
                                        "applications",
-                                       gs_app_get_id_no_prefix (app),
+                                       gs_app_get_id (app),
                                        NULL);
        symlink_desktop = g_file_new_for_path (app_desktop);
        ret = g_file_make_symbolic_link (symlink_desktop,
@@ -231,7 +231,7 @@ gs_plugin_app_remove (GsPlugin *plugin, GsApp *app,
        /* remove the shared desktop file */
        app_desktop = g_build_filename (g_get_user_data_dir (),
                                        "applications",
-                                       gs_app_get_id_no_prefix (app),
+                                       gs_app_get_id (app),
                                        NULL);
        file_app = g_file_new_for_path (app_desktop);
        if (!g_file_delete (file_app, NULL, error))
diff --git a/src/plugins/gs-plugin-flatpak-system.c b/src/plugins/gs-plugin-flatpak-system.c
index a1b629a..4e27561 100644
--- a/src/plugins/gs-plugin-flatpak-system.c
+++ b/src/plugins/gs-plugin-flatpak-system.c
@@ -64,8 +64,8 @@ gs_plugin_destroy (GsPlugin *plugin)
 void
 gs_plugin_adopt_app (GsPlugin *plugin, GsApp *app)
 {
-       const gchar *id = gs_app_get_id (app);
-       if (id != NULL && g_str_has_prefix (id, GS_FLATPAK_SYSTEM_PREFIX ":")) {
+       const gchar *id = gs_app_get_unique_id (app);
+       if (id != NULL && g_str_has_prefix (id, "system/flatpak/")) {
                gs_app_set_management_plugin (app, gs_plugin_get_name (plugin));
        }
 }
diff --git a/src/plugins/gs-plugin-flatpak-user.c b/src/plugins/gs-plugin-flatpak-user.c
index 02d3b30..5b63cd1 100644
--- a/src/plugins/gs-plugin-flatpak-user.c
+++ b/src/plugins/gs-plugin-flatpak-user.c
@@ -64,8 +64,8 @@ gs_plugin_destroy (GsPlugin *plugin)
 void
 gs_plugin_adopt_app (GsPlugin *plugin, GsApp *app)
 {
-       const gchar *id = gs_app_get_id (app);
-       if (id != NULL && g_str_has_prefix (id, GS_FLATPAK_USER_PREFIX ":")) {
+       const gchar *id = gs_app_get_unique_id (app);
+       if (id != NULL && g_str_has_prefix (id, "user/flatpak/")) {
                gs_app_set_management_plugin (app, gs_plugin_get_name (plugin));
        }
 }
diff --git a/src/plugins/gs-plugin-hardcoded-featured.c b/src/plugins/gs-plugin-hardcoded-featured.c
index 66c8721..009617e 100644
--- a/src/plugins/gs-plugin-hardcoded-featured.c
+++ b/src/plugins/gs-plugin-hardcoded-featured.c
@@ -235,7 +235,7 @@ gs_plugin_refine_app (GsPlugin *plugin,
        const gchar *key = "GnomeSoftware::FeatureTile-css";
        guint i;
        for (i = 0; myapps[i].id != NULL; i++) {
-               if (g_strcmp0 (gs_app_get_id_no_prefix (app),
+               if (g_strcmp0 (gs_app_get_id (app),
                               myapps[i].id) != 0)
                        continue;
                if (gs_app_get_metadata_item (app, key) != NULL)
diff --git a/src/plugins/gs-plugin-key-colors.c b/src/plugins/gs-plugin-key-colors.c
index b3b32d1..65f31ea 100644
--- a/src/plugins/gs-plugin-key-colors.c
+++ b/src/plugins/gs-plugin-key-colors.c
@@ -175,8 +175,10 @@ gs_plugin_refine_app (GsPlugin *plugin,
 
        /* no pixbuf */
        pb = gs_app_get_pixbuf (app);
-       if (pb == NULL)
+       if (pb == NULL) {
+               g_debug ("no pixbuf, so no key colors");
                return TRUE;
+       }
 
        /* get a list of key colors */
        pb_small = gdk_pixbuf_scale_simple (pb, 32, 32, GDK_INTERP_BILINEAR);
diff --git a/src/plugins/gs-plugin-odrs.c b/src/plugins/gs-plugin-odrs.c
index ddd066b..db1c10a 100644
--- a/src/plugins/gs-plugin-odrs.c
+++ b/src/plugins/gs-plugin-odrs.c
@@ -469,7 +469,7 @@ gs_plugin_refine_ratings (GsPlugin *plugin,
 
        /* get ratings */
        review_ratings = g_hash_table_lookup (priv->ratings,
-                                             gs_app_get_id_no_prefix (app));
+                                             gs_app_get_id (app));
        if (review_ratings == NULL)
                return TRUE;
        gs_app_set_review_ratings (app, review_ratings);
@@ -503,7 +503,7 @@ gs_plugin_odrs_fetch_for_app (GsPlugin *plugin, GsApp *app, GError **error)
        g_autoptr(SoupMessage) msg = NULL;
 
        /* look in the cache */
-       cachefn_basename = g_strdup_printf ("%s.json", gs_app_get_id_no_prefix (app));
+       cachefn_basename = g_strdup_printf ("%s.json", gs_app_get_id (app));
        cachefn = gs_utils_get_cache_filename ("reviews",
                                               cachefn_basename,
                                               GS_UTILS_CACHE_FLAG_WRITEABLE,
@@ -516,7 +516,7 @@ gs_plugin_odrs_fetch_for_app (GsPlugin *plugin, GsApp *app, GError **error)
                if (!g_file_get_contents (cachefn, &json_data, NULL, error))
                        return NULL;
                g_debug ("got review data for %s from %s",
-                        gs_app_get_id_no_prefix (app), cachefn);
+                        gs_app_get_id (app), cachefn);
                return gs_plugin_odrs_parse_reviews (plugin,
                                                     json_data, -1,
                                                     error);
@@ -533,7 +533,7 @@ gs_plugin_odrs_fetch_for_app (GsPlugin *plugin, GsApp *app, GError **error)
        json_builder_set_member_name (builder, "user_hash");
        json_builder_add_string_value (builder, priv->user_hash);
        json_builder_set_member_name (builder, "app_id");
-       json_builder_add_string_value (builder, gs_app_get_id_no_prefix (app));
+       json_builder_add_string_value (builder, gs_app_get_id (app));
        json_builder_set_member_name (builder, "locale");
        json_builder_add_string_value (builder, gs_plugin_get_locale (plugin));
        json_builder_set_member_name (builder, "distro");
@@ -639,7 +639,7 @@ gs_plugin_refine_app (GsPlugin *plugin,
        /* not valid */
        if (gs_app_get_kind (app) == AS_APP_KIND_ADDON)
                return TRUE;
-       if (gs_app_get_id_no_prefix (app) == NULL)
+       if (gs_app_get_id (app) == NULL)
                return TRUE;
 
        /* add reviews if possible */
@@ -730,7 +730,7 @@ gs_plugin_review_submit (GsPlugin *plugin,
 
        /* save as we don't re-request the review from the server */
        as_review_set_reviewer_name (review, g_get_real_name ());
-       as_review_add_metadata (review, "app_id", gs_app_get_id_no_prefix (app));
+       as_review_add_metadata (review, "app_id", gs_app_get_id (app));
        as_review_add_metadata (review, "user_skey",
                                gs_app_get_metadata_item (app, "ODRS::user_skey"));
 
diff --git a/src/plugins/gs-plugin-shell-extensions.c b/src/plugins/gs-plugin-shell-extensions.c
index e0c6557..9e2de2e 100644
--- a/src/plugins/gs-plugin-shell-extensions.c
+++ b/src/plugins/gs-plugin-shell-extensions.c
@@ -120,12 +120,13 @@ gs_plugin_shell_extensions_add_app (GsPlugin *plugin,
        gchar *str;
        GVariant *val;
        g_autofree gchar *id = NULL;
-       g_autofree gchar *id_prefix = NULL;
+       g_autofree gchar *unique_id = NULL;
        g_autoptr(AsIcon) ic = NULL;
 
        id = gs_plugin_shell_extensions_id_from_uuid (uuid);
-       id_prefix = g_strdup_printf ("user:%s", id);
-       gs_app_set_id (app, id_prefix);
+       unique_id = g_strdup_printf ("user/*/*/shell-extension/%s/*/*", id);
+       gs_app_set_id (app, id);
+       gs_app_set_unique_id (app, unique_id);
        gs_app_set_metadata (app, "GnomeSoftware::Creator",
                             gs_plugin_get_name (plugin));
        gs_app_set_management_plugin (app, gs_plugin_get_name (plugin));


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