Operating system for OpenComputers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
4.7KB

  1. local serial = require "serialization"
  2. local dl = require "download"
  3. local pkg = {}
  4. pkg.cfgPath = "/boot/cfg/pkg"
  5. pkg.sourcePath = pkg.cfgPath .. "/sources.cfg"
  6. pkg.installedPath = pkg.cfgPath .. "/installed.cfg"
  7. require("pkgfs")
  8. local function getSources()
  9. local f = io.open(pkg.sourcePath,"rb")
  10. if not f then return {} end
  11. local c = f:read("*a")
  12. f:close()
  13. return serial.unserialize(c)
  14. end
  15. local function saveSources(t)
  16. fs.makeDirectory(pkg.cfgPath)
  17. local f = io.open(pkg.sourcePath,"wb")
  18. f:write(serial.serialize(t))
  19. f:close()
  20. end
  21. local function getInstalled()
  22. local f = io.open(pkg.installedPath,"rb")
  23. if not f then return {} end
  24. local c = f:read("*a")
  25. f:close()
  26. return serial.unserialize(c)
  27. end
  28. local function saveInstalled(t)
  29. fs.makeDirectory(pkg.cfgPath)
  30. local f = io.open(pkg.installedPath,"wb")
  31. if not f then return false end
  32. f:write(serial.serialize(t))
  33. f:close()
  34. end
  35. local function getRepoMeta(repo)
  36. if not getSources()[repo].cache or not fs.exists("/boot/cfg/pkg/repo-"..repo..".cfg") then
  37. dl(getSources()[repo].path.."/packages.cfg","/boot/cfg/pkg/repo-"..repo..".cfg")
  38. end
  39. local f = io.open("/boot/cfg/pkg/repo-"..repo..".cfg","rb")
  40. local rt = serial.unserialize(f:read("*a"))
  41. f:close()
  42. if not getSources()[repo].cache then
  43. fs.remove("/boot/cfg/pkg/repo-"..repo..".cfg")
  44. end
  45. return rt
  46. end
  47. local function activatePackage(path,compressed)
  48. require("pkgfs").add(path,compressed)
  49. end
  50. local function deactivatePackage(path)
  51. require("pkgfs").remove(path)
  52. end
  53. 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.
  54. local sources = getSources()
  55. sources[name] = {path=path,cache=cache,name=name}
  56. saveSources(sources)
  57. end
  58. function pkg.delRepo(name) -- string -- boolean -- Removes a repository from the list of repositories.
  59. local sources = getSources()
  60. sources[name] = nil
  61. saveSources(sources)
  62. end
  63. function pkg.update() -- Re-download cached repository indexes.
  64. for repo,meta in pairs(getSources()) do
  65. fs.remove("/boot/cfg/pkg/repo-"..repo..".cfg")
  66. if meta.cache then
  67. getRepoMeta(repo)
  68. end
  69. end
  70. end
  71. function pkg.list(filter) -- string -- -- Print a list of available packages matching *filter*.
  72. filter = filter or ""
  73. local pkglist = {}
  74. for repo,_ in pairs(getSources()) do
  75. for pkg,meta in pairs(getRepoMeta(repo)) do
  76. if pkg:find(filter) or (pkg.meta or ""):find(filter) then
  77. meta.repo = repo
  78. pkglist[pkg] = meta
  79. end
  80. end
  81. end
  82. for k,v in pairs(pkglist) do
  83. print(string.format("%s/%s\n %s",v.repo,k,v.description))
  84. end
  85. end
  86. function pkg.getMeta(pkgname) -- string -- table -- Returns the metadata for a the package specified in *pkgname*.
  87. print("Finding package "..pkgname)
  88. for repo,info in pairs(getSources()) do
  89. local pkg = getRepoMeta(repo)[pkgname]
  90. if pkg then
  91. print("Package "..pkgname.." located in repo "..repo.." at "..info.path)
  92. pkg.repository = info
  93. return pkg
  94. end
  95. end
  96. end
  97. function pkg.get(pkgname,auto) -- string boolean -- boolean -- Downloads and mounts a package, identified as *pkgname*, onto the pkgfs.
  98. local pkginfo = pkg.getMeta(pkgname)
  99. if not pkginfo then error("unable to locate package "..pkgname) end
  100. pkginfo.manual = not auto
  101. fs.makeDirectory("/boot/pkg")
  102. for k,v in ipairs(pkginfo.dependencies or {}) do
  103. if not getInstalled()[v] then
  104. pkg.get(v)
  105. end
  106. end
  107. dl(pkginfo.repository.path.."/"..pkginfo.filename,"/boot/pkg/"..pkginfo.filename)
  108. local installed = getInstalled()
  109. installed[pkgname] = pkginfo
  110. saveInstalled(installed)
  111. pcall(activatePackage,"/boot/pkg/"..pkginfo.filename,pkginfo.compressed)
  112. return true
  113. end
  114. 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.
  115. pkg.update()
  116. fs.makeDirectory("/boot/pkg")
  117. local installed = getInstalled()
  118. for repo,info in pairs(getSources()) do
  119. for pkgname,pkginfo in pairs(getRepoMeta(repo)) do
  120. if installed[pkgname] and pkginfo.version ~= installed[pkgname].version or force then
  121. pkg.remove(pkgname)
  122. dl(info.path.."/"..pkginfo.filename,"/boot/pkg/"..pkginfo.filename)
  123. installed[pkgname] = pkg
  124. pcall(activatePackage,"/boot/pkg/"..pkginfo.filename,pkginfo.compressed)
  125. end
  126. end
  127. end
  128. saveInstalled(installed)
  129. end
  130. function pkg.remove(pkgname) -- string -- boolean -- Remove the package *pkgname* from the pkgfs and package directory.
  131. local installed = getInstalled()
  132. local pkginfo = installed[pkgname]
  133. if not pkginfo then return true end
  134. pcall(deactivatePackage,"/boot/pkg/"..pkginfo.filename)
  135. fs.remove("/boot/pkg/"..pkginfo.filename)
  136. installed[pkgname] = nil
  137. saveInstalled(installed)
  138. return true
  139. end
  140. return pkg