Changeset

13626:ac60c21015c7

core.configmanager: Add ways to read config values from files Inspired by something MattJ said Allows retrieving config values from files which are expected to be relative to the config directory, extending on the ENV_ method of retrieving config values from outside the config file. - FileLine retrieves the first line, stripping any trailing newline - FileContents reads the whole file - FileLines reads lines into an array
author Kim Alvefur <zash@zash.se>
date Thu, 16 Jan 2025 15:05:00 +0100
parents 13625:ff13dd315e68
children 13627:2db7b3b65363
files CHANGES core/configmanager.lua spec/scansion/admins.txt spec/scansion/prosody.cfg.lua
diffstat 4 files changed, 37 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES	Thu Jan 16 11:35:19 2025 +0000
+++ b/CHANGES	Thu Jan 16 15:05:00 2025 +0100
@@ -60,6 +60,7 @@
 
 - The configuration file now supports referring and appending to options previously set
 - Direct usage of the Lua API in the config file is deprecated, but can now be accessed via Lua.* instead
+- Convenience functions for reading values from files
 
 ## Changes
 
--- a/core/configmanager.lua	Thu Jan 16 11:35:19 2025 +0000
+++ b/core/configmanager.lua	Thu Jan 16 15:05:00 2025 +0100
@@ -161,15 +161,43 @@
 		end;
 	};
 
+	-- For reading config values out of files.
+	local function filereader(basepath, defaultmode)
+		return function(filename, mode)
+			local f, err = io.open(resolve_relative_path(basepath, filename));
+			if not f then error(err, 2); end
+			local content, err = f:read(mode or defaultmode);
+			f:close();
+			if not content then error(err, 2); end
+			return content;
+		end
+	end
+
+	-- Collect lines into an array
+	local function linereader(basepath)
+		return function(filename)
+			local ret = {};
+			for line in io.lines(resolve_relative_path(basepath, filename)) do
+				t_insert(ret, line);
+			end
+			return ret;
+		end
+	end
+
 	parser = {};
 	function parser.load(data, config_file, config_table)
 		local set_options = {}; -- set_options[host.."/"..option_name] = true (when the option has been set already in this file)
 		local warnings = {};
 		local env;
+		local config_path = config_file:gsub("[^"..path_sep.."]+$", "");
+
 		-- The ' = true' are needed so as not to set off __newindex when we assign the functions below
 		env = setmetatable({
 			Host = true, host = true, VirtualHost = true,
 			Component = true, component = true,
+			FileContents = true,
+			FileLine = true,
+			FileLines = true,
 			Include = true, include = true, RunScript = true }, {
 				__index = function (_, k)
 					if k:match("^ENV_") then
@@ -293,7 +321,6 @@
 				end
 				local path_pos, glob = file:match("()([^"..path_sep.."]+)$");
 				local path = file:sub(1, math_max(path_pos-2,0));
-				local config_path = config_file:gsub("[^"..path_sep.."]+$", "");
 				if #path > 0 then
 					path = resolve_relative_path(config_path, path);
 				else
@@ -308,7 +335,7 @@
 				return;
 			end
 			-- Not a wildcard, so resolve (potentially) relative path and run through config parser
-			file = resolve_relative_path(config_file:gsub("[^"..path_sep.."]+$", ""), file);
+			file = resolve_relative_path(config_path, file);
 			local f, err = io.open(file);
 			if f then
 				local ret, err = parser.load(f:read("*a"), file, config_table);
@@ -325,9 +352,13 @@
 		env.include = env.Include;
 
 		function env.RunScript(file)
-			return dofile(resolve_relative_path(config_file:gsub("[^"..path_sep.."]+$", ""), file));
+			return dofile(resolve_relative_path(config_path, file));
 		end
 
+		env.FileContents = filereader(config_path, "*a");
+		env.FileLine = filereader(config_path, "*l");
+		env.FileLines = linereader(config_path);
+
 		local chunk, err = envload(data, "@"..config_file, env);
 
 		if not chunk then
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/scansion/admins.txt	Thu Jan 16 15:05:00 2025 +0100
@@ -0,0 +1,1 @@
+admin@localhost
--- a/spec/scansion/prosody.cfg.lua	Thu Jan 16 11:35:19 2025 +0000
+++ b/spec/scansion/prosody.cfg.lua	Thu Jan 16 15:05:00 2025 +0100
@@ -1,6 +1,6 @@
 --luacheck: ignore
 
-admins = { "admin@localhost" }
+admins = FileLines("admins.txt")
 
 network_backend = ENV_PROSODY_NETWORK_BACKEND or "epoll"
 network_settings = Lua.require"prosody.util.json".decode(ENV_PROSODY_NETWORK_SETTINGS or "{}")