4ff6e7f3c1e571b060bf115f208f9e7e2a45634c
[project/luci.git] / libs / uvl / luasrc / uvl.lua
1 --[[
2
3 UCI Validation Layer - Main Library
4 (c) 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
5 (c) 2008 Steven Barth <steven@midlink.org>
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 $Id$
14
15 ]]--
16
17
18 --- UVL - UCI Validation Layer
19 -- @class module
20 -- @cstyle instance
21
22 module( "luci.uvl", package.seeall )
23
24 require("luci.fs")
25 require("luci.util")
26 require("luci.model.uci")
27 require("luci.uvl.errors")
28 require("luci.uvl.datatypes")
29 require("luci.uvl.validation")
30 require("luci.uvl.dependencies")
31
32
33 TYPE_SCHEME = 0x00
34 TYPE_CONFIG = 0x01
35 TYPE_SECTION = 0x02
36 TYPE_VARIABLE = 0x03
37 TYPE_OPTION = 0x04
38 TYPE_ENUM = 0x05
39
40 --- Boolean; default true;
41 -- treat sections found in config but not in scheme as error
42 STRICT_UNKNOWN_SECTIONS = true
43
44 --- Boolean; default true;
45 -- treat options found in config but not in scheme as error
46 STRICT_UNKNOWN_OPTIONS = true
47
48 --- Boolean; default true;
49 -- treat failed external validators as error
50 STRICT_EXTERNAL_VALIDATORS = true
51
52 --- Boolean; default true;
53 -- treat list values stored as options like errors
54 STRICT_LIST_TYPE = true
55
56
57 local default_schemedir = "/lib/uci/schema"
58 local default_savedir = "/tmp/.uvl"
59 local ERR = luci.uvl.errors
60
61
62 --- Object constructor
63 -- @class function
64 -- @name UVL
65 -- @param schemedir Path to the scheme directory (optional)
66 -- @return Instance object
67 UVL = luci.util.class()
68
69 function UVL.__init__( self, schemedir )
70 self.schemedir = schemedir or default_schemedir
71 self.packages = { }
72 self.beenthere = { }
73 self.depseen = { }
74 self.uci = luci.model.uci
75 self.err = luci.uvl.errors
76 self.dep = luci.uvl.dependencies
77 self.datatypes = luci.uvl.datatypes
78 end
79
80
81 --- Parse given scheme and return the scheme tree.
82 -- @param scheme Name of the scheme to parse
83 -- @return Table containing the parsed scheme or nil on error
84 -- @return String containing the reason for errors (if any)
85 function UVL.get_scheme( self, scheme )
86 if not self.packages[scheme] then
87 local ok, err = self:read_scheme( scheme )
88 if not ok then
89 return nil, err
90 end
91 end
92 return self.packages[scheme], nil
93 end
94
95 --- Validate given configuration, section or option.
96 -- @param config Name of the configuration to validate
97 -- @param section Name of the section to validate (optional)
98 -- @param option Name of the option to validate (optional)
99 -- @return Boolean indicating whether the given config validates
100 -- @return String containing the reason for errors (if any)
101 function UVL.validate( self, config, section, option )
102 if config and section and option then
103 return self:validate_option( config, section, option )
104 elseif config and section then
105 return self:validate_section( config, section )
106 elseif config then
107 return self:validate_config( config )
108 end
109 end
110
111 --- Validate given configuration.
112 -- @param config Name of the configuration to validate
113 -- @return Boolean indicating whether the given config validates
114 -- @return String containing the reason for errors (if any)
115 function UVL.validate_config( self, config, uci )
116
117 if not self.packages[config] then
118 local ok, err = self:read_scheme(config)
119 if not ok then
120 return false, err
121 end
122 end
123
124 local co = luci.uvl.config( self, uci or config, uci and config )
125 local sc = { }
126
127 self.beenthere = { }
128 self.depseen = { }
129
130 if not co:config() then
131 return false, co:errors()
132 end
133
134 local function _uci_foreach( type, func )
135 for k, v in pairs(co:config()) do
136 if v['.type'] == type then
137 sc[type] = sc[type] + 1
138 local ok, err = func( k, v )
139 if not ok then co:error(err) end
140 end
141 end
142 end
143
144 for k, v in pairs( self.packages[config].sections ) do
145 sc[k] = 0
146 _uci_foreach( k,
147 function(s)
148 return self:_validate_section( co:section(s) )
149 end
150 )
151 end
152
153 if STRICT_UNKNOWN_SECTIONS then
154 for k, v in pairs(co:config()) do
155 local so = co:section(k)
156 if not self.beenthere[so:cid()] then
157 co:error(ERR.SECT_UNKNOWN(so))
158 end
159 end
160 end
161
162 for _, k in ipairs(luci.util.keys(sc)) do
163 local so = co:section(k)
164 if so:scheme('required') and sc[k] == 0 then
165 co:error(ERR.SECT_REQUIRED(so))
166 elseif so:scheme('unique') and sc[k] > 1 then
167 co:error(ERR.SECT_UNIQUE(so))
168 end
169 end
170
171 return co:ok(), co:errors()
172 end
173
174 --- Validate given config section.
175 -- @param config Name of the configuration to validate
176 -- @param section Name of the section to validate
177 -- @return Boolean indicating whether the given config validates
178 -- @return String containing the reason for errors (if any)
179 function UVL.validate_section( self, config, section, uci )
180
181 if not self.packages[config] then
182 local ok, err = self:read_scheme( config )
183 if not ok then
184 return false, err
185 end
186 end
187
188 local co = luci.uvl.config( self, uci or config, uci and config )
189 local so = co:section( section )
190
191 self.beenthere = { }
192 self.depseen = { }
193
194 if not co:config() then
195 return false, co:errors()
196 end
197
198 if so:config() then
199 return self:_validate_section( so )
200 else
201 return false, ERR.SECT_NOTFOUND(so)
202 end
203 end
204
205 --- Validate given config option.
206 -- @param config Name of the configuration to validate
207 -- @param section Name of the section to validate
208 -- @param option Name of the option to validate
209 -- @return Boolean indicating whether the given config validates
210 -- @return String containing the reason for errors (if any)
211 function UVL.validate_option( self, config, section, option, uci )
212
213 if not self.packages[config] then
214 local ok, err = self:read_scheme( config )
215 if not ok then
216 return false, err
217 end
218 end
219
220 local co = luci.uvl.config( self, uci or config, uci and config )
221 local so = co:section( section )
222 local oo = so:option( option )
223
224 if not co:config() then
225 return false, co:errors()
226 end
227
228 if so:config() and oo:config() then
229 return self:_validate_option( oo )
230 else
231 return false, ERR.OPT_NOTFOUND(oo)
232 end
233 end
234
235
236 function UVL._validate_section( self, section )
237
238 self.beenthere[section:cid()] = true
239
240 if section:config() then
241 if section:scheme('named') == true and
242 section:config('.anonymous') == true
243 then
244 return false, ERR.SECT_NAMED(section)
245 end
246
247 for _, v in ipairs(section:variables()) do
248 local ok, err = self:_validate_option( v )
249 if not ok then
250 section:error(err)
251 end
252 end
253
254 local ok, err = luci.uvl.dependencies.check( self, section )
255 if not ok then
256 section:error(err)
257 end
258 else
259 return false, ERR.SECT_NOTFOUND(section)
260 end
261
262 if STRICT_UNKNOWN_OPTIONS and not section:scheme('dynamic') then
263 for k, v in pairs(section:config()) do
264 local oo = section:option(k)
265 if k:sub(1,1) ~= "." and not self.beenthere[oo:cid()] then
266 section:error(ERR.OPT_NOTFOUND(oo))
267 end
268 end
269 end
270
271 return section:ok(), section:errors()
272 end
273
274 function UVL._validate_option( self, option, nodeps )
275
276 self.beenthere[option:cid()] = true
277
278 if not option:scheme() and not option:parent():scheme('dynamic') then
279 return false, option:error(ERR.OPT_UNKNOWN(option))
280
281 elseif option:scheme() then
282 if option:scheme('required') and not option:value() then
283 return false, option:error(ERR.OPT_REQUIRED(option))
284
285 elseif option:value() then
286 local val = option:value()
287
288 if option:scheme('type') == "reference" or
289 option:scheme('type') == "enum"
290 then
291 if not option:scheme('values') or
292 not option:scheme('values')[val]
293 then
294 return false, option:error( ERR.OPT_BADVALUE(
295 option, { val, table.concat(
296 luci.util.keys(option:scheme('values') or {}), ", "
297 ) }
298 ) )
299 end
300 elseif option:scheme('type') == "list" then
301 if type(val) ~= "table" and STRICT_LIST_TYPE then
302 return false, option:error(ERR.OPT_NOTLIST(option))
303 end
304 elseif option:scheme('datatype') then
305 local dt = option:scheme('datatype')
306
307 if self.datatypes[dt] then
308 val = ( type(val) == "table" and val or { val } )
309 for i, v in ipairs(val) do
310 if not self.datatypes[dt]( v ) then
311 return false, option:error(
312 ERR.OPT_INVVALUE(option, {v, dt})
313 )
314 end
315 end
316 else
317 return false, option:error(ERR.OPT_DATATYPE(option, dt))
318 end
319 end
320 end
321
322 if not nodeps then
323 local ok, err = luci.uvl.dependencies.check( self, option )
324 if not ok then
325 option:error(err)
326 end
327 end
328
329 local ok, err = luci.uvl.validation.check( self, option )
330 if not ok and STRICT_EXTERNAL_VALIDATORS then
331 return false, option:error(err)
332 end
333 end
334
335 return option:ok(), option:errors()
336 end
337
338 --- Find all parts of given scheme and construct validation tree.
339 -- This is normally done on demand, so you don't have to call this function
340 -- by yourself.
341 -- @param scheme Name of the scheme to parse
342 function UVL.read_scheme( self, scheme )
343
344 local so = luci.uvl.scheme( self, scheme )
345
346 local schemes = { }
347 local files = luci.fs.glob(self.schemedir .. '/*/' .. scheme)
348
349 if files then
350 for i, file in ipairs( files ) do
351 if not luci.fs.access(file) then
352 return so:error(ERR.SME_READ(so,file))
353 end
354
355 local uci = luci.model.uci.cursor( luci.fs.dirname(file), default_savedir )
356
357 local sd, err = uci:get_all( luci.fs.basename(file) )
358
359 if not sd then
360 return false, ERR.UCILOAD(so, err)
361 end
362
363 table.insert( schemes, sd )
364 end
365
366 return self:_read_scheme_parts( so, schemes )
367 else
368 return false, so:error(ERR.SME_FIND(so, self.schemedir))
369 end
370 end
371
372 -- Process all given parts and construct validation tree
373 function UVL._read_scheme_parts( self, scheme, schemes )
374
375 -- helper function to check for required fields
376 local function _req( c, t, r )
377 for i, v in ipairs(r) do
378 if not t[v] then
379 return false, ERR.SME_REQFLD({c,t}, v)
380 end
381 end
382 return true
383 end
384
385 -- helper function to validate references
386 local function _ref( c, t )
387 local k, n
388 if c == TYPE_SECTION then
389 k = "package"
390 n = 1
391 elseif c == TYPE_VARIABLE then
392 k = "section"
393 n = 2
394 elseif c == TYPE_ENUM then
395 k = "variable"
396 n = 3
397 end
398
399 local r = luci.util.split( t[k], "." )
400 r[1] = ( #r[1] > 0 and r[1] or scheme:sid() )
401
402 if #r ~= n then
403 return false, ERR.SME_BADREF(scheme, k)
404 end
405
406 return r
407 end
408
409 -- helper function to read bools
410 local function _bool( v )
411 return ( v == "true" or v == "yes" or v == "on" or v == "1" )
412 end
413
414
415 local ok, err
416
417 -- Step 1: get all sections
418 for i, conf in ipairs( schemes ) do
419 for k, v in pairs( conf ) do
420 if v['.type'] == 'section' then
421
422 ok, err = _req( TYPE_SECTION, v, { "name", "package" } )
423 if err then return false, scheme:error(err) end
424
425 local r, err = _ref( TYPE_SECTION, v )
426 if err then return false, scheme:error(err) end
427
428 self.packages[r[1]] =
429 self.packages[r[1]] or {
430 ["name"] = r[1];
431 ["sections"] = { };
432 ["variables"] = { };
433 }
434
435 local p = self.packages[r[1]]
436 p.sections[v.name] = p.sections[v.name] or { }
437 p.variables[v.name] = p.variables[v.name] or { }
438
439 local s = p.sections[v.name]
440 local so = scheme:section(v.name)
441
442 for k, v2 in pairs(v) do
443 if k ~= "name" and k ~= "package" and k:sub(1,1) ~= "." then
444 if k == "depends" then
445 s.depends = self:_read_dependency( v2, s.depends )
446 if not s.depends then
447 return false, scheme:error(
448 ERR.SME_BADDEP(so, luci.util.serialize_data(s.depends))
449 )
450 end
451 elseif k == "dynamic" or k == "unique" or
452 k == "required" or k == "named"
453 then
454 s[k] = _bool(v2)
455 else
456 s[k] = v2
457 end
458 end
459 end
460
461 s.dynamic = s.dynamic or false
462 s.unique = s.unique or false
463 s.required = s.required or false
464 s.named = s.named or false
465 end
466 end
467 end
468
469 -- Step 2: get all variables
470 for i, conf in ipairs( schemes ) do
471 for k, v in pairs( conf ) do
472 if v['.type'] == "variable" then
473
474 ok, err = _req( TYPE_VARIABLE, v, { "name", "section" } )
475 if err then return false, scheme:error(err) end
476
477 local r, err = _ref( TYPE_VARIABLE, v )
478 if err then return false, scheme:error(err) end
479
480 local p = self.packages[r[1]]
481 if not p then
482 return false, scheme:error(
483 ERR.SME_VBADPACK({scheme:sid(), '', v.name}, r[1])
484 )
485 end
486
487 local s = p.variables[r[2]]
488 if not s then
489 return false, scheme:error(
490 ERR.SME_VBADSECT({scheme:sid(), '', v.name}, r[2])
491 )
492 end
493
494 s[v.name] = s[v.name] or { }
495
496 local t = s[v.name]
497 local so = scheme:section(r[2])
498 local to = so:option(v.name)
499
500 for k, v2 in pairs(v) do
501 if k ~= "name" and k ~= "section" and k:sub(1,1) ~= "." then
502 if k == "depends" then
503 t.depends = self:_read_dependency( v2, t.depends )
504 if not t.depends then
505 return false, scheme:error(so:error(
506 ERR.SME_BADDEP(to, luci.util.serialize_data(v2))
507 ))
508 end
509 elseif k == "validator" then
510 t.validators = self:_read_validator( v2, t.validators )
511 if not t.validators then
512 return false, scheme:error(so:error(
513 ERR.SME_BADVAL(to, luci.util.serialize_data(v2))
514 ))
515 end
516 elseif k == "valueof" then
517 local values, err = self:_read_reference( v2 )
518 if err then
519 return false, scheme:error(so:error(
520 ERR.REFERENCE(to, luci.util.serialize_data(v2)):child(err)
521 ))
522 end
523 t.type = "reference"
524 t.values = values
525 elseif k == "required" then
526 t[k] = _bool(v2)
527 else
528 t[k] = t[k] or v2
529 end
530 end
531 end
532
533 t.type = t.type or "variable"
534 t.datatype = t.datatype or "string"
535 t.required = t.required or false
536 end
537 end
538 end
539
540 -- Step 3: get all enums
541 for i, conf in ipairs( schemes ) do
542 for k, v in pairs( conf ) do
543 if v['.type'] == "enum" then
544
545 ok, err = _req( TYPE_ENUM, v, { "value", "variable" } )
546 if err then return false, scheme:error(err) end
547
548 local r, err = _ref( TYPE_ENUM, v )
549 if err then return false, scheme:error(err) end
550
551 local p = self.packages[r[1]]
552 if not p then
553 return false, scheme:error(
554 ERR.SME_EBADPACK({scheme:sid(), '', '', v.value}, r[1])
555 )
556 end
557
558 local s = p.variables[r[2]]
559 if not s then
560 return false, scheme:error(
561 ERR.SME_EBADSECT({scheme:sid(), '', '', v.value}, r[2])
562 )
563 end
564
565 local t = s[r[3]]
566 if not t then
567 return false, scheme:error(
568 ERR.SME_EBADOPT({scheme:sid(), '', '', v.value}, r[3])
569 )
570 end
571
572
573 local so = scheme:section(r[2])
574 local oo = so:option(r[3])
575 local eo = oo:enum(v.value)
576
577 if t.type ~= "enum" then
578 return false, scheme:error(ERR.SME_EBADTYPE(eo))
579 end
580
581 if not t.values then
582 t.values = { [v.value] = v.title or v.value }
583 else
584 t.values[v.value] = v.title or v.value
585 end
586
587 if not t.enum_depends then
588 t.enum_depends = { }
589 end
590
591 if v.default then
592 if t.default then
593 return false, scheme:error(ERR.SME_EBADDEF(eo))
594 end
595 t.default = v.value
596 end
597
598 if v.depends then
599 t.enum_depends[v.value] = self:_read_dependency(
600 v.depends, t.enum_depends[v.value]
601 )
602
603 if not t.enum_depends[v.value] then
604 return false, scheme:error(so:error(oo:error(
605 ERR.SME_BADDEP(eo, luci.util.serialize_data(v.depends))
606 )))
607 end
608 end
609 end
610 end
611 end
612
613 return self
614 end
615
616 -- Read a dependency specification
617 function UVL._read_dependency( self, values, deps )
618 local expr = "%$?[a-zA-Z0-9_]+"
619 if values then
620 values = ( type(values) == "table" and values or { values } )
621 for _, value in ipairs(values) do
622 local parts = luci.util.split( value, "%s*,%s*", nil, true )
623 local condition = { }
624 for i, val in ipairs(parts) do
625 local k, v = unpack(luci.util.split(val, "%s*=%s*", nil, true))
626
627 if k and (
628 k:match("^"..expr.."%."..expr.."%."..expr.."$") or
629 k:match("^"..expr.."%."..expr.."$") or
630 k:match("^"..expr.."$")
631 ) then
632 condition[k] = v or true
633 else
634 return nil
635 end
636 end
637
638 if not deps then
639 deps = { condition }
640 else
641 table.insert( deps, condition )
642 end
643 end
644 end
645
646 return deps
647 end
648
649 -- Read a validator specification
650 function UVL._read_validator( self, values, validators )
651 if values then
652 values = ( type(values) == "table" and values or { values } )
653 for _, value in ipairs(values) do
654 local validator
655
656 if value:match("^exec:") then
657 validator = value:gsub("^exec:","")
658 elseif value:match("^lua:") then
659 validator = self:_resolve_function( (value:gsub("^lua:","") ) )
660 end
661
662 if validator then
663 if not validators then
664 validators = { validator }
665 else
666 table.insert( validators, validator )
667 end
668 else
669 return nil
670 end
671 end
672
673 return validators
674 end
675 end
676
677 -- Read a reference specification (XXX: We should validate external configs too...)
678 function UVL._read_reference( self, values )
679 local val = { }
680 values = ( type(values) == "table" and values or { values } )
681
682 for _, value in ipairs(values) do
683 local ref = luci.util.split(value, ".")
684
685 if #ref == 2 or #ref == 3 then
686 local co = luci.uvl.config( self, ref[1] )
687 if not co:config() then return false, co:errors() end
688
689 for k, v in pairs(co:config()) do
690 if v['.type'] == ref[2] then
691 if #ref == 2 then
692 if v['.anonymous'] == true then
693 return false, ERR.SME_INVREF('', value)
694 end
695 val[k] = k -- XXX: title/description would be nice
696 elseif v[ref[3]] then
697 val[v[ref[3]]] = v[ref[3]] -- XXX: dito
698 end
699 end
700 end
701 else
702 return false, ERR.SME_BADREF('', value)
703 end
704 end
705
706 return val, nil
707 end
708
709 -- Resolve given path
710 function UVL._resolve_function( self, value )
711 local path = luci.util.split(value, ".")
712
713 for i=1, #path-1 do
714 local stat, mod = luci.util.copcall(
715 require, table.concat(path, ".", 1, i)
716 )
717
718 if stat and mod then
719 for j=i+1, #path-1 do
720 if not type(mod) == "table" then
721 break
722 end
723 mod = mod[path[j]]
724 if not mod then
725 break
726 end
727 end
728 mod = type(mod) == "table" and mod[path[#path]] or nil
729 if type(mod) == "function" then
730 return mod
731 end
732 end
733 end
734 end
735
736
737 --- Object representation of an uvl item - base class.
738 uvlitem = luci.util.class()
739
740 function uvlitem.cid(self)
741 return table.concat( self.cref, '.' )
742 end
743
744 function uvlitem.sid(self)
745 return table.concat( self.sref, '.' )
746 end
747
748 function uvlitem.scheme(self, opt)
749 local s
750
751 if #self.sref == 4 or #self.sref == 3 then
752 s = self.s
753 .packages[self.sref[1]]
754 .variables[self.sref[2]][self.sref[3]]
755 elseif #self.sref == 2 then
756 s = self.s
757 .packages[self.sref[1]]
758 .sections[self.sref[2]]
759 else
760 s = self.s
761 .packages[self.sref[1]]
762 end
763
764 if s and opt then
765 return s[opt]
766 elseif s then
767 return s
768 end
769 end
770
771 function uvlitem.config(self, opt)
772 local c
773
774 if #self.cref == 4 or #self.cref == 3 then
775 c = self.c[self.cref[2]][self.cref[3]]
776 elseif #self.cref == 2 then
777 c = self.c[self.cref[2]]
778 else
779 c = self.c
780 end
781
782 if c and opt then
783 return c[opt]
784 elseif c then
785 return c
786 end
787 end
788
789 function uvlitem.title(self)
790 return self:scheme() and self:scheme('title') or
791 self.cref[3] or self.cref[2] or self.cref[1]
792 end
793
794 function uvlitem.type(self)
795 if self.t == luci.uvl.TYPE_CONFIG then
796 return 'config'
797 elseif self.t == luci.uvl.TYPE_SECTION then
798 return 'section'
799 elseif self.t == luci.uvl.TYPE_OPTION then
800 return 'option'
801 elseif self.t == luci.uvl.TYPE_ENUM then
802 return 'enum'
803 end
804 end
805
806 function uvlitem.error(self, ...)
807 if not self.e then
808 local errconst = { ERR.CONFIG, ERR.SECTION, ERR.OPTION, ERR.OPTION }
809 self.e = errconst[#self.cref]( self )
810 end
811
812 return self.e:child( ... )
813 end
814
815 function uvlitem.errors(self)
816 return self.e
817 end
818
819 function uvlitem.ok(self)
820 return not self:errors()
821 end
822
823 function uvlitem.parent(self)
824 if self.p then
825 return self.p
826 elseif #self.cref == 3 or #self.cref == 4 then
827 return luci.uvl.section( self.s, self.c, self.cref[1], self.cref[2] )
828 elseif #self.cref == 2 then
829 return luci.uvl.config( self.s, self.c, self.cref[1] )
830 else
831 return nil
832 end
833 end
834
835 function uvlitem._loadconf(self, co, c)
836 if not co then
837 local uci, err = luci.model.uci.cursor(), nil
838 co, err = uci:get_all(c)
839
840 if err then
841 self:error(ERR.UCILOAD(self, err))
842 end
843 end
844 return co
845 end
846
847
848 --- Object representation of a scheme.
849 -- @class scheme
850 -- @cstyle instance
851 -- @name luci.uvl.scheme
852
853 --- Scheme instance constructor.
854 -- @class function
855 -- @name scheme
856 -- @param scheme Scheme instance
857 -- @param co Configuration data
858 -- @param c Configuration name
859 -- @return Config instance
860 scheme = luci.util.class(uvlitem)
861
862 function scheme.__init__(self, scheme, co, c)
863 if not c then
864 c, co = co, nil
865 end
866
867 self.cref = { c }
868 self.sref = { c }
869 self.c = self:_loadconf(co, c)
870 self.s = scheme
871 self.t = luci.uvl.TYPE_SCHEME
872 end
873
874 --- Add an error to scheme.
875 -- @return Scheme error context
876 function scheme.error(self, ...)
877 if not self.e then self.e = ERR.SCHEME( self ) end
878 return self.e:child( ... )
879 end
880
881 --- Get an associated config object.
882 -- @return Config instance
883 function scheme.config(self)
884 local co = luci.uvl.config( self.s, self.cref[1] )
885 co.p = self
886
887 return co
888 end
889
890 --- Get all section objects associated with this scheme.
891 -- @return Table containing all associated luci.uvl.section instances
892 function scheme.sections(self)
893 local v = { }
894 if self.s.packages[self.sref[1]].sections then
895 for o, _ in pairs( self.s.packages[self.sref[1]].sections ) do
896 table.insert( v, luci.uvl.option(
897 self.s, self.c, self.cref[1], self.cref[2], o
898 ) )
899 end
900 end
901 return v
902 end
903
904 --- Get an associated section object.
905 -- @param s Section to select
906 -- @return Section instance
907 function scheme.section(self, s)
908 local so = luci.uvl.section( self.s, self.c, self.cref[1], s )
909 so.p = self
910
911 return so
912 end
913
914
915 --- Object representation of a config.
916 -- @class config
917 -- @cstyle instance
918 -- @name luci.uvl.config
919
920 --- Config instance constructor.
921 -- @class function
922 -- @name config
923 -- @param scheme Scheme instance
924 -- @param co Configuration data
925 -- @param c Configuration name
926 -- @return Config instance
927 config = luci.util.class(uvlitem)
928
929 function config.__init__(self, scheme, co, c)
930 if not c then
931 c, co = co, nil
932 end
933
934 self.cref = { c }
935 self.sref = { c }
936 self.c = self:_loadconf(co, c)
937 self.s = scheme
938 self.t = luci.uvl.TYPE_CONFIG
939 end
940
941 --- Get all section objects associated with this config.
942 -- @return Table containing all associated luci.uvl.section instances
943 function config.sections(self)
944 local v = { }
945 if self.s.packages[self.sref[1]].sections then
946 for o, _ in pairs( self.s.packages[self.sref[1]].sections ) do
947 table.insert( v, luci.uvl.option(
948 self.s, self.c, self.cref[1], self.cref[2], o
949 ) )
950 end
951 end
952 return v
953 end
954
955 --- Get an associated section object.
956 -- @param s Section to select
957 -- @return Section instance
958 function config.section(self, s)
959 local so = luci.uvl.section( self.s, self.c, self.cref[1], s )
960 so.p = self
961
962 return so
963 end
964
965
966 --- Object representation of a scheme/config section.
967 -- @class module
968 -- @cstyle instance
969 -- @name luci.uvl.section
970
971 --- Section instance constructor.
972 -- @class function
973 -- @name section
974 -- @param scheme Scheme instance
975 -- @param co Configuration data
976 -- @param c Configuration name
977 -- @param s Section name
978 -- @return Section instance
979 section = luci.util.class(uvlitem)
980
981 function section.__init__(self, scheme, co, c, s)
982 self.cref = { c, s }
983 self.sref = { c, co and co[s] and co[s]['.type'] or s }
984 self.c = self:_loadconf(co, c)
985 self.s = scheme
986 self.t = luci.uvl.TYPE_SECTION
987 end
988
989 --- Get all option objects associated with this section.
990 -- @return Table containing all associated luci.uvl.option instances
991 function section.variables(self)
992 local v = { }
993 if self.s.packages[self.sref[1]].variables[self.sref[2]] then
994 for o, _ in pairs(
995 self.s.packages[self.sref[1]].variables[self.sref[2]]
996 ) do
997 table.insert( v, luci.uvl.option(
998 self.s, self.c, self.cref[1], self.cref[2], o
999 ) )
1000 end
1001 end
1002 return v
1003 end
1004
1005 --- Get an associated option object.
1006 -- @param o Option to select
1007 -- @return Option instance
1008 function section.option(self, o)
1009 local oo = luci.uvl.option( self.s, self.c, self.cref[1], self.cref[2], o )
1010 oo.p = self
1011
1012 return oo
1013 end
1014
1015
1016 --- Object representation of a scheme/config option.
1017 -- @class module
1018 -- @cstyle instance
1019 -- @name luci.uvl.option
1020
1021 --- Section instance constructor.
1022 -- @class function
1023 -- @name option
1024 -- @param scheme Scheme instance
1025 -- @param co Configuration data
1026 -- @param c Configuration name
1027 -- @param s Section name
1028 -- @param o Option name
1029 -- @return Option instance
1030 option = luci.util.class(uvlitem)
1031
1032 function option.__init__(self, scheme, co, c, s, o)
1033 self.cref = { c, s, o }
1034 self.sref = { c, co and co[s] and co[s]['.type'] or s, o }
1035 self.c = self:_loadconf(co, c)
1036 self.s = scheme
1037 self.t = luci.uvl.TYPE_OPTION
1038 end
1039
1040 --- Get the value of this option.
1041 -- @return The associated configuration value
1042 function option.value(self)
1043 return self:config()
1044 end
1045
1046 --- Get the associated section information in scheme.
1047 -- @return Table containing the scheme properties
1048 function option.section(self)
1049 return self.s.packages[self.sref[1]].sections[self.sref[2]]
1050 end
1051
1052 --- Construct an enum object instance from given or default value.
1053 -- @param v Value to select
1054 -- @return Enum instance for selected value
1055 function option.enum(self, val)
1056 return enum(
1057 self.s, self.c,
1058 self.cref[1], self.cref[2], self.cref[3],
1059 val or self:value()
1060 )
1061 end
1062
1063
1064 --- Object representation of a enum value.
1065 -- @class module
1066 -- @cstyle instance
1067 -- @name luci.uvl.enum
1068
1069 --- Section instance constructor.
1070 -- @class function
1071 -- @name enum
1072 -- @param scheme Scheme instance
1073 -- @param co Configuration data
1074 -- @param c Configuration name
1075 -- @param s Section name
1076 -- @param o Enum name
1077 -- @param v Enum value
1078 -- @return Enum value instance
1079 enum = luci.util.class(option)
1080
1081 function enum.__init__(self, scheme, co, c, s, o, v)
1082 self.cref = { c, s, o, v }
1083 self.sref = { c, co and co[s] and co[s]['.type'] or s, o, v }
1084 self.c = self:_loadconf(co, c)
1085 self.s = scheme
1086 self.t = luci.uvl.TYPE_ENUM
1087 end