local serial = require "serialization" local dl = require "download" local pkg = {} pkg.cfgPath = "/boot/cfg/pkg" pkg.sourcePath = pkg.cfgPath .. "/sources.cfg" pkg.installedPath = pkg.cfgPath .. "/installed.cfg" require("pkgfs") local function getSources() local f = io.open(pkg.sourcePath,"rb") if not f then return {} end local c = f:read("*a") f:close() return serial.unserialize(c) end local function saveSources(t) fs.makeDirectory(pkg.cfgPath) local f = io.open(pkg.sourcePath,"wb") f:write(serial.serialize(t)) f:close() end local function getInstalled() local f = io.open(pkg.installedPath,"rb") if not f then return {} end local c = f:read("*a") f:close() return serial.unserialize(c) end local function saveInstalled(t) fs.makeDirectory(pkg.cfgPath) local f = io.open(pkg.installedPath,"wb") if not f then return false end f:write(serial.serialize(t)) f:close() end local function getRepoMeta(repo) if not getSources()[repo].cache or not fs.exists("/boot/cfg/pkg/repo-"..repo..".cfg") then dl(getSources()[repo].path.."/packages.cfg","/boot/cfg/pkg/repo-"..repo..".cfg") end local f = io.open("/boot/cfg/pkg/repo-"..repo..".cfg","rb") local rt = serial.unserialize(f:read("*a")) f:close() if not getSources()[repo].cache then fs.remove("/boot/cfg/pkg/repo-"..repo..".cfg") end return rt end local function activatePackage(path,compressed) require("pkgfs").add(path,compressed) end local function deactivatePackage(path) require("pkgfs").remove(path) end function pkg.addRepo(name,path,cache) -- string string boolean -- boolean -- Adds a repository, referred to as *name*, to the list of package sources, with the remote path *path*. If *cache* is set, keep a local copy of the repository index. local sources = getSources() sources[name] = {path=path,cache=cache,name=name} saveSources(sources) end function pkg.delRepo(name) -- string -- boolean -- Removes a repository from the list of repositories. local sources = getSources() sources[name] = nil saveSources(sources) end function pkg.update() -- Re-download cached repository indexes. for repo,meta in pairs(getSources()) do fs.remove("/boot/cfg/pkg/repo-"..repo..".cfg") if meta.cache then getRepoMeta(repo) end end end function pkg.list(filter) -- string -- -- Print a list of available packages matching *filter*. filter = filter or "" local pkglist = {} for repo,_ in pairs(getSources()) do for pkg,meta in pairs(getRepoMeta(repo)) do if pkg:find(filter) or (pkg.meta or ""):find(filter) then meta.repo = repo pkglist[pkg] = meta end end end for k,v in pairs(pkglist) do print(string.format("%s/%s\n %s",v.repo,k,v.description)) end end function pkg.getMeta(pkgname) -- string -- table -- Returns the metadata for a the package specified in *pkgname*. print("Finding package "..pkgname) for repo,info in pairs(getSources()) do local pkg = getRepoMeta(repo)[pkgname] if pkg then print("Package "..pkgname.." located in repo "..repo.." at "..info.path) pkg.repository = info return pkg end end end function pkg.get(pkgname,auto) -- string boolean -- boolean -- Downloads and mounts a package, identified as *pkgname*, onto the pkgfs. local pkginfo = pkg.getMeta(pkgname) if not pkginfo then error("unable to locate package "..pkgname) end pkginfo.manual = not auto fs.makeDirectory("/boot/pkg") for k,v in ipairs(pkginfo.dependencies or {}) do if not getInstalled()[v] then pkg.get(v) end end dl(pkginfo.repository.path.."/"..pkginfo.filename,"/boot/pkg/"..pkginfo.filename) local installed = getInstalled() installed[pkgname] = pkginfo saveInstalled(installed) pcall(activatePackage,"/boot/pkg/"..pkginfo.filename,pkginfo.compressed) return true end function pkg.upgrade(force) -- boolean -- boolean -- Upgrades all packages on the system to the current version stored in the relevant repository. If *force* is set, re-download all packages. pkg.update() fs.makeDirectory("/boot/pkg") local installed = getInstalled() for repo,info in pairs(getSources()) do for pkgname,pkginfo in pairs(getRepoMeta(repo)) do if installed[pkgname] and pkginfo.version ~= installed[pkgname].version or force then pkg.remove(pkgname) dl(info.path.."/"..pkginfo.filename,"/boot/pkg/"..pkginfo.filename) installed[pkgname] = pkg pcall(activatePackage,"/boot/pkg/"..pkginfo.filename,pkginfo.compressed) end end end saveInstalled(installed) end function pkg.remove(pkgname) -- string -- boolean -- Remove the package *pkgname* from the pkgfs and package directory. local installed = getInstalled() local pkginfo = installed[pkgname] if not pkginfo then return true end pcall(deactivatePackage,"/boot/pkg/"..pkginfo.filename) fs.remove("/boot/pkg/"..pkginfo.filename) installed[pkgname] = nil saveInstalled(installed) return true end return pkg