* luci/libs: uvl: add support for list values in schemes and configurations

This commit is contained in:
Jo-Philipp Wich 2008-08-18 20:37:13 +00:00
parent 63c48c8dde
commit 70aa9bb855
2 changed files with 95 additions and 76 deletions

View file

@ -46,6 +46,10 @@ STRICT_UNKNOWN_OPTIONS = true
-- treat failed external validators as error -- treat failed external validators as error
STRICT_EXTERNAL_VALIDATORS = true STRICT_EXTERNAL_VALIDATORS = true
--- Boolean; default true;
-- treat list values stored as options like errors
STRICT_LIST_TYPE = true
local default_schemedir = "/etc/scheme" local default_schemedir = "/etc/scheme"
@ -193,8 +197,8 @@ function UVL.validate_section( self, config, section )
self, co, co[section]['.type'], config, section self, co, co[section]['.type'], config, section
) ) ) )
else else
return false, "Section '" .. config .. '.' .. section .. return false, 'Section "' .. config .. '.' .. section ..
"' not found in config. Nothing to do." '" not found in config. Nothing to do.'
end end
end end
@ -227,9 +231,9 @@ function UVL.validate_option( self, config, section, option )
self, co, co[section]['.type'], config, section, option self, co, co[section]['.type'], config, section, option
) ) ) )
else else
return false, "Option '" .. return false, 'Option "' ..
config .. '.' .. section .. '.' .. option .. config .. '.' .. section .. '.' .. option ..
"' not found in config. Nothing to do." '" not found in config. Nothing to do.'
end end
end end
@ -252,7 +256,7 @@ function UVL._validate_section( self, section )
return false, err return false, err
end end
else else
print( "Error, scheme section '" .. section:sid() .. "' not found in data" ) return false, 'Option "' .. section:sid() .. '" not found in config'
end end
if STRICT_UNKNOWN_OPTIONS and not section:section().dynamic then if STRICT_UNKNOWN_OPTIONS and not section:section().dynamic then
@ -271,44 +275,45 @@ end
function UVL._validate_option( self, option, nodeps ) function UVL._validate_option( self, option, nodeps )
if not option:option() and local item = option:option()
not ( option:section() and option:section().dynamic ) local val = option:value()
then
return false, "Option '" .. option:cid() .. if not item and not ( option:section() and option:section().dynamic ) then
"' not found in scheme" return false, 'Option "' .. option:cid() ..
'" not found in scheme'
elseif item then
if item.required and not val then
return false, 'Mandatory variable "' .. option:cid() ..
'" does not have a value'
end end
if option:option() then if item.type == "enum" and val then
if option:option().required and not option:value() then if not item.values or not item.values[val] then
return false, "Mandatory variable '" .. option:cid() .. return false, 'Value "' .. ( val or '<nil>' ) ..
"' doesn't have a value" '" of given option "' .. option:cid() ..
'" is not defined in enum { ' ..
table.concat( luci.util.keys(item.values), ", " ) ..
' }'
end end
elseif item.type == "list" and val then
if option:option().type == "enum" and option:value() then if type(val) ~= "table" and STRICT_LIST_TYPE then
if not option:option().values or return false, 'Option "' .. option:cid() ..
not option:option().values[option:value()] '" is defined as list but stored as plain value'
then
return false, "Value '" .. ( option:value() or '<nil>' ) ..
"' of given option '" .. option:cid() ..
"' is not defined in enum { " ..
table.concat(luci.util.keys(option:option().values),", ") ..
" }"
end end
end end
if option:option().datatype and option:value() then if item.datatype and val then
if self.datatypes[option:option().datatype] then if self.datatypes[item.datatype] then
if not self.datatypes[option:option().datatype]( if not self.datatypes[item.datatype]( val ) then
option:value() return false, 'Value "' .. ( val or '<nil>' ) ..
) then '" of given option "' .. option:cid() ..
return false, "Value '" .. ( option:value() or '<nil>' ) .. '" does not validate as datatype "' ..
"' of given option '" .. option:cid() .. item.datatype .. '"'
"' doesn't validate as datatype '" ..
option:option().datatype .. "'"
end end
else else
return false, "Unknown datatype '" .. return false, 'Unknown datatype "' ..
option:option().datatype .. "' encountered" item.datatype .. '" encountered'
end end
end end
@ -346,7 +351,7 @@ function UVL.read_scheme( self, scheme )
return self:_read_scheme_parts( scheme, schemes ) return self:_read_scheme_parts( scheme, schemes )
else else
error( error(
'Can\'t find scheme "' .. scheme .. 'Can not find scheme "' .. scheme ..
'" in "' .. self.schemedir .. '"' '" in "' .. self.schemedir .. '"'
) )
end end
@ -426,7 +431,7 @@ function UVL._read_scheme_parts( self, scheme, schemes )
for k, v2 in pairs(v) do for k, v2 in pairs(v) do
if k ~= "name" and k ~= "package" and k:sub(1,1) ~= "." then if k ~= "name" and k ~= "package" and k:sub(1,1) ~= "." then
if k:match("^depends") then if k == "depends" then
s["depends"] = _assert( s["depends"] = _assert(
self:_read_dependency( v2, s["depends"] ), self:_read_dependency( v2, s["depends"] ),
'Section "%s" in scheme "%s" has malformed ' .. 'Section "%s" in scheme "%s" has malformed ' ..
@ -471,13 +476,13 @@ function UVL._read_scheme_parts( self, scheme, schemes )
for k, v2 in pairs(v) do for k, v2 in pairs(v) do
if k ~= "name" and k ~= "section" and k:sub(1,1) ~= "." then if k ~= "name" and k ~= "section" and k:sub(1,1) ~= "." then
if k:match("^depends") then if k == "depends" then
t["depends"] = _assert( t["depends"] = _assert(
self:_read_dependency( v2, t["depends"] ), self:_read_dependency( v2, t["depends"] ),
'Invalid reference "%s" in "%s.%s.%s"', 'Invalid reference "%s" in "%s.%s.%s"',
v2, v.name, scheme, k v2, v.name, scheme, k
) )
elseif k:match("^validator") then elseif k == "validator" then
t["validators"] = _assert( t["validators"] = _assert(
self:_read_validator( v2, t["validators"] ), self:_read_validator( v2, t["validators"] ),
'Variable "%s" in scheme "%s" has malformed ' .. 'Variable "%s" in scheme "%s" has malformed ' ..
@ -507,7 +512,6 @@ function UVL._read_scheme_parts( self, scheme, schemes )
_req( TYPE_ENUM, v, { "value", "variable" } ) _req( TYPE_ENUM, v, { "value", "variable" } )
local r = _ref( TYPE_ENUM, v ) local r = _ref( TYPE_ENUM, v )
local p = _assert( self.packages[r[1]], local p = _assert( self.packages[r[1]],
'Enum "%s" in scheme "%s" references unknown package "%s"', 'Enum "%s" in scheme "%s" references unknown package "%s"',
v.value, scheme, r[1] ) v.value, scheme, r[1] )
@ -548,17 +552,20 @@ function UVL._read_scheme_parts( self, scheme, schemes )
end end
-- Read a dependency specification -- Read a dependency specification
function UVL._read_dependency( self, value, deps ) function UVL._read_dependency( self, values, deps )
local expr = "%$?[a-zA-Z0-9_]+"
if values then
values = ( type(values) == "table" and values or { values } )
for _, value in ipairs(values) do
local parts = luci.util.split( value, "%s*,%s*", nil, true ) local parts = luci.util.split( value, "%s*,%s*", nil, true )
local condition = { } local condition = { }
for i, val in ipairs(parts) do for i, val in ipairs(parts) do
local k, v = unpack(luci.util.split( val, "%s*=%s*", nil, true )) local k, v = unpack(luci.util.split(val, "%s*=%s*", nil, true))
if k and ( if k and (
k:match("^%$?[a-zA-Z0-9_]+%.%$?[a-zA-Z0-9_]+%.%$?[a-zA-Z0-9_]+$") or k:match("^"..expr.."%."..expr.."%."..expr.."$") or
k:match("^%$?[a-zA-Z0-9_]+%.%$?[a-zA-Z0-9_]+$") or k:match("^"..expr.."%."..expr.."$") or
k:match("^%$?[a-zA-Z0-9_]+$") k:match("^"..expr.."$")
) then ) then
condition[k] = v or true condition[k] = v or true
else else
@ -571,13 +578,17 @@ function UVL._read_dependency( self, value, deps )
else else
table.insert( deps, condition ) table.insert( deps, condition )
end end
end
end
return deps return deps
end end
-- Read a validator specification -- Read a validator specification
function UVL._read_validator( self, value, validators ) function UVL._read_validator( self, values, validators )
if value then if values then
values = ( type(values) == "table" and values or { values } )
for _, value in ipairs(values) do
local validator local validator
if value:match("^exec:") then if value:match("^exec:") then
@ -592,10 +603,13 @@ function UVL._read_validator( self, value, validators )
else else
table.insert( validators, validator ) table.insert( validators, validator )
end end
else
return nil
end
end
return validators return validators
end end
end
end end
-- Resolve given path -- Resolve given path

View file

@ -69,8 +69,8 @@ $Id$
Usage: Usage:
uvl --help uvl --help
uvl [--silent] [--schemedir=DIR] uvl [--silent] [--schemedir=DIR]
[--no-strict-sections] [--no-strict-options] [--no-strict-sections] [--no-strict-options] [--no-strict-validators]
[--no-strict-validators] config[.section[.option]] [--no-strict-lists] config[.section[.option]]
Options: Options:
--help --help
@ -90,6 +90,9 @@ Options:
--no-strict-validators --no-strict-validators
Don't invalidate config if an external validator fails. Don't invalidate config if an external validator fails.
--no-strict-lists
Don't invalidate lists that are stored options.
]=]) ]=])
os.exit(255) os.exit(255)
else else
@ -99,6 +102,8 @@ else
( options['no-strict-options'] and false or true ) ( options['no-strict-options'] and false or true )
luci.uvl.STRICT_EXTERNAL_VALIDATORS = luci.uvl.STRICT_EXTERNAL_VALIDATORS =
( options['no-strict-validators'] and false or true ) ( options['no-strict-validators'] and false or true )
luci.uvl.STRICT_LIST_TYPE =
( options['no-strict-lists'] and false or true )
local uvl = luci.uvl.UVL( local uvl = luci.uvl.UVL(
type(options.schemedir) == "string" and options.schemedir or nil type(options.schemedir) == "string" and options.schemedir or nil