Advertisement
gridcaster

github

Jun 5th, 2021
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.52 KB | None | 0 0
  1. local JSON = dofile("apis/dkjson")
  2.  
  3. -- Build a github API url, with authorization headers.
  4. local function getAPI(path, auth)
  5. local url = ('https://api.github.com/%s'):format(path)
  6. local headers
  7. if auth and auth.type == 'oauth' then
  8. headers = { ['Authorization'] = ('token %s'):format(auth.token) }
  9. end
  10. local req = http.get(url, headers)
  11. if req then
  12. return req.getResponseCode(), JSON.decode(req.readAll())
  13. else
  14. return nil, {}
  15. end
  16. end
  17.  
  18. local function encodeURI(s)
  19. return s:gsub(' ', '%%20')
  20. end
  21.  
  22. -- A class for authorization
  23. local authFile = '.github-auth'
  24. local function writeAuth(data)
  25. f = fs.open(authFile, 'w')
  26. f.write(textutils.serialize(data))
  27. f.close()
  28. end
  29. local function getAuthTable()
  30. local authTable = {}
  31. if fs.exists(authFile) then
  32. f = fs.open(authFile, 'r')
  33. authTable = textutils.unserialize(f.readAll())
  34. f.close()
  35. end
  36. return authTable
  37. end
  38. local Auth = {}
  39. Auth.__index = Auth
  40. Auth.new = function(type, user, token)
  41. return setmetatable({type=type, user=user, token=token}, Auth)
  42. end
  43. Auth.get = function(user)
  44. local authTable = getAuthTable()
  45. local auth = authTable[user]
  46. if auth then
  47. auth = Auth.new(auth.type, auth.user, auth.token)
  48. end
  49. return auth
  50. end
  51. Auth.checkToken = function(self)
  52. local status, request = getAPI('user', self)
  53. return status == 200
  54. end
  55. Auth.save = function(self)
  56. local authTable = getAuthTable()
  57. authTable[self.user] = self
  58. writeAuth(authTable)
  59. end
  60. Auth.delete = function(user)
  61. local authTable = getAuthTable()
  62. authTable[user] = nil
  63. writeAuth(authTable)
  64. end
  65.  
  66. -- A class for a blob (aka a file)
  67. local Blob = {}
  68. Blob.__index = Blob
  69. Blob.new = function(repo, sha, path)
  70. return setmetatable({repo=repo, sha=sha, path=path}, Blob)
  71. end
  72. Blob.fullPath = function(self)
  73. if self.parent then
  74. return fs.combine(self.parent:fullPath(), self.path)
  75. else
  76. return self.path
  77. end
  78. end
  79.  
  80. -- A class for a tree (aka a folder)
  81. local Tree = {}
  82. Tree.__index = Tree
  83. Tree.new = function(repo, sha, path)
  84. local url = ('repos/%s/%s/git/trees/%s'):format(repo.user, repo.name, sha)
  85. local status, data = getAPI(url, repo.auth)
  86. if not status then
  87. error('Could not get github API from ' ..url)
  88. end
  89. if data.tree then
  90. local tree = setmetatable({
  91. repo=repo, sha=data.sha,
  92. path=path or '', size=0,
  93. contents={}
  94. }, Tree)
  95. for _, childdata in ipairs(data.tree) do
  96. childdata.fullPath = fs.combine(tree:fullPath(), childdata.path)
  97. local child
  98. if childdata.type == 'blob' then
  99. child = Blob.new(repo, childdata.sha, childdata.path)
  100. child.size = childdata.size
  101. elseif childdata.type == 'tree' then
  102. child = Tree.new(repo, childdata.sha, childdata.path)
  103. else
  104. error("uh oh", JSON.encode(childdata))
  105. child = childdata
  106. end
  107. tree.size = tree.size + child.size
  108. child.parent = tree
  109. table.insert(tree.contents, child)
  110. end
  111. return tree
  112. else
  113. error("uh oh", JSON.encode(data))
  114. end
  115. end
  116. local function walkTree(t, level)
  117. for _, item in ipairs(t.contents) do
  118. coroutine.yield(item, level)
  119. if getmetatable(item) == Tree then
  120. walkTree(item, level + 1)
  121. end
  122. end
  123. end
  124. Tree.iter = function(self)
  125. return coroutine.wrap(function()
  126. walkTree(self, 0)
  127. end)
  128. end
  129. Tree.cloneTo = function(self, dest, onProgress)
  130. if not fs.exists(dest) then
  131. fs.makeDir(dest)
  132. elseif not fs.isDir(dest) then
  133. return error("Destination is a file!")
  134. end
  135.  
  136. for item in self:iter() do
  137. local gitpath = item:fullPath()
  138. local path = fs.combine(dest, gitpath)
  139. if getmetatable(item) == Tree then
  140. fs.makeDir(path)
  141. elseif getmetatable(item) == Blob then
  142. local data = http.get(
  143. ('https://raw.github.com/%s/%s/%s/%s'):format(
  144. self.repo.user, self.repo.name, self.sha,
  145. encodeURI(gitpath)
  146. )
  147. )
  148. local h = fs.open(path, 'w')
  149. local text = data.readAll()
  150. h.write(text)
  151. h.close()
  152. end
  153. if onProgress then onProgress(item) end
  154. end
  155. end
  156. Tree.fullPath = Blob.fullPath
  157.  
  158. -- A class for a release
  159. local Release = {}
  160. Release.__index = Release
  161. Release.new = function(repo, tag)
  162. return setmetatable({repo=repo, tag=tag}, Release)
  163. end
  164. Release.tree = function(self)
  165. return self.repo:tree(self.tag)
  166. end
  167.  
  168. -- A class for a repository
  169. local __repoPriv = setmetatable({}, {mode='k'})
  170. local Repository = {}
  171. Repository.__index = Repository
  172. Repository.new = function(user, name, auth)
  173. local r = setmetatable({user=user, name=name, auth=auth}, Repository)
  174. __repoPriv[r] = {trees={}}
  175. return r
  176. end
  177. Repository.tree = function(self, sha)
  178. sha = sha or "master"
  179. if not __repoPriv[self].trees[sha] then
  180. __repoPriv[self].trees[sha] = Tree.new(self, sha)
  181. end
  182. return __repoPriv[self].trees[sha]
  183. end
  184. local function releaseFromURL(url, repo)
  185. local status, data = getAPI(url, repo.auth)
  186. if not status then
  187. error('Could not get release github API from ' .. url)
  188. end
  189. -- format is described at https://developer.github.com/v3/repos/releases/
  190. return Release.new(repo, data["tag_name"])
  191. end
  192. Repository.latestRelease = function(self)
  193. return releaseFromURL(('repos/%s/%s/releases/latest'):format(self.user, self.name), self)
  194. end
  195. Repository.releaseForTag = function(self, tag)
  196. return releaseFromURL(('repos/%s/%s/releases/tags/%s'):format(self.user, self.name, tag), self)
  197. end
  198. Repository.__tostring = function(self) return ("Repo@%s/%s"):format(self.user, self.name) end
  199.  
  200. -- Export members
  201. local github = {}
  202. github.Repository = Repository
  203. github.Blob = Blob
  204. github.Tree = Tree
  205. github.Auth = Auth
  206. github.Release = Release
  207. github.repo = Repository.new
  208. return github
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement