From a12296639b3d846a6f9a25f3ada35fdf6125f092 Mon Sep 17 00:00:00 2001 From: Dan Ports Date: Sun, 12 Apr 2020 17:30:31 -0700 Subject: [PATCH] #26: Fetch tree and blob contents lazily. --- apis/github | 80 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/apis/github b/apis/github index aa01e91..e2e6655 100644 --- a/apis/github +++ b/apis/github @@ -76,51 +76,84 @@ Blob.fullPath = function(self) return self.path end end +Blob.getContents = function(self) + local data = http.get( + ('https://raw.github.com/%s/%s/%s/%s'):format( + self.repo.user, self.repo.name, self.sha, + encodeURI(self:fullPath()) + ) + ) + return data.readAll() +end -- A class for a tree (aka a folder) local Tree = {} Tree.__index = Tree Tree.new = function(repo, sha, path) - local url = ('repos/%s/%s/git/trees/%s'):format(repo.user, repo.name, sha) - local status, data = getAPI(url, repo.auth) + return setmetatable({ + repo = repo, + sha = sha, + path = path or '' + }, Tree) +end +Tree.getContents = function(self) + if self.contents then + return self.contents + end + + local url = ('repos/%s/%s/git/trees/%s'):format(self.repo.user, self.repo.name, self.sha) + local status, data = getAPI(url, self.repo.auth) if not status then error('Could not get github API from ' ..url) end if data.tree then - local tree = setmetatable({ - repo=repo, sha=data.sha, - path=path or '', size=0, - contents={} - }, Tree) + self.sha = data.sha + self.size = 0 + self.contents = {} for _, childdata in ipairs(data.tree) do - childdata.fullPath = fs.combine(tree:fullPath(), childdata.path) + childdata.fullPath = fs.combine(self:fullPath(), childdata.path) local child if childdata.type == 'blob' then - child = Blob.new(repo, childdata.sha, childdata.path) + child = Blob.new(self.repo, childdata.sha, childdata.path) child.size = childdata.size elseif childdata.type == 'tree' then - child = Tree.new(repo, childdata.sha, childdata.path) + child = Tree.new(self.repo, childdata.sha, childdata.path) else - error("uh oh", JSON.encode(childdata)) - child = childdata + error("Unknown tree node type", JSON.encode(childdata)) end - tree.size = tree.size + child.size - child.parent = tree - table.insert(tree.contents, child) + self.size = self.size + (child.size or 0) + child.parent = self + table.insert(self.contents, child) end - return tree + return self.contents else - error("uh oh", JSON.encode(data)) + error("No tree data returned", JSON.encode(data)) end end local function walkTree(t, level) - for _, item in ipairs(t.contents) do + for _, item in ipairs(t:getContents()) do coroutine.yield(item, level) if getmetatable(item) == Tree then walkTree(item, level + 1) end end end +Tree.getFullSize = function(self) + local size = 0 + for item in self:iter() do + if getmetatable(item) == Blob then + size = size + item.size + end + end + return size +end +Tree.getChild = function(self, path) + for _, item in ipairs(self:getContents()) do + if item.path == path then + return item + end + end +end Tree.iter = function(self) return coroutine.wrap(function() walkTree(self, 0) @@ -134,19 +167,12 @@ Tree.cloneTo = function(self, dest, onProgress) end for item in self:iter() do - local gitpath = item:fullPath() - local path = fs.combine(dest, gitpath) + local path = fs.combine(dest, item:fullPath()) if getmetatable(item) == Tree then fs.makeDir(path) elseif getmetatable(item) == Blob then - local data = http.get( - ('https://raw.github.com/%s/%s/%s/%s'):format( - self.repo.user, self.repo.name, self.sha, - encodeURI(gitpath) - ) - ) + local text = item:getContents() local h = fs.open(path, 'w') - local text = data.readAll() h.write(text) h.close() end