[gnome-software: 60/72] gs-plugin-loader: Split ACTION_REFINE out to GsPluginJobRefine




commit 55329cbb2aeab35d3e8f830c64b81f4e4b563c9c
Author: Philip Withnall <pwithnall endlessos org>
Date:   Wed Nov 24 14:11:18 2021 +0000

    gs-plugin-loader: Split ACTION_REFINE out to GsPluginJobRefine
    
    This splits out most of the implementation of `ACTION_REFINE` out to
    `GsPluginJobRefine`, and deletes the enum member.
    
    The code copied to the `run_async()` vfunc in `GsPluginJobRefine` is the
    code from `gs_plugin_loader_job_process_async()` and
    `gs_plugin_loader_process_thread_cb()`. It’s then been simplified to
    drop irrelevant calls — for example, all the
    filtering/sorting/truncation calls have been dropped, because it’s not
    possible to set filter-flags/sort-func/max-results on a
    `GsPluginJobRefine`.
    
    The `run_async()` code currently calls `gs_plugin_loader_run_refine()`,
    which is still in `gs-plugin-loader.c`. Hence, it currently won’t
    compile. The following few commits will rework that code. Reworking it
    in this commit would have been too confusing to review.
    
    Signed-off-by: Philip Withnall <pwithnall endlessos org>
    
    Helps: #1472

 lib/gs-plugin-job-refine.c | 284 +++++++++++++++++++++++++++++++++++++++++++--
 lib/gs-plugin-job-refine.h |   7 ++
 lib/gs-plugin-loader.c     |  21 +---
 lib/gs-plugin-types.h      |   2 -
 lib/gs-plugin.c            |   6 -
 5 files changed, 282 insertions(+), 38 deletions(-)
---
diff --git a/lib/gs-plugin-job-refine.c b/lib/gs-plugin-job-refine.c
index a12e27e8b..5433e083e 100644
--- a/lib/gs-plugin-job-refine.c
+++ b/lib/gs-plugin-job-refine.c
@@ -8,28 +8,266 @@
  * SPDX-License-Identifier: GPL-2.0+
  */
 
+/**
+ * SECTION:gs-plugin-job-refine
+ * @short_description: A plugin job to refine #GsApps and add more data
+ *
+ * #GsPluginJobRefine is a #GsPluginJob representing a refine operation.
+ *
+ * It’s used to query and add more data to a set of #GsApps. The data to be set
+ * is controlled by the #GsPluginRefineFlags, and is looked up for all the apps
+ * in a #GsAppList by the loaded plugins.
+ *
+ * This class is a wrapper around #GsPluginClass.refine_async, calling it for
+ * all loaded plugins, with some additional refinements done on the results.
+ *
+ * In particular, if an app in the #GsAppList has %GS_APP_QUIRK_IS_WILDCARD,
+ * refining it will replace it with zero or more non-wildcard #GsApps in the
+ * #GsAppList, all of which are candidates for what the wildcard represents.
+ * For example, they may have the same ID as the wildcard, or match its name.
+ * Refining is the canonical process for resolving wildcards.
+ *
+ * This means that the #GsAppList at the end of the refine operation may not
+ * match the #GsAppList passed in as input. Retrieve the final #GsAppList using
+ * gs_plugin_job_refine_get_result_list(). The #GsAppList which was passed
+ * into the job will not be modified.
+ *
+ * See also: #GsPluginClass.refine_async
+ * Since: 42
+ */
+
 #include "config.h"
 
 #include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+
+#include "gs-enums.h"
+#include "gs-plugin-job-private.h"
+#include "gs-plugin-job-refine.h"
+#include "gs-utils.h"
+
+struct _GsPluginJobRefine
+{
+       GsPluginJob parent;
+
+       GsAppList *app_list;  /* (owned) */
+       GsAppList *result_list;  /* (owned) (nullable) */
+       GsPluginRefineFlags flags;
+};
+
+G_DEFINE_TYPE (GsPluginJobRefine, gs_plugin_job_refine, GS_TYPE_PLUGIN_JOB)
+
+typedef enum {
+       PROP_APP_LIST = 1,
+       PROP_FLAGS,
+} GsPluginJobRefineProperty;
+
+static GParamSpec *props[PROP_FLAGS + 1] = { NULL, };
+
+static void
+gs_plugin_job_refine_dispose (GObject *object)
+{
+       GsPluginJobRefine *self = GS_PLUGIN_JOB_REFINE (object);
+
+       g_clear_object (&self->app_list);
+       g_clear_object (&self->result_list);
+
+       G_OBJECT_CLASS (gs_plugin_job_refine_parent_class)->dispose (object);
+}
+
+static void
+gs_plugin_job_refine_constructed (GObject *object)
+{
+       GsPluginJobRefine *self = GS_PLUGIN_JOB_REFINE (object);
+
+       G_OBJECT_CLASS (gs_plugin_job_refine_parent_class)->constructed (object);
+
+       /* FIXME: the plugins should specify this, rather than hardcoding */
+       if (self->flags & (GS_PLUGIN_REFINE_FLAGS_REQUIRE_ORIGIN_UI |
+                          GS_PLUGIN_REFINE_FLAGS_REQUIRE_ORIGIN_HOSTNAME))
+               self->flags |= GS_PLUGIN_REFINE_FLAGS_REQUIRE_ORIGIN;
+       if (self->flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SIZE)
+               self->flags |= GS_PLUGIN_REFINE_FLAGS_REQUIRE_RUNTIME;
+}
+
+static void
+gs_plugin_job_refine_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+       GsPluginJobRefine *self = GS_PLUGIN_JOB_REFINE (object);
+
+       switch ((GsPluginJobRefineProperty) prop_id) {
+       case PROP_APP_LIST:
+               g_value_set_object (value, self->app_list);
+               break;
+       case PROP_FLAGS:
+               g_value_set_flags (value, self->flags);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+gs_plugin_job_refine_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+       GsPluginJobRefine *self = GS_PLUGIN_JOB_REFINE (object);
+
+       switch ((GsPluginJobRefineProperty) prop_id) {
+       case PROP_APP_LIST:
+               /* Construct only. */
+               g_assert (self->app_list == NULL);
+               self->app_list = g_value_dup_object (value);
+               g_object_notify_by_pspec (object, props[PROP_APP_LIST]);
+               break;
+       case PROP_FLAGS:
+               /* Construct only. */
+               g_assert (self->flags == 0);
+               self->flags = g_value_get_flags (value);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static gboolean
+app_is_valid_filter (GsApp    *app,
+                     gpointer  user_data)
+{
+       GsPluginJobRefine *self = GS_PLUGIN_JOB_REFINE (user_data);
+
+       return gs_plugin_loader_app_is_valid (app, self->flags);
+}
+
+static void
+gs_plugin_job_refine_run_async (GsPluginJob         *job,
+                                GsPluginLoader      *plugin_loader,
+                                GCancellable        *cancellable,
+                                GAsyncReadyCallback  callback,
+                                gpointer             user_data)
+{
+       GsPluginJobRefine *self = GS_PLUGIN_JOB_REFINE (job);
+       g_autoptr(GTask) task = NULL;
+       g_autoptr(GError) local_error = NULL;
+       g_autofree gchar *job_debug = NULL;
+       g_autoptr(GsAppList) result_list = NULL;
+
+       /* check required args */
+       task = g_task_new (job, cancellable, callback, user_data);
+       g_task_set_name (task, G_STRFUNC);
+
+       /* Operate on a copy of the input list so we don’t modify it when
+        * resolving wildcards. */
+       result_list = gs_app_list_copy (self->app_list);
+
+       /* run refine() on each one if required */
+       if (self->flags != 0) {
+               if (!gs_plugin_loader_run_refine (helper, result_list, cancellable, &local_error)) {
+                       gs_utils_error_convert_gio (&local_error);
+                       g_task_return_error (task, g_steal_pointer (&local_error));
+                       return;
+               }
+       } else {
+               g_debug ("no refine flags set for transaction");
+       }
+
+       gs_app_list_filter (result_list, app_is_valid_filter, self);
+
+       /* show elapsed time */
+       job_debug = gs_plugin_job_to_string (job);
+       g_debug ("%s", job_debug);
+
+       /* success */
+       g_set_object (&self->result_list, result_list);
+       g_task_return_boolean (task, TRUE);
+}
+
+static gboolean
+gs_plugin_job_refine_run_finish (GsPluginJob   *self,
+                                 GAsyncResult  *result,
+                                 GError       **error)
+{
+       return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+gs_plugin_job_refine_class_init (GsPluginJobRefineClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GsPluginJobClass *job_class = GS_PLUGIN_JOB_CLASS (klass);
+
+       object_class->dispose = gs_plugin_job_refine_dispose;
+       object_class->constructed = gs_plugin_job_refine_constructed;
+       object_class->get_property = gs_plugin_job_refine_get_property;
+       object_class->set_property = gs_plugin_job_refine_set_property;
+
+       job_class->run_async = gs_plugin_job_refine_run_async;
+       job_class->run_finish = gs_plugin_job_refine_run_finish;
+
+       /**
+        * GsPluginJobRefine:app-list:
+        *
+        * List of #GsApps to refine.
+        *
+        * This will not change during the course of the operation.
+        *
+        * Since: 42
+        */
+       props[PROP_APP_LIST] =
+               g_param_spec_object ("app-list", "App List",
+                                    "List of GsApps to refine.",
+                                    GS_TYPE_APP_LIST,
+                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                                    G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+       /**
+        * GsPluginJobRefine:flags:
+        *
+        * Flags to control what to refine.
+        *
+        * Since: 42
+        */
+       props[PROP_FLAGS] =
+               g_param_spec_flags ("flags", "Flags",
+                                   "Flags to control what to refine.",
+                                    GS_TYPE_PLUGIN_REFINE_FLAGS, GS_PLUGIN_REFINE_FLAGS_NONE,
+                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                                    G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+       g_object_class_install_properties (object_class, G_N_ELEMENTS (props), props);
+}
+
+static void
+gs_plugin_job_refine_init (GsPluginJobRefine *self)
+{
+}
 
 /**
  * gs_plugin_job_refine_new:
  * @app_list: the list of #GsApps to refine
  * @flags: flags to affect what is refined
  *
- * Create a new #GsPluginJob for refining the given @app_list.
+ * Create a new #GsPluginJobRefine for refining the given @app_list.
  *
- * Returns: (transfer full): a new #GsPluginJob
+ * Returns: (transfer full): a new #GsPluginJobRefine
  * Since: 42
  */
 GsPluginJob *
 gs_plugin_job_refine_new (GsAppList           *app_list,
                           GsPluginRefineFlags  flags)
 {
-       return gs_plugin_job_newv (GS_PLUGIN_ACTION_REFINE,
-                                  "list", app_list,
-                                  "refine-flags", flags,
-                                  NULL);
+       return g_object_new (GS_TYPE_PLUGIN_JOB_REFINE,
+                            "app-list", app_list,
+                            "flags", flags,
+                            NULL);
 }
 
 /**
@@ -37,17 +275,39 @@ gs_plugin_job_refine_new (GsAppList           *app_list,
  * @app: the #GsApp to refine
  * @flags: flags to affect what is refined
  *
- * Create a new #GsPluginJob for refining the given @app.
+ * Create a new #GsPluginJobRefine for refining the given @app.
  *
- * Returns: (transfer full): a new #GsPluginJob
+ * Returns: (transfer full): a new #GsPluginJobRefine
  * Since: 42
  */
 GsPluginJob *
 gs_plugin_job_refine_new_for_app (GsApp               *app,
                                   GsPluginRefineFlags  flags)
 {
-       return gs_plugin_job_newv (GS_PLUGIN_ACTION_REFINE,
-                                  "app", app,
-                                  "refine-flags", flags,
-                                  NULL);
+       g_autoptr(GsAppList) list = gs_app_list_new ();
+       gs_app_list_add (list, app);
+
+       return gs_plugin_job_refine_new (list, flags);
+}
+
+/**
+ * gs_plugin_job_refine_get_result_list:
+ * @self: a #GsPluginJobRefine
+ *
+ * Get the full list of refined #GsApps. This includes apps created in place of
+ * wildcards, if wildcards were provided in the #GsAppList passed to
+ * gs_plugin_job_refine_new().
+ *
+ * If this is called before the job is complete, %NULL will be returned.
+ *
+ * Returns: (transfer none) (nullable): the job results, or %NULL on error
+ *   or if called before the job has completed
+ * Since: 42
+ */
+GsAppList *
+gs_plugin_job_refine_get_result_list (GsPluginJobRefine *self)
+{
+       g_return_val_if_fail (GS_IS_PLUGIN_JOB_REFINE (self), NULL);
+
+       return self->result_list;
 }
diff --git a/lib/gs-plugin-job-refine.h b/lib/gs-plugin-job-refine.h
index 8b1491b31..ed207bc6e 100644
--- a/lib/gs-plugin-job-refine.h
+++ b/lib/gs-plugin-job-refine.h
@@ -11,14 +11,21 @@
 #pragma once
 
 #include <glib.h>
+#include <glib-object.h>
 
 #include "gs-plugin-job.h"
 
 G_BEGIN_DECLS
 
+#define GS_TYPE_PLUGIN_JOB_REFINE (gs_plugin_job_refine_get_type ())
+
+G_DECLARE_FINAL_TYPE (GsPluginJobRefine, gs_plugin_job_refine, GS, PLUGIN_JOB_REFINE, GsPluginJob)
+
 GsPluginJob    *gs_plugin_job_refine_new_for_app       (GsApp               *app,
                                                         GsPluginRefineFlags  flags);
 GsPluginJob    *gs_plugin_job_refine_new               (GsAppList           *app_list,
                                                         GsPluginRefineFlags  flags);
 
+GsAppList      *gs_plugin_job_refine_get_result_list   (GsPluginJobRefine   *self);
+
 G_END_DECLS
diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c
index 9b80e560b..cc4a2697e 100644
--- a/lib/gs-plugin-loader.c
+++ b/lib/gs-plugin-loader.c
@@ -615,16 +615,6 @@ gs_plugin_loader_call_vfunc (GsPluginLoaderHelper *helper,
        if (gs_plugin_job_get_interactive (helper->plugin_job))
                gs_plugin_interactive_inc (plugin);
        switch (action) {
-       case GS_PLUGIN_ACTION_REFINE:
-               if (g_strcmp0 (helper->function_name, "gs_plugin_refine") == 0) {
-                       GsPluginRefineFunc plugin_func = func;
-                       ret = plugin_func (plugin, list, refine_flags, cancellable, &error_local);
-               } else {
-                       g_critical ("function_name %s invalid for %s",
-                                   helper->function_name,
-                                   gs_plugin_action_to_string (action));
-               }
-               break;
        case GS_PLUGIN_ACTION_UPDATE:
                if (g_strcmp0 (helper->function_name, "gs_plugin_update_app") == 0) {
                        GsPluginActionFunc plugin_func = func;
@@ -1147,7 +1137,7 @@ gs_plugin_loader_run_results (GsPluginLoaderHelper *helper,
 #endif
 
        /* Refining is done separately as it’s a special action */
-       g_assert (action != GS_PLUGIN_ACTION_REFINE);
+       g_assert (!GS_IS_PLUGIN_JOB_REFINE (helper->plugin_job));
 
        /* Download updated external appstream before anything else */
 #ifdef ENABLE_EXTERNAL_APPSTREAM
@@ -3430,7 +3420,7 @@ gs_plugin_loader_process_thread_cb (GTask *task,
                gs_plugin_loader_pending_apps_add (plugin_loader, helper);
 
        /* run each plugin */
-       if (action != GS_PLUGIN_ACTION_REFINE) {
+       if (!GS_IS_PLUGIN_JOB_REFINE (helper->plugin_job)) {
                if (!gs_plugin_loader_run_results (helper, cancellable, &error)) {
                        if (add_to_pending_array) {
                                gs_app_set_state_recover (gs_plugin_job_get_app (helper->plugin_job));
@@ -3518,10 +3508,8 @@ gs_plugin_loader_process_thread_cb (GTask *task,
                        return;
                }
                break;
-       case GS_PLUGIN_ACTION_REFINE:
-               break;
        default:
-               if (!helper->anything_ran) {
+               if (!helper->anything_ran && !GS_IS_PLUGIN_JOB_REFINE (helper->plugin_job)) {
                        g_debug ("no plugin could handle %s",
                                 gs_plugin_action_to_string (action));
                }
@@ -3696,9 +3684,6 @@ gs_plugin_loader_process_thread_cb (GTask *task,
                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);
                break;
-       case GS_PLUGIN_ACTION_REFINE:
-               gs_app_list_filter (list, gs_plugin_loader_app_is_valid_filter, helper);
-               break;
        case GS_PLUGIN_ACTION_GET_POPULAR:
                gs_app_list_filter (list, gs_plugin_loader_app_is_valid_filter, helper);
                gs_app_list_filter (list, gs_plugin_loader_filter_qt_for_gtk, NULL);
diff --git a/lib/gs-plugin-types.h b/lib/gs-plugin-types.h
index 4d3f58489..91548cd21 100644
--- a/lib/gs-plugin-types.h
+++ b/lib/gs-plugin-types.h
@@ -210,7 +210,6 @@ typedef enum {
  * @GS_PLUGIN_ACTION_SEARCH_PROVIDES:          Get the search results for a provide query
  * @GS_PLUGIN_ACTION_GET_CATEGORIES:           Get the list of categories
  * @GS_PLUGIN_ACTION_GET_CATEGORY_APPS:                Get the apps for a specific category
- * @GS_PLUGIN_ACTION_REFINE:                   Refine the application
  * @GS_PLUGIN_ACTION_REFRESH:                  Refresh all the sources
  * @GS_PLUGIN_ACTION_FILE_TO_APP:              Convert the file to an application
  * @GS_PLUGIN_ACTION_URL_TO_APP:               Convert the URI to an application
@@ -249,7 +248,6 @@ typedef enum {
        GS_PLUGIN_ACTION_SEARCH_PROVIDES,
        GS_PLUGIN_ACTION_GET_CATEGORIES,
        GS_PLUGIN_ACTION_GET_CATEGORY_APPS,
-       GS_PLUGIN_ACTION_REFINE,
        GS_PLUGIN_ACTION_REFRESH,
        GS_PLUGIN_ACTION_FILE_TO_APP,
        GS_PLUGIN_ACTION_URL_TO_APP,
diff --git a/lib/gs-plugin.c b/lib/gs-plugin.c
index 32284a270..ca4d5038b 100644
--- a/lib/gs-plugin.c
+++ b/lib/gs-plugin.c
@@ -1683,8 +1683,6 @@ gs_plugin_action_to_function_name (GsPluginAction action)
                return "gs_plugin_add_shortcut";
        if (action == GS_PLUGIN_ACTION_REMOVE_SHORTCUT)
                return "gs_plugin_remove_shortcut";
-       if (action == GS_PLUGIN_ACTION_REFINE)
-               return "gs_plugin_refine";
        if (action == GS_PLUGIN_ACTION_UPDATE)
                return "gs_plugin_update";
        if (action == GS_PLUGIN_ACTION_DOWNLOAD)
@@ -1791,8 +1789,6 @@ gs_plugin_action_to_string (GsPluginAction action)
                return "get-categories";
        if (action == GS_PLUGIN_ACTION_GET_CATEGORY_APPS)
                return "get-category-apps";
-       if (action == GS_PLUGIN_ACTION_REFINE)
-               return "refine";
        if (action == GS_PLUGIN_ACTION_REFRESH)
                return "refresh";
        if (action == GS_PLUGIN_ACTION_FILE_TO_APP)
@@ -1875,8 +1871,6 @@ gs_plugin_action_from_string (const gchar *action)
                return GS_PLUGIN_ACTION_GET_CATEGORIES;
        if (g_strcmp0 (action, "get-category-apps") == 0)
                return GS_PLUGIN_ACTION_GET_CATEGORY_APPS;
-       if (g_strcmp0 (action, "refine") == 0)
-               return GS_PLUGIN_ACTION_REFINE;
        if (g_strcmp0 (action, "refresh") == 0)
                return GS_PLUGIN_ACTION_REFRESH;
        if (g_strcmp0 (action, "file-to-app") == 0)


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