Bump UCI version
[project/luci.git] / libs / uci / luasrc / model / uci.lua
1 --[[
2 LuCI - UCI model
3
4 Description:
5 Generalized UCI model
6
7 FileId:
8 $Id$
9
10 License:
11 Copyright 2008 Steven Barth <steven@midlink.org>
12
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
16
17 http://www.apache.org/licenses/LICENSE-2.0
18
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.
24
25 ]]--
26 local os = require "os"
27 local uci = require "uci"
28 local util = require "luci.util"
29 local table = require "table"
30
31
32 local setmetatable, rawget, rawset = setmetatable, rawget, rawset
33 local error, pairs, ipairs, tostring = error, pairs, ipairs, tostring
34 local require, getmetatable, type = require, getmetatable, type
35
36 --- LuCI UCI model library.
37 -- @cstyle instance
38 module "luci.model.uci"
39
40 --- Create a new UCI-Cursor.
41 -- @class function
42 -- @name cursor
43 -- @return UCI-Cursor
44 cursor = uci.cursor
45
46 APIVERSION = uci.APIVERSION
47
48 --- Create a new Cursor initialized to the state directory.
49 -- @return UCI cursor
50 function cursor_state()
51 return cursor(nil, "/var/state")
52 end
53
54
55 local Cursor = getmetatable(cursor())
56
57 --- Applies UCI configuration changes
58 -- @param configlist List of UCI configurations
59 -- @param command Don't apply only return the command
60 function Cursor.apply(self, configlist, command)
61 configlist = self:_affected(configlist)
62 local reloadcmd = "/sbin/luci-reload " .. table.concat(configlist, " ")
63
64 return command and reloadcmd or os.execute(reloadcmd .. " >/dev/null 2>&1")
65 end
66
67
68 --- Delete all sections of a given type that match certain criteria.
69 -- @param config UCI config
70 -- @param type UCI section type
71 -- @param comparator Function that will be called for each section and
72 -- returns a boolean whether to delete the current section (optional)
73 function Cursor.delete_all(self, config, stype, comparator)
74 local del = {}
75
76 if type(comparator) == "table" then
77 local tbl = comparator
78 comparator = function(section)
79 for k, v in pairs(tbl) do
80 if section[k] ~= v then
81 return false
82 end
83 end
84 return true
85 end
86 end
87
88 local function helper (section)
89
90 if not comparator or comparator(section) then
91 del[#del+1] = section[".name"]
92 end
93 end
94
95 self:foreach(config, stype, helper)
96
97 for i, j in ipairs(del) do
98 self:delete(config, j)
99 end
100 end
101
102 --- Create a new section and initialize it with data.
103 -- @param config UCI config
104 -- @param type UCI section type
105 -- @param name UCI section name (optional)
106 -- @param values Table of key - value pairs to initialize the section with
107 -- @return Name of created section
108 function Cursor.section(self, config, type, name, values)
109 local stat = true
110 if name then
111 stat = self:set(config, name, type)
112 else
113 name = self:add(config, type)
114 stat = name and true
115 end
116
117 if stat and values then
118 stat = self:tset(config, name, values)
119 end
120
121 return stat and name
122 end
123
124 --- Updated the data of a section using data from a table.
125 -- @param config UCI config
126 -- @param section UCI section name (optional)
127 -- @param values Table of key - value pairs to update the section with
128 function Cursor.tset(self, config, section, values)
129 local stat = true
130 for k, v in pairs(values) do
131 if k:sub(1, 1) ~= "." then
132 stat = stat and self:set(config, section, k, v)
133 end
134 end
135 return stat
136 end
137
138 --- Get an option or list and return values as table.
139 -- @param config UCI config
140 -- @param section UCI section name
141 -- @param option UCI option
142 -- @return UCI value
143 function Cursor.get_list(self, config, section, option)
144 if config and section and option then
145 local val = self:get(config, section, option)
146 return ( type(val) == "table" and val or { val } )
147 end
148 return nil
149 end
150
151 --- Set given values as list.
152 -- @param config UCI config
153 -- @param section UCI section name
154 -- @param option UCI option
155 -- @param value UCI value
156 -- @return Boolean whether operation succeeded
157 function Cursor.set_list(self, config, section, option, value)
158 if config and section and option then
159 return self:set(
160 config, section, option,
161 ( type(value) == "table" and value or { value } )
162 )
163 end
164 return false
165 end
166
167 -- Return a list of initscripts affected by configuration changes.
168 function Cursor._affected(self, configlist)
169 configlist = type(configlist) == "table" and configlist or {configlist}
170
171 local c = cursor()
172 c:load("ucitrack")
173
174 -- Resolve dependencies
175 local reloadlist = {}
176
177 local function _resolve_deps(name)
178 local reload = {name}
179 local deps = {}
180
181 c:foreach("ucitrack", name,
182 function(section)
183 if section.affects then
184 for i, aff in ipairs(section.affects) do
185 deps[#deps+1] = aff
186 end
187 end
188 end)
189
190 for i, dep in ipairs(deps) do
191 for j, add in ipairs(_resolve_deps(dep)) do
192 reload[#reload+1] = add
193 end
194 end
195
196 return reload
197 end
198
199 -- Collect initscripts
200 for j, config in ipairs(configlist) do
201 for i, e in ipairs(_resolve_deps(config)) do
202 if not util.contains(reloadlist, e) then
203 reloadlist[#reloadlist+1] = e
204 end
205 end
206 end
207
208 return reloadlist
209 end
210
211
212 --- Add an anonymous section.
213 -- @class function
214 -- @name Cursor.add
215 -- @param config UCI config
216 -- @param type UCI section type
217 -- @return Name of created section
218
219 --- Get a table of unsaved changes.
220 -- @class function
221 -- @name Cursor.changes
222 -- @param config UCI config
223 -- @return Table of changes
224
225 --- Commit unsaved changes.
226 -- @class function
227 -- @name Cursor.commit
228 -- @param config UCI config
229 -- @return Boolean whether operation succeeded
230 -- @see Cursor.revert
231
232 --- Deletes a section or an option.
233 -- @class function
234 -- @name Cursor.delete
235 -- @param config UCI config
236 -- @param section UCI section name
237 -- @param option UCI option (optional)
238 -- @return Boolean whether operation succeeded
239
240 --- Call a function for every section of a certain type.
241 -- @class function
242 -- @name Cursor.foreach
243 -- @param config UCI config
244 -- @param type UCI section type
245 -- @param callback Function to be called
246 -- @return Boolean whether operation succeeded
247
248 --- Get a section type or an option
249 -- @class function
250 -- @name Cursor.get
251 -- @param config UCI config
252 -- @param section UCI section name
253 -- @param option UCI option (optional)
254 -- @return UCI value
255
256 --- Get all sections of a config or all values of a section.
257 -- @class function
258 -- @name Cursor.get_all
259 -- @param config UCI config
260 -- @param section UCI section name (optional)
261 -- @return Table of UCI sections or table of UCI values
262
263 --- Manually load a config.
264 -- @class function
265 -- @name Cursor.load
266 -- @param config UCI config
267 -- @return Boolean whether operation succeeded
268 -- @see Cursor.save
269 -- @see Cursor.unload
270
271 --- Revert unsaved changes.
272 -- @class function
273 -- @name Cursor.revert
274 -- @param config UCI config
275 -- @return Boolean whether operation succeeded
276 -- @see Cursor.commit
277
278 --- Saves changes made to a config to make them committable.
279 -- @class function
280 -- @name Cursor.save
281 -- @param config UCI config
282 -- @return Boolean whether operation succeeded
283 -- @see Cursor.load
284 -- @see Cursor.unload
285
286 --- Set a value or create a named section.
287 -- @class function
288 -- @name Cursor.set
289 -- @param config UCI config
290 -- @param section UCI section name
291 -- @param option UCI option or UCI section type
292 -- @param value UCI value or nil if you want to create a section
293 -- @return Boolean whether operation succeeded
294
295 --- Get the configuration directory.
296 -- @class function
297 -- @name Cursor.get_confdir
298 -- @return Configuration directory
299
300 --- Get the directory for uncomitted changes.
301 -- @class function
302 -- @name Cursor.get_savedir
303 -- @return Save directory
304
305 --- Set the configuration directory.
306 -- @class function
307 -- @name Cursor.set_confdir
308 -- @param directory UCI configuration directory
309 -- @return Boolean whether operation succeeded
310
311 --- Set the directory for uncommited changes.
312 -- @class function
313 -- @name Cursor.set_savedir
314 -- @param directory UCI changes directory
315 -- @return Boolean whether operation succeeded
316
317 --- Discard changes made to a config.
318 -- @class function
319 -- @name Cursor.unload
320 -- @param config UCI config
321 -- @return Boolean whether operation succeeded
322 -- @see Cursor.load
323 -- @see Cursor.save