--- Copyright 2008-2011 Jo-Philipp Wich <xm@subsignal.org>
+-- Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org>
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Licensed to the public under the Apache License 2.0.
local ipkg = "opkg --force-removal-of-dependent-packages --force-overwrite --nocase"
local icfg = "/etc/opkg.conf"
---- LuCI OPKG call abstraction library
module "luci.model.ipkg"
-- Internal action function
local function _action(cmd, ...)
- local pkg = ""
+ local cmdline = { ipkg, cmd }
+
+ local k, v
for k, v in pairs({...}) do
- pkg = pkg .. " '" .. v:gsub("'", "") .. "'"
+ cmdline[#cmdline+1] = util.shellquote(v)
end
- local c = "%s %s %s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" %{ ipkg, cmd, pkg }
+ local c = "%s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" % table.concat(cmdline, " ")
local r = os.execute(c)
local e = fs.readfile("/tmp/opkg.stderr")
local o = fs.readfile("/tmp/opkg.stdout")
end
-- Internal lookup function
-local function _lookup(act, pkg)
- local cmd = ipkg .. " " .. act
+local function _lookup(cmd, pkg)
+ local cmdline = { ipkg, cmd }
if pkg then
- cmd = cmd .. " '" .. pkg:gsub("'", "") .. "'"
+ cmdline[#cmdline+1] = util.shellquote(pkg)
end
-- OPKG 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))
+ os.execute("%s >%s 2>/dev/null" %{ table.concat(cmdline, " "), tmpfile })
local data = _parselist(io.lines(tmpfile))
os.remove(tmpfile)
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 OPKG return code, STDOUT and STDERR
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 OPKG return code, STDOUT and STDERR
function remove(...)
return _action("remove", ...)
end
---- Update package lists.
--- @return Boolean indicating the status of the action
--- @return OPKG return code, STDOUT and STDERR
function update()
return _action("update")
end
---- Upgrades all installed packages.
--- @return Boolean indicating the status of the action
--- @return OPKG return code, STDOUT and STDERR
function upgrade()
return _action("upgrade")
end
-- List helper
-function _list(action, pat, cb)
- local fd = io.popen(ipkg .. " " .. action ..
- (pat and (" '%s'" % pat:gsub("'", "")) or ""))
+local function _list(action, pat, cb)
+ local cmdline = { ipkg, action }
+ if pat then
+ cmdline[#cmdline+1] = util.shellquote(pat)
+ end
+ local fd = io.popen(table.concat(cmdline, " "))
if fd then
- local name, version, desc
+ local name, version, sz, desc
while true do
local line = fd:read("*l")
if not line then break end
- name, version, desc = line:match("^(.-) %- (.-) %- (.+)")
+ name, version, sz, desc = line:match("^(.-) %- (.-) %- (.-) %- (.+)")
if not name then
- name, version = line:match("^(.-) %- (.+)")
+ name, version, sz = line:match("^(.-) %- (.-) %- (.+)")
desc = ""
end
- cb(name, version, desc)
+ if name and version then
+ if #version > 26 then
+ version = version:sub(1,21) .. ".." .. version:sub(-3,-1)
+ end
+
+ cb(name, version, sz, desc)
+ end
name = nil
version = nil
+ sz = nil
desc = nil
end
end
end
---- List all packages known to opkg.
--- @param pat Only find packages matching this pattern, nil lists all packages
--- @param cb Callback function invoked for each package, receives name, version and description as arguments
--- @return nothing
function list_all(pat, cb)
- _list("list", pat, cb)
+ _list("list --size", pat, cb)
end
---- List installed packages.
--- @param pat Only find packages matching this pattern, nil lists all packages
--- @param cb Callback function invoked for each package, receives name, version and description as arguments
--- @return nothing
function list_installed(pat, cb)
- _list("list_installed", pat, cb)
+ _list("list_installed --size", pat, cb)
end
---- Find packages that match the given pattern.
--- @param pat Find packages whose names or descriptions match this pattern, nil results in zero results
--- @param cb Callback function invoked for each patckage, receives name, version and description as arguments
--- @return nothing
function find(pat, cb)
- _list("find", pat, cb)
+ _list("find --size", pat, cb)
end
---- Determines the overlay root used by opkg.
--- @return String containing the directory path of the overlay root.
function overlay_root()
local od = "/"
local fd = io.open(icfg, "r")
return od
end
+
+function compare_versions(ver1, comp, ver2)
+ if not ver1 or not ver2
+ or not comp or not (#comp > 0) then
+ error("Invalid parameters")
+ return nil
+ end
+ -- correct compare string
+ if comp == "<>" or comp == "><" or comp == "!=" or comp == "~=" then comp = "~="
+ elseif comp == "<=" or comp == "<" or comp == "=<" then comp = "<="
+ elseif comp == ">=" or comp == ">" or comp == "=>" then comp = ">="
+ elseif comp == "=" or comp == "==" then comp = "=="
+ elseif comp == "<<" then comp = "<"
+ elseif comp == ">>" then comp = ">"
+ else
+ error("Invalid compare string")
+ return nil
+ end
+
+ local av1 = util.split(ver1, "[%.%-]", nil, true)
+ local av2 = util.split(ver2, "[%.%-]", nil, true)
+
+ local max = table.getn(av1)
+ if (table.getn(av1) < table.getn(av2)) then
+ max = table.getn(av2)
+ end
+
+ for i = 1, max, 1 do
+ local s1 = av1[i] or ""
+ local s2 = av2[i] or ""
+
+ -- first "not equal" found return true
+ if comp == "~=" and (s1 ~= s2) then return true end
+ -- first "lower" found return true
+ if (comp == "<" or comp == "<=") and (s1 < s2) then return true end
+ -- first "greater" found return true
+ if (comp == ">" or comp == ">=") and (s1 > s2) then return true end
+ -- not equal then return false
+ if (s1 ~= s2) then return false end
+ end
+
+ -- all equal and not compare greater or lower then true
+ return not (comp == "<" or comp == ">")
+end