Software / code / prosody
Comparison
core/configmanager.lua @ 11200:bf8f2da84007
Merge 0.11->trunk
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Thu, 05 Nov 2020 22:31:25 +0100 |
| parent | 10375:3d0adbc74c39 |
| child | 12083:ec21e379c145 |
comparison
equal
deleted
inserted
replaced
| 11199:6c7c50a4de32 | 11200:bf8f2da84007 |
|---|---|
| 5 -- This project is MIT/X11 licensed. Please see the | 5 -- This project is MIT/X11 licensed. Please see the |
| 6 -- COPYING file in the source package for more information. | 6 -- COPYING file in the source package for more information. |
| 7 -- | 7 -- |
| 8 | 8 |
| 9 local _G = _G; | 9 local _G = _G; |
| 10 local setmetatable, rawget, rawset, io, os, error, dofile, type, pairs = | 10 local setmetatable, rawget, rawset, io, os, error, dofile, type, pairs, ipairs = |
| 11 setmetatable, rawget, rawset, io, os, error, dofile, type, pairs; | 11 setmetatable, rawget, rawset, io, os, error, dofile, type, pairs, ipairs; |
| 12 local format, math_max = string.format, math.max; | 12 local format, math_max, t_insert = string.format, math.max, table.insert; |
| 13 | 13 |
| 14 local envload = require"util.envload".envload; | 14 local envload = require"util.envload".envload; |
| 15 local deps = require"util.dependencies"; | 15 local deps = require"util.dependencies"; |
| 16 local resolve_relative_path = require"util.paths".resolve_relative_path; | 16 local resolve_relative_path = require"util.paths".resolve_relative_path; |
| 17 local glob_to_pattern = require"util.paths".glob_to_pattern; | 17 local glob_to_pattern = require"util.paths".glob_to_pattern; |
| 18 local path_sep = package.config:sub(1,1); | 18 local path_sep = package.config:sub(1,1); |
| 19 local get_traceback_table = require "util.debug".get_traceback_table; | |
| 19 | 20 |
| 20 local encodings = deps.softreq"util.encodings"; | 21 local encodings = deps.softreq"util.encodings"; |
| 21 local nameprep = encodings and encodings.stringprep.nameprep or function (host) return host:lower(); end | 22 local nameprep = encodings and encodings.stringprep.nameprep or function (host) return host:lower(); end |
| 22 | 23 |
| 23 local _M = {}; | 24 local _M = {}; |
| 98 end | 99 end |
| 99 | 100 |
| 100 -- Built-in Lua parser | 101 -- Built-in Lua parser |
| 101 do | 102 do |
| 102 local pcall = _G.pcall; | 103 local pcall = _G.pcall; |
| 104 local function get_line_number(config_file) | |
| 105 local tb = get_traceback_table(nil, 2); | |
| 106 for i = 1, #tb do | |
| 107 if tb[i].info.short_src == config_file then | |
| 108 return tb[i].info.currentline; | |
| 109 end | |
| 110 end | |
| 111 end | |
| 103 parser = {}; | 112 parser = {}; |
| 104 function parser.load(data, config_file, config_table) | 113 function parser.load(data, config_file, config_table) |
| 114 local set_options = {}; -- set_options[host.."/"..option_name] = true (when the option has been set already in this file) | |
| 115 local warnings = {}; | |
| 105 local env; | 116 local env; |
| 106 -- The ' = true' are needed so as not to set off __newindex when we assign the functions below | 117 -- The ' = true' are needed so as not to set off __newindex when we assign the functions below |
| 107 env = setmetatable({ | 118 env = setmetatable({ |
| 108 Host = true, host = true, VirtualHost = true, | 119 Host = true, host = true, VirtualHost = true, |
| 109 Component = true, component = true, | 120 Component = true, component = true, |
| 113 return os.getenv(k:sub(5)); | 124 return os.getenv(k:sub(5)); |
| 114 end | 125 end |
| 115 return rawget(_G, k); | 126 return rawget(_G, k); |
| 116 end, | 127 end, |
| 117 __newindex = function (_, k, v) | 128 __newindex = function (_, k, v) |
| 129 local host = env.__currenthost or "*"; | |
| 130 local option_path = host.."/"..k; | |
| 131 if set_options[option_path] then | |
| 132 t_insert(warnings, ("%s:%d: Duplicate option '%s'"):format(config_file, get_line_number(config_file), k)); | |
| 133 end | |
| 134 set_options[option_path] = true; | |
| 118 set(config_table, env.__currenthost or "*", k, v); | 135 set(config_table, env.__currenthost or "*", k, v); |
| 119 end | 136 end |
| 120 }); | 137 }); |
| 121 | 138 |
| 122 rawset(env, "__currenthost", "*") -- Default is global | 139 rawset(env, "__currenthost", "*") -- Default is global |
| 123 function env.VirtualHost(name) | 140 function env.VirtualHost(name) |
| 124 name = nameprep(name); | 141 if not name then |
| 142 error("Host must have a name", 2); | |
| 143 end | |
| 144 local prepped_name = nameprep(name); | |
| 145 if not prepped_name then | |
| 146 error(format("Name of Host %q contains forbidden characters", name), 0); | |
| 147 end | |
| 148 name = prepped_name; | |
| 125 if rawget(config_table, name) and rawget(config_table[name], "component_module") then | 149 if rawget(config_table, name) and rawget(config_table[name], "component_module") then |
| 126 error(format("Host %q clashes with previously defined %s Component %q, for services use a sub-domain like conference.%s", | 150 error(format("Host %q clashes with previously defined %s Component %q, for services use a sub-domain like conference.%s", |
| 127 name, config_table[name].component_module:gsub("^%a+$", { component = "external", muc = "MUC"}), name, name), 0); | 151 name, config_table[name].component_module:gsub("^%a+$", { component = "external", muc = "MUC"}), name, name), 0); |
| 128 end | 152 end |
| 129 rawset(env, "__currenthost", name); | 153 rawset(env, "__currenthost", name); |
| 137 end; | 161 end; |
| 138 end | 162 end |
| 139 env.Host, env.host = env.VirtualHost, env.VirtualHost; | 163 env.Host, env.host = env.VirtualHost, env.VirtualHost; |
| 140 | 164 |
| 141 function env.Component(name) | 165 function env.Component(name) |
| 142 name = nameprep(name); | 166 if not name then |
| 167 error("Component must have a name", 2); | |
| 168 end | |
| 169 local prepped_name = nameprep(name); | |
| 170 if not prepped_name then | |
| 171 error(format("Name of Component %q contains forbidden characters", name), 0); | |
| 172 end | |
| 173 name = prepped_name; | |
| 143 if rawget(config_table, name) and rawget(config_table[name], "defined") | 174 if rawget(config_table, name) and rawget(config_table[name], "defined") |
| 144 and not rawget(config_table[name], "component_module") then | 175 and not rawget(config_table[name], "component_module") then |
| 145 error(format("Component %q clashes with previously defined Host %q, for services use a sub-domain like conference.%s", | 176 error(format("Component %q clashes with previously defined Host %q, for services use a sub-domain like conference.%s", |
| 146 name, name, name), 0); | 177 name, name, name), 0); |
| 147 end | 178 end |
| 193 file = resolve_relative_path(config_file:gsub("[^"..path_sep.."]+$", ""), file); | 224 file = resolve_relative_path(config_file:gsub("[^"..path_sep.."]+$", ""), file); |
| 194 local f, err = io.open(file); | 225 local f, err = io.open(file); |
| 195 if f then | 226 if f then |
| 196 local ret, err = parser.load(f:read("*a"), file, config_table); | 227 local ret, err = parser.load(f:read("*a"), file, config_table); |
| 197 if not ret then error(err:gsub("%[string.-%]", file), 0); end | 228 if not ret then error(err:gsub("%[string.-%]", file), 0); end |
| 229 if err then | |
| 230 for _, warning in ipairs(err) do | |
| 231 t_insert(warnings, warning); | |
| 232 end | |
| 233 end | |
| 198 end | 234 end |
| 199 if not f then error("Error loading included "..file..": "..err, 0); end | 235 if not f then error("Error loading included "..file..": "..err, 0); end |
| 200 return f, err; | 236 return f, err; |
| 201 end | 237 end |
| 202 env.include = env.Include; | 238 env.include = env.Include; |
| 215 | 251 |
| 216 if not ok then | 252 if not ok then |
| 217 return nil, err; | 253 return nil, err; |
| 218 end | 254 end |
| 219 | 255 |
| 220 return true; | 256 return true, warnings; |
| 221 end | 257 end |
| 222 | 258 |
| 223 end | 259 end |
| 224 | 260 |
| 225 return _M; | 261 return _M; |