aboutsummaryrefslogtreecommitdiffstats
path: root/core/modulemanager.lua
diff options
context:
space:
mode:
authorMatthew Wild <mwild1@gmail.com>2022-02-04 14:20:00 +0000
committerMatthew Wild <mwild1@gmail.com>2022-02-04 14:20:00 +0000
commit61d33dd36446c1a6d801c1d3781c4051641af615 (patch)
tree18971a4ff195a04efd5685fd7b79c46365893e71 /core/modulemanager.lua
parent4bdff5a4529443c19df04f16ee35939ef324f516 (diff)
downloadprosody-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.
Diffstat (limited to 'core/modulemanager.lua')
-rw-r--r--core/modulemanager.lua32
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;