Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local git = { token = nil }
- local function indexBy(contents, key)
- local indexedContents = {}
- for _, entry in ipairs(contents) do
- indexedContents[entry[key]] = entry
- end
- return indexedContents
- end
- local BASE64_CHARACTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
- local function decodeBase64(data)
- --http://lua-users.org/wiki/BaseSixtyFour
- data = string.gsub(data, '[^' .. BASE64_CHARACTERS .. '=]', '')
- return (data:gsub('.', function(x)
- if (x == '=') then
- return ''
- end
- local r, f = '', (BASE64_CHARACTERS:find(x) - 1)
- for i = 6, 1, -1 do
- r = r .. (f % 2 ^ i - f % 2 ^ (i - 1) > 0 and '1' or '0')
- end
- return r;
- end) :gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
- if (#x ~= 8) then
- return ''
- end
- local c = 0
- for i = 1, 8 do
- c = c + (x:sub(i, i) == '1' and 2 ^ (8 - i) or 0)
- end
- return string.char(c)
- end))
- end
- local function fetchFile(url)
- if git.token == nil then
- return http.get(url).readAll()
- else
- return http.get(url, { Authorization = "Bearer " .. git.token }).readAll()
- end
- end
- local function fetchJson(url)
- return textutils.unserializeJSON(fetchFile(url))
- end
- function git.fetchContents(user, repo, path)
- if path == nil then
- path = ""
- end
- return fetchJson("https://api.github.com/repos/" .. user .. "/" .. repo .. "/contents/" .. path)
- end
- function git.fetchTree(user, repo, branch)
- return fetchJson("https://api.github.com/repos/" .. user .. "/" .. repo .. "/git/trees/" .. branch .. "?recursive=1")
- end
- local function clearLines(targetY)
- local _, cursorY = term.getCursorPos()
- for y = targetY, cursorY do
- term.setCursorPos(1, y)
- term.clearLine()
- end
- term.setCursorPos(1, targetY)
- end
- function git.checkoutLibrary(user, repo, library, targetDir)
- local repoContents = indexBy(git.fetchContents(user, repo), "path")
- local contentsDefinitionFile = repoContents["contents.json"]
- if contentsDefinitionFile == nil then
- error("Repo " .. user .. "/" .. repo .. " doesn't define contents.json")
- end
- local contentsDefinition = fetchJson(contentsDefinitionFile.download_url)
- local libraryDefinition = indexBy(contentsDefinition, "name")[library]
- if libraryDefinition == nil then
- error("Library " .. library .. " doesn't exist in repo " .. user .. "/" .. repo)
- end
- local version = libraryDefinition["version"]
- local rootPackage = libraryDefinition["package"]
- if rootPackage == nil then
- rootPackage = ""
- end
- local libraryContentsDefinition = libraryDefinition["contents"]
- if libraryContentsDefinition == nil then
- error("Library " .. user .. "/" .. repo .. "/" .. library .. " doesn't define any contents")
- end
- local contentUrls = git.fetchLibraryContentInfo(user, repo, library, libraryContentsDefinition, rootPackage)
- print("Pulling library " .. library .. " in version " .. version)
- local entryCount = #contentUrls
- local _, cursorY = term.getCursorPos()
- for index, entry in pairs(contentUrls) do
- clearLines(cursorY)
- io.write(index .. "/" .. entryCount .. ": " .. entry.path)
- local blobConfig = fetchJson(entry.url)
- if blobConfig["encoding"] ~= "base64" then
- error("Unknown blob encoding at " .. entry.url)
- end
- local data = decodeBase64(blobConfig["content"])
- local path = targetDir .. "/" .. entry.path
- local dir = fs.getDir(path)
- if fs.exists(dir) then
- fs.makeDir(dir)
- end
- local file = fs.open("path", "w")
- file.write(data)
- file.close()
- end
- clearLines(cursorY)
- print("done")
- end
- local PathTree = {}
- PathTree.__index = PathTree
- function PathTree.new()
- local tree = { children = {}, path = "" }
- setmetatable(tree, PathTree)
- return tree
- end
- function PathTree:getOrCreateChild(name)
- local child = self.children[name]
- if child == nil then
- child = PathTree.new()
- if self.path == "" then
- child.path = name
- else
- child.path = self.path .. "/" .. name
- end
- self.children[name] = child
- end
- return child
- end
- function PathTree:insert(rawPath)
- local node = self
- for part in string.gmatch(rawPath, "[^/]+") do
- node = node:getOrCreateChild(part)
- end
- return node
- end
- function PathTree:remove(childName)
- self.children[childName] = nil
- end
- function PathTree:getChildrenDeep(children)
- if children == nil then
- children = {}
- end
- for _, child in pairs(self.children) do
- table.insert(children, child)
- child:getChildrenDeep(children)
- end
- return children
- end
- local function removeExcludedTree(tree, excludedTree)
- for name, subExcludedTree in pairs(excludedTree.children) do
- if subExcludedTree.exclude then
- tree:remove(name)
- else
- local subTree = tree.children[name]
- if subTree ~= nil then
- removeExcludedTree(subTree, excludedTree)
- end
- end
- end
- end
- local function removeNonIncludedTree(tree, includedTree)
- if includedTree.children["*"] ~= nil then
- return
- end
- for name, subTree in pairs(tree.children) do
- local subIncludeTree = includedTree.children[name]
- if subIncludeTree == nil then
- tree:remove(name)
- else
- removeNonIncludedTree(subTree, subIncludeTree)
- end
- end
- end
- local function removeBasePath(path, basePath)
- local pathIterator = string.gmatch(path, "[^/]+")
- for basePathPart in string.gmatch(basePath, "[^/]+") do
- local pathPart = pathIterator()
- if basePathPart ~= pathPart then
- return nil
- end
- end
- local remainingParts = {}
- for remainingPart in pathIterator do
- table.insert(remainingParts, remainingPart)
- end
- return table.concat(remainingParts, "/")
- end
- function git.fetchLibraryContentInfo(user, repo, library, contentsDefinition, basePath)
- local gitPaths = indexBy(git.fetchTree(user, repo, "master")["tree"], "path")
- local gitPathsTree = PathTree.new()
- for path, entry in pairs(gitPaths) do
- path = removeBasePath(path, basePath)
- if path ~= nil and path ~= "" and entry.type == "blob" then
- gitPathsTree:insert(path).url = entry.url
- end
- end
- if gitPathsTree == nil then
- error("library " .. library .. " has invalid basePath: " .. basePath)
- end
- local includedPathsTree = PathTree.new()
- local excludedPathsTree = PathTree.new()
- for _, includedPath in pairs(contentsDefinition["include"]) do
- includedPathsTree:insert(includedPath)
- end
- for _, excludedPath in pairs(contentsDefinition["exclude"]) do
- excludedPathsTree:insert(excludedPath).exclude = true
- end
- removeExcludedTree(gitPathsTree, excludedPathsTree)
- removeNonIncludedTree(gitPathsTree, includedPathsTree)
- local children = {}
- for _, child in pairs(gitPathsTree:getChildrenDeep()) do
- if child.url ~= nil then
- table.insert(children, child)
- end
- end
- return children
- end
- return git
Add Comment
Please, Sign In to add comment