mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-14 06:52:20 +00:00
Allow plugins to depend on each other
The only things that plugins can declare is that they should be run before, after or never with regard to another plugin.
This commit is contained in:
parent
feb038099b
commit
08a37992f9
@ -30,6 +30,12 @@
|
||||
#include "fu-plugin.h"
|
||||
#include "fu-plugin-vfuncs.h"
|
||||
|
||||
void
|
||||
fu_plugin_init (FuPlugin *plugin)
|
||||
{
|
||||
fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "upower");
|
||||
}
|
||||
|
||||
static fwup_resource *
|
||||
fu_plugin_uefi_find (fwup_resource_iter *iter, const gchar *guid_str, GError **error)
|
||||
{
|
||||
|
108
src/fu-engine.c
108
src/fu-engine.c
@ -2661,16 +2661,23 @@ fu_engine_plugin_set_coldplug_delay_cb (FuPlugin *plugin, guint duration, FuEngi
|
||||
static gint
|
||||
fu_engine_plugin_sort_cb (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
FuPlugin *plugin1 = *((FuPlugin **) a);
|
||||
FuPlugin *plugin2 = *((FuPlugin **) b);
|
||||
return g_strcmp0 (fu_plugin_get_name (plugin1),
|
||||
fu_plugin_get_name (plugin2));
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
@ -2745,8 +2752,99 @@ fu_engine_load_plugins (FuEngine *self, GError **error)
|
||||
g_strdup (fu_plugin_get_name (plugin)),
|
||||
g_object_ref (plugin));
|
||||
}
|
||||
g_ptr_array_sort (self->plugins, fu_engine_plugin_sort_cb);
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
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");
|
||||
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);
|
||||
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);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,11 @@ void fu_plugin_set_supported (FuPlugin *plugin,
|
||||
GPtrArray *supported_guids);
|
||||
void fu_plugin_set_smbios (FuPlugin *plugin,
|
||||
FuSmbios *smbios);
|
||||
guint fu_plugin_get_order (FuPlugin *plugin);
|
||||
void fu_plugin_set_order (FuPlugin *plugin,
|
||||
guint order);
|
||||
GPtrArray *fu_plugin_get_rules (FuPlugin *plugin,
|
||||
FuPluginRule rule);
|
||||
gboolean fu_plugin_open (FuPlugin *plugin,
|
||||
const gchar *filename,
|
||||
GError **error);
|
||||
|
@ -43,6 +43,8 @@ typedef struct {
|
||||
GModule *module;
|
||||
GUsbContext *usb_ctx;
|
||||
gboolean enabled;
|
||||
guint order;
|
||||
GPtrArray *rules[FU_PLUGIN_RULE_LAST];
|
||||
gchar *name;
|
||||
FuHwids *hwids;
|
||||
GPtrArray *supported_guids;
|
||||
@ -1210,6 +1212,73 @@ fu_plugin_runner_get_results (FuPlugin *plugin, FuDevice *device, GError **error
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_plugin_get_order:
|
||||
* @plugin: a #FuPlugin
|
||||
*
|
||||
* Gets the plugin order, where higher numbers are run after lower
|
||||
* numbers.
|
||||
*
|
||||
* Returns: the integer value
|
||||
**/
|
||||
guint
|
||||
fu_plugin_get_order (FuPlugin *plugin)
|
||||
{
|
||||
FuPluginPrivate *priv = fu_plugin_get_instance_private (plugin);
|
||||
return priv->order;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_plugin_set_order:
|
||||
* @plugin: a #FuPlugin
|
||||
* @order: a integer value
|
||||
*
|
||||
* Sets the plugin order, where higher numbers are run after lower
|
||||
* numbers.
|
||||
**/
|
||||
void
|
||||
fu_plugin_set_order (FuPlugin *plugin, guint order)
|
||||
{
|
||||
FuPluginPrivate *priv = fu_plugin_get_instance_private (plugin);
|
||||
priv->order = order;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_plugin_add_rule:
|
||||
* @plugin: a #FuPlugin
|
||||
* @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
|
||||
* @name: a plugin name, e.g. "upower"
|
||||
*
|
||||
* If the plugin name is found, the rule will be used to sort the plugin list,
|
||||
* for example the plugin specified by @name will be ordered after this plugin
|
||||
* when %FU_PLUGIN_RULE_RUN_AFTER is used.
|
||||
*
|
||||
* NOTE: The depsolver is iterative and may not solve overly-complicated rules;
|
||||
* If depsolving fails then fwupd will not start.
|
||||
**/
|
||||
void
|
||||
fu_plugin_add_rule (FuPlugin *plugin, FuPluginRule rule, const gchar *name)
|
||||
{
|
||||
FuPluginPrivate *priv = fu_plugin_get_instance_private (plugin);
|
||||
g_ptr_array_add (priv->rules[rule], g_strdup (name));
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_plugin_get_rules:
|
||||
* @plugin: a #FuPlugin
|
||||
* @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS
|
||||
*
|
||||
* Gets the plugin IDs that should be run after this plugin.
|
||||
*
|
||||
* Returns: (element-type utf8) (transfer none): the list of plugin names, e.g. ['appstream']
|
||||
**/
|
||||
GPtrArray *
|
||||
fu_plugin_get_rules (FuPlugin *plugin, FuPluginRule rule)
|
||||
{
|
||||
FuPluginPrivate *priv = fu_plugin_get_instance_private (plugin);
|
||||
return priv->rules[rule];
|
||||
}
|
||||
|
||||
static void
|
||||
fu_plugin_class_init (FuPluginClass *klass)
|
||||
{
|
||||
@ -1267,6 +1336,8 @@ fu_plugin_init (FuPlugin *plugin)
|
||||
priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, (GDestroyNotify) g_object_unref);
|
||||
priv->devices_delay = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
|
||||
priv->rules[i] = g_ptr_array_new_with_free_func (g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1285,6 +1356,9 @@ fu_plugin_finalize (GObject *object)
|
||||
}
|
||||
}
|
||||
|
||||
for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++)
|
||||
g_ptr_array_unref (priv->rules[i]);
|
||||
|
||||
if (priv->usb_ctx != NULL)
|
||||
g_object_unref (priv->usb_ctx);
|
||||
if (priv->hwids != NULL)
|
||||
|
@ -63,6 +63,22 @@ typedef enum {
|
||||
FU_PLUGIN_VERIFY_FLAG_LAST
|
||||
} FuPluginVerifyFlags;
|
||||
|
||||
/**
|
||||
* FuPluginRule:
|
||||
* @FU_PLUGIN_RULE_CONFLICTS: The plugin conflicts with another
|
||||
* @FU_PLUGIN_RULE_RUN_AFTER: Order the plugin after another
|
||||
* @FU_PLUGIN_RULE_RUN_BEFORE: Order the plugin before another
|
||||
*
|
||||
* The rules used for ordering plugins.
|
||||
* Plugins are expected to add rules in fu_plugin_initialize().
|
||||
**/
|
||||
typedef enum {
|
||||
FU_PLUGIN_RULE_CONFLICTS,
|
||||
FU_PLUGIN_RULE_RUN_AFTER,
|
||||
FU_PLUGIN_RULE_RUN_BEFORE,
|
||||
FU_PLUGIN_RULE_LAST
|
||||
} FuPluginRule;
|
||||
|
||||
typedef struct FuPluginData FuPluginData;
|
||||
|
||||
/* for plugins to use */
|
||||
@ -108,6 +124,9 @@ const gchar *fu_plugin_get_smbios_string (FuPlugin *plugin,
|
||||
guint8 offset);
|
||||
GBytes *fu_plugin_get_smbios_data (FuPlugin *plugin,
|
||||
guint8 structure_type);
|
||||
void fu_plugin_add_rule (FuPlugin *plugin,
|
||||
FuPluginRule rule,
|
||||
const gchar *name);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user