* luci/libs: uvl: add support for list values in schemes and configurations
authorJo-Philipp Wich <jow@openwrt.org>
Mon, 18 Aug 2008 20:37:13 +0000 (20:37 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Mon, 18 Aug 2008 20:37:13 +0000 (20:37 +0000)
libs/uvl/luasrc/uvl.lua
libs/uvl/root/usr/bin/uvl

index 514f75b1dc0e69cedb407aba1c55a45565b4fe8b..afa3cc71701aa7baba06ee39f53229a54c9406db 100644 (file)
@@ -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 '<nil>' ) ..
-                                       "' 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 '<nil>' ) ..
+                                       '" 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 '<nil>' ) ..
-                                               "' 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 '<nil>' ) ..
+                                               '" 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
 
index cc30d042148232286ee0f4dbf415731848f37223..1631208f067151669410fcfb4f85b076c46298f1 100755 (executable)
@@ -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