libs: remove http folder
[project/luci.git] / libs / uci / luasrc / model / uci.lua
index e26f9030adb0dac848a494e3dbfc508a79dc5a8a..66bd0a026ee55634a66ea2c2460158e7c546c48b 100644 (file)
@@ -31,9 +31,15 @@ local table = require "table"
 
 local setmetatable, rawget, rawset = setmetatable, rawget, rawset
 local error, pairs, ipairs, tostring = error, pairs, ipairs, tostring
-local require, getmetatable = require, getmetatable
+local require, getmetatable, type = require, getmetatable, type
 
 --- LuCI UCI model library.
+-- The typical workflow for UCI is:  Get a cursor instance from the
+-- cursor factory, modify data (via Cursor.add, Cursor.delete, etc.),
+-- save the changes to the staging area via Cursor.save and finally
+-- Cursor.commit the data to the actual config files.
+-- LuCI then needs to Cursor.apply the changes so deamons etc. are
+-- reloaded.
 -- @cstyle     instance
 module "luci.model.uci"
 
@@ -52,30 +58,50 @@ function cursor_state()
 end
 
 
-local Cursor = getmetatable(cursor())
+inst = cursor()
+inst_state = cursor_state()
 
---- Applies the new config
--- @param config               UCI config
-function Cursor.apply(self, config)
-       local conf = require "luci.config"
-       return conf.uci_oncommit[config] and
-        os.execute(conf.uci_oncommit[config] .. " >/dev/null 2>&1")
+local Cursor = getmetatable(inst)
+
+--- Applies UCI configuration changes
+-- @param configlist           List of UCI configurations
+-- @param command                      Don't apply only return the command
+function Cursor.apply(self, configlist, command)
+       configlist = self:_affected(configlist)
+       local reloadcmd = "/sbin/luci-reload " .. table.concat(configlist, " ")
+
+       return command and reloadcmd or os.execute(reloadcmd .. " >/dev/null 2>&1")
 end
 
+
 --- Delete all sections of a given type that match certain criteria.
 -- @param config               UCI config
 -- @param type                 UCI section type
 -- @param comparator   Function that will be called for each section and
 -- returns a boolean whether to delete the current section (optional)
-function Cursor.delete_all(self, config, type, comparator)
+function Cursor.delete_all(self, config, stype, comparator)
        local del = {}
+
+       if type(comparator) == "table" then
+               local tbl = comparator
+               comparator = function(section)
+                       for k, v in pairs(tbl) do
+                               if section[k] ~= v then
+                                       return false
+                               end
+                       end
+                       return true
+               end
+       end
+
        local function helper (section)
+
                if not comparator or comparator(section) then
-                       table.insert(del, section[".name"])
+                       del[#del+1] = section[".name"]
                end
        end
 
-       self:foreach(config, type, helper)
+       self:foreach(config, stype, helper)
 
        for i, j in ipairs(del) do
                self:delete(config, j)
@@ -118,6 +144,16 @@ function Cursor.tset(self, config, section, values)
        return stat
 end
 
+--- Get a boolean option and return it's value as true or false.
+-- @param config       UCI config
+-- @param section      UCI section name
+-- @param option       UCI option
+-- @return                     Boolean
+function Cursor.get_bool(self, ...)
+       local val = self:get(...)
+       return ( val == "1" or val == "true" or val == "yes" or val == "on" )
+end
+
 --- Get an option or list and return values as table.
 -- @param config       UCI config
 -- @param section      UCI section name
@@ -147,20 +183,48 @@ function Cursor.set_list(self, config, section, option, value)
        return false
 end
 
+-- Return a list of initscripts affected by configuration changes.
+function Cursor._affected(self, configlist)
+       configlist = type(configlist) == "table" and configlist or {configlist}
 
-Cursor._changes = Cursor.changes
-function Cursor.changes(self, config)
-       if config then
-               return Cursor._changes(self, config)
-       else
-               local changes = {}
-               for k,v in pairs(require "luci.fs".dir(self:get_savedir())) do
-                       if v ~= "." and v ~= ".." then
-                               util.update(changes, Cursor._changes(self, v))
+       local c = cursor()
+       c:load("ucitrack")
+
+       -- Resolve dependencies
+       local reloadlist = {}
+
+       local function _resolve_deps(name)
+               local reload = {name}
+               local deps = {}
+
+               c:foreach("ucitrack", name,
+                       function(section)
+                               if section.affects then
+                                       for i, aff in ipairs(section.affects) do
+                                               deps[#deps+1] = aff
+                                       end
+                               end
+                       end)
+
+               for i, dep in ipairs(deps) do
+                       for j, add in ipairs(_resolve_deps(dep)) do
+                               reload[#reload+1] = add
+                       end
+               end
+
+               return reload
+       end
+
+       -- Collect initscripts
+       for j, config in ipairs(configlist) do
+               for i, e in ipairs(_resolve_deps(config)) do
+                       if not util.contains(reloadlist, e) then
+                               reloadlist[#reloadlist+1] = e
                        end
                end
-               return changes
        end
+
+       return reloadlist
 end
 
 
@@ -171,18 +235,20 @@ end
 -- @param type         UCI section type
 -- @return                     Name of created section
 
---- Get a table of unsaved changes.
+--- Get a table of saved but uncommitted changes.
 -- @class function
 -- @name Cursor.changes
 -- @param config       UCI config
 -- @return                     Table of changes
+-- @see Cursor.save
 
---- Commit unsaved changes.
+--- Commit saved changes.
 -- @class function
 -- @name Cursor.commit
 -- @param config       UCI config
 -- @return                     Boolean whether operation succeeded
 -- @see Cursor.revert
+-- @see Cursor.save
 
 --- Deletes a section or an option.
 -- @class function
@@ -223,12 +289,13 @@ end
 -- @see Cursor.save
 -- @see Cursor.unload
 
---- Revert unsaved changes.
+--- Revert saved but uncommitted changes.
 -- @class function
 -- @name Cursor.revert
 -- @param config       UCI config
 -- @return                     Boolean whether operation succeeded
 -- @see Cursor.commit
+-- @see Cursor.save
 
 --- Saves changes made to a config to make them committable.
 -- @class function