trivial: Move the plugin list to a new object

FuEngine is getting somewhat large and complicated, so split out as much plugin
list-specific functionality as possible
This commit is contained in:
Richard Hughes 2017-11-22 09:05:53 +00:00
parent 3483410076
commit e7e95452fd
5 changed files with 485 additions and 162 deletions

View File

@ -43,6 +43,7 @@
#include "fu-keyring.h"
#include "fu-pending.h"
#include "fu-plugin.h"
#include "fu-plugin-list.h"
#include "fu-plugin-private.h"
#include "fu-quirks.h"
#include "fu-smbios.h"
@ -70,8 +71,7 @@ struct _FuEngine
gboolean coldplug_running;
guint coldplug_id;
guint coldplug_delay;
GPtrArray *plugins; /* of FuPlugin */
GHashTable *plugins_hash; /* of name : FuPlugin */
FuPluginList *plugin_list;
GPtrArray *supported_guids;
FuSmbios *smbios;
FuHwids *hwids;
@ -242,21 +242,6 @@ fu_engine_get_item_by_guid (FuEngine *self, const gchar *guid)
return NULL;
}
static FuPlugin *
fu_engine_get_plugin_by_name (FuEngine *self, const gchar *name, GError **error)
{
for (guint i = 0; i < self->plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
if (g_strcmp0 (fu_plugin_get_name (plugin), name) == 0)
return plugin;
}
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_FOUND,
"no plugin %s found", name);
return NULL;
}
static void
fu_engine_set_release_from_appstream (FuEngine *self,
FwupdRelease *rel,
@ -467,7 +452,9 @@ fu_engine_unlock (FuEngine *self, const gchar *device_id, GError **error)
return FALSE;
/* get the plugin */
plugin = fu_engine_get_plugin_by_name (self, fu_device_get_plugin (item->device), error);
plugin = fu_plugin_list_find_by_name (self->plugin_list,
fu_device_get_plugin (item->device),
error);
if (plugin == NULL)
return FALSE;
@ -626,7 +613,9 @@ fu_engine_verify_update (FuEngine *self, const gchar *device_id, GError **error)
return FALSE;
/* get the plugin */
plugin = fu_engine_get_plugin_by_name (self, fu_device_get_plugin (item->device), error);
plugin = fu_plugin_list_find_by_name (self->plugin_list,
fu_device_get_plugin (item->device),
error);
if (plugin == NULL)
return FALSE;
@ -718,7 +707,9 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error)
return FALSE;
/* get the plugin */
plugin = fu_engine_get_plugin_by_name (self, fu_device_get_plugin (item->device), error);
plugin = fu_plugin_list_find_by_name (self->plugin_list,
fu_device_get_plugin (item->device),
error);
if (plugin == NULL)
return FALSE;
@ -1077,6 +1068,7 @@ fu_engine_install (FuEngine *self,
FuDeviceItem *item;
FuPlugin *plugin;
GBytes *blob_fw;
GPtrArray *plugins;
const gchar *tmp;
const gchar *version;
gboolean is_downgrade;
@ -1247,7 +1239,9 @@ fu_engine_install (FuEngine *self,
}
/* get the plugin */
plugin = fu_engine_get_plugin_by_name (self, fu_device_get_plugin (item->device), error);
plugin = fu_plugin_list_find_by_name (self->plugin_list,
fu_device_get_plugin (item->device),
error);
if (plugin == NULL)
return FALSE;
@ -1281,8 +1275,9 @@ fu_engine_install (FuEngine *self,
}
/* signal to all the plugins the update is about to happen */
for (guint j = 0; j < self->plugins->len; j++) {
FuPlugin *plugin_tmp = g_ptr_array_index (self->plugins, j);
plugins = fu_plugin_list_get_all (self->plugin_list);
for (guint j = 0; j < plugins->len; j++) {
FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j);
if (!fu_plugin_runner_update_prepare (plugin_tmp, item->device, error))
return FALSE;
}
@ -1309,8 +1304,8 @@ fu_engine_install (FuEngine *self,
g_warning ("failed to attach device after failed update: %s",
error_attach->message);
}
for (guint j = 0; j < self->plugins->len; j++) {
FuPlugin *plugin_tmp = g_ptr_array_index (self->plugins, j);
for (guint j = 0; j < plugins->len; j++) {
FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j);
g_autoptr(GError) error_local = NULL;
if (!fu_plugin_runner_update_cleanup (plugin_tmp,
item->device,
@ -1336,8 +1331,8 @@ fu_engine_install (FuEngine *self,
return FALSE;
/* signal to all the plugins the update has happened */
for (guint j = 0; j < self->plugins->len; j++) {
FuPlugin *plugin_tmp = g_ptr_array_index (self->plugins, j);
for (guint j = 0; j < plugins->len; j++) {
FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j);
g_autoptr(GError) error_local = NULL;
if (!fu_plugin_runner_update_cleanup (plugin_tmp, item->device, &error_local)) {
g_warning ("failed to update-cleanup: %s",
@ -1396,7 +1391,7 @@ fu_engine_get_item_by_id_fallback_pending (FuEngine *self, const gchar *id, GErr
item = fu_engine_get_item_by_id (self, fu_device_get_id (dev), NULL);
if (item == NULL) {
tmp = fu_device_get_plugin (dev);
plugin = fu_engine_get_plugin_by_name (self, tmp, error);
plugin = fu_plugin_list_find_by_name (self->plugin_list, tmp, error);
if (plugin == NULL)
return NULL;
item = fu_engine_add_item (self, dev, plugin);
@ -2446,7 +2441,9 @@ fu_engine_clear_results (FuEngine *self, const gchar *device_id, GError **error)
return FALSE;
/* get the plugin */
plugin = fu_engine_get_plugin_by_name (self, fu_device_get_plugin (item->device), error);
plugin = fu_plugin_list_find_by_name (self->plugin_list,
fu_device_get_plugin (item->device),
error);
if (plugin == NULL)
return FALSE;
@ -2480,7 +2477,9 @@ fu_engine_get_results (FuEngine *self, const gchar *device_id, GError **error)
return NULL;
/* get the plugin */
plugin = fu_engine_get_plugin_by_name (self, fu_device_get_plugin (item->device), error);
plugin = fu_plugin_list_find_by_name (self->plugin_list,
fu_device_get_plugin (item->device),
error);
if (plugin == NULL)
return FALSE;
@ -2494,14 +2493,16 @@ fu_engine_get_results (FuEngine *self, const gchar *device_id, GError **error)
static void
fu_engine_plugins_setup (FuEngine *self)
{
GPtrArray *plugins;
g_autoptr(AsProfileTask) ptask = NULL;
ptask = as_profile_start_literal (self->profile, "FuMain:setup");
g_assert (ptask != NULL);
for (guint i = 0; i < self->plugins->len; i++) {
plugins = fu_plugin_list_get_all (self->plugin_list);
for (guint i = 0; i < plugins->len; i++) {
g_autoptr(GError) error = NULL;
g_autoptr(AsProfileTask) ptask2 = NULL;
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
FuPlugin *plugin = g_ptr_array_index (plugins, i);
ptask2 = as_profile_start (self->profile,
"FuMain:setup{%s}",
fu_plugin_get_name (plugin));
@ -2516,6 +2517,7 @@ fu_engine_plugins_setup (FuEngine *self)
static void
fu_engine_plugins_coldplug (FuEngine *self)
{
GPtrArray *plugins;
g_autoptr(AsProfileTask) ptask = NULL;
g_autoptr(GString) str = g_string_new (NULL);
@ -2523,9 +2525,10 @@ fu_engine_plugins_coldplug (FuEngine *self)
self->coldplug_running = TRUE;
/* prepare */
for (guint i = 0; i < self->plugins->len; i++) {
plugins = fu_plugin_list_get_all (self->plugin_list);
for (guint i = 0; i < plugins->len; i++) {
g_autoptr(GError) error = NULL;
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
FuPlugin *plugin = g_ptr_array_index (plugins, i);
if (!fu_plugin_runner_coldplug_prepare (plugin, &error))
g_warning ("failed to prepare coldplug: %s", error->message);
}
@ -2539,10 +2542,10 @@ fu_engine_plugins_coldplug (FuEngine *self)
/* exec */
ptask = as_profile_start_literal (self->profile, "FuMain:coldplug");
g_assert (ptask != NULL);
for (guint i = 0; i < self->plugins->len; i++) {
for (guint i = 0; i < plugins->len; i++) {
g_autoptr(GError) error = NULL;
g_autoptr(AsProfileTask) ptask2 = NULL;
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
FuPlugin *plugin = g_ptr_array_index (plugins, i);
ptask2 = as_profile_start (self->profile,
"FuMain:coldplug{%s}",
fu_plugin_get_name (plugin));
@ -2554,16 +2557,16 @@ fu_engine_plugins_coldplug (FuEngine *self)
}
/* cleanup */
for (guint i = 0; i < self->plugins->len; i++) {
for (guint i = 0; i < plugins->len; i++) {
g_autoptr(GError) error = NULL;
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
FuPlugin *plugin = g_ptr_array_index (plugins, i);
if (!fu_plugin_runner_coldplug_cleanup (plugin, &error))
g_warning ("failed to cleanup coldplug: %s", error->message);
}
/* print what we do have */
for (guint i = 0; i < self->plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
for (guint i = 0; i < plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index (plugins, i);
if (!fu_plugin_get_enabled (plugin))
continue;
g_string_append_printf (str, "%s, ", fu_plugin_get_name (plugin));
@ -2580,13 +2583,15 @@ fu_engine_plugins_coldplug (FuEngine *self)
static void
fu_engine_plugin_device_register (FuEngine *self, FuDevice *device)
{
GPtrArray *plugins;
if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REGISTERED)) {
g_warning ("already registered %s, ignoring",
fu_device_get_id (device));
return;
}
for (guint i = 0; i < self->plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
plugins = fu_plugin_list_get_all (self->plugin_list);
for (guint i = 0; i < plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index (plugins, i);
fu_plugin_runner_device_register (plugin, device);
}
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_REGISTERED);
@ -2693,7 +2698,9 @@ fu_engine_plugin_device_removed_cb (FuPlugin *plugin,
}
/* get the plugin */
plugin_old = fu_engine_get_plugin_by_name (self, fu_device_get_plugin (item->device), &error);
plugin_old = fu_plugin_list_find_by_name (self->plugin_list,
fu_device_get_plugin (item->device),
&error);
if (plugin_old == NULL) {
g_debug ("%s", error->message);
return;
@ -2762,35 +2769,17 @@ fu_engine_plugin_set_coldplug_delay_cb (FuPlugin *plugin, guint duration, FuEngi
duration, self->coldplug_delay);
}
static gint
fu_engine_plugin_sort_cb (gconstpointer a, gconstpointer b)
{
FuPlugin **pa = (FuPlugin **) a;
FuPlugin **pb = (FuPlugin **) b;
if (fu_plugin_get_order (*pa) < fu_plugin_get_order (*pb))
return -1;
if (fu_plugin_get_order (*pa) > fu_plugin_get_order (*pb))
return 1;
return 0;
}
/* for the self tests to use */
void
fu_engine_add_plugin (FuEngine *self, FuPlugin *plugin)
{
g_ptr_array_add (self->plugins, g_object_ref (plugin));
g_hash_table_insert (self->plugins_hash,
g_strdup (fu_plugin_get_name (plugin)),
g_object_ref (plugin));
fu_plugin_list_add (self->plugin_list, plugin);
}
static gboolean
fu_engine_load_plugins (FuEngine *self, GError **error)
{
FuPlugin *dep;
GPtrArray *deps;
const gchar *fn;
gboolean changes;
guint dep_loop_check = 0;
g_autoptr(GDir) dir = NULL;
/* search */
@ -2861,101 +2850,14 @@ fu_engine_load_plugins (FuEngine *self, GError **error)
self);
/* add */
fu_engine_add_plugin (self, plugin);
fu_plugin_list_add (self->plugin_list, plugin);
}
/* order by deps */
do {
changes = FALSE;
for (guint i = 0; i < self->plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
deps = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_RUN_AFTER);
for (guint j = 0; j < deps->len && !changes; j++) {
const gchar *plugin_name = g_ptr_array_index (deps, j);
dep = fu_engine_get_plugin_by_name (self, plugin_name, NULL);
if (dep == NULL) {
g_debug ("cannot find plugin '%s' "
"requested by '%s'",
plugin_name,
fu_plugin_get_name (plugin));
continue;
}
if (!fu_plugin_get_enabled (dep))
continue;
if (fu_plugin_get_order (plugin) <= fu_plugin_get_order (dep)) {
g_debug ("%s [%u] to be ordered after %s [%u] "
"so promoting to [%u]",
fu_plugin_get_name (plugin),
fu_plugin_get_order (plugin),
fu_plugin_get_name (dep),
fu_plugin_get_order (dep),
fu_plugin_get_order (dep) + 1);
fu_plugin_set_order (plugin, fu_plugin_get_order (dep) + 1);
changes = TRUE;
}
}
}
for (guint i = 0; i < self->plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
deps = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_RUN_BEFORE);
for (guint j = 0; j < deps->len && !changes; j++) {
const gchar *plugin_name = g_ptr_array_index (deps, j);
dep = fu_engine_get_plugin_by_name (self, plugin_name, NULL);
if (dep == NULL) {
g_debug ("cannot find plugin '%s' "
"requested by '%s'",
plugin_name,
fu_plugin_get_name (plugin));
continue;
}
if (!fu_plugin_get_enabled (dep))
continue;
if (fu_plugin_get_order (plugin) >= fu_plugin_get_order (dep)) {
g_debug ("%s [%u] to be ordered before %s [%u] "
"so promoting to [%u]",
fu_plugin_get_name (plugin),
fu_plugin_get_order (plugin),
fu_plugin_get_name (dep),
fu_plugin_get_order (dep),
fu_plugin_get_order (dep) + 1);
fu_plugin_set_order (dep, fu_plugin_get_order (plugin) + 1);
changes = TRUE;
}
}
}
/* check we're not stuck */
if (dep_loop_check++ > 100) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"got stuck in dep loop");
/* depsolve into the correct order */
if (!fu_plugin_list_depsolve (self->plugin_list, error))
return FALSE;
}
} while (changes);
/* check for conflicts */
for (guint i = 0; i < self->plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
if (!fu_plugin_get_enabled (plugin))
continue;
deps = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_CONFLICTS);
for (guint j = 0; j < deps->len && !changes; j++) {
const gchar *plugin_name = g_ptr_array_index (deps, j);
dep = fu_engine_get_plugin_by_name (self, plugin_name, NULL);
if (dep == NULL)
continue;
if (!fu_plugin_get_enabled (dep))
continue;
g_debug ("disabling %s as conflicts with %s",
fu_plugin_get_name (dep),
fu_plugin_get_name (plugin));
fu_plugin_set_enabled (dep, FALSE);
}
}
/* sort by order */
g_ptr_array_sort (self->plugins, fu_engine_plugin_sort_cb);
/* success */
return TRUE;
}
@ -2971,11 +2873,14 @@ fu_engine_load_plugins (FuEngine *self, GError **error)
gboolean
fu_engine_check_plugins_pending (FuEngine *self, GError **error)
{
GPtrArray *plugins;
g_return_val_if_fail (FU_IS_ENGINE (self), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
for (guint i = 0; i < self->plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
plugins = fu_plugin_list_get_all (self->plugin_list);
for (guint i = 0; i < plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index (plugins, i);
if (fu_plugin_has_device_delay (plugin)) {
g_set_error (error,
FWUPD_ERROR,
@ -3124,12 +3029,10 @@ fu_engine_init (FuEngine *self)
self->hwids = fu_hwids_new ();
self->quirks = fu_quirks_new ();
self->pending = fu_pending_new ();
self->plugin_list = fu_plugin_list_new ();
self->profile = as_profile_new ();
self->store = as_store_new ();
self->supported_guids = g_ptr_array_new_with_free_func (g_free);
self->plugins = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
self->plugins_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) g_object_unref);
}
static void
@ -3142,17 +3045,16 @@ fu_engine_finalize (GObject *obj)
if (self->coldplug_id != 0)
g_source_remove (self->coldplug_id);
g_hash_table_unref (self->plugins_hash);
g_object_unref (self->config);
g_object_unref (self->smbios);
g_object_unref (self->quirks);
g_object_unref (self->hwids);
g_object_unref (self->pending);
g_object_unref (self->plugin_list);
g_object_unref (self->profile);
g_object_unref (self->store);
g_ptr_array_unref (self->devices);
g_ptr_array_unref (self->supported_guids);
g_ptr_array_unref (self->plugins);
G_OBJECT_CLASS (fu_engine_parent_class)->finalize (obj);
}

295
src/fu-plugin-list.c Normal file
View File

@ -0,0 +1,295 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <glib-object.h>
#include "fu-plugin-list.h"
#include "fu-plugin-private.h"
#include "fwupd-error.h"
/**
* SECTION:fu-plugin-list
* @short_description: a list of plugins
*
* This list of plugins provides a way to get the specific plugin quickly using
* a hash table and also any plugin-list specific functionality such as
* sorting by dependancy order.
*
* See also: #FuPlugin
*/
static void fu_plugin_list_finalize (GObject *obj);
struct _FuPluginList
{
GObject parent_instance;
GPtrArray *plugins; /* of FuPlugin */
GHashTable *plugins_hash; /* of name : FuPlugin */
};
G_DEFINE_TYPE (FuPluginList, fu_plugin_list, G_TYPE_OBJECT)
/**
* fu_plugin_list_get_all:
* @self: A #FuPluginList
*
* Gets all the plugins that have been added.
*
* Returns: (transfer none) (element-type FuPlugin): the plugins
*
* Since: 1.0.2
**/
GPtrArray *
fu_plugin_list_get_all (FuPluginList *self)
{
g_return_val_if_fail (FU_IS_PLUGIN_LIST (self), NULL);
return self->plugins;
}
/**
* fu_plugin_list_add:
* @self: A #FuPluginList
* @plugin: A #FuPlugin
*
* Adds a plugin to the list. The plugin name is used for a hash key and must
* be set before calling this function.
*
* Since: 1.0.2
**/
void
fu_plugin_list_add (FuPluginList *self, FuPlugin *plugin)
{
g_return_if_fail (FU_IS_PLUGIN_LIST (self));
g_return_if_fail (FU_IS_PLUGIN (plugin));
g_return_if_fail (fu_plugin_get_name (plugin) != NULL);
g_ptr_array_add (self->plugins, g_object_ref (plugin));
g_hash_table_insert (self->plugins_hash,
g_strdup (fu_plugin_get_name (plugin)),
g_object_ref (plugin));
}
/**
* fu_plugin_list_find_by_name:
* @self: A #FuPluginList
* @name: A #FuPlugin name, e.g. "dfu"
* @error: A #GError, or %NULL
*
* Finds a specific plugin using the plugin name.
*
* Returns: (transfer none): a plugin, or %NULL
*
* Since: 1.0.2
**/
FuPlugin *
fu_plugin_list_find_by_name (FuPluginList *self, const gchar *name, GError **error)
{
g_return_val_if_fail (FU_IS_PLUGIN_LIST (self), NULL);
g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
for (guint i = 0; i < self->plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
if (g_strcmp0 (fu_plugin_get_name (plugin), name) == 0)
return plugin;
}
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_FOUND,
"no plugin %s found", name);
return NULL;
}
static gint
fu_plugin_list_sort_cb (gconstpointer a, gconstpointer b)
{
FuPlugin **pa = (FuPlugin **) a;
FuPlugin **pb = (FuPlugin **) b;
if (fu_plugin_get_order (*pa) < fu_plugin_get_order (*pb))
return -1;
if (fu_plugin_get_order (*pa) > fu_plugin_get_order (*pb))
return 1;
return 0;
}
/**
* fu_plugin_list_depsolve:
* @self: A #FuPluginList
* @error: A #GError, or %NULL
*
* Depsolves the list of plugins into the correct order. Some plugin methods
* are called on all plugins and for some situations the order they are called
* may be important. Use fu_plugin_add_rule() to affect the depsolved order
* if required.
*
* Returns: %TRUE for success, or %FALSE if the set could not be depsolved
*
* Since: 1.0.2
**/
gboolean
fu_plugin_list_depsolve (FuPluginList *self, GError **error)
{
FuPlugin *dep;
GPtrArray *deps;
gboolean changes;
guint dep_loop_check = 0;
g_return_val_if_fail (FU_IS_PLUGIN_LIST (self), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
/* order by deps */
do {
changes = FALSE;
for (guint i = 0; i < self->plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
deps = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_RUN_AFTER);
for (guint j = 0; j < deps->len && !changes; j++) {
const gchar *plugin_name = g_ptr_array_index (deps, j);
dep = fu_plugin_list_find_by_name (self, plugin_name, NULL);
if (dep == NULL) {
g_debug ("cannot find plugin '%s' "
"requested by '%s'",
plugin_name,
fu_plugin_get_name (plugin));
continue;
}
if (!fu_plugin_get_enabled (dep))
continue;
if (fu_plugin_get_order (plugin) <= fu_plugin_get_order (dep)) {
g_debug ("%s [%u] to be ordered after %s [%u] "
"so promoting to [%u]",
fu_plugin_get_name (plugin),
fu_plugin_get_order (plugin),
fu_plugin_get_name (dep),
fu_plugin_get_order (dep),
fu_plugin_get_order (dep) + 1);
fu_plugin_set_order (plugin, fu_plugin_get_order (dep) + 1);
changes = TRUE;
}
}
}
for (guint i = 0; i < self->plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
deps = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_RUN_BEFORE);
for (guint j = 0; j < deps->len && !changes; j++) {
const gchar *plugin_name = g_ptr_array_index (deps, j);
dep = fu_plugin_list_find_by_name (self, plugin_name, NULL);
if (dep == NULL) {
g_debug ("cannot find plugin '%s' "
"requested by '%s'",
plugin_name,
fu_plugin_get_name (plugin));
continue;
}
if (!fu_plugin_get_enabled (dep))
continue;
if (fu_plugin_get_order (plugin) >= fu_plugin_get_order (dep)) {
g_debug ("%s [%u] to be ordered before %s [%u] "
"so promoting to [%u]",
fu_plugin_get_name (plugin),
fu_plugin_get_order (plugin),
fu_plugin_get_name (dep),
fu_plugin_get_order (dep),
fu_plugin_get_order (dep) + 1);
fu_plugin_set_order (dep, fu_plugin_get_order (plugin) + 1);
changes = TRUE;
}
}
}
/* check we're not stuck */
if (dep_loop_check++ > 100) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"got stuck in dep loop");
return FALSE;
}
} while (changes);
/* check for conflicts */
for (guint i = 0; i < self->plugins->len; i++) {
FuPlugin *plugin = g_ptr_array_index (self->plugins, i);
if (!fu_plugin_get_enabled (plugin))
continue;
deps = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_CONFLICTS);
for (guint j = 0; j < deps->len && !changes; j++) {
const gchar *plugin_name = g_ptr_array_index (deps, j);
dep = fu_plugin_list_find_by_name (self, plugin_name, NULL);
if (dep == NULL)
continue;
if (!fu_plugin_get_enabled (dep))
continue;
g_debug ("disabling %s as conflicts with %s",
fu_plugin_get_name (dep),
fu_plugin_get_name (plugin));
fu_plugin_set_enabled (dep, FALSE);
}
}
/* sort by order */
g_ptr_array_sort (self->plugins, fu_plugin_list_sort_cb);
return TRUE;
}
static void
fu_plugin_list_class_init (FuPluginListClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = fu_plugin_list_finalize;
}
static void
fu_plugin_list_init (FuPluginList *self)
{
self->plugins = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
self->plugins_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) g_object_unref);
}
static void
fu_plugin_list_finalize (GObject *obj)
{
FuPluginList *self = FU_PLUGIN_LIST (obj);
g_ptr_array_unref (self->plugins);
g_hash_table_unref (self->plugins_hash);
G_OBJECT_CLASS (fu_plugin_list_parent_class)->finalize (obj);
}
/**
* fu_plugin_list_new:
*
* Creates a new plugin list.
*
* Returns: (transfer full): a #FuPluginList
*
* Since: 1.0.2
**/
FuPluginList *
fu_plugin_list_new (void)
{
FuPluginList *self;
self = g_object_new (FU_TYPE_PLUGIN_LIST, NULL);
return FU_PLUGIN_LIST (self);
}

47
src/fu-plugin-list.h Normal file
View File

@ -0,0 +1,47 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __FU_PLUGIN_LIST_H
#define __FU_PLUGIN_LIST_H
G_BEGIN_DECLS
#include <glib-object.h>
#include "fu-plugin.h"
#define FU_TYPE_PLUGIN_LIST (fu_plugin_list_get_type ())
G_DECLARE_FINAL_TYPE (FuPluginList, fu_plugin_list, FU, PLUGIN_LIST, GObject)
FuPluginList *fu_plugin_list_new (void);
void fu_plugin_list_add (FuPluginList *self,
FuPlugin *plugin);
GPtrArray *fu_plugin_list_get_all (FuPluginList *self);
FuPlugin *fu_plugin_list_find_by_name (FuPluginList *self,
const gchar *name,
GError **error);
gboolean fu_plugin_list_depsolve (FuPluginList *self,
GError **error);
G_END_DECLS
#endif /* __FU_PLUGIN_LIST_H */

View File

@ -36,6 +36,7 @@
#include "fu-keyring.h"
#include "fu-pending.h"
#include "fu-plugin-private.h"
#include "fu-plugin-list.h"
#include "fu-progressbar.h"
#include "fu-hwids.h"
#include "fu-smbios.h"
@ -694,6 +695,80 @@ fu_plugin_module_func (void)
g_unlink (pending_cap);
}
static void
fu_plugin_list_func (void)
{
GPtrArray *plugins;
FuPlugin *plugin;
g_autoptr(FuPluginList) plugin_list = fu_plugin_list_new ();
g_autoptr(FuPlugin) plugin1 = fu_plugin_new ();
g_autoptr(FuPlugin) plugin2 = fu_plugin_new ();
g_autoptr(GError) error = NULL;
fu_plugin_set_name (plugin1, "plugin1");
fu_plugin_set_name (plugin2, "plugin2");
/* get all the plugins */
fu_plugin_list_add (plugin_list, plugin1);
fu_plugin_list_add (plugin_list, plugin2);
plugins = fu_plugin_list_get_all (plugin_list);
g_assert_cmpint (plugins->len, ==, 2);
/* get a single plugin */
plugin = fu_plugin_list_find_by_name (plugin_list, "plugin1", &error);
g_assert_no_error (error);
g_assert (plugin != NULL);
g_assert_cmpstr (fu_plugin_get_name (plugin), ==, "plugin1");
/* does not exist */
plugin = fu_plugin_list_find_by_name (plugin_list, "nope", &error);
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert (plugin == NULL);
}
static void
fu_plugin_list_depsolve_func (void)
{
GPtrArray *plugins;
FuPlugin *plugin;
gboolean ret;
g_autoptr(FuPluginList) plugin_list = fu_plugin_list_new ();
g_autoptr(FuPlugin) plugin1 = fu_plugin_new ();
g_autoptr(FuPlugin) plugin2 = fu_plugin_new ();
g_autoptr(GError) error = NULL;
fu_plugin_set_name (plugin1, "plugin1");
fu_plugin_set_name (plugin2, "plugin2");
/* add rule then depsolve */
fu_plugin_list_add (plugin_list, plugin1);
fu_plugin_list_add (plugin_list, plugin2);
fu_plugin_add_rule (plugin1, FU_PLUGIN_RULE_RUN_AFTER, "plugin2");
ret = fu_plugin_list_depsolve (plugin_list, &error);
g_assert_no_error (error);
g_assert (ret);
plugins = fu_plugin_list_get_all (plugin_list);
g_assert_cmpint (plugins->len, ==, 2);
plugin = g_ptr_array_index (plugins, 0);
g_assert_cmpstr (fu_plugin_get_name (plugin), ==, "plugin2");
g_assert_cmpint (fu_plugin_get_order (plugin), ==, 0);
g_assert (fu_plugin_get_enabled (plugin));
/* add another rule, then re-depsolve */
fu_plugin_add_rule (plugin1, FU_PLUGIN_RULE_CONFLICTS, "plugin2");
ret = fu_plugin_list_depsolve (plugin_list, &error);
g_assert_no_error (error);
g_assert (ret);
plugin = fu_plugin_list_find_by_name (plugin_list, "plugin1", &error);
g_assert_no_error (error);
g_assert (plugin != NULL);
g_assert (fu_plugin_get_enabled (plugin));
plugin = fu_plugin_list_find_by_name (plugin_list, "plugin2", &error);
g_assert_no_error (error);
g_assert (plugin != NULL);
g_assert (!fu_plugin_get_enabled (plugin));
}
static void
fu_pending_func (void)
{
@ -1088,6 +1163,8 @@ main (int argc, char **argv)
g_test_add_func ("/fwupd/smbios", fu_smbios_func);
g_test_add_func ("/fwupd/smbios3", fu_smbios3_func);
g_test_add_func ("/fwupd/pending", fu_pending_func);
g_test_add_func ("/fwupd/plugin-list", fu_plugin_list_func);
g_test_add_func ("/fwupd/plugin-list{depsolve}", fu_plugin_list_depsolve_func);
g_test_add_func ("/fwupd/plugin{delay}", fu_plugin_delay_func);
g_test_add_func ("/fwupd/plugin{module}", fu_plugin_module_func);
g_test_add_func ("/fwupd/plugin{quirks}", fu_plugin_quirks_func);

View File

@ -132,6 +132,7 @@ executable(
'fu-keyring.c',
'fu-pending.c',
'fu-plugin.c',
'fu-plugin-list.c',
'fu-quirks.c',
'fu-smbios.c',
'fu-usb-device.c',
@ -193,6 +194,7 @@ if get_option('enable-tests')
'fu-keyring.c',
'fu-keyring-result.c',
'fu-plugin.c',
'fu-plugin-list.c',
'fu-progressbar.c',
'fu-quirks.c',
'fu-smbios.c',