mirror of
https://git.proxmox.com/git/fwupd
synced 2025-07-27 06:10:13 +00:00
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:
parent
3483410076
commit
e7e95452fd
226
src/fu-engine.c
226
src/fu-engine.c
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* depsolve into the correct order */
|
||||
if (!fu_plugin_list_depsolve (self->plugin_list, error))
|
||||
return FALSE;
|
||||
|
||||
/* check we're not stuck */
|
||||
if (dep_loop_check++ > 100) {
|
||||
g_set_error (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_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
295
src/fu-plugin-list.c
Normal 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
47
src/fu-plugin-list.h
Normal 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 */
|
||||
|
@ -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);
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user