Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local args = {...}
- local gitProfile = {
- api = "https://api.github.com/repos",
- raw = "https://raw.githubusercontent.com",
- username = "Morganamilo",
- reponame = "LunaOS",
- access_token = "31b6f63ef3e86f2e9972e2dae485ea6b02442bea"
- }
- local blacklist = {
- ".gitignore",
- "README.md",
- "docs"
- }
- local function isBlacklisted(str)
- for k,v in pairs(blacklist) do
- if v == str:sub(1, #v) then
- return true
- end
- end
- return false
- end
- local git = {}
- local utils = {}
- local numToHex = {"1", "2", "3", "4", "5", "6", "7", "b", "9", "a", "b", "c", "d", "e", "f"}
- numToHex[0] = "0"
- numToHex[16] = "-"
- local whitespace = {" ", "\t", "\n", "\r"}
- local escapes = {["\\\""] = "\"", ["\\\\"] = "\\", ["\\b"] = "\b", ["\\f"] = "\f", ["\\n"] = "\n", ["\\r"] = "\r", ["\\t"] = "\t", ["\\/"] = "/"}
- local control = {":",",","{", "}", "[", "]"}
- local JSON = {}
- local xSize, ySize = term.getSize()
- local paneSize = 9
- local paneStart = math.floor(ySize/2 - paneSize / 2)
- local drawText
- local drawBackground
- local drawBar
- local drawDots
- local decodeImage
- local drawImage
- local width = xSize - 6
- local imageStart = paneStart
- local textStart = paneStart + 5
- local barStart = paneStart + 9
- local filesToDownload = 100
- local filesDownloaded = 0
- local image = " "
- local function drawBackground()
- local backgroundPos = math.floor((xSize - width) / 2) + 1
- local whitespace = string.rep(" ", width)
- local textColour = string.rep("8", width)
- for y = 5, 8 do
- term.setCursorPos(backgroundPos, y)
- term.blit(whitespace, textColour, textColour)
- end
- end
- local function drawText(text)
- local width = width - 2
- local textPos = math.floor((xSize - width) / 2) + 1
- local textColour = string.rep("b", width)
- local backgroundColour = string.rep("7", width)
- for y = textStart, textStart + 3 do
- local t = text:sub(1 + (y - textStart) * width, (y - textStart + 1) * width)
- local prePad = string.rep(" ", math.floor(math.max(width - #t, 0) / 2))
- local postPad = string.rep(" ", width - #prePad - #t)
- t = prePad .. t .. postPad
- term.setCursorPos(textPos + width - #t , y)
- term.blit(t, textColour, backgroundColour)
- end
- end
- local function drawBar(percent)
- local width = width - 2
- local percent = math.floor((percent * width) + 0.5)
- local backgroundPos = math.floor((xSize - width) / 2) + 1
- local whitespace = string.rep(" ", width)
- local textColour = string.rep("9", percent) .. string.rep("8", width - percent)
- term.setCursorPos(backgroundPos, barStart)
- term.blit(whitespace, textColour, textColour)
- end
- local function decodeImage(image)
- local decodeImage = {size = {}, text = {}, textColour = {}, colour = {}}
- decodeImage.size[1] = string.byte(image:sub(1,1))
- decodeImage.size[2] = string.byte(image:sub(2,2))
- for n = 3, #image, 3 do
- local text = image:sub(n,n)
- local textColour = string.byte(image, n + 1)
- local colour = string.byte(image, n + 2)
- local l = #decodeImage.text + 1
- decodeImage.text[l] = text
- decodeImage.textColour[l] = numToHex[textColour]
- decodeImage.colour[l] = numToHex[colour]
- end
- return decodeImage
- end
- local function drawImage()
- for y = 1, image.size[2] do
- local pixel = ""
- local text = ""
- local textColour = ""
- for x = 1, image.size[1] do
- pixel = pixel .. image.colour[x + ((y - 1)* image.size[1])] or " "
- text = text .. image.text[x + ((y - 1)* image.size[1])] or "0"
- textColour = textColour .. image.textColour[x + ((y - 1)* image.size[1])] or "0"
- end
- term.setCursorPos(1 + math.floor(xSize/2 - image.size[1]/2), imageStart + y - 1)
- term.blit(text, textColour, pixel)
- end
- end
- function JSON.escape(str)
- for k, v in pairs(escapes) do
- str = str:gsub(v, k)
- end
- return str
- end
- function JSON.unescape(str)
- for k, v in pairs(escapes) do
- str = str:gsub(k, v)
- end
- return str
- end
- function JSON.isArray(tbl)
- local size = 0
- for k in pairs(tbl) do
- if type(k) ~= "number" then return false end
- size = math.max(k, size)
- end
- return size
- end
- function JSON.valueToJson(value, indentLevel)
- local t = type(value)
- if t == "string" then
- return '"' .. JSON.escape(value) .. '"'
- elseif t == "number" then
- return value
- elseif t == "boolean" then
- return tostring(value)
- elseif t == 'table' then
- if indentLevel then indentLevel = indentLevel + 2 end
- return JSON.encodeInternl(value, indentLevel)
- elseif t == "nil" then
- return "null"
- else
- error("Error: Unserializable type: " .. t, 0)
- end
- end
- function JSON.keyToJson(key)
- if type(key) == "string" then
- return '"' .. JSON.escape(key) .. '"'
- else
- error("Error: Key must be string, got " .. type(key), 0)
- end
- end
- function JSON.encodeInternl(tbl, indentLevel)
- assert(type(tbl) == "table", "Error: Table expected got " .. type(tbl), 2)
- local isA = JSON.isArray(tbl)
- local jsonStr = (isA and "[" or "{")
- local indent
- if indentLevel then
- indent = string.rep("\t", indentLevel + 1)
- end
- if isA then
- for i = 1, isA do
- if indentLevel then jsonStr = jsonStr.. "\n ".. indent end
- jsonStr = jsonStr .. JSON.valueToJson(tbl[i], indentLevel) .. ","
- end
- else
- for k,v in pairs(tbl) do
- if indentLevel then jsonStr = jsonStr .. "\n ".. indent end
- jsonStr = jsonStr .. JSON.keyToJson(k) .. ":" .. JSON.valueToJson(v, indentLevel) .. ","
- end
- end
- if isA ~= 0 then jsonStr = jsonStr:sub(1,#jsonStr - 1) end --remove last comma
- if indentLevel then jsonStr = jsonStr .. "\n" .. string.rep("\t", indentLevel) end
- return jsonStr ..(isA and "]" or "}"), indentLevel
- end
- function JSON.encode(tbl, readable)
- local encoded = JSON.encodeInternl(tbl, readable and 0 or nil)
- return encoded
- end
- -------------------------------------------------------------
- function JSON.nextValue(str, start)
- local isIn = utils.indexOf
- for pos = start, #str do
- local c = str:sub(pos, pos)
- if not isIn(whitespace, c) then
- return c, pos
- end
- end
- error("Error: Unexpected end of input near" .. start, 0)
- end
- function JSON.parseArray(str, start)
- local array = {}
- local counter = 1
- local closeChar, closePos = JSON.nextValue(str, start + 1)
- if closeChar == "]" then
- closeChar, closePos = JSON.nextValue(str, closePos + 1)
- return array, closePos
- end
- while true do
- local c
- c, start = JSON.nextValue(str, start + 1)
- array[counter], start = JSON.parseValue(str, start)
- counter = counter + 1
- c, start = JSON.nextValue(str, start)
- if c == "]" then
- return array, start + 1
- elseif c ~= "," then
- error("Error: Expected ',' near" .. start, 0)
- end
- end
- end
- function JSON.parseObject(str, start)
- local c
- local object = {}
- if JSON.nextValue(str, start + 1) == "}" then return object, start + 2 end
- while true do
- local k, v
- c, start = JSON.nextValue(str, start + 1)
- k, v, start = JSON.parsePair(str, start)
- object[k] = v
- c, start = JSON.nextValue(str, start)
- if c == "}" then
- return object, start + 1
- elseif c ~= "," then
- error("Error: Expected ',' near " .. start, 0)
- end
- end
- end
- function JSON.parsePair(str, start)
- local key
- local val
- local c
- key, start = JSON.parseValue(str, start)
- c, start = JSON.nextValue(str, start)
- assert(type(key) == "string", "Error: key must be string near" .. start, 0)
- if c ~= ":" then
- error("Error: Expected ':' near " .. start, 0)
- else
- c, start = JSON.nextValue(str, start + 1)
- end
- value, start = JSON.parseValue(str, start)
- return key, value, start
- end
- function JSON.parseValue(str, start)
- if str:sub(start, start) == "\"" then
- return JSON.parseString(str, start + 1)
- else
- return JSON.parseNonString(str, start)
- end
- end
- function JSON.parseString(str, start)
- for pos = start, #str do
- local c = str:sub(pos, pos)
- if c == "\"" then
- local isEscped = false
- for p = pos - 1, start +1, -1 do
- if str:sub(p,p) == "\\" then isEscped = not isEscped
- else break end
- end
- if not isEscped then
- return JSON.unescape(str:sub(start, pos - 1)), pos + 1
- end
- end
- end
- end
- function JSON.parseNonString(str, start)
- local endPos
- local isIn = utils.indexOf
- local prevC
- if str:sub(start, start) == "{" then
- return JSON.parseObject(str, start)
- elseif str:sub(start, start) == "[" then
- return JSON.parseArray(str, start)
- end
- for pos = start, #str do
- local c = str:sub(pos, pos)
- if isIn(control, c) or isIn(whitespace, c) then
- endPos = pos
- break
- end
- end
- if not endPos then error("Error: Unexpected end of input near" .. start, 0) end
- prevC = str:sub(start, endPos - 1)
- if prevC == "null" then
- return nil, endPos
- elseif prevC == "true" then
- return true, endPos
- elseif prevC== "false" then
- return false, endPos
- elseif tonumber(prevC) then
- return tonumber(prevC), endPos
- end
- error("Error: Invalid value near" .. start, 0)
- end
- -----------------------------------------------------------------------------
- function JSON.decode(str)
- local result
- local c, start = JSON.nextValue(str, 1)
- if c == "{" then
- result = JSON.parseObject(str, start)
- elseif c == "[" then
- result = JSON.parseArray(str, start)
- else
- error("Error: No Object or Array", 2)
- end
- return result
- end
- function JSON.download(url, name)
- local data = utils.download(url, name)
- return JSON.decode(data)
- end
- function git.getTreeName()
- if args[1] == "latest" then
- gitProfile.tree = "master"
- elseif args[1] == "stable" then
- gitProfile.tree = "stable"
- else
- gitProfile.tree = git.getLatestRelease()
- end
- end
- function git.getTree()
- local tree = JSON.download(gitProfile.api .. "/" .. gitProfile.username .. "/" .. gitProfile.reponame .. "/git/trees/" .. gitProfile.tree .. "?recursive=1&access_token=" .. gitProfile.access_token, "Tree " .. gitProfile.tree).tree
- filesToDownload = #tree
- return tree
- end
- function git.getLatestRelease()
- local release = JSON.download(gitProfile.api .. "/" .. gitProfile.username .. "/" .. gitProfile.reponame .. "/releases?access_token=" .. gitProfile.access_token, "Releases")[1]
- return release.tag_name
- end
- function git.downloadFiles()
- local tree = git.getTree()
- for _,object in pairs(tree) do
- if not isBlacklisted(object.path) then
- if object.type == "blob" then
- git.downloadBlob(object.path)
- else
- fs.makeDir(object.path)
- end
- end
- filesDownloaded = filesDownloaded + 1
- end
- end
- function git.downloadBlob(path)
- local url = gitProfile.raw .. "/" .. gitProfile.username .. "/" .. gitProfile.reponame .. "/" .. gitProfile.tree .. "/"
- local urlPath = ""
- for match in path:gmatch("[^/]+") do
- urlPath = urlPath .. textutils.urlEncode(match) .. "/"
- end
- urlPath = urlPath:sub(1, -2):gsub("%+", "%%20")
- local data = utils.download(url .. urlPath, path)
- local file = fs.open(path, "w")
- if not file then
- error("Error: Failed to create file" .. path)
- end
- file.write(data)
- file.close()
- end
- function utils.indexOf(tbl, value)
- for k, v in pairs(tbl) do
- if v == value then return k end
- end
- end
- function utils.download(url, name)
- local tries = 0
- --drawBackground()
- drawText("Downloading: " .. (name or url))
- drawBar(filesDownloaded/filesToDownload)
- while tries < 5 do
- http.request(url)
- local event, _url, data = coroutine.yield()
- if event == "http_success" and url == _url then
- return data.readAll()
- elseif event == "http_failure" then
- tries = tries + 1
- end
- end
- drawText("Error: Download failed " .. url)
- term.setCursorPos(1, ySize)
- error()
- end
- if not term.blit then
- error("ComputerCraft version it too old", 0)
- end
- if not http then
- error("HTTP API is required to download LunaOS.", 0)
- end
- if not term.native().isColour() then
- error("An advanced computer is required to install LunaOS.", 0)
- end
- term.setBackgroundColour(colours.grey)
- term.clear()
- image = decodeImage(image)
- drawImage()
- git.getTreeName()
- git.downloadFiles()
- term.setCursorPos(1, ySize)
- os.reboot()
Advertisement
Add Comment
Please, Sign In to add comment