123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- -- 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 os = require "os"
- local io = require "io"
- local fs = require "nixio.fs"
- local util = require "luci.util"
- local type = type
- local pairs = pairs
- local error = error
- local table = table
- local ipkg = "opkg --force-removal-of-dependent-packages --force-overwrite --nocase"
- local icfg = "/etc/opkg.conf"
- module "luci.model.ipkg"
- -- Internal action function
- local function _action(cmd, ...)
- local pkg = ""
- for k, v in pairs({...}) do
- pkg = pkg .. " '" .. v:gsub("'", "") .. "'"
- end
- local c = "%s %s %s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" %{ ipkg, cmd, pkg }
- local r = os.execute(c)
- local e = fs.readfile("/tmp/opkg.stderr")
- local o = fs.readfile("/tmp/opkg.stdout")
- fs.unlink("/tmp/opkg.stderr")
- fs.unlink("/tmp/opkg.stdout")
- return r, o or "", e or ""
- end
- -- Internal parser function
- local function _parselist(rawdata)
- if type(rawdata) ~= "function" then
- error("OPKG: Invalid rawdata given")
- end
- local data = {}
- local c = {}
- local l = nil
- for line in rawdata do
- if line:sub(1, 1) ~= " " then
- 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 j in val:gmatch("([^ ]+)") do
- c.Status[j] = true
- end
- else
- c[key] = val
- end
- l = key
- end
- else
- -- Multi-line field
- c[l] = c[l] .. "\n" .. line
- end
- end
- return data
- end
- -- Internal lookup function
- local function _lookup(act, pkg)
- local cmd = ipkg .. " " .. act
- if pkg then
- cmd = cmd .. " '" .. pkg:gsub("'", "") .. "'"
- 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))
- local data = _parselist(io.lines(tmpfile))
- os.remove(tmpfile)
- return data
- end
- function info(pkg)
- return _lookup("info", pkg)
- end
- function status(pkg)
- return _lookup("status", pkg)
- end
- function install(...)
- return _action("install", ...)
- end
- function installed(pkg)
- local p = status(pkg)[pkg]
- return (p and p.Status and p.Status.installed)
- end
- function remove(...)
- return _action("remove", ...)
- end
- function update()
- return _action("update")
- end
- function upgrade()
- return _action("upgrade")
- end
- -- List helper
- local function _list(action, pat, cb)
- local fd = io.popen(ipkg .. " " .. action ..
- (pat and (" '%s'" % pat:gsub("'", "")) or ""))
- if fd then
- local name, version, sz, desc
- while true do
- local line = fd:read("*l")
- if not line then break end
- name, version, sz, desc = line:match("^(.-) %- (.-) %- (.-) %- (.+)")
- if not name then
- name, version, sz = line:match("^(.-) %- (.-) %- (.+)")
- desc = ""
- end
- 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
- fd:close()
- end
- end
- function list_all(pat, cb)
- _list("list --size", pat, cb)
- end
- function list_installed(pat, cb)
- _list("list_installed --size", pat, cb)
- end
- function find(pat, cb)
- _list("find --size", pat, cb)
- end
- function overlay_root()
- local od = "/"
- local fd = io.open(icfg, "r")
- if fd then
- local ln
- repeat
- ln = fd:read("*l")
- if ln and ln:match("^%s*option%s+overlay_root%s+") then
- od = ln:match("^%s*option%s+overlay_root%s+(%S+)")
- local s = fs.stat(od)
- if not s or s.type ~= "dir" then
- od = "/"
- end
- break
- end
- until not ln
- fd:close()
- end
- 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
|