libs/ipkg: use -force-defaults to ensure non-interactive execution
[project/luci.git] / libs / ipkg / luasrc / model / ipkg.lua
index 4c2716a..a04f0a4 100644 (file)
 --[[
-LuCI - IPKG wrapper library
+LuCI - Lua Configuration Interface
 
-Description:
-Wrapper for the ipkg Package manager
-
-Any return value of false or nil can be interpreted as an error
-
-FileId:
-$Id$
-
-License:
-Copyright 2008 Steven Barth <steven@midlink.org>
+(c) 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
+(c) 2008 Steven Barth <steven@midlink.org>
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
-You may obtain a copy of the License at 
-
-       http://www.apache.org/licenses/LICENSE-2.0 
+You may obtain a copy of the License at
 
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
+http://www.apache.org/licenses/LICENSE-2.0
 
+$Id$
 ]]--
-module("luci.model.ipkg", package.seeall)
-require("luci.util")
-require("luci.fs")
-
-ipkg = luci.fs.access("/bin/opkg") and "opkg" or "ipkg"
-
--- Returns repository information
-function info(pkg)
-       return _lookup("info", pkg)
-end
 
--- Returns a table with status information
-function status(pkg)
-       return _lookup("status", pkg)
-end
-
--- Installs packages
-function install(...)
-       return _action("install", ...)
-end
-
--- Returns whether a package is installed
-function installed(pkg, ...)
-       local p = status(...)[pkg]
-       return (p and p.Status and p.Status.installed)
-end
+local os   = require "os"
+local io   = require "io"
+local util = require "luci.util"
 
--- Removes packages
-function remove(...)
-       return _action("remove", ...)
-end
+local type  = type
+local pairs = pairs
+local error = error
 
--- Updates package lists
-function update()
-       return _action("update")
-end
+local ipkg = "opkg -force-defaults"
 
--- Upgrades installed packages
-function upgrade()
-       return _action("upgrade")
-end
+--- LuCI IPKG/OPKG call abstraction library
+module "luci.model.ipkg"
 
 
 -- Internal action function
-function _action(cmd, ...)
+local function _action(cmd, ...)
        local pkg = ""
        arg.n = nil
        for k, v in pairs(arg) do
                pkg = pkg .. " '" .. v:gsub("'", "") .. "'"
        end
-       
+
        local c = ipkg.." "..cmd.." "..pkg.." >/dev/null 2>&1"
        local r = os.execute(c)
-       return (r == 0), r      
-end
-
--- Internal lookup function
-function _lookup(act, pkg)
-       local cmd = ipkg .. " " .. act
-       if pkg then
-               cmd = cmd .. " '" .. pkg:gsub("'", "") .. "'"
-       end
-       
-       return _parselist(luci.util.exec(cmd .. " 2>/dev/null"))
+       return (r == 0), r
 end
 
 -- Internal parser function
-function _parselist(rawdata)   
-       if type(rawdata) ~= "string" then
+local function _parselist(rawdata)
+       if type(rawdata) ~= "function" then
                error("IPKG: Invalid rawdata given")
        end
-       
-       rawdata = luci.util.split(rawdata) 
+
        local data = {}
        local c = {}
        local l = nil
-       
-       for k, line in pairs(rawdata) do
+
+       for line in rawdata do
                if line:sub(1, 1) ~= " " then
-                       local split = luci.util.split(line, ":", 1)
-                       local key = nil
-                       local val = nil
-                       
-                       if split[1] then
-                               key = luci.util.trim(split[1])
-                       end
-                       
-                       if split[2] then
-                               val = luci.util.trim(split[2])
-                       end
-                       
+                       local key, val = line:match("(.-): ?(.*)%s*")
+
                        if key and val then
                                if key == "Package" then
                                        c = {Package = val}
                                        data[val] = c
                                elseif key == "Status" then
                                        c.Status = {}
-                                       for i, j in pairs(luci.util.split(val, " ")) do
+                                       for j in val:gmatch("([^ ]+)") do
                                                c.Status[j] = true
                                        end
                                else
@@ -132,9 +70,80 @@ function _parselist(rawdata)
                        end
                else
                        -- Multi-line field
-                       c[l] = c[l] .. "\n" .. line:sub(2)
+                       c[l] = c[l] .. "\n" .. line
                end
        end
-       
+
        return data
-end
\ No newline at end of file
+end
+
+-- Internal lookup function
+local function _lookup(act, pkg)
+       local cmd = ipkg .. " " .. act
+       if pkg then
+               cmd = cmd .. " '" .. pkg:gsub("'", "") .. "'"
+       end
+
+       -- IPKG sometimes kills the whole machine because it sucks
+       -- Therefore we have to use a sucky approach too and use
+       -- tmpfiles instead of directly reading the output
+       local tmpfile = os.tmpname()
+       os.execute(cmd .. (" >%s 2>/dev/null" % tmpfile))
+
+       local data = _parselist(io.lines(tmpfile))
+       os.remove(tmpfile)
+       return data
+end
+
+
+--- Return information about installed and available packages.
+-- @param pkg Limit output to a (set of) packages
+-- @return Table containing package information
+function info(pkg)
+       return _lookup("info", pkg)
+end
+
+--- Return the package status of one or more packages.
+-- @param pkg Limit output to a (set of) packages
+-- @return Table containing package status information
+function status(pkg)
+       return _lookup("status", pkg)
+end
+
+--- Install one or more packages.
+-- @param ... List of packages to install
+-- @return Boolean indicating the status of the action
+-- @return IPKG return code
+function install(...)
+       return _action("install", ...)
+end
+
+--- Determine whether a given package is installed.
+-- @param pkg Package
+-- @return Boolean
+function installed(pkg)
+       local p = status(pkg)[pkg]
+       return (p and p.Status and p.Status.installed)
+end
+
+--- Remove one or more packages.
+-- @param ... List of packages to install
+-- @return Boolean indicating the status of the action
+-- @return IPKG return code
+function remove(...)
+       return _action("remove", ...)
+end
+
+--- Update package lists.
+-- @return Boolean indicating the status of the action
+-- @return IPKG return code
+function update()
+       return _action("update")
+end
+
+--- Upgrades all installed packages.
+-- @return Boolean indicating the status of the action
+-- @return IPKG return code
+function upgrade()
+       return _action("upgrade")
+end