-- acf model for packages (apk) local mymodule = {} modelfunctions = require("modelfunctions") posix = require("posix") fs = require("acf.fs") format = require("acf.format") local configfile = "/etc/apk/repositories" local worldfile = "/etc/apk/world" local cachelink = "/etc/apk/cache" local lbuconffile = "/etc/lbu/lbu.conf" local repo = nil local install_cache = false local upgrade_cache = false local toplevel -- ################################################################################ -- LOCAL FUNCTIONS local function gettoplevel() if not toplevel then toplevel = {} local top = format.string_to_table(fs.read_file(worldfile) or "", "%s+") for i,name in ipairs(top) do toplevel[name] = i end end return toplevel end local reload_upgrades = function() if repo then -- clear out upgrade info for name,value in pairs(repo) do if value then value.upgrade = nil end end -- read in which need upgrades local f = modelfunctions.run_executable({"apk", "version", "-l", "<"}) for line in string.gmatch(f, "[^\n]+") do local name = string.match(line, "(%S+)%-%d") if name and repo[name] then repo[name].upgrade = true end end upgrade_cache = true end return repo end local reload_installed = function() if repo then -- clear out installed info for name,value in pairs(repo) do if value then value.installed = nil value.comment = nil end end -- read in which are installed local f = modelfunctions.run_executable({"apk", "info", "-vv"}) for line in string.gmatch(f, "[^\n]+") do local name, ver, comment = string.match(line, "(%S+)%-(%d+%S*)%s+%-%s+(.*)") if name then if not repo[name] then repo[name] = {} end repo[name].installed = ver repo[name].comment = comment end end install_cache = true end return repo end local repository = function() if not repo then -- read in all of the packages local f,errtxt = modelfunctions.run_executable({"apk", "search"}) repo = {} install_cache = false upgrade_cache = false for line in string.gmatch(f, "[^\n]+") do local name, ver = string.match(line, "(.*)%-(%d+.*)") if name and (not repo[name] or repo[name].version < ver) then repo[name] = {} repo[name].version = ver end end end if not install_cache then reload_installed() end if not upgrade_cache then reload_upgrades() end return repo end -- Find all the packages that this package depends on (using recursion) local find_dependents find_dependents = function(package) repo = repo or repository() if not repo[package] then return {} end if not repo[package].dependents then repo[package].dependents = {} local f = modelfunctions.run_executable({"apk", "info", "-R", package}) for line in string.gmatch(f, "[^\n]+") do if not line:find(":") and not line:find("^%s*$") then table.insert(repo[package].dependents, line) for i,dep in ipairs(find_dependents(line, saved, output)) do table.insert(repo[package].dependents, dep) end end end end return repo[package].dependents end local function upgrade_available(package) local retval = false repo = repo or repository() if repo[package] and repo[package].upgrade then retval = true else -- check the dependents for i,dep in ipairs(find_dependents(package)) do if repo[dep] and repo[dep].upgrade then retval = true break end end end return retval end local resetpermissions = function(self) if self.sessiondata then self.sessiondata.menu = nil end if self.sessiondata then self.sessiondata.permissions = nil end end -- ################################################################################ -- PUBLIC FUNCTIONS mymodule.get_loaded_packages = function() repo = repository() toplevel = gettoplevel() -- read in the loaded packages local top = cfe({ type="list", value={}, label="Top Level Packages"}) local depend = cfe({ type="list", value={}, label="Dependent Packages"}) for name,value in pairs(repo) do if value.installed then local temp = {} temp.name = name temp.version = value.installed temp.description = value.comment temp.upgrade = value.upgrade if toplevel[name] then top.value[#top.value+1] = temp else depend.value[#depend.value+1] = temp end end end table.sort(top.value, function(a,b) return (a.name < b.name) end) table.sort(depend.value, function(a,b) return (a.name < b.name) end) return cfe({ type="group", value={toplevel=top, dependent=depend}, label="Installed Packages" }) end mymodule.get_available_packages = function() repo = repository() -- available are all except same version installed local available = cfe({ type="list", value={}, label="Available Packages" }) for name,value in pairs(repo) do if value.version and (not value.installed or value.upgrade) then local temp = {} temp.name = name temp.version = value.version temp.upgrade = value.upgrade available.value[#available.value + 1] = temp end end table.sort(available.value, function(a,b) return (a.name < b.name) end) return available end mymodule.get_delete_package = function(self, clientdata) local result = {} result.package = cfe({ value=clientdata.package, label="Package" }) return cfe({ type="group", value=result, label="Result of Delete" }) end mymodule.delete_package = function(self, deleterequest) deleterequest.descr, deleterequest.errtxt = modelfunctions.run_executable({"apk", "del", deleterequest.value.package.value}, true) if deleterequest.errtxt == "" then deleterequest.errtxt = "Failed to delete package." end -- Destroy menu and permissions info in session so recalculated resetpermissions(self) return deleterequest end mymodule.get_install_package = function(self, clientdata) local result = {} result.package = cfe({ value=clientdata.package, label="Package" }) return cfe({ type="group", value=result, label="Result of Install" }) end mymodule.install_package = function(self, installrequest) installrequest.descr, installrequest.errtxt = modelfunctions.run_executable({"apk", "add", installrequest.value.package.value}, true) if not installrequest.errtxt then -- Destroy menu and permissions info in session so recalculated resetpermissions(self) end return installrequest end mymodule.get_upgrade_package = function(self, clientdata) local result = {} result.package = cfe({ value=clientdata.package, label="Package" }) return cfe({ type="group", value=result, label="Result of Upgrade" }) end mymodule.upgrade_package = function(self, upgraderequest) upgraderequest.descr, upgraderequest.errtxt = modelfunctions.run_executable({"apk", "fix", "-u", upgraderequest.value.package.value}, true) if upgraderequest.errtxt == "" then upgraderequest.errtxt = "Failed to upgrade package." end -- Destroy menu and permissions info in session so recalculated resetpermissions(self) return upgraderequest end mymodule.get_update_all = function(self, clientdata) local result = {} return cfe({ type="group", value=result, label="Result of Update" }) end mymodule.update_all = function(self, updaterequest) updaterequest.descr, updaterequest.errtxt = modelfunctions.run_executable({"apk", "update"}, true) if updaterequest.errtxt == "" then updaterequest.errtxt = "Failed to update index." end return updaterequest end mymodule.get_upgrade_all = function(self, clientdata) local result = {} return cfe({ type="group", value=result, label="Result of Upgrade" }) end mymodule.upgrade_all = function(self, upgraderequest) upgraderequest.descr, upgraderequest.errtxt = modelfunctions.run_executable({"apk", "upgrade", "-U"}, true) if upgraderequest.errtxt == "" then upgraderequest.errtxt = "Failed to upgrade packages." end -- Destroy menu and permissions info in session so recalculated resetpermissions(self) return upgraderequest end mymodule.get_cache = function() local cache = {} cache.enable = cfe({ type="boolean", value=false, label="Enable Cache" }) cache.directory = cfe({ label="Cache Directory" }) local link = posix.stat(cachelink, "type") if link == "link" then cache.enable.value = true cache.directory.value = posix.readlink(cachelink) else if link then cache.enable.errtxt = cachelink.." exists but is not a link" end local lbu_media = format.parse_ini_file(fs.read_file(lbuconffile), "", "LBU_MEDIA") if lbu_media then cache.directory.value = "/media/"..lbu_media.."/cache" end end return cfe({ type="group", value=cache, label="Cache Settings" }) end mymodule.update_cache = function(self, cache) cache.value.enable.errtxt = nil if not cache.value.enable.value then os.remove(cachelink) else local success = false cache.errtxt = "Failed to set cache" if cache.value.directory.value == "" then cache.value.directory.errtxt = "Directory must be defined" else local dir = posix.stat(cache.value.directory.value, "type") if dir and dir ~= "directory" then cache.value.directory.errtxt = "Path exists but is not a directory" elseif not dir then success = fs.create_directory(cache.value.directory.value) if not success then cache.value.directory.errtxt = "Failed to create directory" end else success = true end end if success then os.remove(cachelink) posix.link(cache.value.directory.value, cachelink, true) cache.errtxt = nil end end return cache end mymodule.get_configfile = function() return modelfunctions.getfiledetails(configfile) end mymodule.update_configfile = function(self, newconfig) return modelfunctions.setfiledetails(self, newconfig, {configfile}) end mymodule.get_package_details = function(package) repo = repo or repository() local details = {} details.package = cfe({ value=package, label="Package" }) details.version = cfe({ label="Available Version" }) details.installed = cfe({ label="Installed Version" }) details.comment = cfe({ label="Description" }) details.webpage = cfe({ label="Web Page" }) details.size = cfe({ label="Size" }) details.upgrade = cfe({ label="Upgrade Details" }) if not repo[package] then details.package.errtxt = "Invalid package" else details.version.value = repo[package].version if repo[package].installed then details.installed.value = repo[package].installed details.comment.value = repo[package].comment local cmdresult = format.string_to_table((modelfunctions.run_executable({"apk", "info", "-ws", package})), "\n") for i,line in ipairs(cmdresult) do if string.find(line, " webpage:$") then details.webpage.value = cmdresult[i+1] or "" elseif string.find(line, " size:$") then details.size.value = cmdresult[i+1] or "" end end local dependents = find_dependents(package) table.insert(dependents, 1, package) local revdeps = {} details.upgrade.value = {} for i,val in ipairs(dependents) do if not revdeps[val] then revdeps[val] = true if repo[val] and repo[val].upgrade then table.insert(details.upgrade.value, val.." "..repo[val].installed.." -> "..repo[val].version) end end end details.upgrade.value = table.concat(details.upgrade.value, "\n") end end return cfe({ type="group", value=details, label="Package Details" }) end return mymodule