From 70aa9bb855db019e08b6931f916e67c563018a9d Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Mon, 18 Aug 2008 20:37:13 +0000 Subject: [PATCH] * luci/libs: uvl: add support for list values in schemes and configurations --- libs/uvl/luasrc/uvl.lua | 166 +++++++++++++++++++++----------------- libs/uvl/root/usr/bin/uvl | 9 ++- 2 files changed, 97 insertions(+), 78 deletions(-) diff --git a/libs/uvl/luasrc/uvl.lua b/libs/uvl/luasrc/uvl.lua index 514f75b1d..afa3cc717 100644 --- a/libs/uvl/luasrc/uvl.lua +++ b/libs/uvl/luasrc/uvl.lua @@ -46,6 +46,10 @@ STRICT_UNKNOWN_OPTIONS = true -- treat failed external validators as error STRICT_EXTERNAL_VALIDATORS = true +--- Boolean; default true; +-- treat list values stored as options like errors +STRICT_LIST_TYPE = true + local default_schemedir = "/etc/scheme" @@ -193,8 +197,8 @@ function UVL.validate_section( self, config, section ) self, co, co[section]['.type'], config, section ) ) else - return false, "Section '" .. config .. '.' .. section .. - "' not found in config. Nothing to do." + return false, 'Section "' .. config .. '.' .. section .. + '" not found in config. Nothing to do.' end end @@ -227,9 +231,9 @@ function UVL.validate_option( self, config, section, option ) self, co, co[section]['.type'], config, section, option ) ) else - return false, "Option '" .. + return false, 'Option "' .. config .. '.' .. section .. '.' .. option .. - "' not found in config. Nothing to do." + '" not found in config. Nothing to do.' end end @@ -252,7 +256,7 @@ function UVL._validate_section( self, section ) return false, err end else - print( "Error, scheme section '" .. section:sid() .. "' not found in data" ) + return false, 'Option "' .. section:sid() .. '" not found in config' end if STRICT_UNKNOWN_OPTIONS and not section:section().dynamic then @@ -271,44 +275,45 @@ end function UVL._validate_option( self, option, nodeps ) - if not option:option() and - not ( option:section() and option:section().dynamic ) - then - return false, "Option '" .. option:cid() .. - "' not found in scheme" - end + local item = option:option() + local val = option:value() - if option:option() then - if option:option().required and not option:value() then - return false, "Mandatory variable '" .. option:cid() .. - "' doesn't have a value" + if not item and not ( option:section() and option:section().dynamic ) then + 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 - if option:option().type == "enum" and option:value() then - if not option:option().values or - not option:option().values[option:value()] - then - return false, "Value '" .. ( option:value() or '' ) .. - "' of given option '" .. option:cid() .. - "' is not defined in enum { " .. - table.concat(luci.util.keys(option:option().values),", ") .. - " }" + if item.type == "enum" and val then + if not item.values or not item.values[val] then + return false, 'Value "' .. ( val or '' ) .. + '" of given option "' .. option:cid() .. + '" is not defined in enum { ' .. + table.concat( luci.util.keys(item.values), ", " ) .. + ' }' + end + elseif item.type == "list" and val then + if type(val) ~= "table" and STRICT_LIST_TYPE then + return false, 'Option "' .. option:cid() .. + '" is defined as list but stored as plain value' end end - if option:option().datatype and option:value() then - if self.datatypes[option:option().datatype] then - if not self.datatypes[option:option().datatype]( - option:value() - ) then - return false, "Value '" .. ( option:value() or '' ) .. - "' of given option '" .. option:cid() .. - "' doesn't validate as datatype '" .. - option:option().datatype .. "'" + if item.datatype and val then + if self.datatypes[item.datatype] then + if not self.datatypes[item.datatype]( val ) then + return false, 'Value "' .. ( val or '' ) .. + '" of given option "' .. option:cid() .. + '" does not validate as datatype "' .. + item.datatype .. '"' end else - return false, "Unknown datatype '" .. - option:option().datatype .. "' encountered" + return false, 'Unknown datatype "' .. + item.datatype .. '" encountered' end end @@ -346,7 +351,7 @@ function UVL.read_scheme( self, scheme ) return self:_read_scheme_parts( scheme, schemes ) else error( - 'Can\'t find scheme "' .. scheme .. + 'Can not find scheme "' .. scheme .. '" in "' .. self.schemedir .. '"' ) end @@ -426,7 +431,7 @@ function UVL._read_scheme_parts( self, scheme, schemes ) for k, v2 in pairs(v) do if k ~= "name" and k ~= "package" and k:sub(1,1) ~= "." then - if k:match("^depends") then + if k == "depends" then s["depends"] = _assert( self:_read_dependency( v2, s["depends"] ), '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 if k ~= "name" and k ~= "section" and k:sub(1,1) ~= "." then - if k:match("^depends") then + if k == "depends" then t["depends"] = _assert( self:_read_dependency( v2, t["depends"] ), 'Invalid reference "%s" in "%s.%s.%s"', v2, v.name, scheme, k ) - elseif k:match("^validator") then + elseif k == "validator" then t["validators"] = _assert( self:_read_validator( v2, t["validators"] ), '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" } ) local r = _ref( TYPE_ENUM, v ) - local p = _assert( self.packages[r[1]], 'Enum "%s" in scheme "%s" references unknown package "%s"', v.value, scheme, r[1] ) @@ -548,53 +552,63 @@ function UVL._read_scheme_parts( self, scheme, schemes ) end -- Read a dependency specification -function UVL._read_dependency( self, value, deps ) - local parts = luci.util.split( value, "%s*,%s*", nil, true ) - local condition = { } - - for i, val in ipairs(parts) do - local k, v = unpack(luci.util.split( val, "%s*=%s*", nil, true )) - - if k and ( - k:match("^%$?[a-zA-Z0-9_]+%.%$?[a-zA-Z0-9_]+%.%$?[a-zA-Z0-9_]+$") or - k:match("^%$?[a-zA-Z0-9_]+%.%$?[a-zA-Z0-9_]+$") or - k:match("^%$?[a-zA-Z0-9_]+$") - ) then - condition[k] = v or true - else - return nil - end - end +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 condition = { } + for i, val in ipairs(parts) do + local k, v = unpack(luci.util.split(val, "%s*=%s*", nil, true)) + + if k and ( + k:match("^"..expr.."%."..expr.."%."..expr.."$") or + k:match("^"..expr.."%."..expr.."$") or + k:match("^"..expr.."$") + ) then + condition[k] = v or true + else + return nil + end + end - if not deps then - deps = { condition } - else - table.insert( deps, condition ) + if not deps then + deps = { condition } + else + table.insert( deps, condition ) + end + end end return deps end -- Read a validator specification -function UVL._read_validator( self, value, validators ) - if value then - local validator - - if value:match("^exec:") then - validator = value:gsub("^exec:","") - elseif value:match("^lua:") then - validator = self:_resolve_function( (value:gsub("^lua:","") ) ) - end +function UVL._read_validator( self, values, validators ) + if values then + values = ( type(values) == "table" and values or { values } ) + for _, value in ipairs(values) do + local validator + + if value:match("^exec:") then + validator = value:gsub("^exec:","") + elseif value:match("^lua:") then + validator = self:_resolve_function( (value:gsub("^lua:","") ) ) + end - if validator then - if not validators then - validators = { validator } + if validator then + if not validators then + validators = { validator } + else + table.insert( validators, validator ) + end else - table.insert( validators, validator ) + return nil end - - return validators end + + return validators end end diff --git a/libs/uvl/root/usr/bin/uvl b/libs/uvl/root/usr/bin/uvl index cc30d0421..1631208f0 100755 --- a/libs/uvl/root/usr/bin/uvl +++ b/libs/uvl/root/usr/bin/uvl @@ -69,8 +69,8 @@ $Id$ Usage: uvl --help uvl [--silent] [--schemedir=DIR] - [--no-strict-sections] [--no-strict-options] - [--no-strict-validators] config[.section[.option]] + [--no-strict-sections] [--no-strict-options] [--no-strict-validators] + [--no-strict-lists] config[.section[.option]] Options: --help @@ -90,6 +90,9 @@ Options: --no-strict-validators Don't invalidate config if an external validator fails. + + --no-strict-lists + Don't invalidate lists that are stored options. ]=]) os.exit(255) else @@ -99,6 +102,8 @@ else ( options['no-strict-options'] and false or true ) luci.uvl.STRICT_EXTERNAL_VALIDATORS = ( 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( type(options.schemedir) == "string" and options.schemedir or nil -- 2.25.1