[gnome-software/wip/hughsie/vnd.flatpak.ref: 5/12] Do not rely on the AppStream plugin to handle searching in flatpak



commit 17b6888ab9143f407e5cb51653adf030f059e95f
Author: Richard Hughes <richard hughsie com>
Date:   Tue Sep 13 16:52:39 2016 +0100

    Do not rely on the AppStream plugin to handle searching in flatpak
    
    This removes the flatpak symlink cache which turned out to be an inflexible
    workaround as we couldn't force a specific remote to be refreshed syncronously.
    
    This also adds support for vnd.flatpak.ref

 configure.ac                             |    2 +-
 src/gnome-software-local-file.desktop.in |    2 +-
 src/plugins/gs-flatpak-symlinks.c        |  189 ++--------------
 src/plugins/gs-flatpak-symlinks.h        |    2 +-
 src/plugins/gs-flatpak.c                 |  371 +++++++++++++++++++++++++++++-
 src/plugins/gs-flatpak.h                 |   20 ++
 src/plugins/gs-plugin-appstream.c        |   16 +--
 src/plugins/gs-plugin-flatpak-system.c   |   54 +++++
 src/plugins/gs-plugin-flatpak-user.c     |   54 +++++
 9 files changed, 513 insertions(+), 197 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 4e1a6e6..0a7c49f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -84,7 +84,7 @@ dnl ---------------------------------------------------------------------------
 dnl - Check library dependencies
 dnl ---------------------------------------------------------------------------
 PKG_CHECK_MODULES(GTK, gtk+-3.0 >= 3.20.0 gio-unix-2.0)
-PKG_CHECK_MODULES(APPSTREAM, appstream-glib >= 0.6.1)
+PKG_CHECK_MODULES(APPSTREAM, appstream-glib >= 0.6.4)
 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/gnome-software-local-file.desktop.in b/src/gnome-software-local-file.desktop.in
index 5ca6c72..d5d6d6f 100644
--- a/src/gnome-software-local-file.desktop.in
+++ b/src/gnome-software-local-file.desktop.in
@@ -8,4 +8,4 @@ Type=Application
 Icon=system-software-install
 StartupNotify=true
 NoDisplay=true
-MimeType=application/x-rpm;application/x-redhat-package-manager;application/x-deb;application/x-app-package;application/vnd.ms-cab-compressed;application/vnd.flatpak;application/vnd.flatpak.repo;x-scheme-handler/apt;application/vnd.snap;
+MimeType=application/x-rpm;application/x-redhat-package-manager;application/x-deb;application/x-app-package;application/vnd.ms-cab-compressed;application/vnd.flatpak;application/vnd.flatpak.repo;application/vnd.flatpak.ref;x-scheme-handler/apt;application/vnd.snap;
diff --git a/src/plugins/gs-flatpak-symlinks.c b/src/plugins/gs-flatpak-symlinks.c
index cff6c5a..1212482 100644
--- a/src/plugins/gs-flatpak-symlinks.c
+++ b/src/plugins/gs-flatpak-symlinks.c
@@ -27,117 +27,11 @@
 #include "gs-flatpak-symlinks.h"
 
 static gboolean
-gs_flatpak_symlinks_remote_valid (FlatpakRemote *xremote)
-{
-       if (xremote == NULL)
-               return FALSE;
-       if (flatpak_remote_get_disabled (xremote))
-               return FALSE;
-       if (flatpak_remote_get_noenumerate (xremote))
-               return FALSE;
-       return TRUE;
-}
-
-/* encode the symlink name with ${scope}:${name}[.xml.gz] */
-static gboolean
-gs_flatpak_symlinks_check_exist (FlatpakRemote *xremote,
-                                const gchar *cache_dir,
-                                const gchar *prefix,
-                                const gchar *kind,
-                                GError **error)
-{
-       g_autofree gchar *appstream_dir_fn = NULL;
-       g_autofree gchar *flatpak_remote_fn = NULL;
-       g_autofree gchar *subdir = NULL;
-       g_autofree gchar *symlink_source = NULL;
-       g_autofree gchar *symlink_target = NULL;
-       g_autofree gchar *xml_dir = NULL;
-       g_autoptr(GFile) appstream_dir = NULL;
-
-       /* get the AppStream data location */
-       appstream_dir = flatpak_remote_get_appstream_dir (xremote, NULL);
-       if (appstream_dir == NULL) {
-               g_debug ("no appstream dir for %s, skipping",
-                        flatpak_remote_get_name (xremote));
-               return TRUE;
-       }
-
-       /* ensure all the remotes have an XML symlink */
-       appstream_dir_fn = g_file_get_path (appstream_dir);
-       subdir = g_build_filename (cache_dir, kind, NULL);
-       if (g_strcmp0 (kind, "xmls") == 0) {
-               flatpak_remote_fn = g_strdup_printf ("%s:%s.xml.gz",
-                                                    prefix,
-                                                    flatpak_remote_get_name (xremote));
-               symlink_target = g_build_filename (appstream_dir_fn,
-                                                  "appstream.xml.gz",
-                                                  NULL);
-       } else {
-               flatpak_remote_fn = g_strdup_printf ("%s:%s",
-                                                    prefix,
-                                                    flatpak_remote_get_name (xremote));
-               symlink_target = g_build_filename (appstream_dir_fn,
-                                                  "icons",
-                                                  NULL);
-       }
-       symlink_source = g_build_filename (subdir,
-                                          flatpak_remote_fn,
-                                          NULL);
-       if (!gs_mkdir_parent (symlink_source, error))
-               return FALSE;
-
-       /* check XML symbolic link is correct */
-       if (g_file_test (symlink_source, G_FILE_TEST_IS_SYMLINK)) {
-               g_autofree gchar *symlink_target_actual = NULL;
-
-               /* target does not exist */
-               symlink_target_actual = g_file_read_link (symlink_source, NULL);
-               if (!g_file_test (symlink_target_actual, G_FILE_TEST_EXISTS)) {
-                       g_debug ("symlink %s is dangling (no %s), deleting",
-                                 symlink_source, symlink_target_actual);
-                       return gs_utils_unlink (symlink_source, error);
-               }
-
-               /* same */
-               if (g_strcmp0 (symlink_target_actual, symlink_target) == 0) {
-                       g_debug ("symlink %s already points to %s",
-                                symlink_source, symlink_target);
-                       return TRUE;
-               }
-               g_warning ("symlink incorrect expected %s target to "
-                          "be %s, got %s, deleting",
-                          symlink_source,
-                          symlink_target,
-                          symlink_target_actual);
-               if (!gs_utils_unlink (symlink_source, error))
-                       return FALSE;
-       }
-
-       /* create it if required, but only if the destination exists */
-       if (!g_file_test (symlink_source, G_FILE_TEST_EXISTS)) {
-               if (g_file_test (symlink_target, G_FILE_TEST_EXISTS)) {
-                       g_debug ("creating missing symbolic link from %s to %s",
-                                symlink_source, symlink_target);
-                       if (!gs_utils_symlink (symlink_target, symlink_source, error))
-                               return FALSE;
-               } else {
-                       g_debug ("not creating missing symbolic link from "
-                                "%s to %s as target does not yet exist",
-                                symlink_source, symlink_target);
-               }
-       }
-
-       return TRUE;
-}
-
-/* encode the symlink name with ${scope}:${name}, i.e. the origin */
-static gboolean
-gs_flatpak_symlinks_check_valid (FlatpakInstallation *installation,
-                                const gchar *cache_dir,
-                                const gchar *prefix,
-                                const gchar *kind,
-                                GCancellable *cancellable,
-                                GError **error)
+gs_flatpak_symlinks_cleanup_kind (const gchar *cache_dir,
+                                 const gchar *prefix,
+                                 const gchar *kind,
+                                 GCancellable *cancellable,
+                                 GError **error)
 {
        const gchar *tmp;
        g_autofree gchar *subdir = NULL;
@@ -147,8 +41,10 @@ gs_flatpak_symlinks_check_valid (FlatpakInstallation *installation,
        if (!g_file_test (subdir, G_FILE_TEST_EXISTS))
                return TRUE;
        dir = g_dir_open (subdir, 0, error);
-       if (dir == NULL)
+       if (dir == NULL) {
+               gs_utils_error_convert_gio (error);
                return FALSE;
+       }
        while ((tmp = g_dir_read_name (dir)) != NULL) {
                gchar *str;
                g_autofree gchar *fn = NULL;
@@ -164,21 +60,7 @@ gs_flatpak_symlinks_check_valid (FlatpakInstallation *installation,
                fn = g_build_filename (subdir, tmp, NULL);
                if (!g_file_test (fn, G_FILE_TEST_IS_SYMLINK))
                        continue;
-
-               /* can we find a valid remote for this file */
-               origin = g_strdup (tmp + strlen (prefix_colon));
-               str = g_strrstr (origin, ".xml.gz");
-               if (str != NULL)
-                       *str = '\0';
-               xremote = flatpak_installation_get_remote_by_name (installation,
-                                                                  origin,
-                                                                  cancellable,
-                                                                  NULL);
-               if (gs_flatpak_symlinks_remote_valid (xremote)) {
-                       g_debug ("%s remote symlink is valid", origin);
-                       continue;
-               }
-               g_debug ("deleting %s symlink as no longer valid", fn);
+               g_debug ("deleting %s as symlinks no longer required", fn);
                if (!gs_utils_unlink (fn, error))
                        return FALSE;
        }
@@ -186,14 +68,12 @@ gs_flatpak_symlinks_check_valid (FlatpakInstallation *installation,
 }
 
 gboolean
-gs_flatpak_symlinks_rebuild (FlatpakInstallation *installation,
+gs_flatpak_symlinks_cleanup (FlatpakInstallation *installation,
                             GCancellable *cancellable,
                             GError **error)
 {
        const gchar *prefix = "flatpak";
-       guint i;
        g_autofree gchar *cache_dir = NULL;
-       g_autoptr(GPtrArray) xremotes = NULL;
 
        /* use the correct symlink target */
        cache_dir = g_build_filename (g_get_user_data_dir (),
@@ -202,47 +82,18 @@ gs_flatpak_symlinks_rebuild (FlatpakInstallation *installation,
        if (flatpak_installation_get_is_user (installation))
                prefix = "user-flatpak";
 
-       /* go through each remote checking the symlink is in place */
-       xremotes = flatpak_installation_list_remotes (installation,
-                                                     cancellable,
-                                                     error);
-       if (xremotes == NULL)
-               return FALSE;
-       for (i = 0; i < xremotes->len; i++) {
-               FlatpakRemote *xremote = g_ptr_array_index (xremotes, i);
-               if (!gs_flatpak_symlinks_remote_valid (xremote))
-                       continue;
-               g_debug ("found remote %s:%s",
-                        prefix,
-                        flatpak_remote_get_name (xremote));
-               if (!gs_flatpak_symlinks_check_exist (xremote,
-                                                     cache_dir,
-                                                     prefix,
-                                                     "icons",
-                                                     error))
-                       return FALSE;
-               if (!gs_flatpak_symlinks_check_exist (xremote,
-                                                     cache_dir,
-                                                     prefix,
-                                                     "xmls",
-                                                     error))
-                       return FALSE;
-       }
-
        /* go through each symlink and check the remote still valid */
-       if (!gs_flatpak_symlinks_check_valid (installation,
-                                             cache_dir,
-                                             prefix,
-                                             "icons",
-                                             cancellable,
-                                             error))
+       if (!gs_flatpak_symlinks_cleanup_kind (cache_dir,
+                                              prefix,
+                                              "icons",
+                                              cancellable,
+                                              error))
                return FALSE;
-       if (!gs_flatpak_symlinks_check_valid (installation,
-                                             cache_dir,
-                                             prefix,
-                                             "xmls",
-                                             cancellable,
-                                             error))
+       if (!gs_flatpak_symlinks_cleanup_kind (cache_dir,
+                                              prefix,
+                                              "xmls",
+                                              cancellable,
+                                              error))
                return FALSE;
 
        /* success */
diff --git a/src/plugins/gs-flatpak-symlinks.h b/src/plugins/gs-flatpak-symlinks.h
index aeda415..e8f9dc6 100644
--- a/src/plugins/gs-flatpak-symlinks.h
+++ b/src/plugins/gs-flatpak-symlinks.h
@@ -26,7 +26,7 @@
 
 G_BEGIN_DECLS
 
-gboolean        gs_flatpak_symlinks_rebuild    (FlatpakInstallation    *installation,
+gboolean        gs_flatpak_symlinks_cleanup    (FlatpakInstallation    *installation,
                                                 GCancellable           *cancellable,
                                                 GError                 **error);
 
diff --git a/src/plugins/gs-flatpak.c b/src/plugins/gs-flatpak.c
index a657117..0399dae 100644
--- a/src/plugins/gs-flatpak.c
+++ b/src/plugins/gs-flatpak.c
@@ -42,10 +42,18 @@ struct _GsFlatpak {
        GFileMonitor            *monitor;
        AsAppScope               scope;
        GsPlugin                *plugin;
+       AsStore                 *store;
 };
 
 G_DEFINE_TYPE (GsFlatpak, gs_flatpak, G_TYPE_OBJECT)
 
+/* we have to do this until we hard dep on 0.6.11 */
+#define _FLATPAK_CHECK_VERSION(major,minor,micro)    \
+    (FLATPAK_MAJOR_VERSION > (major) || \
+     (FLATPAK_MAJOR_VERSION == (major) && FLATPAK_MINOR_VERSION > (minor)) || \
+     (FLATPAK_MAJOR_VERSION == (major) && FLATPAK_MINOR_VERSION == (minor) && \
+      FLATPAK_MICRO_VERSION >= (micro)))
+
 static gboolean
 gs_flatpak_refresh_appstream (GsFlatpak *self, guint cache_age,
                              GsPluginRefreshFlags flags,
@@ -105,10 +113,110 @@ gs_plugin_flatpak_changed_cb (GFileMonitor *monitor,
                g_warning ("failed to get initial available data: %s",
                           error_md->message);
        }
+}
+
+static gboolean
+gs_flatpak_add_apps_from_xremote (GsFlatpak *self,
+                                 FlatpakRemote *xremote,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+       GPtrArray *apps;
+       guint i;
+       g_autofree gchar *appstream_dir_fn = NULL;
+       g_autofree gchar *appstream_fn = NULL;
+       g_autofree gchar *only_app_id = NULL;
+       g_autoptr(AsStore) store = NULL;
+       g_autoptr(GFile) appstream_dir = NULL;
+       g_autoptr(GFile) file = NULL;
+
+       /* get the AppStream data location */
+       appstream_dir = flatpak_remote_get_appstream_dir (xremote, NULL);
+       if (appstream_dir == NULL) {
+               g_debug ("no appstream dir for %s, skipping",
+                        flatpak_remote_get_name (xremote));
+               return TRUE;
+       }
+
+       /* load the file into a temp store */
+       appstream_dir_fn = g_file_get_path (appstream_dir);
+       appstream_fn = g_build_filename (appstream_dir_fn,
+                                        "appstream.xml.gz", NULL);
+       if (!g_file_test (appstream_fn, G_FILE_TEST_EXISTS)) {
+               g_debug ("no %s appstream metadata found: %s",
+                        flatpak_remote_get_name (xremote),
+                        appstream_fn);
+               return TRUE;
+       }
+       file = g_file_new_for_path (appstream_fn);
+       store = as_store_new ();
+       as_store_set_add_flags (store, AS_STORE_ADD_FLAG_USE_UNIQUE_ID);
+       if (!as_store_from_file (store, file, NULL, cancellable, error)) {
+               gs_utils_error_convert_appstream (error);
+               return FALSE;
+       }
+
+       /* only add the specific app for noenumerate=true */
+       if (flatpak_remote_get_noenumerate (xremote)) {
+               g_autofree gchar *tmp = NULL;
+               tmp = g_strdup (flatpak_remote_get_name (xremote));
+               g_strdelimit (tmp, "-", '\0');
+               only_app_id = g_strdup_printf ("%s.desktop", tmp);
+       }
 
-       /* ensure the AppStream symlink cache is up to date */
-       if (!gs_flatpak_symlinks_rebuild (self->installation, NULL, &error))
-               g_warning ("failed to check symlinks: %s", error->message);
+       /* get all the apps and fix them up */
+       apps = as_store_get_apps (store);
+       for (i = 0; i < apps->len; i++) {
+               AsApp *app = g_ptr_array_index (apps, i);
+
+               /* filter to app */
+               if (only_app_id != NULL &&
+                   g_strcmp0 (as_app_get_id (app), only_app_id) != 0) {
+                       as_app_set_kind (app, AS_APP_KIND_UNKNOWN);
+                       continue;
+               }
+
+               /* add */
+               as_app_set_scope (app, self->scope);
+               as_app_set_origin (app, flatpak_remote_get_name (xremote));
+               as_app_add_keyword (app, NULL, "flatpak");
+               g_debug ("adding %s", as_app_get_unique_id (app));
+       }
+
+       /* add them to the main store */
+       as_store_add_apps (self->store, apps);
+       return TRUE;
+}
+
+static gboolean
+gs_flatpak_rescan_appstream_store (GsFlatpak *self,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+       guint i;
+       g_autoptr(GPtrArray) xremotes = NULL;
+
+       /* remove all components */
+       as_store_remove_all (self->store);
+
+       /* go through each remote adding metadata */
+       xremotes = flatpak_installation_list_remotes (self->installation,
+                                                     cancellable,
+                                                     error);
+       if (xremotes == NULL) {
+               gs_plugin_flatpak_error_convert (error);
+               return FALSE;
+       }
+       for (i = 0; i < xremotes->len; i++) {
+               FlatpakRemote *xremote = g_ptr_array_index (xremotes, i);
+               if (flatpak_remote_get_disabled (xremote))
+                       continue;
+               g_debug ("found remote %s",
+                        flatpak_remote_get_name (xremote));
+               if (!gs_flatpak_add_apps_from_xremote (self, xremote, cancellable, error))
+                       return FALSE;
+       }
+       return TRUE;
 }
 
 gboolean
@@ -154,8 +262,8 @@ gs_flatpak_setup (GsFlatpak *self, GCancellable *cancellable, GError **error)
        g_signal_connect (self->monitor, "changed",
                          G_CALLBACK (gs_plugin_flatpak_changed_cb), self);
 
-       /* ensure the AppStream symlink cache is up to date */
-       if (!gs_flatpak_symlinks_rebuild (self->installation, cancellable, error))
+       /* ensure the legacy AppStream symlink cache is deleted */
+       if (!gs_flatpak_symlinks_cleanup (self->installation, cancellable, error))
                return FALSE;
 
        /* success */
@@ -251,11 +359,10 @@ gs_flatpak_refresh_appstream (GsFlatpak *self, guint cache_age,
                something_changed = TRUE;
        }
 
-       /* ensure the AppStream symlink cache is up to date */
-       if (something_changed) {
-               if (!gs_flatpak_symlinks_rebuild (self->installation,
-                                                 cancellable,
-                                                 error))
+       /* ensure the AppStream store is up to date */
+       if (something_changed ||
+           as_store_get_size (self->store) == 0) {
+               if (!gs_flatpak_rescan_appstream_store (self, cancellable, error))
                        return FALSE;
        }
 
@@ -627,6 +734,10 @@ gs_flatpak_app_install_source (GsFlatpak *self, GsApp *app,
                return FALSE;
        }
 
+       /* refresh the AppStream data manually */
+       if (!gs_flatpak_add_apps_from_xremote (self, xremote, cancellable, error))
+               return FALSE;
+
        /* success */
        gs_app_set_state (app, AS_APP_STATE_INSTALLED);
        return TRUE;
@@ -1403,6 +1514,21 @@ gs_plugin_refine_item_size (GsFlatpak *self,
        return TRUE;
 }
 
+static gboolean
+gs_flatpak_refine_appstream (GsFlatpak *self, GsApp *app, GError **error)
+{
+       AsApp *item;
+       const gchar *unique_id = gs_app_get_unique_id (app);
+       if (unique_id == NULL)
+               return TRUE;
+       item = as_store_get_app_by_unique_id (self->store,
+                                             unique_id,
+                                             AS_STORE_SEARCH_FLAG_USE_WILDCARDS);
+       if (item == NULL)
+               return TRUE;
+       return gs_appstream_refine_app (self->plugin, app, item, error);
+}
+
 gboolean
 gs_flatpak_refine_app (GsFlatpak *self,
                       GsApp *app,
@@ -1423,6 +1549,10 @@ gs_flatpak_refine_app (GsFlatpak *self,
                                  gs_app_get_id (app));
        g_assert (ptask != NULL);
 
+       /* always do AppStream properties */
+       if (!gs_flatpak_refine_appstream (self, app, error))
+               return FALSE;
+
        /* flatpak apps can always be removed */
        gs_app_remove_quirk (app, AS_APP_QUIRK_COMPULSORY);
 
@@ -1491,6 +1621,46 @@ gs_flatpak_refine_app (GsFlatpak *self,
 }
 
 gboolean
+gs_flatpak_refine_wildcard (GsFlatpak *self, GsApp *app,
+                           GsAppList *list, GsPluginRefineFlags flags,
+                           GCancellable *cancellable, GError **error)
+{
+       const gchar *id;
+       guint i;
+       g_autoptr(GPtrArray) items = NULL;
+
+       /* not valid */
+       id = gs_app_get_id (app);
+       if (id == NULL)
+               return TRUE;
+
+       /* find all apps when matching any prefixes */
+       items = as_store_get_apps_by_id (self->store, id);
+       for (i = 0; i < items->len; i++) {
+               AsApp *item = NULL;
+               g_autoptr(GsApp) new = NULL;
+
+               /* does the app have an installation method */
+               item = g_ptr_array_index (items, i);
+               if (as_app_get_bundle_default (item) == NULL) {
+                       g_debug ("not using %s for wildcard as no bundle",
+                                as_app_get_id (item));
+                       continue;
+               }
+
+               /* new app */
+               g_debug ("found %s for wildcard %s",
+                        as_app_get_unique_id (item), id);
+               new = gs_appstream_create_app (self->plugin, item);
+               gs_app_set_scope (new, self->scope);
+               if (!gs_flatpak_refine_app (self, new, flags, cancellable, error))
+                       return FALSE;
+               gs_app_list_add (list, new);
+       }
+       return TRUE;
+}
+
+gboolean
 gs_flatpak_launch (GsFlatpak *self,
                   GsApp *app,
                   GCancellable *cancellable,
@@ -2020,6 +2190,139 @@ gs_flatpak_file_to_app_repo (GsFlatpak *self,
        return TRUE;
 }
 
+static gboolean
+gs_flatpak_update_appstream_for_remote (GsFlatpak *self,
+                                       const gchar *remote_name,
+                                       GCancellable *cancellable,
+                                       GError **error)
+{
+       g_autoptr(AsProfileTask) ptask = NULL;
+
+       /* search categories for the search term */
+       ptask = as_profile_start (gs_plugin_get_profile (self->plugin),
+                                 "flatpak::update-appstream{%s}",
+                                 remote_name);
+       g_assert (ptask != NULL);
+
+       /* get the new appstream data */
+       if (!flatpak_installation_update_appstream_sync (self->installation,
+                                                        remote_name,
+                                                        NULL,
+                                                        NULL,
+                                                        cancellable,
+                                                        error)) {
+               gs_plugin_flatpak_error_convert (error);
+               return FALSE;
+       }
+       return TRUE;
+}
+
+static gboolean
+gs_flatpak_file_to_app_ref (GsFlatpak *self,
+                           GsAppList *list,
+                           GFile *file,
+                           GCancellable *cancellable,
+                           GError **error)
+{
+       const gchar *remote_name;
+       gsize len = 0;
+       g_autofree gchar *contents = NULL;
+       g_autofree gchar *unique_id = NULL;
+       g_autoptr(FlatpakRemoteRef) xref = NULL;
+       g_autoptr(GBytes) ref_file_data = NULL;
+       g_autoptr(GsApp) app = NULL;
+       g_autoptr(FlatpakRemote) xremote = NULL;
+       g_autofree gchar *origin_url = NULL;
+       g_autofree gchar *origin_title = NULL;
+
+       /* get file data */
+       if (!g_file_load_contents (file,
+                                  cancellable,
+                                  &contents,
+                                  &len,
+                                  NULL,
+                                  error)) {
+               gs_utils_error_convert_gio (error);
+               return FALSE;
+       }
+
+#if _FLATPAK_CHECK_VERSION(0,6,10)
+       /* install the remote, but not the app */
+       ref_file_data = g_bytes_new (contents, len);
+       xref = flatpak_installation_install_ref_file (self->installation,
+                                                     ref_file_data,
+                                                     cancellable,
+                                                     error);
+       if (xref == NULL) {
+               gs_plugin_flatpak_error_convert (error);
+               return FALSE;
+       }
+#else
+       g_set_error_literal (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_NOT_SUPPORTED,
+                            "not new enough libflatpak to support flatpakref");
+       return FALSE;
+#endif
+
+       /* create a virtual 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, unique_id, app);
+       }
+
+       /* load metadata */
+       gs_app_set_kind (app, AS_APP_KIND_DESKTOP);
+       gs_app_set_state (app, AS_APP_STATE_AVAILABLE_LOCAL);
+       gs_flatpak_set_metadata (self, app, FLATPAK_REF (xref));
+
+       /* FIXME: perhaps use the data from the flatpakref file as a fallback? */
+
+       /* set the origin data */
+       remote_name = flatpak_remote_ref_get_remote_name (xref);
+       g_debug ("auto-created remote name: %s", remote_name);
+       xremote = flatpak_installation_get_remote_by_name (self->installation,
+                                                          remote_name,
+                                                          cancellable,
+                                                          error);
+       if (xremote == NULL) {
+               gs_plugin_flatpak_error_convert (error);
+               return FALSE;
+       }
+       origin_title = flatpak_remote_get_title (xremote);
+       origin_url = flatpak_remote_get_url (xremote);
+       if (origin_url == NULL) {
+               g_set_error (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_INVALID_FORMAT,
+                            "no URL for remote %s",
+                            flatpak_remote_get_name (xremote));
+               return FALSE;
+       }
+       gs_app_set_origin (app, remote_name);
+       gs_app_set_origin_hostname (app, origin_url);
+       gs_app_set_origin_ui (app, origin_title);
+
+       /* get the new appstream data */
+       if (!gs_flatpak_update_appstream_for_remote (self, remote_name,
+                                                    cancellable, error)) {
+               gs_plugin_flatpak_error_convert (error);
+               return FALSE;
+       }
+
+       /* parse it */
+       if (!gs_flatpak_add_apps_from_xremote (self, xremote, cancellable, error))
+               return FALSE;
+
+       /* success */
+       gs_app_list_add (list, app);
+       return TRUE;
+}
+
 gboolean
 gs_flatpak_file_to_app (GsFlatpak *self,
                        GsAppList *list,
@@ -2034,6 +2337,9 @@ gs_flatpak_file_to_app (GsFlatpak *self,
        const gchar *mimetypes_repo[] = {
                "application/vnd.flatpak.repo",
                NULL };
+       const gchar *mimetypes_ref[] = {
+               "application/vnd.flatpak.ref",
+               NULL };
 
        /* does this match any of the mimetypes_bundle we support */
        content_type = gs_utils_get_content_type (file, cancellable, error);
@@ -2053,9 +2359,50 @@ gs_flatpak_file_to_app (GsFlatpak *self,
                                                    cancellable,
                                                    error);
        }
+       if (g_strv_contains (mimetypes_ref, content_type)) {
+               return gs_flatpak_file_to_app_ref (self,
+                                                  list,
+                                                  file,
+                                                  cancellable,
+                                                  error);
+       }
        return TRUE;
 }
 
+gboolean
+gs_flatpak_search (GsFlatpak *self,
+                  gchar **values,
+                  GsAppList *list,
+                  GCancellable *cancellable,
+                  GError **error)
+{
+       return gs_appstream_store_search (self->plugin, self->store,
+                                         values, list,
+                                         cancellable, error);
+}
+
+gboolean
+gs_flatpak_add_category_apps (GsFlatpak *self,
+                             GsCategory *category,
+                             GsAppList *list,
+                             GCancellable *cancellable,
+                             GError **error)
+{
+       return gs_appstream_store_add_category_apps (self->plugin, self->store,
+                                                    category, list,
+                                                    cancellable, error);
+}
+
+gboolean
+gs_flatpak_add_categories (GsFlatpak *self,
+                          GPtrArray *list,
+                          GCancellable *cancellable,
+                          GError **error)
+{
+       return gs_appstream_store_add_categories (self->plugin, self->store,
+                                                 list, cancellable, error);
+}
+
 static void
 gs_flatpak_finalize (GObject *object)
 {
@@ -2064,6 +2411,7 @@ gs_flatpak_finalize (GObject *object)
        self = GS_FLATPAK (object);
 
        g_object_unref (self->plugin);
+       g_object_unref (self->store);
        g_hash_table_unref (self->broken_remotes);
 
        G_OBJECT_CLASS (gs_flatpak_parent_class)->finalize (object);
@@ -2081,6 +2429,9 @@ gs_flatpak_init (GsFlatpak *self)
 {
        self->broken_remotes = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                      g_free, NULL);
+       self->store = as_store_new ();
+       as_store_set_add_flags (self->store, AS_STORE_ADD_FLAG_USE_UNIQUE_ID);
+       as_store_set_watch_flags (self->store, AS_STORE_WATCH_FLAG_REMOVED);
 }
 
 GsFlatpak *
diff --git a/src/plugins/gs-flatpak.h b/src/plugins/gs-flatpak.h
index 980270b..d7c4865 100644
--- a/src/plugins/gs-flatpak.h
+++ b/src/plugins/gs-flatpak.h
@@ -69,6 +69,12 @@ gboolean     gs_flatpak_refine_app           (GsFlatpak              *self,
                                                 GsPluginRefineFlags    flags,
                                                 GCancellable           *cancellable,
                                                 GError                 **error);
+gboolean       gs_flatpak_refine_wildcard      (GsFlatpak              *self,
+                                                GsApp                  *app,
+                                                GsAppList              *list,
+                                                GsPluginRefineFlags     flags,
+                                                GCancellable           *cancellable,
+                                                GError                 **error);
 gboolean       gs_flatpak_launch               (GsFlatpak              *self,
                                                 GsApp                  *app,
                                                 GCancellable           *cancellable,
@@ -90,6 +96,20 @@ gboolean     gs_flatpak_file_to_app          (GsFlatpak              *self,
                                                 GFile                  *file,
                                                 GCancellable           *cancellable,
                                                 GError                 **error);
+gboolean       gs_flatpak_search               (GsFlatpak              *self,
+                                                gchar                  **values,
+                                                GsAppList              *list,
+                                                GCancellable           *cancellable,
+                                                GError                 **error);
+gboolean       gs_flatpak_add_categories       (GsFlatpak              *self,
+                                                GPtrArray              *list,
+                                                GCancellable           *cancellable,
+                                                GError                 **error);
+gboolean       gs_flatpak_add_category_apps    (GsFlatpak              *self,
+                                                GsCategory             *category,
+                                                GsAppList              *list,
+                                                GCancellable           *cancellable,
+                                                GError                 **error);
 
 G_END_DECLS
 
diff --git a/src/plugins/gs-plugin-appstream.c b/src/plugins/gs-plugin-appstream.c
index 1a59dae..29f85e1 100644
--- a/src/plugins/gs-plugin-appstream.c
+++ b/src/plugins/gs-plugin-appstream.c
@@ -282,20 +282,6 @@ gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
                }
        }
 
-       /* add keyword for non-package sources */
-       for (i = 0; i < items->len; i++) {
-               AsBundle *bundle;
-               app = g_ptr_array_index (items, i);
-               bundle = as_app_get_bundle_default (app);
-               if (bundle == NULL)
-                       continue;
-               g_debug ("Adding keyword '%s' to %s",
-                        as_bundle_kind_to_string (as_bundle_get_kind (bundle)),
-                        as_app_get_unique_id (app));
-               as_app_add_keyword (app, NULL,
-                                   as_bundle_kind_to_string (as_bundle_get_kind (bundle)));
-       }
-
        /* fix up these */
        for (i = 0; i < items->len; i++) {
                app = g_ptr_array_index (items, i);
@@ -354,7 +340,7 @@ gs_plugin_refine_from_id (GsPlugin *plugin,
        if (item == NULL) {
                guint i;
                GPtrArray *apps;
-               g_debug ("no app with ID %s found in appstream", unique_id);
+               g_debug ("no app with ID %s found in system appstream", unique_id);
                apps = as_store_get_apps (priv->store);
                for (i = 0; i < apps->len; i++) {
                        item = g_ptr_array_index (apps, i);
diff --git a/src/plugins/gs-plugin-flatpak-system.c b/src/plugins/gs-plugin-flatpak-system.c
index 2f1ea84..240abeb 100644
--- a/src/plugins/gs-plugin-flatpak-system.c
+++ b/src/plugins/gs-plugin-flatpak-system.c
@@ -135,6 +135,19 @@ gs_plugin_refine_app (GsPlugin *plugin,
 }
 
 gboolean
+gs_plugin_refine_wildcard (GsPlugin *plugin,
+                          GsApp *app,
+                          GsAppList *list,
+                          GsPluginRefineFlags flags,
+                          GCancellable *cancellable,
+                          GError **error)
+{
+       GsPluginData *priv = gs_plugin_get_data (plugin);
+       return gs_flatpak_refine_wildcard (priv->flatpak, app, list, flags,
+                                          cancellable, error);
+}
+
+gboolean
 gs_plugin_launch (GsPlugin *plugin,
                  GsApp *app,
                  GCancellable *cancellable,
@@ -193,3 +206,44 @@ gs_plugin_file_to_app (GsPlugin *plugin,
        return gs_flatpak_file_to_app (priv->flatpak, list, file,
                                       cancellable, error);
 }
+
+gboolean
+gs_plugin_add_search (GsPlugin *plugin,
+                     gchar **values,
+                     GsAppList *list,
+                     GCancellable *cancellable,
+                     GError **error)
+{
+       GsPluginData *priv = gs_plugin_get_data (plugin);
+       return gs_flatpak_search (priv->flatpak,
+                                 values,
+                                 list,
+                                 cancellable,
+                                 error);
+}
+
+gboolean
+gs_plugin_add_categories (GsPlugin *plugin,
+                         GPtrArray *list,
+                         GCancellable *cancellable,
+                         GError **error)
+{
+       GsPluginData *priv = gs_plugin_get_data (plugin);
+       return gs_flatpak_add_categories (priv->flatpak, list,
+                                         cancellable, error);
+}
+
+gboolean
+gs_plugin_add_category_apps (GsPlugin *plugin,
+                            GsCategory *category,
+                            GsAppList *list,
+                            GCancellable *cancellable,
+                            GError **error)
+{
+       GsPluginData *priv = gs_plugin_get_data (plugin);
+       return gs_flatpak_add_category_apps (priv->flatpak,
+                                            category,
+                                            list,
+                                            cancellable,
+                                            error);
+}
diff --git a/src/plugins/gs-plugin-flatpak-user.c b/src/plugins/gs-plugin-flatpak-user.c
index 3ad59a6..9c3ff48 100644
--- a/src/plugins/gs-plugin-flatpak-user.c
+++ b/src/plugins/gs-plugin-flatpak-user.c
@@ -135,6 +135,19 @@ gs_plugin_refine_app (GsPlugin *plugin,
 }
 
 gboolean
+gs_plugin_refine_wildcard (GsPlugin *plugin,
+                          GsApp *app,
+                          GsAppList *list,
+                          GsPluginRefineFlags flags,
+                          GCancellable *cancellable,
+                          GError **error)
+{
+       GsPluginData *priv = gs_plugin_get_data (plugin);
+       return gs_flatpak_refine_wildcard (priv->flatpak, app, list, flags,
+                                          cancellable, error);
+}
+
+gboolean
 gs_plugin_launch (GsPlugin *plugin,
                  GsApp *app,
                  GCancellable *cancellable,
@@ -195,3 +208,44 @@ gs_plugin_file_to_app (GsPlugin *plugin,
        return gs_flatpak_file_to_app (priv->flatpak, list, file,
                                       cancellable, error);
 }
+
+gboolean
+gs_plugin_add_search (GsPlugin *plugin,
+                     gchar **values,
+                     GsAppList *list,
+                     GCancellable *cancellable,
+                     GError **error)
+{
+       GsPluginData *priv = gs_plugin_get_data (plugin);
+       return gs_flatpak_search (priv->flatpak,
+                                 values,
+                                 list,
+                                 cancellable,
+                                 error);
+}
+
+gboolean
+gs_plugin_add_categories (GsPlugin *plugin,
+                         GPtrArray *list,
+                         GCancellable *cancellable,
+                         GError **error)
+{
+       GsPluginData *priv = gs_plugin_get_data (plugin);
+       return gs_flatpak_add_categories (priv->flatpak, list,
+                                         cancellable, error);
+}
+
+gboolean
+gs_plugin_add_category_apps (GsPlugin *plugin,
+                            GsCategory *category,
+                            GsAppList *list,
+                            GCancellable *cancellable,
+                            GError **error)
+{
+       GsPluginData *priv = gs_plugin_get_data (plugin);
+       return gs_flatpak_add_category_apps (priv->flatpak,
+                                            category,
+                                            list,
+                                            cancellable,
+                                            error);
+}


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