X-Git-Url: https://git.archive.openwrt.org/?p=project%2Fluci.git;a=blobdiff_plain;f=libs%2Fcbi%2Fluasrc%2Fcbi.lua;h=09ba553ec2f0f985b6ef8d6717bf2c8e306cf4ab;hp=12bf18c2adfc9be39ee0269537814e50957d863b;hb=9befed193ae828c2b58390e8c0efafdab37f45b8;hpb=d463d0b8357764ca9018549fa624c428f56fcd87 diff --git a/libs/cbi/luasrc/cbi.lua b/libs/cbi/luasrc/cbi.lua index 12bf18c2a..09ba553ec 100644 --- a/libs/cbi/luasrc/cbi.lua +++ b/libs/cbi/luasrc/cbi.lua @@ -47,24 +47,27 @@ REMOVE_PREFIX = "cbi.rts." -- Loads a CBI map from given file, creating an environment and returns it function load(cbimap, ...) require("luci.fs") - require("luci.i18n") + local i18n = require "luci.i18n" require("luci.config") require("luci.util") local cbidir = luci.util.libpath() .. "/model/cbi/" - local func, err = loadfile(cbidir..cbimap..".lua") - - if not func then - return nil - end + local func, err = loadfile(cbimap) or loadfile(cbidir..cbimap..".lua") + assert(func, err) luci.i18n.loadc("cbi") + luci.i18n.loadc("uvl") - luci.util.resfenv(func) - luci.util.updfenv(func, luci.cbi) - luci.util.extfenv(func, "translate", luci.i18n.translate) - luci.util.extfenv(func, "translatef", luci.i18n.translatef) - luci.util.extfenv(func, "arg", {...}) + local env = { + translate=i18n.translate, + translatef=i18n.translatef, + arg={...} + } + + setfenv(func, setmetatable(env, {__index = + function(tbl, key) + return rawget(tbl, key) or _M[key] or _G[key] + end})) local maps = {func()} @@ -78,8 +81,42 @@ function load(cbimap, ...) return maps end +local function _uvl_validate_section(node, name) + local co = node.map:get() + + luci.uvl.STRICT_UNKNOWN_OPTIONS = false + luci.uvl.STRICT_UNKNOWN_SECTIONS = false -function _uvl_strip_remote_dependencies(deps) + local function tag_fields(e) + if e.option and node.fields[e.option] then + node.fields[e.option].error = e + elseif e.childs then + for _, c in ipairs(e.childs) do tag_fields(c) end + end + end + + local function tag_section(e) + local s = { } + for _, c in ipairs(e.childs) do + if c.childs and not c:is(luci.uvl.errors.ERR_DEPENDENCY) then + table.insert( s, c.childs[1]:string() ) + else + table.insert( s, c:string() ) + end + end + if #s > 0 then node.error = s end + end + + local stat, err = node.map.validator:validate_section(node.config, name, co) + if err then + node.map.save = false + tag_fields(err) + tag_section(err) + end + +end + +local function _uvl_strip_remote_dependencies(deps) local clean = {} for k, v in pairs(deps) do @@ -174,13 +211,16 @@ function Map.__init__(self, config, ...) self.config = config self.parsechain = {self.config} self.template = "cbi/map" + self.apply_on_parse = nil self.uci = uci.cursor() + self.save = true if not self.uci:load(self.config) then error("Unable to read UCI data: " .. self.config) end self.validator = luci.uvl.UVL() self.scheme = self.validator:get_scheme(self.config) + end function Map.get_scheme(self, sectiontype, option) @@ -202,24 +242,42 @@ end function Map.parse(self, ...) Node.parse(self, ...) - for i, config in ipairs(self.parsechain) do - self.uci:save(config) - end - if luci.http.formvalue("cbi.apply") then + if self.save then for i, config in ipairs(self.parsechain) do - self.uci:commit(config) - self.uci:apply(config) - - -- Refresh data because commit changes section names - self.uci:load(config) + self.uci:save(config) end + if luci.http.formvalue("cbi.apply") then + for i, config in ipairs(self.parsechain) do + self.uci:commit(config) + + -- Refresh data because commit changes section names + self.uci:load(config) + end + if self.apply_on_parse then + self.uci:apply(self.parsechain) + else + self._apply = function() + local cmd = self.uci:apply(self.parsechain, true) + return io.popen(cmd) + end + end - -- Reparse sections - Node.parse(self, ...) + -- Reparse sections + Node.parse(self, ...) + end + for i, config in ipairs(self.parsechain) do + self.uci:unload(config) + end end - for i, config in ipairs(self.parsechain) do - self.uci:unload(config) +end + +function Map.render(self, ...) + Node.render(self, ...) + if self._apply then + local fp = self._apply() + fp:read("*a") + fp:close() end end @@ -343,7 +401,7 @@ function SimpleForm.field(self, class, ...) end if instanceof(class, AbstractValue) then - local obj = class(self, ...) + local obj = class(self, section, ...) obj.track_missing = true section:append(obj) return obj @@ -385,6 +443,10 @@ function AbstractSection.__init__(self, map, sectiontype, ...) self.config = map.config self.optionals = {} self.defaults = {} + self.fields = {} + self.tag_error = {} + self.tag_invalid = {} + self.tag_deperror = {} self.optional = true self.addremove = false @@ -413,6 +475,7 @@ function AbstractSection.option(self, class, option, ...) Node._i18n(obj, self.config, self.section or self.sectiontype, option, ...) self:append(obj) + self.fields[option] = obj return obj elseif class == true then error("No valid class was given and autodetection failed.") @@ -597,7 +660,6 @@ function NamedSection.parse(self) local s = self.section local active = self:cfgvalue(s) - if self.addremove then local path = self.config.."."..s if active then -- Remove the section @@ -616,6 +678,10 @@ function NamedSection.parse(self) AbstractSection.parse_dynamic(self, s) if luci.http.formvalue("cbi.submit") then Node.parse(self, s) + + if not self.override_scheme and self.map.scheme then + _uvl_validate_section(self, s) + end end AbstractSection.parse_optionals(self, s) end @@ -669,12 +735,40 @@ end function TypedSection.parse(self) if self.addremove then + -- Remove + local crval = REMOVE_PREFIX .. self.config + local name = luci.http.formvaluetable(crval) + for k,v in pairs(name) do + if k:sub(-2) == ".x" then + k = k:sub(1, #k - 2) + end + if self:cfgvalue(k) and self:checkscope(k) then + self:remove(k) + end + end + end + + local co + for i, k in ipairs(self:cfgsections()) do + AbstractSection.parse_dynamic(self, k) + if luci.http.formvalue("cbi.submit") then + Node.parse(self, k) + + if not self.override_scheme and self.map.scheme then + _uvl_validate_section(self, k) + end + end + AbstractSection.parse_optionals(self, k) + end + + if self.addremove then -- Create + local created local crval = CREATE_PREFIX .. self.config .. "." .. self.sectiontype local name = luci.http.formvalue(crval) if self.anonymous then if name then - self:create() + created = self:create() end else if name then @@ -690,27 +784,14 @@ function TypedSection.parse(self) end if name and #name > 0 then - self:create(name) + created = self:create(name) and name end end end - -- Remove - crval = REMOVE_PREFIX .. self.config - name = luci.http.formvaluetable(crval) - for k,v in pairs(name) do - if self:cfgvalue(k) and self:checkscope(k) then - self:remove(k) - end - end - end - - for i, k in ipairs(self:cfgsections()) do - AbstractSection.parse_dynamic(self, k) - if luci.http.formvalue("cbi.submit") then - Node.parse(self, k) + if created then + AbstractSection.parse_optionals(self, created) end - AbstractSection.parse_optionals(self, k) end end @@ -766,6 +847,7 @@ function AbstractValue.__init__(self, map, section, option, ...) self.config = map.config self.tag_invalid = {} self.tag_missing = {} + self.tag_reqerror = {} self.tag_error = {} self.deps = {} self.cast = "string" @@ -784,6 +866,7 @@ function AbstractValue.__init__(self, map, section, option, ...) self.cast = (vs.type == "list") and "list" or "string" self.title = self.title or vs.title self.description = self.description or vs.descr + self.default = vs.default if vs.depends and not self.override_dependencies then for i, deps in ipairs(vs.depends) do @@ -1011,8 +1094,11 @@ function ListValue.__init__(self, ...) end for k, v in pairs(vs.values) do local deps = {} - if vs.enum_depends and vs.enum_depends[k] then - deps = _uvl_strip_remote_dependencies(vs.enum_depends[k]) + if not self.override_dependencies + and vs.enum_depends and vs.enum_depends[k] then + for i, dep in ipairs(vs.enum_depends[k]) do + table.insert(deps, _uvl_strip_remote_dependencies(dep)) + end end self:value(k, v, unpack(deps)) end @@ -1021,6 +1107,10 @@ function ListValue.__init__(self, ...) end function ListValue.value(self, key, val, ...) + if luci.util.contains(self.keylist, key) then + return + end + val = val or key table.insert(self.keylist, tostring(key)) table.insert(self.vallist, tostring(val)) @@ -1067,6 +1157,10 @@ function MultiValue.render(self, ...) end function MultiValue.value(self, key, val) + if luci.util.contains(self.keylist, key) then + return + end + val = val or key table.insert(self.keylist, tostring(key)) table.insert(self.vallist, tostring(val)) @@ -1149,8 +1243,9 @@ function DynamicList.validate(self, value, section) local valid = {} for i, v in ipairs(value) do - if v and #v > 0 and - not luci.http.formvalue("cbi.rle."..section.."."..self.option.."."..i) then + if v and #v > 0 + and not luci.http.formvalue("cbi.rle."..section.."."..self.option.."."..i) + and not luci.http.formvalue("cbi.rle."..section.."."..self.option.."."..i..".x") then table.insert(valid, v) end end