Operating system for OpenComputers
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

192 linhas
5.9KB

  1. local serial = require "serialization"
  2. local dl = require "download"
  3. local mtar = require "libmtar"
  4. local pkg = {}
  5. pkg.cfgPath = "/boot/cfg/pkg"
  6. pkg.sourcePath = pkg.cfgPath .. "/sources.cfg"
  7. pkg.installedPath = pkg.cfgPath .. "/installed.cfg"
  8. local w, lz16 = pcall(require,"liblz16")
  9. if not w then lz16 = nil end
  10. fs.makeDirectory("/boot/pkg")
  11. fs.makeDirectory("/boot/cfg/pkg")
  12. require "pkgfs"
  13. local function getSources()
  14. local f = io.open(pkg.sourcePath,"rb")
  15. if not f then return {main={path="https://oc.shadowkat.net/psychos/pkg",cache=true,name="main"}} end
  16. local c = f:read("*a")
  17. f:close()
  18. return serial.unserialize(c)
  19. end
  20. local function saveSources(t)
  21. fs.makeDirectory(pkg.cfgPath)
  22. local f = io.open(pkg.sourcePath,"wb")
  23. f:write(serial.serialize(t))
  24. f:close()
  25. end
  26. local function getInstalled()
  27. local f = io.open(pkg.installedPath,"rb")
  28. if not f then return {} end
  29. local c = f:read("*a")
  30. f:close()
  31. return serial.unserialize(c)
  32. end
  33. local function saveInstalled(t)
  34. fs.makeDirectory(pkg.cfgPath)
  35. local f = io.open(pkg.installedPath,"wb")
  36. if not f then return false end
  37. f:write(serial.serialize(t))
  38. f:close()
  39. end
  40. local function getRepoMeta(repo)
  41. if not getSources()[repo].cache or not fs.exists("/boot/cfg/pkg/repo-"..repo..".cfg") then
  42. dl(getSources()[repo].path.."/packages.cfg","/boot/cfg/pkg/repo-"..repo..".cfg")
  43. end
  44. local f = io.open("/boot/cfg/pkg/repo-"..repo..".cfg","rb")
  45. local rt = serial.unserialize(f:read("*a"))
  46. f:close()
  47. if not getSources()[repo].cache then
  48. fs.remove("/boot/cfg/pkg/repo-"..repo..".cfg")
  49. end
  50. return rt
  51. end
  52. local function activatePackage(path,compressed)
  53. require("pkgfs").add(path,compressed)
  54. end
  55. local function deactivatePackage(path)
  56. require("pkgfs").remove(path)
  57. end
  58. local function fnormalize(s)
  59. return table.concat(fs.segments(s),"/")
  60. end
  61. local function installSystemPackage(path,comp)
  62. local f
  63. if comp and lz16 then
  64. f = lz16.open(path,"rb")
  65. else
  66. f = io.open(path,"rb")
  67. end
  68. for fname, read, size in mtar.iter(f) do
  69. local opath = "/boot/"..fnormalize(fname)
  70. print(opath..": "..tostring(size))
  71. fs.makeDirectory(opath:match("(.+)/[^/]+"))
  72. local of = io.open(opath,"wb")
  73. if not of then error("unable to open "..opath.." for writing") end
  74. local tmp
  75. repeat
  76. tmp = read(2048) or ""
  77. of:write(tmp)
  78. until not tmp or tmp:len() < 1
  79. of:close()
  80. end
  81. return true
  82. end
  83. 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.
  84. local sources = getSources()
  85. sources[name] = {path=path,cache=cache,name=name}
  86. saveSources(sources)
  87. end
  88. function pkg.delRepo(name) -- string -- boolean -- Removes a repository from the list of repositories.
  89. local sources = getSources()
  90. sources[name] = nil
  91. saveSources(sources)
  92. end
  93. function pkg.update() -- Re-download cached repository indexes.
  94. for repo,meta in pairs(getSources()) do
  95. fs.remove("/boot/cfg/pkg/repo-"..repo..".cfg")
  96. if meta.cache then
  97. getRepoMeta(repo)
  98. end
  99. end
  100. end
  101. function pkg.list(filter,installed) -- string boolean -- -- Print a list of available packages matching *filter*, optionally filtering to only installed packages if *installed* is set.
  102. filter = filter or ""
  103. local pkglist = {}
  104. for repo,_ in pairs(getSources()) do
  105. for pkg,meta in pairs(getRepoMeta(repo)) do
  106. if pkg:find(filter) or (pkg.meta or ""):find(filter) then
  107. meta.repo = repo
  108. pkglist[pkg] = meta
  109. end
  110. end
  111. end
  112. for k,v in pairs(pkglist) do
  113. if v.system then io.write("\27[31m") end
  114. print(string.format("%s/%s: %s\27[0m\n %s\n Authors: %s",v.repo,k,v.name,v.description,v.authors))
  115. end
  116. end
  117. function pkg.getMeta(pkgname) -- string -- table -- Returns the metadata for a the package specified in *pkgname*.
  118. print("Finding package "..pkgname)
  119. for repo,info in pairs(getSources()) do
  120. local pkg = getRepoMeta(repo)[pkgname]
  121. if pkg then
  122. print("Package "..pkgname.." located in repo "..repo.." at "..info.path)
  123. pkg.repository = info
  124. return pkg
  125. end
  126. end
  127. end
  128. function pkg.get(pkgname,auto) -- string boolean -- boolean -- Downloads and mounts a package, identified as *pkgname,* onto the pkgfs. Setting *auto* will flag the package as automatically installed; this is used for dependencies.
  129. local pkginfo = pkg.getMeta(pkgname)
  130. if not pkginfo then error("unable to locate package "..pkgname) end
  131. pkginfo.manual = not auto
  132. fs.makeDirectory("/boot/pkg")
  133. for k,v in ipairs(pkginfo.dependencies or {}) do
  134. if not getInstalled()[v] then
  135. pkg.get(v,true)
  136. end
  137. end
  138. dl(pkginfo.repository.path.."/"..pkginfo.filename,"/boot/pkg/"..pkginfo.filename)
  139. local installed = getInstalled()
  140. installed[pkgname] = pkginfo
  141. saveInstalled(installed)
  142. if pkginfo.system then
  143. local rv = installSystemPackage("/boot/pkg/"..pkginfo.filename,pkginfo.compressed)
  144. fs.remove("/boot/pkg/"..pkginfo.filename)
  145. return rv
  146. end
  147. pcall(activatePackage,"/boot/pkg/"..pkginfo.filename,pkginfo.compressed)
  148. return true
  149. end
  150. function pkg.upgrade(force) -- boolean -- -- Upgrades all packages on the system to the current version stored in the relevant repository. If *force* is set, re-download all packages.
  151. pkg.update()
  152. fs.makeDirectory("/boot/pkg")
  153. local installed = getInstalled()
  154. for repo,info in pairs(getSources()) do
  155. for pkgname,pkginfo in pairs(getRepoMeta(repo)) do
  156. if installed[pkgname] and pkginfo.version ~= installed[pkgname].version or force then
  157. pkg.remove(pkgname)
  158. pkg.get(pkgname,pkginfo.auto)
  159. end
  160. end
  161. end
  162. end
  163. function pkg.remove(pkgname) -- string -- boolean -- Remove the package *pkgname* from the pkgfs and package directory.
  164. local installed = getInstalled()
  165. local pkginfo = installed[pkgname]
  166. if not pkginfo then return true end
  167. pcall(deactivatePackage,"/boot/pkg/"..pkginfo.filename)
  168. fs.remove("/boot/pkg/"..pkginfo.filename)
  169. if pkginfo.system then
  170. for k,v in pairs(pkginfo.files) do
  171. fs.remove(v)
  172. end
  173. end
  174. installed[pkgname] = nil
  175. saveInstalled(installed)
  176. return true
  177. end
  178. return pkg