[gnome-software/wip/hughsie/gs_plugin_add_alternates] Allow the front-end to get alternate versions of applications
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/wip/hughsie/gs_plugin_add_alternates] Allow the front-end to get alternate versions of applications
- Date: Wed, 26 Sep 2018 08:25:32 +0000 (UTC)
commit 9db1693b8d144621d335f858a3ec9bb07cbd817e
Author: Richard Hughes <richard hughsie com>
Date: Tue Sep 25 17:49:21 2018 +0100
Allow the front-end to get alternate versions of applications
The idea here is that the frontend can say 'get me all different variants of
'gimp.desktop' and flatpak will return 'org.gimp.GIMP:stable', snap will return
'gimp:candidate', and the package manager would return just 'gimp'.
lib/gs-cmd.c | 19 ++++++++++++++-
lib/gs-plugin-loader.c | 22 +++++++++++++++++
lib/gs-plugin-types.h | 2 ++
lib/gs-plugin-vfuncs.h | 21 +++++++++++++++++
lib/gs-plugin.c | 6 +++++
plugins/core/gs-appstream.c | 47 +++++++++++++++++++++++++++++++++++++
plugins/core/gs-appstream.h | 6 +++++
plugins/core/gs-plugin-appstream.c | 11 +++++++++
plugins/dummy/gs-plugin-dummy.c | 14 +++++++++++
plugins/dummy/gs-self-test.c | 33 ++++++++++++++++++++++++++
plugins/flatpak/gs-flatpak.c | 16 +++++++++++++
plugins/flatpak/gs-flatpak.h | 5 ++++
plugins/flatpak/gs-plugin-flatpak.c | 16 +++++++++++++
13 files changed, 217 insertions(+), 1 deletion(-)
---
diff --git a/lib/gs-cmd.c b/lib/gs-cmd.c
index 6a79d940..34cfc36d 100644
--- a/lib/gs-cmd.c
+++ b/lib/gs-cmd.c
@@ -434,6 +434,23 @@ main (int argc, char **argv)
break;
}
}
+ } else if (argc == 3 && g_strcmp0 (argv[1], "get-alternates") == 0) {
+ app = gs_app_new (argv[2]);
+ for (i = 0; i < repeat; i++) {
+ g_autoptr(GsPluginJob) plugin_job = NULL;
+ if (list != NULL)
+ g_object_unref (list);
+ plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_GET_ALTERNATES,
+ "app", app,
+ "refine-flags", self->refine_flags,
+ "max-results", self->max_results,
+ NULL);
+ list = gs_plugin_loader_job_process (self->plugin_loader, plugin_job, NULL, &error);
+ if (list == NULL) {
+ ret = FALSE;
+ break;
+ }
+ }
} else if (argc == 4 && g_strcmp0 (argv[1], "action") == 0) {
GsPluginAction action = gs_plugin_action_from_string (argv[2]);
if (action == GS_PLUGIN_ACTION_UNKNOWN) {
@@ -674,7 +691,7 @@ main (int argc, char **argv)
GS_PLUGIN_ERROR_FAILED,
"Did not recognise option, use 'installed', "
"'updates', 'popular', 'get-categories', "
- "'get-category-apps', 'filename-to-app', "
+ "'get-category-apps', 'get-alternates', 'filename-to-app', "
"'action install', 'action remove', "
"'sources', 'refresh', 'launch' or 'search'");
}
diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c
index 6a6d5c81..996467c0 100644
--- a/lib/gs-plugin-loader.c
+++ b/lib/gs-plugin-loader.c
@@ -109,6 +109,11 @@ typedef gboolean (*GsPluginSearchFunc) (GsPlugin *plugin,
GsAppList *list,
GCancellable *cancellable,
GError **error);
+typedef gboolean (*GsPluginAlternatesFunc) (GsPlugin *plugin,
+ GsApp *app,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error);
typedef gboolean (*GsPluginCategoryFunc) (GsPlugin *plugin,
GsCategory *category,
GsAppList *list,
@@ -688,6 +693,13 @@ gs_plugin_loader_call_vfunc (GsPluginLoaderHelper *helper,
cancellable, &error_local);
}
break;
+ case GS_PLUGIN_ACTION_GET_ALTERNATES:
+ {
+ GsPluginAlternatesFunc plugin_func = func;
+ ret = plugin_func (plugin, app, list,
+ cancellable, &error_local);
+ }
+ break;
case GS_PLUGIN_ACTION_GET_CATEGORIES:
{
GsPluginCategoriesFunc plugin_func = func;
@@ -3304,6 +3316,7 @@ gs_plugin_loader_process_thread_cb (GTask *task,
case GS_PLUGIN_ACTION_SEARCH:
case GS_PLUGIN_ACTION_SEARCH_FILES:
case GS_PLUGIN_ACTION_SEARCH_PROVIDES:
+ case GS_PLUGIN_ACTION_GET_ALTERNATES:
gs_plugin_loader_convert_unavailable (list, gs_plugin_job_get_search (helper->plugin_job));
break;
default:
@@ -3353,6 +3366,7 @@ gs_plugin_loader_process_thread_cb (GTask *task,
case GS_PLUGIN_ACTION_SEARCH:
case GS_PLUGIN_ACTION_SEARCH_FILES:
case GS_PLUGIN_ACTION_SEARCH_PROVIDES:
+ case GS_PLUGIN_ACTION_GET_ALTERNATES:
gs_app_list_filter (list, gs_plugin_loader_app_is_valid, helper);
gs_app_list_filter (list, gs_plugin_loader_filter_qt_for_gtk, NULL);
gs_app_list_filter (list, gs_plugin_loader_get_app_is_compatible, plugin_loader);
@@ -3595,6 +3609,13 @@ gs_plugin_loader_job_process_async (GsPluginLoader *plugin_loader,
GS_PLUGIN_REFINE_FLAGS_REQUIRE_SETUP_ACTION);
}
+ /* always add the original app to the list so it can be sorted */
+ if (action == GS_PLUGIN_ACTION_GET_ALTERNATES) {
+ GsApp *app = gs_plugin_job_get_app (plugin_job);
+ GsAppList *list = gs_plugin_job_get_list (plugin_job);
+ gs_app_list_add (list, app);
+ }
+
/* check required args */
task = g_task_new (plugin_loader, cancellable_job, callback, user_data);
switch (action) {
@@ -3685,6 +3706,7 @@ gs_plugin_loader_job_process_async (GsPluginLoader *plugin_loader,
/* set up a hang handler */
switch (action) {
+ case GS_PLUGIN_ACTION_GET_ALTERNATES:
case GS_PLUGIN_ACTION_GET_CATEGORY_APPS:
case GS_PLUGIN_ACTION_GET_FEATURED:
case GS_PLUGIN_ACTION_GET_INSTALLED:
diff --git a/lib/gs-plugin-types.h b/lib/gs-plugin-types.h
index 14dfdffc..1576d34a 100644
--- a/lib/gs-plugin-types.h
+++ b/lib/gs-plugin-types.h
@@ -251,6 +251,7 @@ typedef enum {
* @GS_PLUGIN_ACTION_DESTROY: Destroy the plugin
* @GS_PLUGIN_ACTION_PURCHASE: Purchase an app
* @GS_PLUGIN_ACTION_DOWNLOAD: Download an application
+ * @GS_PLUGIN_ACTION_GET_ALTERNATES: Get the alternates for a specific application
*
* The plugin action.
**/
@@ -299,6 +300,7 @@ typedef enum {
GS_PLUGIN_ACTION_DESTROY,
GS_PLUGIN_ACTION_PURCHASE,
GS_PLUGIN_ACTION_DOWNLOAD,
+ GS_PLUGIN_ACTION_GET_ALTERNATES,
/*< private >*/
GS_PLUGIN_ACTION_LAST
} GsPluginAction;
diff --git a/lib/gs-plugin-vfuncs.h b/lib/gs-plugin-vfuncs.h
index fcf53a98..52995c4d 100644
--- a/lib/gs-plugin-vfuncs.h
+++ b/lib/gs-plugin-vfuncs.h
@@ -146,6 +146,27 @@ gboolean gs_plugin_add_search_what_provides (GsPlugin *plugin,
GCancellable *cancellable,
GError **error);
+/**
+ * gs_plugin_add_alternates
+ * @plugin: a #GsPlugin
+ * @app: a #GsApp
+ * @list: a #GsAppList
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: a #GError, or %NULL
+ *
+ * Called when trying to find alternates to a specific app, for instance
+ * finding a flatpak version of an existing distro packaged application.
+ *
+ * Plugins are expected to add new apps using gs_app_list_add().
+ *
+ * Returns: %TRUE for success or if not relevant
+ **/
+gboolean gs_plugin_add_alternates (GsPlugin *plugin,
+ GsApp *app,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error);
+
/**
* gs_plugin_setup:
* @plugin: a #GsPlugin
diff --git a/lib/gs-plugin.c b/lib/gs-plugin.c
index ad8d66e7..8543aade 100644
--- a/lib/gs-plugin.c
+++ b/lib/gs-plugin.c
@@ -1800,6 +1800,8 @@ gs_plugin_action_to_function_name (GsPluginAction action)
return "gs_plugin_destroy";
if (action == GS_PLUGIN_ACTION_PURCHASE)
return "gs_plugin_app_purchase";
+ if (action == GS_PLUGIN_ACTION_GET_ALTERNATES)
+ return "gs_plugin_add_alternates";
return NULL;
}
@@ -1902,6 +1904,8 @@ gs_plugin_action_to_string (GsPluginAction action)
return "destroy";
if (action == GS_PLUGIN_ACTION_PURCHASE)
return "purchase";
+ if (action == GS_PLUGIN_ACTION_GET_ALTERNATES)
+ return "get-alternates";
return NULL;
}
@@ -2004,6 +2008,8 @@ gs_plugin_action_from_string (const gchar *action)
return GS_PLUGIN_ACTION_DESTROY;
if (g_strcmp0 (action, "purchase") == 0)
return GS_PLUGIN_ACTION_PURCHASE;
+ if (g_strcmp0 (action, "get-alternates") == 0)
+ return GS_PLUGIN_ACTION_GET_ALTERNATES;
return GS_PLUGIN_ACTION_UNKNOWN;
}
diff --git a/plugins/core/gs-appstream.c b/plugins/core/gs-appstream.c
index c7d10bdb..8ae3e4bd 100644
--- a/plugins/core/gs-appstream.c
+++ b/plugins/core/gs-appstream.c
@@ -1096,6 +1096,53 @@ gs_appstream_add_recent (GsPlugin *plugin,
return TRUE;
}
+gboolean
+gs_appstream_add_alternates (GsPlugin *plugin,
+ AsStore *store,
+ GsApp *app,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GPtrArray *apps = as_store_get_apps (store);
+ g_autoptr(AsProfileTask) ptask = NULL;
+
+ /* find out how many packages are in each category */
+ ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
+ "appstream::add-alternatives");
+ g_assert (ptask != NULL);
+
+ /* find apps that provide the new name */
+ for (guint i = 0; i < apps->len; i++) {
+ AsApp *item = g_ptr_array_index (apps, i);
+ GPtrArray *provides = as_app_get_provides (item);
+ if (g_strcmp0 (as_app_get_id (item), gs_app_get_id (app)) == 0) {
+ for (guint j = 0; j < provides->len; j++) {
+ AsProvide *tmp = g_ptr_array_index (provides, j);
+ if (as_provide_get_kind (tmp) == AS_PROVIDE_KIND_ID) {
+ g_autoptr(GsApp) app2 = NULL;
+ app2 = gs_app_new (as_app_get_id (item));
+ gs_app_add_quirk (app2, AS_APP_QUIRK_MATCH_ANY_PREFIX);
+ gs_app_list_add (list, app2);
+ }
+ }
+ } else if (as_app_get_id (item) != NULL) {
+ for (guint j = 0; j < provides->len; j++) {
+ AsProvide *tmp = g_ptr_array_index (provides, j);
+ if (as_provide_get_kind (tmp) == AS_PROVIDE_KIND_ID &&
+ g_strcmp0 (as_provide_get_value (tmp), gs_app_get_id (app)) == 0) {
+ g_autoptr(GsApp) app2 = NULL;
+ app2 = gs_app_new (as_app_get_id (item));
+ gs_app_add_quirk (app2, AS_APP_QUIRK_MATCH_ANY_PREFIX);
+ gs_app_list_add (list, app2);
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
gboolean
gs_appstream_add_featured (GsPlugin *plugin,
AsStore *store,
diff --git a/plugins/core/gs-appstream.h b/plugins/core/gs-appstream.h
index 55a3d3f5..29ccc11a 100644
--- a/plugins/core/gs-appstream.h
+++ b/plugins/core/gs-appstream.h
@@ -60,6 +60,12 @@ gboolean gs_appstream_add_featured (GsPlugin *plugin,
GsAppList *list,
GCancellable *cancellable,
GError **error);
+gboolean gs_appstream_add_alternates (GsPlugin *plugin,
+ AsStore *store,
+ GsApp *app,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error);
gboolean gs_appstream_add_recent (GsPlugin *plugin,
AsStore *store,
GsAppList *list,
diff --git a/plugins/core/gs-plugin-appstream.c b/plugins/core/gs-plugin-appstream.c
index 22138a37..79c833a1 100644
--- a/plugins/core/gs-plugin-appstream.c
+++ b/plugins/core/gs-plugin-appstream.c
@@ -671,6 +671,17 @@ gs_plugin_add_recent (GsPlugin *plugin,
cancellable, error);
}
+gboolean
+gs_plugin_add_alternates (GsPlugin *plugin,
+ GsApp *app,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GsPluginData *priv = gs_plugin_get_data (plugin);
+ return gs_appstream_add_alternates (plugin, priv->store, app, list, cancellable, error);
+}
+
gboolean
gs_plugin_refresh (GsPlugin *plugin,
guint cache_age,
diff --git a/plugins/dummy/gs-plugin-dummy.c b/plugins/dummy/gs-plugin-dummy.c
index 6f739ff7..9db12879 100644
--- a/plugins/dummy/gs-plugin-dummy.c
+++ b/plugins/dummy/gs-plugin-dummy.c
@@ -280,6 +280,20 @@ gs_plugin_dummy_timeout_add (guint timeout_ms, GCancellable *cancellable)
g_main_loop_run (helper->loop);
}
+gboolean
+gs_plugin_add_alternates (GsPlugin *plugin,
+ GsApp *app,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ if (g_strcmp0 (gs_app_get_id (app), "zeus.desktop") == 0) {
+ g_autoptr(GsApp) app2 = gs_app_new ("chiron.desktop");
+ gs_app_list_add (list, app2);
+ }
+ return TRUE;
+}
+
gboolean
gs_plugin_add_search (GsPlugin *plugin,
gchar **values,
diff --git a/plugins/dummy/gs-self-test.c b/plugins/dummy/gs-self-test.c
index f7d2675f..513e43b8 100644
--- a/plugins/dummy/gs-self-test.c
+++ b/plugins/dummy/gs-self-test.c
@@ -439,6 +439,36 @@ gs_plugins_dummy_search_func (GsPluginLoader *plugin_loader)
g_assert_cmpint (gs_app_get_kind (app), ==, AS_APP_KIND_DESKTOP);
}
+static void
+gs_plugins_dummy_search_alternate_func (GsPluginLoader *plugin_loader)
+{
+ GsApp *app_tmp;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GsAppList) list = NULL;
+ g_autoptr(GsApp) app = NULL;
+ g_autoptr(GsPluginJob) plugin_job = NULL;
+
+ /* get search result based on addon keyword */
+ app = gs_app_new ("zeus.desktop");
+ plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_GET_ALTERNATES,
+ "app", app,
+ "refine-flags", GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
+ NULL);
+ list = gs_plugin_loader_job_process (plugin_loader, plugin_job, NULL, &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
+ g_assert (list != NULL);
+
+ /* make sure there is the original app, and the alternate */
+ g_assert_cmpint (gs_app_list_length (list), ==, 2);
+ app_tmp = gs_app_list_index (list, 0);
+ g_assert_cmpstr (gs_app_get_id (app_tmp), ==, "zeus.desktop");
+ g_assert_cmpint (gs_app_get_kind (app_tmp), ==, AS_APP_KIND_DESKTOP);
+ app_tmp = gs_app_list_index (list, 1);
+ g_assert_cmpstr (gs_app_get_id (app_tmp), ==, "chiron.desktop");
+ g_assert_cmpint (gs_app_get_kind (app_tmp), ==, AS_APP_KIND_DESKTOP);
+}
+
static void
gs_plugins_dummy_hang_func (GsPluginLoader *plugin_loader)
{
@@ -908,6 +938,9 @@ main (int argc, char **argv)
g_test_add_data_func ("/gnome-software/plugins/dummy/search",
plugin_loader,
(GTestDataFunc) gs_plugins_dummy_search_func);
+ g_test_add_data_func ("/gnome-software/plugins/dummy/search-alternate",
+ plugin_loader,
+ (GTestDataFunc) gs_plugins_dummy_search_alternate_func);
g_test_add_data_func ("/gnome-software/plugins/dummy/hang",
plugin_loader,
(GTestDataFunc) gs_plugins_dummy_hang_func);
diff --git a/plugins/flatpak/gs-flatpak.c b/plugins/flatpak/gs-flatpak.c
index 62694f01..b03d8ac8 100644
--- a/plugins/flatpak/gs-flatpak.c
+++ b/plugins/flatpak/gs-flatpak.c
@@ -2537,6 +2537,22 @@ gs_flatpak_add_featured (GsFlatpak *self,
return TRUE;
}
+gboolean
+gs_flatpak_add_alternates (GsFlatpak *self,
+ GsApp *app,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(GsAppList) list_tmp = gs_app_list_new ();
+ if (!gs_appstream_add_alternates (self->plugin, self->store, app, list_tmp,
+ cancellable, error))
+ return FALSE;
+ gs_flatpak_claim_app_list (self, list_tmp);
+ gs_app_list_add_list (list, list_tmp);
+ return TRUE;
+}
+
gboolean
gs_flatpak_add_recent (GsFlatpak *self,
GsAppList *list,
diff --git a/plugins/flatpak/gs-flatpak.h b/plugins/flatpak/gs-flatpak.h
index fde3396d..5bead17d 100644
--- a/plugins/flatpak/gs-flatpak.h
+++ b/plugins/flatpak/gs-flatpak.h
@@ -128,6 +128,11 @@ gboolean gs_flatpak_add_featured (GsFlatpak *self,
GsAppList *list,
GCancellable *cancellable,
GError **error);
+gboolean gs_flatpak_add_alternates (GsFlatpak *self,
+ GsApp *app,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error);
gboolean gs_flatpak_add_recent (GsFlatpak *self,
GsAppList *list,
guint64 age,
diff --git a/plugins/flatpak/gs-plugin-flatpak.c b/plugins/flatpak/gs-plugin-flatpak.c
index 4aedd182..af74f910 100644
--- a/plugins/flatpak/gs-plugin-flatpak.c
+++ b/plugins/flatpak/gs-plugin-flatpak.c
@@ -993,6 +993,22 @@ gs_plugin_add_popular (GsPlugin *plugin,
return TRUE;
}
+gboolean
+gs_plugin_add_alternates (GsPlugin *plugin,
+ GsApp *app,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GsPluginData *priv = gs_plugin_get_data (plugin);
+ for (guint i = 0; i < priv->flatpaks->len; i++) {
+ GsFlatpak *flatpak = g_ptr_array_index (priv->flatpaks, i);
+ if (!gs_flatpak_add_alternates (flatpak, app, list, cancellable, error))
+ return FALSE;
+ }
+ return TRUE;
+}
+
gboolean
gs_plugin_add_featured (GsPlugin *plugin,
GsAppList *list,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]