1 -- Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org>
2 -- Copyright 2008 Steven Barth <steven@midlink.org>
3 -- Licensed to the public under the Apache License 2.0.
5 local os = require "os"
6 local io = require "io"
7 local fs = require "nixio.fs"
8 local util = require "luci.util"
15 local ipkg = "opkg --force-removal-of-dependent-packages --force-overwrite --nocase"
16 local icfg = "/etc/opkg.conf"
18 module "luci.model.ipkg"
21 -- Internal action function
22 local function _action(cmd, ...)
24 for k, v in pairs({...}) do
25 pkg = pkg .. " '" .. v:gsub("'", "") .. "'"
28 local c = "%s %s %s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" %{ ipkg, cmd, pkg }
29 local r = os.execute(c)
30 local e = fs.readfile("/tmp/opkg.stderr")
31 local o = fs.readfile("/tmp/opkg.stdout")
33 fs.unlink("/tmp/opkg.stderr")
34 fs.unlink("/tmp/opkg.stdout")
36 return r, o or "", e or ""
39 -- Internal parser function
40 local function _parselist(rawdata)
41 if type(rawdata) ~= "function" then
42 error("OPKG: Invalid rawdata given")
49 for line in rawdata do
50 if line:sub(1, 1) ~= " " then
51 local key, val = line:match("(.-): ?(.*)%s*")
54 if key == "Package" then
57 elseif key == "Status" then
59 for j in val:gmatch("([^ ]+)") do
69 c[l] = c[l] .. "\n" .. line
76 -- Internal lookup function
77 local function _lookup(act, pkg)
78 local cmd = ipkg .. " " .. act
80 cmd = cmd .. " '" .. pkg:gsub("'", "") .. "'"
83 -- OPKG sometimes kills the whole machine because it sucks
84 -- Therefore we have to use a sucky approach too and use
85 -- tmpfiles instead of directly reading the output
86 local tmpfile = os.tmpname()
87 os.execute(cmd .. (" >%s 2>/dev/null" % tmpfile))
89 local data = _parselist(io.lines(tmpfile))
96 return _lookup("info", pkg)
100 return _lookup("status", pkg)
103 function install(...)
104 return _action("install", ...)
107 function installed(pkg)
108 local p = status(pkg)[pkg]
109 return (p and p.Status and p.Status.installed)
113 return _action("remove", ...)
117 return _action("update")
121 return _action("upgrade")
125 local function _list(action, pat, cb)
126 local fd = io.popen(ipkg .. " " .. action ..
127 (pat and (" '%s'" % pat:gsub("'", "")) or ""))
130 local name, version, sz, desc
132 local line = fd:read("*l")
133 if not line then break end
135 name, version, sz, desc = line:match("^(.-) %- (.-) %- (.-) %- (.+)")
138 name, version, sz = line:match("^(.-) %- (.-) %- (.+)")
142 if name and version then
143 if #version > 26 then
144 version = version:sub(1,21) .. ".." .. version:sub(-3,-1)
147 cb(name, version, sz, desc)
160 function list_all(pat, cb)
161 _list("list --size", pat, cb)
164 function list_installed(pat, cb)
165 _list("list_installed --size", pat, cb)
168 function find(pat, cb)
169 _list("find --size", pat, cb)
173 function overlay_root()
175 local fd = io.open(icfg, "r")
182 if ln and ln:match("^%s*option%s+overlay_root%s+") then
183 od = ln:match("^%s*option%s+overlay_root%s+(%S+)")
185 local s = fs.stat(od)
186 if not s or s.type ~= "dir" then
200 function compare_versions(ver1, comp, ver2)
201 if not ver1 or not ver2
202 or not comp or not (#comp > 0) then
203 error("Invalid parameters")
206 -- correct compare string
207 if comp == "<>" or comp == "><" or comp == "!=" or comp == "~=" then comp = "~="
208 elseif comp == "<=" or comp == "<" or comp == "=<" then comp = "<="
209 elseif comp == ">=" or comp == ">" or comp == "=>" then comp = ">="
210 elseif comp == "=" or comp == "==" then comp = "=="
211 elseif comp == "<<" then comp = "<"
212 elseif comp == ">>" then comp = ">"
214 error("Invalid compare string")
218 local av1 = util.split(ver1, "[%.%-]", nil, true)
219 local av2 = util.split(ver2, "[%.%-]", nil, true)
221 local max = table.getn(av1)
222 if (table.getn(av1) < table.getn(av2)) then
223 max = table.getn(av2)
227 local s1 = av1[i] or ""
228 local s2 = av2[i] or ""
230 -- first "not equal" found return true
231 if comp == "~=" and (s1 ~= s2) then return true end
232 -- first "lower" found return true
233 if (comp == "<" or comp == "<=") and (s1 < s2) then return true end
234 -- first "greater" found return true
235 if (comp == ">" or comp == ">=") and (s1 > s2) then return true end
236 -- not equal then return false
237 if (s1 ~= s2) then return false end
240 -- all equal and not compare greater or lower then true
241 return not (comp == "<" or comp == ">")