you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
$Id$
-- @class module
-- @cstyle instance
-local fs = require "luci.fs"
+local fs = require "nixio.fs"
local uci = require "luci.model.uci"
local util = require "luci.util"
+local nutil = require "nixio.util"
local table = require "table"
local string = require "string"
local require, pcall, ipairs, pairs = require, pcall, ipairs, pairs
local type, error, tonumber, tostring = type, error, tonumber, tostring
-local unpack, loadfile = unpack, loadfile
+local unpack, loadfile, collectgarbage = unpack, loadfile, collectgarbage
module "luci.uvl"
local TYPE_OPTION = 0x03
local TYPE_ENUM = 0x04
+local PAT_EXPR1 = "^%$?[%w_]+$"
+local PAT_EXPR2 = "^%$?[%w_]+%.%$?[%w_]+$"
+local PAT_EXPR3 = "^%$?[%w_]+%.%$?[%w_]+%.%$?[%w_]+$"
+
--- Boolean; default true;
-- treat sections found in config but not in scheme as error
STRICT_UNKNOWN_SECTIONS = true
-- @class function
-- @name UVL
-- @param schemedir Path to the scheme directory (optional)
+-- @param configdir Override config directory (optional)
-- @return Instance object
UVL = util.class()
-function UVL.__init__( self, schemedir )
+function UVL.__init__( self, schemedir, configdir )
self.schemedir = schemedir or default_schemedir
+ self.configdir = configdir
self.packages = { }
self.beenthere = { }
self.depseen = { }
if STRICT_UNKNOWN_OPTIONS and not section:scheme('dynamic') then
for k, v in pairs(section:config()) do
local oo = section:option(k)
- if k:sub(1,1) ~= "." and not self.beenthere[oo:cid()] then
+ if k:byte(1) == 46 and not self.beenthere[oo:cid()] then
section:error(ERR.OPT_UNKNOWN(oo))
end
end
end
elseif option:scheme() then
+ if not nodeps then
+ local ok, err = dependencies.check( self, option )
+ if not ok then
+ if not err:is_all(
+ ERR.ERR_OPT_REQUIRED,
+ ERR.ERR_DEP_NOTEQUAL,
+ ERR.ERR_DEP_NOVALUE
+ ) then
+ option:error(err)
+ return false, option:errors()
+ else
+ return true
+ end
+ end
+ end
+
if option:scheme('required') and not option:value() then
return false, option:error(ERR.OPT_REQUIRED(option))
return false, option:error(ERR.OPT_DATATYPE(option, dt))
end
end
-
+
val = ( type(val) == "table" and val or { val } )
for _, v in ipairs(val) do
if option:scheme('minlength') then
return false, option:error(ERR.OPT_RANGE(option))
end
end
-
+
if option:scheme('maxlength') then
if #v > option:scheme('maxlength') then
return false, option:error(ERR.OPT_RANGE(option))
end
end
-
- v = tonumber(v)
-
+
+ local w = tonumber(v)
+
if option:scheme('minimum') then
- if not v or v < option:scheme('minimum') then
+ if not w or w < option:scheme('minimum') then
return false, option:error(ERR.OPT_RANGE(option))
end
end
-
+
if option:scheme('maximum') then
- if not v or v > option:scheme('maximum') then
+ if not w or w > option:scheme('maximum') then
return false, option:error(ERR.OPT_RANGE(option))
end
end
end
-
- if not nodeps then
- local ok, err = dependencies.check( self, option )
- if not ok then
- option:error(err)
- end
- end
end
local ok, err = validation.check( self, option )
local bc = "%s/bytecode/%s.lua" %{ self.schemedir, shm }
if not fs.access(bc) then
- local files = fs.glob(self.schemedir .. '/*/' .. shm)
+ local files = nutil.consume((fs.glob(self.schemedir .. '/*/' .. shm)))
- if files then
+ if #files > 0 then
local ok, err
- for i, file in ipairs( files ) do
+ for _, file in ipairs(files) do
if not fs.access(file) then
return false, so:error(ERR.SME_READ(so,file))
end
local so = scheme:section(v.name)
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:byte(1) == 46 then
if k == "depends" then
s.depends = self:_read_dependency( v2, s.depends )
if not s.depends then
s.named = s.named or false
end
-
- -- Step 2: get all variables
+-- Step 2: get all variables
function UVL._parse_var(self, scheme, k, v)
local ok, err = _req( TYPE_OPTION, k, v, { "name", "section" } )
if err then error(scheme:error(err)) end
local to = so:option(v.name)
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:byte(1) == 46 then
if k == "depends" then
t.depends = self:_read_dependency( v2, t.depends )
if not t.depends then
t.valueof = type(v2) == "table" and v2 or {v2}
elseif k == "required" then
t[k] = _bool(v2)
- elseif k == "minlength" or k == "maxlength"
- or k == "minimum" or k == "maximum" then
+ elseif k == "minlength" or k == "maxlength" or
+ k == "minimum" or k == "maximum"
+ then
t[k] = tonumber(v2)
else
t[k] = t[k] or v2
local k, e, v = val:match("%s*([%w$_.]+)%s*(=?)%s*(.*)")
if k and (
- k:match("^"..expr.."%."..expr.."%."..expr.."$") or
- k:match("^"..expr.."%."..expr.."$") or
- k:match("^"..expr.."$")
+ k:match(PAT_EXPR1) or k:match(PAT_EXPR2) or k:match(PAT_EXPR3)
) then
condition[k] = (e == '=') and v or true
else
validator = self:_resolve_function( (value:gsub("^lua:","") ) )
elseif value:match("^regexp:") then
local pattern = value:gsub("^regexp:","")
- validator = function( type, dtype, pack, sect, optn, ... )
- local values = { ... }
+ validator = function( type, dtype, pack, sect, optn, arg1, arg2, arg3, arg4, arg5 )
+ local values = { arg1, arg2, arg3, arg4, arg5 }
for _, v in ipairs(values) do
local ok, match =
pcall( string.match, v, pattern )
local c = self.c
if c and c[r[2]] and c[r[2]]['.anonymous'] and c[r[2]]['.index'] then
r[2] = '@' .. c[r[2]]['.type'] ..
- '[' .. tostring(c[r[2]]['.index']) .. ']'
+ '[' .. tostring(c[r[2]]['.index']) .. ']'
end
return table.concat( r, '.' )
end
end
end
-function uvlitem.error(self, ...)
+function uvlitem.error(self, arg1, arg2, arg3, arg4, arg5)
if not self.e then
local errconst = { ERR.CONFIG, ERR.SECTION, ERR.OPTION, ERR.OPTION }
self.e = errconst[#self.cref]( self )
end
- return self.e:child( ... )
+ return self.e:child( arg1, arg2, arg3, arg4, arg5 )
end
function uvlitem.errors(self)
end
end
-function uvlitem._loadconf(self, co, c)
+function uvlitem._loadconf(self, co, c, configdir)
co = co or self._configcache
if not co then
local err
- co, err = uci.cursor():get_all(c)
+ co, err = uci.cursor(configdir):get_all(c)
if err then
self:error(ERR.UCILOAD(self, err))
self.cref = { c }
self.sref = { c }
- self.c = self:_loadconf(co, c)
+ self.c = self:_loadconf(co, c, scheme.configdir)
self.s = scheme
self.t = TYPE_SCHEME
end
--- Add an error to scheme.
-- @return Scheme error context
-function scheme.error(self, ...)
+function scheme.error(self, arg1, arg2, arg3, arg4, arg5)
if not self.e then self.e = ERR.SCHEME( self ) end
- return self.e:child( ... )
+ return self.e:child( arg1, arg2, arg3, arg4, arg5 )
end
--- Get an associated config object.
if not c then
c, co = co, nil
end
-
self.cref = { c }
self.sref = { c }
- self.c = self:_loadconf(co, c)
+ self.c = self:_loadconf(co, c, scheme.configdir)
self.s = scheme
self.t = TYPE_CONFIG
end
function section.__init__(self, scheme, co, c, s)
self.cref = { c, s }
self.sref = { c, co and co[s] and co[s]['.type'] or s }
- self.c = self:_loadconf(co, c)
+ self.c = self:_loadconf(co, c, scheme.configdir)
self.s = scheme
self.t = TYPE_SECTION
end
function option.__init__(self, scheme, co, c, s, o)
self.cref = { c, s, o }
self.sref = { c, co and co[s] and co[s]['.type'] or s, o }
- self.c = self:_loadconf(co, c)
+ self.c = self:_loadconf(co, c, scheme.configdir)
self.s = scheme
self.t = TYPE_OPTION
end
function enum.__init__(self, scheme, co, c, s, o, v)
self.cref = { c, s, o, v }
self.sref = { c, co and co[s] and co[s]['.type'] or s, o, v }
- self.c = self:_loadconf(co, c)
+ self.c = self:_loadconf(co, c, scheme.configdir)
self.s = scheme
self.t = TYPE_ENUM
end