11 Copyright 2008 Steven Barth <steven@midlink.org>
13 Licensed under the Apache License, Version 2.0 (the "License");
14 you may not use this file except in compliance with the License.
15 You may obtain a copy of the License at
17 http://www.apache.org/licenses/LICENSE-2.0
19 Unless required by applicable law or agreed to in writing, software
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
26 local os = require "os"
27 local uci = require "uci"
28 local util = require "luci.util"
29 local table = require "table"
32 local setmetatable, rawget, rawset = setmetatable, rawget, rawset
33 local error, pairs, ipairs, tostring = error, pairs, ipairs, tostring
34 local require, getmetatable = require, getmetatable
36 --- LuCI UCI model library.
38 module "luci.model.uci"
40 --- Create a new UCI-Cursor.
46 APIVERSION = uci.APIVERSION
48 --- Create a new Cursor initialized to the state directory.
50 function cursor_state()
51 return cursor(nil, "/var/state")
55 local Cursor = getmetatable(cursor())
57 --- Applies the new config
58 -- @param config UCI config
59 function Cursor.apply(self, config)
60 local conf = require "luci.config"
61 return conf.uci_oncommit[config] and
62 os.execute(conf.uci_oncommit[config] .. " >/dev/null 2>&1")
65 --- Delete all sections of a given type that match certain criteria.
66 -- @param config UCI config
67 -- @param type UCI section type
68 -- @param comparator Function that will be called for each section and
69 -- returns a boolean whether to delete the current section (optional)
70 function Cursor.delete_all(self, config, type, comparator)
73 if type(comparator) == "table" then
74 local tbl = comparator
75 comparator = function(section)
76 for k, v in pairs(tbl) do
77 if not section[k] == v then
85 local function helper (section)
87 if not comparator or comparator(section) then
88 table.insert(del, section[".name"])
92 self:foreach(config, type, helper)
94 for i, j in ipairs(del) do
95 self:delete(config, j)
99 --- Create a new section and initialize it with data.
100 -- @param config UCI config
101 -- @param type UCI section type
102 -- @param name UCI section name (optional)
103 -- @param values Table of key - value pairs to initialize the section with
104 -- @return Name of created section
105 function Cursor.section(self, config, type, name, values)
108 stat = self:set(config, name, type)
110 name = self:add(config, type)
114 if stat and values then
115 stat = self:tset(config, name, values)
121 --- Updated the data of a section using data from a table.
122 -- @param config UCI config
123 -- @param section UCI section name (optional)
124 -- @param values Table of key - value pairs to update the section with
125 function Cursor.tset(self, config, section, values)
127 for k, v in pairs(values) do
128 if k:sub(1, 1) ~= "." then
129 stat = stat and self:set(config, section, k, v)
135 --- Get an option or list and return values as table.
136 -- @param config UCI config
137 -- @param section UCI section name
138 -- @param option UCI option
140 function Cursor.get_list(self, config, section, option)
141 if config and section and option then
142 local val = self:get(config, section, option)
143 return ( type(val) == "table" and val or { val } )
148 --- Set given values as list.
149 -- @param config UCI config
150 -- @param section UCI section name
151 -- @param option UCI option
152 -- @param value UCI value
153 -- @return Boolean whether operation succeeded
154 function Cursor.set_list(self, config, section, option, value)
155 if config and section and option then
157 config, section, option,
158 ( type(value) == "table" and value or { value } )
165 Cursor._changes = Cursor.changes
166 function Cursor.changes(self, config)
168 return Cursor._changes(self, config)
170 local changes = Cursor._changes(self)
171 util.copcall(function()
172 for k,v in pairs(require "luci.fs".dir(self:get_savedir())) do
173 if v ~= "." and v ~= ".." then
174 util.update(changes, Cursor._changes(self, v))
183 --- Add an anonymous section.
186 -- @param config UCI config
187 -- @param type UCI section type
188 -- @return Name of created section
190 --- Get a table of unsaved changes.
192 -- @name Cursor.changes
193 -- @param config UCI config
194 -- @return Table of changes
196 --- Commit unsaved changes.
198 -- @name Cursor.commit
199 -- @param config UCI config
200 -- @return Boolean whether operation succeeded
201 -- @see Cursor.revert
203 --- Deletes a section or an option.
205 -- @name Cursor.delete
206 -- @param config UCI config
207 -- @param section UCI section name
208 -- @param option UCI option (optional)
209 -- @return Boolean whether operation succeeded
211 --- Call a function for every section of a certain type.
213 -- @name Cursor.foreach
214 -- @param config UCI config
215 -- @param type UCI section type
216 -- @param callback Function to be called
217 -- @return Boolean whether operation succeeded
219 --- Get a section type or an option
222 -- @param config UCI config
223 -- @param section UCI section name
224 -- @param option UCI option (optional)
227 --- Get all sections of a config or all values of a section.
229 -- @name Cursor.get_all
230 -- @param config UCI config
231 -- @param section UCI section name (optional)
232 -- @return Table of UCI sections or table of UCI values
234 --- Manually load a config.
237 -- @param config UCI config
238 -- @return Boolean whether operation succeeded
240 -- @see Cursor.unload
242 --- Revert unsaved changes.
244 -- @name Cursor.revert
245 -- @param config UCI config
246 -- @return Boolean whether operation succeeded
247 -- @see Cursor.commit
249 --- Saves changes made to a config to make them committable.
252 -- @param config UCI config
253 -- @return Boolean whether operation succeeded
255 -- @see Cursor.unload
257 --- Set a value or create a named section.
260 -- @param config UCI config
261 -- @param section UCI section name
262 -- @param option UCI option or UCI section type
263 -- @param value UCI value or nil if you want to create a section
264 -- @return Boolean whether operation succeeded
266 --- Get the configuration directory.
268 -- @name Cursor.get_confdir
269 -- @return Configuration directory
271 --- Get the directory for uncomitted changes.
273 -- @name Cursor.get_savedir
274 -- @return Save directory
276 --- Set the configuration directory.
278 -- @name Cursor.set_confdir
279 -- @param directory UCI configuration directory
280 -- @return Boolean whether operation succeeded
282 --- Set the directory for uncommited changes.
284 -- @name Cursor.set_savedir
285 -- @param directory UCI changes directory
286 -- @return Boolean whether operation succeeded
288 --- Discard changes made to a config.
290 -- @name Cursor.unload
291 -- @param config UCI config
292 -- @return Boolean whether operation succeeded