Advertisement
moomoomoo309

WE_Installer

May 29th, 2014
886
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.40 KB | None | 0 0
  1. --[[ /gitget
  2. GitHub downloading utility for CC.
  3. Developed by apemanzilla.
  4.  
  5. This requires ElvishJerricco's JSON parsing API.
  6. Direct link: http://pastebin.com/raw.php?i=4nRg9CHU
  7. ]]--
  8.  
  9. local json = {}
  10. local controls = {["\n"]="\\n", ["\r"]="\\r", ["\t"]="\\t", ["\b"]="\\b", ["\f"]="\\f", ["\""]="\\\"", ["\\"]="\\\\"}
  11.  
  12. local function isArray(t)
  13.     local max = 0
  14.     for k,v in pairs(t) do
  15.         if type(k) ~= "number" then
  16.             return false
  17.         elseif k > max then
  18.             max = k
  19.         end
  20.     end
  21.     return max == #t
  22. end
  23.  
  24. local whites = {['\n']=true; ['\r']=true; ['\t']=true; [' ']=true; [',']=true; [':']=true}
  25. function json.removeWhite(str)
  26.     while whites[str:sub(1, 1)] do
  27.         str = str:sub(2)
  28.     end
  29.     return str
  30. end
  31.  
  32. ------------------------------------------------------------------ encoding
  33.  
  34. local function encodeCommon(val, pretty, tabLevel, tTracking)
  35.     local str = ""
  36.  
  37.     -- Tabbing util
  38.     local function tab(s)
  39.         str = str .. ("\t"):rep(tabLevel) .. s
  40.     end
  41.  
  42.     local function arrEncoding(val, bracket, closeBracket, iterator, loopFunc)
  43.         str = str .. bracket
  44.         if pretty then
  45.             str = str .. "\n"
  46.             tabLevel = tabLevel + 1
  47.         end
  48.         for k,v in iterator(val) do
  49.             tab("")
  50.             loopFunc(k,v)
  51.             str = str .. ","
  52.             if pretty then str = str .. "\n" end
  53.         end
  54.         if pretty then
  55.             tabLevel = tabLevel - 1
  56.         end
  57.         if str:sub(-2) == ",\n" then
  58.             str = str:sub(1, -3) .. "\n"
  59.         elseif str:sub(-1) == "," then
  60.             str = str:sub(1, -2)
  61.         end
  62.         tab(closeBracket)
  63.     end
  64.  
  65.     -- Table encoding
  66.     if type(val) == "table" then
  67.         assert(not tTracking[val], "Cannot encode a table holding itself recursively")
  68.         tTracking[val] = true
  69.         if isArray(val) then
  70.             arrEncoding(val, "[", "]", ipairs, function(k,v)
  71.                 str = str .. encodeCommon(v, pretty, tabLevel, tTracking)
  72.             end)
  73.         else
  74.             arrEncoding(val, "{", "}", pairs, function(k,v)
  75.                 assert(type(k) == "string", "JSON object keys must be strings", 2)
  76.                 str = str .. encodeCommon(k, pretty, tabLevel, tTracking)
  77.                 str = str .. (pretty and ": " or ":") .. encodeCommon(v, pretty, tabLevel, tTracking)
  78.             end)
  79.         end
  80.         -- String encoding
  81.     elseif type(val) == "string" then
  82.         str = '"' .. val:gsub("[%c\"\\]", controls) .. '"'
  83.         -- Number encoding
  84.     elseif type(val) == "number" or type(val) == "boolean" then
  85.         str = tostring(val)
  86.     else
  87.         error("JSON only supports arrays, objects, numbers, booleans, and strings", 2)
  88.     end
  89.     return str
  90. end
  91.  
  92. function json.encode(val)
  93.     return encodeCommon(val, false, 0, {})
  94. end
  95.  
  96. function json.encodePretty(val)
  97.     return encodeCommon(val, true, 0, {})
  98. end
  99.  
  100. ------------------------------------------------------------------ decoding
  101.  
  102. local decodeControls = {}
  103. for k,v in pairs(controls) do
  104.     decodeControls[v] = k
  105. end
  106.  
  107. function json.parseBoolean(str)
  108.     if str:sub(1, 4) == "true" then
  109.         return true, json.removeWhite(str:sub(5))
  110.     else
  111.         return false, json.removeWhite(str:sub(6))
  112.     end
  113. end
  114.  
  115. function json.parseNull(str)
  116.     return nil, json.removeWhite(str:sub(5))
  117. end
  118.  
  119. local numChars = {['e']=true; ['E']=true; ['+']=true; ['-']=true; ['.']=true}
  120. function json.parseNumber(str)
  121.     local i = 1
  122.     while numChars[str:sub(i, i)] or tonumber(str:sub(i, i)) do
  123.         i = i + 1
  124.     end
  125.     local val = tonumber(str:sub(1, i - 1))
  126.     str = json.removeWhite(str:sub(i))
  127.     return val, str
  128. end
  129.  
  130. function json.parseString(str)
  131.     str = str:sub(2)
  132.     local s = ""
  133.     while str:sub(1,1) ~= "\"" do
  134.         local next = str:sub(1,1)
  135.         str = str:sub(2)
  136.         assert(next ~= "\n", "Unclosed string")
  137.  
  138.         if next == "\\" then
  139.             local escape = str:sub(1,1)
  140.             str = str:sub(2)
  141.  
  142.             next = assert(decodeControls[next..escape], "Invalid escape character")
  143.         end
  144.  
  145.         s = s .. next
  146.     end
  147.     return s, json.removeWhite(str:sub(2))
  148. end
  149.  
  150. function json.parseArray(str)
  151.     str = json.removeWhite(str:sub(2))
  152.  
  153.     local val = {}
  154.     local i = 1
  155.     while str:sub(1, 1) ~= "]" do
  156.         local v = nil
  157.         v, str = json.parseValue(str)
  158.         val[i] = v
  159.         i = i + 1
  160.         str = json.removeWhite(str)
  161.     end
  162.     str = json.removeWhite(str:sub(2))
  163.     return val, str
  164. end
  165.  
  166. function json.parseObject(str)
  167.     str = json.removeWhite(str:sub(2))
  168.  
  169.     local val = {}
  170.     while str:sub(1, 1) ~= "}" do
  171.         local k, v = nil, nil
  172.         k, v, str = json.parseMember(str)
  173.         val[k] = v
  174.         str = json.removeWhite(str)
  175.     end
  176.     str = json.removeWhite(str:sub(2))
  177.     return val, str
  178. end
  179.  
  180. function json.parseMember(str)
  181.     local k = nil
  182.     k, str = json.parseValue(str)
  183.     local val = nil
  184.     val, str = json.parseValue(str)
  185.     return k, val, str
  186. end
  187.  
  188. function json.parseValue(str)
  189.     local fchar = str:sub(1, 1)
  190.     if fchar == "{" then
  191.         return json.parseObject(str)
  192.     elseif fchar == "[" then
  193.         return json.parseArray(str)
  194.     elseif tonumber(fchar) ~= nil or numChars[fchar] then
  195.         return json.parseNumber(str)
  196.     elseif str:sub(1, 4) == "true" or str:sub(1, 5) == "false" then
  197.         return json.parseBoolean(str)
  198.     elseif fchar == "\"" then
  199.         return json.parseString(str)
  200.     elseif str:sub(1, 4) == "null" then
  201.         return json.parseNull(str)
  202.     end
  203.     return nil
  204. end
  205.  
  206. function json.decode(str)
  207.     str = json.removeWhite(str)
  208.     t = json.parseValue(str)
  209.     return t
  210. end
  211.  
  212. function json.decodeFromFile(path)
  213.     local file = assert(fs.open(path, "r"))
  214.     local decoded = json.decode(file.readAll())
  215.     file.close()
  216.     return decoded
  217. end
  218.  
  219.  
  220. -- Edit these variables to use preset mode.
  221. -- Whether to download the files asynchronously (huge speed benefits, will also retry failed files)
  222. -- If false will download the files one by one and use the old output (List each file name as it's downloaded) instead of the progress bar
  223. local async = true
  224.  
  225. -- Whether to write to the terminal as files are downloaded
  226. -- Note that unless checked for this will not affect pre-set start/done code below
  227. local silent = false
  228.  
  229. local preset = {
  230.     -- The GitHub account name
  231.     user = "moomoomoo309",
  232.     -- The GitHub repository name
  233.     repo = "WorldEdit-CC",
  234.  
  235.     -- The branch or commit tree to download (defaults to 'master')
  236.     branch = "master",
  237.  
  238.     -- The local folder to save all the files to (defaults to '/')
  239.     path = nil,
  240.  
  241.     -- Function to run before starting the download
  242.     start = function()
  243.         if not silent then print("Downloading files from GitHub...") end
  244.     end,
  245.  
  246.     -- Function to run when the download completes
  247.     done = function()
  248.         if not silent then print("Done") end
  249.     end
  250. }
  251.  
  252. -- Leave the rest of the program alone.
  253. local args = {...}
  254.  
  255. args[1] = preset.user or args[1]
  256. args[2] = preset.repo or args[2]
  257. args[3] = preset.branch or args[3] or "master"
  258. args[4] = preset.path or args[4] or ""
  259.  
  260. if #args < 2 then
  261.     print("Usage:\n"..((shell and shell.getRunningProgram()) or "gitget").." <user> <repo> [branch/tree] [path]") error()
  262. end
  263.  
  264. local function save(data,file)
  265.     local file = shell.resolve(file:gsub("%%20"," "))
  266.     if not (fs.exists(string.sub(file,1,#file - #fs.getName(file))) and fs.isDir(string.sub(file,1,#file - #fs.getName(file)))) then
  267.         if fs.exists(string.sub(file,1,#file - #fs.getName(file))) then fs.delete(string.sub(file,1,#file - #fs.getName(file))) end
  268.         fs.makeDir(string.sub(file,1,#file - #fs.getName(file)))
  269.     end
  270.     local f = fs.open(file,"w")
  271.     f.write(data)
  272.     f.close()
  273. end
  274.  
  275. local function download(url, file)
  276.     save(http.get(url).readAll(),file)
  277. end
  278.  
  279. if not json then
  280.     download("http://pastebin.com/raw.php?i=4nRg9CHU","json")
  281.     os.loadAPI("json")
  282. end
  283.  
  284. preset.start()
  285. local data = json.decode(http.get("https://api.github.com/repos/"..args[1].."/"..args[2].."/git/trees/"..args[3].."?recursive=1").readAll())
  286. if data.message and data.message:find("API rate limit exceeded") then error("Out of API calls, try again later") end
  287. if data.message and data.message == "Not found" then error("Invalid repository",2) else
  288.     for k,v in pairs(data.tree) do
  289.         -- Make directories
  290.         if v.type == "tree" then
  291.             fs.makeDir(fs.combine(args[4],v.path))
  292.             if not hide_progress then
  293.             end
  294.         end
  295.     end
  296.     local drawProgress
  297.     if async and not silent then
  298.         local _, y = term.getCursorPos()
  299.         local wide, _ = term.getSize()
  300.         term.setCursorPos(1, y)
  301.         term.write("[")
  302.         term.setCursorPos(wide - 6, y)
  303.         term.write("]")
  304.         drawProgress = function(done, max)
  305.             local value = done / max
  306.             term.setCursorPos(2,y)
  307.             term.write(("="):rep(math.floor(value * (wide - 8))))
  308.             local percent = math.floor(value * 100) .. "%"
  309.             term.setCursorPos(wide - percent:len(),y)
  310.             term.write(percent)
  311.         end
  312.     end
  313.     local filecount = 0
  314.     local downloaded = 0
  315.     local paths = {}
  316.     local failed = {}
  317.     for k,v in pairs(data.tree) do
  318.         -- Send all HTTP requests (async)
  319.         if v.type == "blob" then
  320.             v.path = v.path:gsub("%s","%%20")
  321.             local url = "https://raw.github.com/"..args[1].."/"..args[2].."/"..args[3].."/"..v.path,fs.combine(args[4],v.path)
  322.             if async then
  323.                 http.request(url)
  324.                 paths[url] = fs.combine(args[4],v.path)
  325.                 filecount = filecount + 1
  326.             else
  327.                 download(url, fs.combine(args[4], v.path))
  328.                 if not silent then print(fs.combine(args[4], v.path)) end
  329.             end
  330.         end
  331.     end
  332.     while downloaded < filecount do
  333.         local e, a, b = os.pullEvent()
  334.         if e == "http_success" then
  335.             save(b.readAll(),paths[a])
  336.             downloaded = downloaded + 1
  337.             if not silent then drawProgress(downloaded,filecount) end
  338.         elseif e == "http_failure" then
  339.             -- Retry in 3 seconds
  340.             failed[os.startTimer(3)] = a
  341.         elseif e == "timer" and failed[a] then
  342.             http.request(failed[a])
  343.         end
  344.     end
  345. end
  346. preset.done()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement