treewide: rework check_site_lib.lua
In addition to significant internal differences in check_site_lib.lua (in
particular unifying error handling to a single place for the upcoming
multi-domain support), this changes the way fields are addressed in site
check scripts: rather than providing a string like 'next_node.ip6', the
path is passed as an array {'next_node', 'ip6'}.
Other changes in site check scripts:
* need_array and need_table now pass the full path to the sub fields to the
subcheck instead of the key and value
* Any check referring to a field inside a table implies that all higher
levels must be tables if they exist: a check for {'next_node', 'ip6'} adds
an implicit (optional) check for {'next_node'}, which allows to remove many
explicit checks for such tables
			
			
This commit is contained in:
		
							parent
							
								
									414dfa8155
								
							
						
					
					
						commit
						7ccdacd294
					
				| @ -1 +1 @@ | |||||||
| need_string_array(in_site('authorized_keys')) | need_string_array(in_site({'authorized_keys'})) | ||||||
|  | |||||||
| @ -1,14 +1,10 @@ | |||||||
| need_string(in_site('autoupdater.branch')) | need_string(in_site({'autoupdater', 'branch'})) | ||||||
| 
 | 
 | ||||||
| local function check_branch(k, _) | need_table({'autoupdater', 'branches'}, function(branch) | ||||||
|    assert_uci_name(k) | 	need_alphanumeric_key(branch) | ||||||
| 
 | 
 | ||||||
|    local prefix = string.format('autoupdater.branches[%q].', k) | 	need_string(in_site(extend(branch, {'name'}))) | ||||||
| 
 | 	need_string_array_match(extend(branch, {'mirrors'}), '^http://') | ||||||
|    need_string(in_site(prefix .. 'name')) | 	need_number(in_site(extend(branch, {'good_signatures'}))) | ||||||
|    need_string_array_match(prefix .. 'mirrors', '^http://') | 	need_string_array_match(in_site(extend(branch, {'pubkeys'})), '^%x+$') | ||||||
|    need_number(in_site(prefix .. 'good_signatures')) | end) | ||||||
|    need_string_array_match(in_site(prefix .. 'pubkeys'), '^%x+$') |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| need_table('autoupdater.branches', check_branch) |  | ||||||
|  | |||||||
| @ -1,15 +1,15 @@ | |||||||
| need_string_match(in_domain('next_node.mac'), '^%x[02468aAcCeE]:%x%x:%x%x:%x%x:%x%x:%x%x$', false) | need_string_match(in_domain({'next_node', 'mac'}), '^%x[02468aAcCeE]:%x%x:%x%x:%x%x:%x%x:%x%x$', false) | ||||||
| 
 | 
 | ||||||
| if need_string_match(in_domain('next_node.ip4'), '^%d+.%d+.%d+.%d+$', false) then | if need_string_match(in_domain({'next_node', 'ip4'}), '^%d+.%d+.%d+.%d+$', false) then | ||||||
| 	need_string_match(in_domain('prefix4'), '^%d+.%d+.%d+.%d+/%d+$') | 	need_string_match(in_domain({'prefix4'}), '^%d+.%d+.%d+.%d+/%d+$') | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| need_string_match(in_domain('next_node.ip6'), '^[%x:]+$', false) | need_string_match(in_domain({'next_node', 'ip6'}), '^[%x:]+$', false) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| for _, config in ipairs({'wifi24', 'wifi5'}) do | for _, config in ipairs({'wifi24', 'wifi5'}) do | ||||||
| 	if need_table(config .. '.ap', nil, false) then | 	if need_table({config}, nil, false) then | ||||||
| 		need_string(in_domain(config .. '.ap.ssid')) | 		need_string(in_domain({config, 'ap', 'ssid'})) | ||||||
| 		need_boolean(config .. '.ap.disabled', false) | 		need_boolean({config, 'ap', 'disabled'}, false) | ||||||
| 	end | 	end | ||||||
| end | end | ||||||
|  | |||||||
| @ -1,3 +1 @@ | |||||||
| if need_table(in_site('config_mode'), nil, false) and need_table(in_site('config_mode.owner'), nil, false) then | need_boolean(in_site({'config_mode', 'owner', 'obligatory'}), false) | ||||||
|   need_boolean(in_site('config_mode.owner.obligatory'), false) |  | ||||||
| end |  | ||||||
|  | |||||||
| @ -1,3 +1 @@ | |||||||
| if need_table(in_site('config_mode'), nil, false) and need_table(in_site('config_mode.geo_location'), nil, false) then | need_boolean(in_site({'config_mode', 'geo_location', 'show_altitude'}), false) | ||||||
|   need_boolean(in_site('config_mode.geo_location.show_altitude'), false) |  | ||||||
| end |  | ||||||
|  | |||||||
| @ -1,75 +1,57 @@ | |||||||
| need_string(in_site('site_code')) | need_string(in_site({'site_code'})) | ||||||
| need_string(in_site('site_name')) | need_string(in_site({'site_name'})) | ||||||
| need_string_match(in_domain('domain_seed'), '^' .. ('%x'):rep(64) .. '$') | need_string_match(in_domain({'domain_seed'}), '^' .. ('%x'):rep(64) .. '$') | ||||||
| 
 | 
 | ||||||
| if need_table('opkg', nil, false) then | need_string({'opkg', 'lede'}, false) | ||||||
| 	need_string('opkg.lede', false) | need_table({'opkg', 'extra'}, function(extra_repo) | ||||||
|  | 	need_alphanumeric_key(extra_repo) | ||||||
|  | 	need_string(extra_repo) | ||||||
|  | end, false) | ||||||
| 
 | 
 | ||||||
| 	function check_repo(k, _) | need_string(in_site({'hostname_prefix'}), false) | ||||||
| 		-- this is not actually a uci name, but using the same naming rules here is fine | need_string(in_site({'timezone'})) | ||||||
| 		assert_uci_name(k) |  | ||||||
| 
 | 
 | ||||||
| 		local path = string.format('opkg.extra[%q]', k) | need_string_array({'ntp_servers'}, false) | ||||||
| 		need_string(path) |  | ||||||
| 	end |  | ||||||
| 
 | 
 | ||||||
| 	need_table('opkg.extra', check_repo, false) | need_string_match(in_domain({'prefix6'}), '^[%x:]+/64$') | ||||||
| end |  | ||||||
| 
 |  | ||||||
| need_string(in_site('hostname_prefix'), false) |  | ||||||
| need_string(in_site('timezone')) |  | ||||||
| 
 |  | ||||||
| need_string_array('ntp_servers', false) |  | ||||||
| 
 |  | ||||||
| need_string_match(in_domain('prefix6'), '^[%x:]+/64$') |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| for _, config in ipairs({'wifi24', 'wifi5'}) do | for _, config in ipairs({'wifi24', 'wifi5'}) do | ||||||
| 	if need_table(config, nil, false) then | 	if need_table({config}, nil, false) then | ||||||
| 		need_string(in_site('regdom')) -- regdom is only required when wifi24 or wifi5 is configured | 		need_string(in_site({'regdom'})) -- regdom is only required when wifi24 or wifi5 is configured | ||||||
| 
 | 
 | ||||||
| 		need_number(config .. '.channel') | 		need_number({config, 'channel'}) | ||||||
| 
 | 
 | ||||||
| 		local rates = {1000, 2000, 5500, 6000, 9000, 11000, 12000, 18000, 24000, 36000, 48000, 54000} | 		local rates = {1000, 2000, 5500, 6000, 9000, 11000, 12000, 18000, 24000, 36000, 48000, 54000} | ||||||
| 		local supported_rates = need_array_of(in_site(config .. '.supported_rates'), rates, false) | 		local supported_rates = need_array_of(in_site({config, 'supported_rates'}), rates, false) | ||||||
| 		if supported_rates then | 		need_array_of({config, 'basic_rate'}, supported_rates or rates, supported_rates ~= nil) | ||||||
| 			need_array_of(config .. '.basic_rate', supported_rates, true) | 
 | ||||||
| 		else | 		if need_table({config, 'ibss'}, nil, false) then | ||||||
| 			need_array_of(config .. '.basic_rate', rates, false) | 			need_string(in_domain({config, 'ibss', 'ssid'})) | ||||||
|  | 			need_string_match(in_domain({config, 'ibss', 'bssid'}), '^%x[02468aAcCeE]:%x%x:%x%x:%x%x:%x%x:%x%x$') | ||||||
|  | 			need_one_of({config, 'ibss', 'mcast_rate'}, supported_rates or rates, false) | ||||||
|  | 			need_number({config, 'ibss', 'vlan'}, false) | ||||||
|  | 			need_boolean({config, 'ibss', 'disabled'}, false) | ||||||
|  | 		end | ||||||
|  | 
 | ||||||
|  | 		if need_table({config, 'mesh'}, nil, false) then | ||||||
|  | 			need_string(in_domain({config, 'mesh', 'id'})) | ||||||
|  | 			need_one_of({config, 'mesh', 'mcast_rate'}, supported_rates or rates, false) | ||||||
|  | 			need_boolean({config, 'mesh', 'disabled'}, false) | ||||||
| 		end | 		end | ||||||
| 	end | 	end | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| need_boolean(in_site('poe_passthrough'), false) | need_boolean(in_site({'poe_passthrough'}), false) | ||||||
| if need_table('dns', nil, false) then | 
 | ||||||
| 	need_number('dns.cacheentries', false) | if need_table({'dns'}, nil, false) then | ||||||
| 	need_string_array_match('dns.servers', '^[%x:]+$', true) | 	need_string_array_match({'dns', 'servers'}, '^[%x:]+$') | ||||||
|  | 	need_number({'dns', 'cacheentries'}, false) | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| if need_table('next_node', nil, false) then | need_string_match(in_domain({'next_node', 'ip6'}), '^[%x:]+$', false) | ||||||
| 	need_string_match(in_domain('next_node.ip6'), '^[%x:]+$', false) | need_string_match(in_domain({'next_node', 'ip4'}), '^%d+.%d+.%d+.%d+$', false) | ||||||
| 	need_string_match(in_domain('next_node.ip4'), '^%d+.%d+.%d+.%d+$', false) |  | ||||||
| end |  | ||||||
| 
 | 
 | ||||||
| for _, config in ipairs({'wifi24', 'wifi5'}) do | need_boolean(in_site({'mesh_on_wan'}), false) | ||||||
|   local rates = {1000, 2000, 5500, 6000, 9000, 11000, 12000, 18000, 24000, 36000, 48000, 54000} | need_boolean(in_site({'mesh_on_lan'}), false) | ||||||
|   rates = need_array_of(in_site(config .. '.supported_rates'), rates, false) or rates | need_boolean(in_site({'single_as_lan'}), false) | ||||||
| 
 |  | ||||||
|   if need_table(config .. '.ibss', nil, false) then |  | ||||||
|     need_string(in_domain(config .. '.ibss.ssid')) |  | ||||||
|     need_string_match(in_domain(config .. '.ibss.bssid'), '^%x[02468aAcCeE]:%x%x:%x%x:%x%x:%x%x:%x%x$') |  | ||||||
|     need_one_of(config .. '.ibss.mcast_rate', rates, false) |  | ||||||
|     need_number(config .. '.ibss.vlan', false) |  | ||||||
|     need_boolean(config .. '.ibss.disabled', false) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   if need_table(config .. '.mesh', nil, false) then |  | ||||||
|     need_string(in_domain(config .. '.mesh.id')) |  | ||||||
|     need_one_of(config .. '.mesh.mcast_rate', rates, false) |  | ||||||
|     need_boolean(config .. '.mesh.disabled', false) |  | ||||||
|   end |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| need_boolean(in_site('mesh_on_wan'), false) |  | ||||||
| need_boolean(in_site('mesh_on_lan'), false) |  | ||||||
| need_boolean(in_site('single_as_lan'), false) |  | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| need_string_match(in_domain('prefix4'), '^%d+.%d+.%d+.%d+/%d+$', false) | need_string_match(in_domain({'prefix4'}), '^%d+.%d+.%d+.%d+/%d+$', false) | ||||||
| need_string_array_match(in_domain('extra_prefixes6'), '^[%x:]+/%d+$', false) | need_string_array_match(in_domain({'extra_prefixes6'}), '^[%x:]+/%d+$', false) | ||||||
|  | |||||||
| @ -1,4 +1,2 @@ | |||||||
| if need_table('mesh', nil, false) and  need_table('mesh.batman_adv', nil, false) then | need_number({'mesh', 'batman_adv', 'gw_sel_class'}, false) | ||||||
| 	need_number('mesh.batman_adv.gw_sel_class', false) | need_one_of({'mesh', 'batman_adv', 'routing_algo'}, {'BATMAN_IV', 'BATMAN_V'}, false) | ||||||
| 	need_one_of('mesh.batman_adv.routing_algo', {'BATMAN_IV', 'BATMAN_V'}, false) |  | ||||||
| end |  | ||||||
|  | |||||||
| @ -1,8 +1,6 @@ | |||||||
| need_boolean(in_site('mesh_vpn.enabled'), false) | need_boolean(in_site({'mesh_vpn', 'enabled'}), false) | ||||||
| need_number('mesh_vpn.mtu') | need_number({'mesh_vpn', 'mtu'}) | ||||||
| 
 | 
 | ||||||
| if need_table(in_site('mesh_vpn.bandwidth_limit'), nil, false) then | need_boolean(in_site({'mesh_vpn', 'bandwidth_limit', 'enabled'}), false) | ||||||
| 	need_boolean(in_site('mesh_vpn.bandwidth_limit.enabled'), false) | need_number(in_site({'mesh_vpn', 'bandwidth_limit', 'ingress'}), false) | ||||||
| 	need_number(in_site('mesh_vpn.bandwidth_limit.ingress'), false) | need_number(in_site({'mesh_vpn', 'bandwidth_limit', 'egress'}), false) | ||||||
| 	need_number(in_site('mesh_vpn.bandwidth_limit.egress'), false) |  | ||||||
| end |  | ||||||
|  | |||||||
| @ -1,30 +1,22 @@ | |||||||
| local fastd_methods = {'salsa2012+gmac', 'salsa2012+umac', 'null+salsa2012+gmac', 'null+salsa2012+umac', 'null'} | local fastd_methods = {'salsa2012+gmac', 'salsa2012+umac', 'null+salsa2012+gmac', 'null+salsa2012+umac', 'null'} | ||||||
| need_array_of('mesh_vpn.fastd.methods', fastd_methods) | need_array_of({'mesh_vpn', 'fastd', 'methods'}, fastd_methods) | ||||||
| need_boolean(in_site('mesh_vpn.fastd.configurable'), false) | need_boolean(in_site({'mesh_vpn', 'fastd', 'configurable'}), false) | ||||||
| 
 | 
 | ||||||
| need_one_of(in_site('mesh_vpn.fastd.syslog_level'), {'error', 'warn', 'info', 'verbose', 'debug', 'debug2'}, false) | need_one_of(in_site({'mesh_vpn', 'fastd', 'syslog_level'}), {'error', 'warn', 'info', 'verbose', 'debug', 'debug2'}, false) | ||||||
| 
 | 
 | ||||||
| local function check_peer(prefix) | local function check_peer(k) | ||||||
| 	return function(k, _) | 	need_alphanumeric_key(k) | ||||||
| 		assert_uci_name(k) |  | ||||||
| 
 | 
 | ||||||
| 		local table = string.format('%s[%q].', prefix, k) | 	need_string_match(in_domain(extend(k, {'key'})), '^%x+$') | ||||||
| 
 | 	need_string_array(in_domain(extend(k, {'remotes'}))) | ||||||
| 		need_string_match(in_domain(table .. 'key'), '^%x+$') |  | ||||||
| 		need_string_array(in_domain(table .. 'remotes')) |  | ||||||
| 	end |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function check_group(prefix) | local function check_group(k) | ||||||
| 	return function(k, _) | 	need_alphanumeric_key(k) | ||||||
| 		assert_uci_name(k) |  | ||||||
| 
 | 
 | ||||||
| 		local table = string.format('%s[%q].', prefix, k) | 	need_number(extend(k, {'limit'}), false) | ||||||
| 
 | 	need_table(extend(k, {'peers'}), check_peer, false) | ||||||
| 		need_number(table .. 'limit', false) | 	need_table(extend(k, {'groups'}), check_group, false) | ||||||
| 		need_table(table .. 'peers', check_peer(table .. 'peers'), false) |  | ||||||
| 		need_table(table .. 'groups', check_group(table .. 'groups'), false) |  | ||||||
| 	end |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| need_table('mesh_vpn.fastd.groups', check_group('mesh_vpn.fastd.groups')) | need_table({'mesh_vpn', 'fastd', 'groups'}, check_group) | ||||||
|  | |||||||
| @ -1 +1 @@ | |||||||
| need_string_array('mesh_vpn.tunneldigger.brokers') | need_string_array({'mesh_vpn', 'tunneldigger', 'brokers'}) | ||||||
|  | |||||||
| @ -1 +1 @@ | |||||||
| need_string(in_site('roles.default'), false) | need_string(in_site({'roles', 'default'}), false) | ||||||
|  | |||||||
| @ -1 +1 @@ | |||||||
| need_boolean(in_site('setup_mode.skip'), false) | need_boolean(in_site({'setup_mode', 'skip'}), false) | ||||||
|  | |||||||
| @ -1,4 +1,2 @@ | |||||||
| if need_table(in_site('config_mode'), nil, false) and need_table(in_site('config_mode.remote_login'), nil, false) then | need_boolean(in_site({'config_mode', 'remote_login', 'show_password_form'}), false) | ||||||
|   need_boolean(in_site('config_mode.remote_login.show_password_form'), false) | need_number(in_site({'config_mode', 'remote_login', 'min_password_length'}), false) | ||||||
|   need_number(in_site('config_mode.remote_login.min_password_length'), false) |  | ||||||
| end |  | ||||||
|  | |||||||
| @ -1,2 +1 @@ | |||||||
| assert(need_boolean(in_site('mesh_vpn.fastd.configurable')) == true, | need_value(in_site({'mesh_vpn', 'fastd', 'configurable'}), true) | ||||||
|        "site.conf error: expected `mesh_vpn.fastd.configurable' to be true") |  | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| need_string(in_site('roles.default')) | need_string(in_site({'roles', 'default'})) | ||||||
| need_string_array(in_site('roles.list')) | need_string_array(in_site({'roles', 'list'})) | ||||||
|  | |||||||
| @ -1,160 +1,168 @@ | |||||||
| function in_site(var) | function in_site(var) | ||||||
|    return var | 	return var | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function in_domain(var) | function in_domain(var) | ||||||
|    return var | 	return var | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| local function loadvar(varname) | local function path_to_string(path) | ||||||
|    local ok, val = pcall(assert(loadstring('return site.' .. varname))) | 	return table.concat(path, '/') | ||||||
|    if ok then |  | ||||||
|       return val |  | ||||||
|    else |  | ||||||
|       return nil |  | ||||||
|    end |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function array_to_string(array) | local function array_to_string(array) | ||||||
|    local string = '' | 	return '[' .. table.concat(array, ', ') .. ']' | ||||||
|    for _, v in ipairs(array) do |  | ||||||
|       if #string >= 1 then |  | ||||||
|          string = string .. ', ' |  | ||||||
|       end |  | ||||||
|       string = string .. v |  | ||||||
|    end |  | ||||||
|    return '[' .. string .. ']' |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function assert_one_of(var, array, msg) | local function var_error(path, val, msg) | ||||||
|    for _, v in ipairs(array) do | 	print(string.format('*** site.conf error: expected %s to %s, but it is %s', path_to_string(path), msg, tostring(val))) | ||||||
|       if v == var then | 	os.exit(1) | ||||||
|          return true |  | ||||||
|       end |  | ||||||
|    end |  | ||||||
| 
 |  | ||||||
|    error(msg) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| local function assert_type(var, t, msg) |  | ||||||
|    assert(type(var) == t, msg) |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| function assert_uci_name(var) | function extend(path, c) | ||||||
|    -- We don't use character classes like %w here to be independent of the locale | 	local p = {unpack(path)} | ||||||
|    assert(var:match('^[0-9a-zA-Z_]+$'), "site.conf error: `" .. var .. "' is not a valid config section name (only alphanumeric characters and the underscore are allowed)") | 
 | ||||||
|  | 	for _, e in ipairs(c) do | ||||||
|  | 		p[#p+1] = e | ||||||
|  | 	end | ||||||
|  | 	return p | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | local function loadpath(path, base, c, ...) | ||||||
|  | 	if not c or base == nil then | ||||||
|  | 		return base | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
|  | 	if type(base) ~= 'table' then | ||||||
|  | 		var_error(path, base, 'be a table') | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
|  | 	return loadpath(extend(path, {c}), base[c], ...) | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | local function loadvar(path) | ||||||
|  | 	return loadpath({}, site, unpack(path)) | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | local function check_type(t) | ||||||
|  | 	return function(val) | ||||||
|  | 		return type(val) == t | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | local function check_one_of(array) | ||||||
|  | 	return function(val) | ||||||
|  | 		for _, v in ipairs(array) do | ||||||
|  | 			if v == val then | ||||||
|  | 				return true | ||||||
|  | 			end | ||||||
|  | 		end | ||||||
|  | 		return false | ||||||
|  | 	end | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | function need(path, check, required, msg) | ||||||
|  | 	local val = loadvar(path) | ||||||
|  | 	if required == false and val == nil then | ||||||
|  | 		return nil | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
|  | 	if not check(val) then | ||||||
|  | 		var_error(path, val, msg) | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
|  | 	return val | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | local function need_type(path, type, required, msg) | ||||||
|  | 	return need(path, check_type(type), required, msg) | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| function need_string(varname, required) | function need_alphanumeric_key(path) | ||||||
|    local var = loadvar(varname) | 	local val = path[#path] | ||||||
| 
 | 	-- We don't use character classes like %w here to be independent of the locale | ||||||
|    if required == false and var == nil then | 	if not val:match('^[0-9a-zA-Z_]+$') then | ||||||
|       return nil | 		var_error(path, val, 'have a key using only alphanumeric characters and underscores') | ||||||
|    end | 	end | ||||||
| 
 |  | ||||||
|    assert_type(var, 'string', "site.conf error: expected `" .. varname .. "' to be a string") |  | ||||||
|    return var |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function need_string_match(varname, pat, required) |  | ||||||
|    local var = need_string(varname, required) |  | ||||||
| 
 | 
 | ||||||
|    if not var then | function need_string(path, required) | ||||||
|       return nil | 	return need_type(path, 'string', required, 'be a string') | ||||||
|    end |  | ||||||
| 
 |  | ||||||
|    assert(var:match(pat), "site.conf error: expected `" .. varname .. "' to match pattern `" .. pat .. "'") |  | ||||||
| 
 |  | ||||||
|    return var |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function need_number(varname, required) | function need_string_match(path, pat, required) | ||||||
|    local var = loadvar(varname) | 	local val = need_string(path, required) | ||||||
|  | 	if not val then | ||||||
|  | 		return nil | ||||||
|  | 	end | ||||||
| 
 | 
 | ||||||
|    if required == false and var == nil then | 	if not val:match(pat) then | ||||||
|       return nil | 		var_error(path, val, "match pattern '" .. pat .. "'") | ||||||
|    end | 	end | ||||||
| 
 | 
 | ||||||
|    assert_type(var, 'number', "site.conf error: expected `" .. varname .. "' to be a number") | 	return val | ||||||
| 
 |  | ||||||
|    return var |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function need_boolean(varname, required) | function need_number(path, required) | ||||||
|    local var = loadvar(varname) | 	return need_type(path, 'number', required, 'be a number') | ||||||
| 
 |  | ||||||
|    if required == false and var == nil then |  | ||||||
|       return nil |  | ||||||
|    end |  | ||||||
| 
 |  | ||||||
|    assert_type(var, 'boolean', "site.conf error: expected `" .. varname .. "' to be a boolean") |  | ||||||
| 
 |  | ||||||
|    return var |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function need_array(varname, subcheck, required) | function need_boolean(path, required) | ||||||
|    local var = loadvar(varname) | 	return need_type(path, 'boolean', required, 'be a boolean') | ||||||
| 
 |  | ||||||
|    if required == false and var == nil then |  | ||||||
|       return nil |  | ||||||
|    end |  | ||||||
| 
 |  | ||||||
|    assert_type(var, 'table', "site.conf error: expected `" .. varname .. "' to be an array") |  | ||||||
| 
 |  | ||||||
|    for _, e in ipairs(var) do |  | ||||||
|       subcheck(e) |  | ||||||
|    end |  | ||||||
| 
 |  | ||||||
|    return var |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function need_table(varname, subcheck, required) | function need_array(path, subcheck, required) | ||||||
|    local var = loadvar(varname) | 	local val = need_type(path, 'table', required, 'be an array') | ||||||
|  | 	if not val then | ||||||
|  | 		return nil | ||||||
|  | 	end | ||||||
| 
 | 
 | ||||||
|    if required == false and var == nil then | 	if subcheck then | ||||||
|       return nil | 		for i = 1, #val do | ||||||
|    end | 			subcheck(extend(path, {i})) | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
| 
 | 
 | ||||||
|    assert_type(var, 'table', "site.conf error: expected `" .. varname .. "' to be a table") | 	return val | ||||||
| 
 |  | ||||||
|    if subcheck then |  | ||||||
|       for k, v in pairs(var) do |  | ||||||
|          subcheck(k, v) |  | ||||||
|       end |  | ||||||
|    end |  | ||||||
| 
 |  | ||||||
|    return var |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function need_one_of(varname, array, required) | function need_table(path, subcheck, required) | ||||||
|    local var = loadvar(varname) | 	local val = need_type(path, 'table', required, 'be a table') | ||||||
|  | 	if not val then | ||||||
|  | 		return nil | ||||||
|  | 	end | ||||||
| 
 | 
 | ||||||
|    if required == false and var == nil then | 	if subcheck then | ||||||
|       return nil | 		for k, _ in pairs(val) do | ||||||
|    end | 			subcheck(extend(path, {k})) | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
| 
 | 
 | ||||||
|    assert_one_of(var, array, "site.conf error: expected `" .. varname .. "' to be one of given array: " .. array_to_string(array)) | 	return val | ||||||
| 
 |  | ||||||
|    return var |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function need_string_array(varname, required) | function need_value(path, value, required) | ||||||
|    local ok, var = pcall(need_array, varname, function(e) assert_type(e, 'string') end, required) | 	return need(path, function(v) | ||||||
|    assert(ok, "site.conf error: expected `" .. varname .. "' to be a string array") | 		return v == value | ||||||
|    return var | 	end, required, 'be ' .. tostring(value)) | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function need_string_array_match(varname, pat, required) | function need_one_of(path, array, required) | ||||||
|    local ok, var = pcall(need_array, varname, function(e) assert(e:match(pat)) end, required) | 	return need(path, check_one_of(array), required, 'be one of the given array ' .. array_to_string(array)) | ||||||
|    assert(ok, "site.conf error: expected `" .. varname .. "' to be a string array matching pattern `" .. pat .. "'") |  | ||||||
|    return var |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function need_array_of(varname, array, required) | function need_string_array(path, required) | ||||||
|    local ok, var = pcall(need_array, varname, function(e) assert_one_of(e, array) end,required) | 	return need_array(path, need_string, required) | ||||||
|    assert(ok, "site.conf error: expected `" .. varname .. "' to be a subset of given array: " .. array_to_string(array)) | end | ||||||
|    return var | 
 | ||||||
|  | function need_string_array_match(path, pat, required) | ||||||
|  | 	return need_array(path, function(e) need_string_match(e, pat) end, required) | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | function need_array_of(path, array, required) | ||||||
|  | 	return need_array(path, function(e) need_one_of(e, array) end, required) | ||||||
| end | end | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user