diff options
author | Matthew Wild <mwild1@gmail.com> | 2022-02-04 14:20:00 +0000 |
---|---|---|
committer | Matthew Wild <mwild1@gmail.com> | 2022-02-04 14:20:00 +0000 |
commit | 61d33dd36446c1a6d801c1d3781c4051641af615 (patch) | |
tree | 18971a4ff195a04efd5685fd7b79c46365893e71 | |
parent | 4bdff5a4529443c19df04f16ee35939ef324f516 (diff) | |
download | prosody-61d33dd36446c1a6d801c1d3781c4051641af615.tar.gz prosody-61d33dd36446c1a6d801c1d3781c4051641af615.zip |
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.
-rw-r--r-- | core/modulemanager.lua | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/core/modulemanager.lua b/core/modulemanager.lua index 436ee378..669df440 100644 --- a/core/modulemanager.lua +++ b/core/modulemanager.lua @@ -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 pluginloader = require "util.pluginloader"; 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 @@ local _ENV = nil; -- 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; |