Software /
code /
prosody
Changeset
12254:5b0c8e499288
modulemanager: Add plugin load filter that reads module metadata from source
Metadata in modules is added using lines formatted as:
--% key: value
Where key is a valid identifier string, and value is also a string (leading
and trailing whitespace are trimmed during parsing).
The initial supported keys are:
--% requires_core_features: feature1, feature2, ...
--% conflicts_core_features: feature1, feature2. ...
These 'features' map to features reported by the new core.features module.
A benefit of this load-time metadata approach compared to e.g. something like
module:requires()/module:conflicts() is that we can continue to look in module
search paths for a suitable module. Aborting an already-loaded module due to
a version conflict would be too late.
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Fri, 04 Feb 2022 14:20:00 +0000 |
parents | 12253:57d35fcde488 |
children | 12255:a3ad9cf740d6 |
files | core/modulemanager.lua |
diffstat | 1 files changed, 32 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/core/modulemanager.lua Fri Feb 04 14:11:46 2022 +0000 +++ b/core/modulemanager.lua Fri Feb 04 14:20:00 2022 +0000 @@ -6,6 +6,7 @@ -- COPYING file in the source package for more information. -- +local array = require "util.array"; local logger = require "util.logger"; local log = logger.init("modulemanager"); local config = require "core.configmanager"; @@ -13,6 +14,8 @@ local envload = require "util.envload"; local set = require "util.set"; +local core_features = require "core.features".available; + local new_multitable = require "util.multitable".new; local api = require "core.moduleapi"; -- Module API container @@ -53,6 +56,35 @@ -- luacheck: std none local loader = pluginloader.init({ + load_filter_cb = function (path, content) + local metadata = {}; + for line in content:gmatch("([^\r\n]+)\r?\n") do + local key, value = line:match("^%-%-%% *([%w_]+): *(.+)$"); + if key then + value = value:gsub("%s+$", ""); + metadata[key] = value; + end + end + + if metadata.conflicts_core_features then + local conflicts_core_features = set.new(array.collect(metadata.conflicts_core_features:gmatch("[^, ]+"))); + local conflicted_features = set.intersection(conflicts_core_features, core_features); + if not conflicted_features:empty() then + log("warn", "Not loading module, due to conflicting features '%s': %s", conflicted_features, path); + return; -- Don't load this module + end + end + if metadata.requires_core_features then + local required_features = set.new(array.collect(metadata.requires_core_features:gmatch("[^, ]+"))); + local missing_features = required_features - core_features; + if not missing_features:empty() then + log("warn", "Not loading module, due to missing features '%s': %s", missing_features, path); + return; -- Don't load this module + end + end + + return path, content, metadata; + end; }); local load_modules_for_host, load, unload, reload, get_module, get_items;