Scheme parsing optimizations

This commit is contained in:
Steven Barth 2008-09-09 15:39:10 +00:00
parent 68ecfaf698
commit c287c8ca7e

View file

@ -362,6 +362,7 @@ function UVL.read_scheme( self, scheme, alias )
local files = luci.fs.glob(self.schemedir .. '/*/' .. scheme) local files = luci.fs.glob(self.schemedir .. '/*/' .. scheme)
if files then if files then
local ok, err
for i, file in ipairs( files ) do for i, file in ipairs( files ) do
if not luci.fs.access(file) then if not luci.fs.access(file) then
return false, so:error(ERR.SME_READ(so,file)) return false, so:error(ERR.SME_READ(so,file))
@ -369,18 +370,32 @@ function UVL.read_scheme( self, scheme, alias )
local uci = luci.model.uci.cursor( luci.fs.dirname(file), default_savedir ) local uci = luci.model.uci.cursor( luci.fs.dirname(file), default_savedir )
local sd, err = uci:get_all( luci.fs.basename(file) ) local sname = luci.fs.basename(file)
local sd, err = uci:load( sname )
if not sd then if not sd then
return false, ERR.UCILOAD(so, err) return false, ERR.UCILOAD(so, err)
end end
table.insert( schemes, sd ) ok, err = pcall(function()
uci:foreach(sname, "package", function(s)
self:_parse_package(so, s[".name"], s)
end)
uci:foreach(sname, "section", function(s)
self:_parse_section(so, s[".name"], s)
end)
uci:foreach(sname, "variable", function(s)
self:_parse_var(so, s[".name"], s)
end)
uci:foreach(sname, "enum", function(s)
self:_parse_enum(so, s[".name"], s)
end)
end)
end end
local ok, err = self:_read_scheme_parts( so, schemes )
if ok and alias then self.packages[alias] = self.packages[scheme] end if ok and alias then self.packages[alias] = self.packages[scheme] end
return ok, err return ok and self, err
else else
return false, so:error(ERR.SME_FIND(so, self.schemedir)) return false, so:error(ERR.SME_FIND(so, self.schemedir))
end end
@ -395,9 +410,6 @@ function UVL.read_scheme( self, scheme, alias )
end end
end end
-- Process all given parts and construct validation tree
function UVL._read_scheme_parts( self, scheme, schemes )
-- helper function to check for required fields -- helper function to check for required fields
local function _req( t, n, c, r ) local function _req( t, n, c, r )
for i, v in ipairs(r) do for i, v in ipairs(r) do
@ -447,50 +459,37 @@ function UVL._read_scheme_parts( self, scheme, schemes )
return ( v == "true" or v == "yes" or v == "on" or v == "1" ) return ( v == "true" or v == "yes" or v == "on" or v == "1" )
end end
local ok, err
-- Step 0: get package meta information -- Step 0: get package meta information
for i, conf in ipairs( schemes ) do function UVL._parse_package(self, scheme, k, v)
for k, v in pairs( conf ) do local sid = scheme:sid()
if v['.type'] == 'package' then local pkg = self.packages[sid] or {
self.packages[scheme:sid()] = ["name"] = sid;
self.packages[scheme:sid()] or {
["name"] = scheme:sid();
["sections"] = { }; ["sections"] = { };
["variables"] = { }; ["variables"] = { };
} }
for k, v2 in pairs(v) do pkg.title = v.title
if k == "title" or k == "description" then pkg.description = v.description
self.packages[scheme:sid()][k] = v2
end self.packages[sid] = pkg
end
end
end
end end
-- Step 1: get all sections -- Step 1: get all sections
for i, conf in ipairs( schemes ) do function UVL._parse_section(self, scheme, k, v)
for k, v in pairs( conf ) do local ok, err = _req( TYPE_SECTION, k, v, { "name", "package" } )
if v['.type'] == 'section' then if err then error(scheme:error(err)) end
ok, err = _req( TYPE_SECTION, k, v, { "name", "package" } )
if err then return false, scheme:error(err) end
local r, err = _ref( TYPE_SECTION, v ) local r, err = _ref( TYPE_SECTION, v )
if err then return false, scheme:error(err) end if err then error(scheme:error(err)) end
self.packages[r[1]] = local p = self.packages[r[1]] or {
self.packages[r[1]] or {
["name"] = r[1]; ["name"] = r[1];
["sections"] = { }; ["sections"] = { };
["variables"] = { }; ["variables"] = { };
} }
local p = self.packages[r[1]]
p.sections[v.name] = p.sections[v.name] or { } p.sections[v.name] = p.sections[v.name] or { }
p.variables[v.name] = p.variables[v.name] or { } p.variables[v.name] = p.variables[v.name] or { }
self.packages[r[1]] = p
local s = p.sections[v.name] local s = p.sections[v.name]
local so = scheme:section(v.name) local so = scheme:section(v.name)
@ -519,32 +518,28 @@ function UVL._read_scheme_parts( self, scheme, schemes )
s.required = s.required or false s.required = s.required or false
s.named = s.named or false s.named = s.named or false
end end
end
end
-- Step 2: get all variables -- Step 2: get all variables
for i, conf in ipairs( schemes ) do function UVL._parse_var(self, scheme, k, v)
for k, v in pairs( conf ) do local ok, err = _req( TYPE_OPTION, k, v, { "name", "section" } )
if v['.type'] == "variable" then if err then error(scheme:error(err)) end
ok, err = _req( TYPE_OPTION, k, v, { "name", "section" } )
if err then return false, scheme:error(err) end
local r, err = _ref( TYPE_OPTION, v ) local r, err = _ref( TYPE_OPTION, v )
if err then return false, scheme:error(err) end if err then error(scheme:error(err)) end
local p = self.packages[r[1]] local p = self.packages[r[1]]
if not p then if not p then
return false, scheme:error( error(scheme:error(
ERR.SME_VBADPACK({scheme:sid(), '', v.name}, r[1]) ERR.SME_VBADPACK({scheme:sid(), '', v.name}, r[1])
) ))
end end
local s = p.variables[r[2]] local s = p.variables[r[2]]
if not s then if not s then
return false, scheme:error( error(scheme:error(
ERR.SME_VBADSECT({scheme:sid(), '', v.name}, r[2]) ERR.SME_VBADSECT({scheme:sid(), '', v.name}, r[2])
) ))
end end
s[v.name] = s[v.name] or { } s[v.name] = s[v.name] or { }
@ -558,23 +553,23 @@ function UVL._read_scheme_parts( self, scheme, schemes )
if k == "depends" then if k == "depends" then
t.depends = self:_read_dependency( v2, t.depends ) t.depends = self:_read_dependency( v2, t.depends )
if not t.depends then if not t.depends then
return false, scheme:error(so:error( error(scheme:error(so:error(
ERR.SME_BADDEP(to, luci.util.serialize_data(v2)) ERR.SME_BADDEP(to, luci.util.serialize_data(v2))
)) )))
end end
elseif k == "validator" then elseif k == "validator" then
t.validators = self:_read_validator( v2, t.validators ) t.validators = self:_read_validator( v2, t.validators )
if not t.validators then if not t.validators then
return false, scheme:error(so:error( error(scheme:error(so:error(
ERR.SME_BADVAL(to, luci.util.serialize_data(v2)) ERR.SME_BADVAL(to, luci.util.serialize_data(v2))
)) )))
end end
elseif k == "valueof" then elseif k == "valueof" then
local values, err = self:_read_reference( v2 ) local values, err = self:_read_reference( v2 )
if err then if err then
return false, scheme:error(so:error( error(scheme:error(so:error(
ERR.REFERENCE(to, luci.util.serialize_data(v2)):child(err) ERR.REFERENCE(to, luci.util.serialize_data(v2)):child(err)
)) )))
end end
t.type = "reference" t.type = "reference"
t.values = values t.values = values
@ -590,39 +585,34 @@ function UVL._read_scheme_parts( self, scheme, schemes )
t.datatype = t.datatype or "string" t.datatype = t.datatype or "string"
t.required = t.required or false t.required = t.required or false
end end
end
end
-- Step 3: get all enums -- Step 3: get all enums
for i, conf in ipairs( schemes ) do function UVL._parse_enum(self, scheme, k, v)
for k, v in pairs( conf ) do local ok, err = _req( TYPE_ENUM, k, v, { "value", "variable" } )
if v['.type'] == "enum" then if err then error(scheme:error(err)) end
ok, err = _req( TYPE_ENUM, k, v, { "value", "variable" } )
if err then return false, scheme:error(err) end
local r, err = _ref( TYPE_ENUM, v ) local r, err = _ref( TYPE_ENUM, v )
if err then return false, scheme:error(err) end if err then error(scheme:error(err)) end
local p = self.packages[r[1]] local p = self.packages[r[1]]
if not p then if not p then
return false, scheme:error( error(scheme:error(
ERR.SME_EBADPACK({scheme:sid(), '', '', v.value}, r[1]) ERR.SME_EBADPACK({scheme:sid(), '', '', v.value}, r[1])
) ))
end end
local s = p.variables[r[2]] local s = p.variables[r[2]]
if not s then if not s then
return false, scheme:error( error(scheme:error(
ERR.SME_EBADSECT({scheme:sid(), '', '', v.value}, r[2]) ERR.SME_EBADSECT({scheme:sid(), '', '', v.value}, r[2])
) ))
end end
local t = s[r[3]] local t = s[r[3]]
if not t then if not t then
return false, scheme:error( error(scheme:error(
ERR.SME_EBADOPT({scheme:sid(), '', '', v.value}, r[3]) ERR.SME_EBADOPT({scheme:sid(), '', '', v.value}, r[3])
) ))
end end
@ -631,7 +621,7 @@ function UVL._read_scheme_parts( self, scheme, schemes )
local eo = oo:enum(v.value) local eo = oo:enum(v.value)
if t.type ~= "enum" and t.type ~= "reference" then if t.type ~= "enum" and t.type ~= "reference" then
return false, scheme:error(ERR.SME_EBADTYPE(eo)) error(scheme:error(ERR.SME_EBADTYPE(eo)))
end end
if not t.values then if not t.values then
@ -646,7 +636,7 @@ function UVL._read_scheme_parts( self, scheme, schemes )
if v.default then if v.default then
if t.default then if t.default then
return false, scheme:error(ERR.SME_EBADDEF(eo)) error(scheme:error(ERR.SME_EBADDEF(eo)))
end end
t.default = v.value t.default = v.value
end end
@ -657,17 +647,12 @@ function UVL._read_scheme_parts( self, scheme, schemes )
) )
if not t.enum_depends[v.value] then if not t.enum_depends[v.value] then
return false, scheme:error(so:error(oo:error( error(scheme:error(so:error(oo:error(
ERR.SME_BADDEP(eo, luci.util.serialize_data(v.depends)) ERR.SME_BADDEP(eo, luci.util.serialize_data(v.depends))
))) ))))
end end
end end
end end
end
end
return self
end
-- Read a dependency specification -- Read a dependency specification
function UVL._read_dependency( self, values, deps ) function UVL._read_dependency( self, values, deps )