Advertisement
RamiLego

LIKO-12 CraftOS Installer

Jan 5th, 2018
365
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.26 KB | None | 0 0
  1. --LIKO-12 CraftOS Installer By RamiLego4Game
  2.  
  3. --CONFIG--
  4. local GithubUsername = "RamiLego4Game" --Your GitHub username as it appears in the URL
  5. local GithubReponame = "CC12" --The repo name as it appears in the URL
  6. local FilterPreReleases = false --Avoid pre-releases.
  7. local Title = "=---< LIKO-12 CraftOS Installer >---=" --The title of the installer (Shown in the top-bar)
  8. local blacklist = {"/Installer.lua","/README.md","/LICENSE","/LICENSE-CraftOS"} --The files to not download
  9. local DownloadAttempsCount = 10 --How many attemps to do before giving up when downloading a file ?
  10. local DownloadAttempsDelay = 2  --The delay between each attemp in seconds.
  11. ----------
  12.  
  13. --The directory where the files will be stored while downloading.
  14. local TempDir = "C:/.temp/Installer/"
  15.  
  16. --Not working--
  17. --local _LIKO_Version = coroutine.yield("BIOS:GetVersion")
  18. --if _LIKO_Version ~= "0.6.0.7_PRE" then color(8) print("DiskOS-Edu requires LIKO-12 V0.6.0.7_PRE !") return end
  19.  
  20. --Verify that the WEB peripheral is available.
  21. if not WEB then
  22.   color(8)
  23.   print("The installer requires WEB peripheral and an internet connection.")
  24.   return
  25. end
  26.  
  27. color(8) print("\n\nWARNING !\n\nYou are about to replace your current operating system with a new one.\n\nAll of your data will be lost in the process !\n\nAre you still sure you want to continue ? (Y/N)\n\n\n",false) color(7)
  28. local answer = string.lower(input() or ""); if answer ~= "y" then return end
  29.  
  30. --Require the JSON library
  31. local json = require("Libraries/JSON")
  32.  
  33. --Get the screen resolution, the terminal size and the font size
  34. local sw, sh = screenSize()
  35. local tw, th = termSize()
  36. local fw, fh = fontSize()
  37.  
  38. --Set the print cursor position
  39. printCursor(0,th)
  40.  
  41. --Draws the progress bar, takes a value between 0 and 1, nil for no progress bar.
  42. local function drawProgress(float)
  43.   rect(0,sh-9, sw,9, false, 12) --Draw the bar
  44.  
  45.   if not float then return end --If no progress value then we are done.
  46.  
  47.   --The progress bar "=" chars
  48.   local progChars = math.floor(float*32+0.5)
  49.   local progStr = string.rep("=", progChars)..string.rep(" ", 32-progChars)
  50.  
  51.   --The % percentage.
  52.   local precent = tostring(math.floor(float*100+0.5))
  53.   precent = string.rep(" ",3-precent:len())..precent
  54.  
  55.   --Draw the text.
  56.   color(1) print("["..progStr.."]"..precent.."%",1, sh-7)
  57. end
  58.  
  59. --Draw the GUI
  60. clear(5) --Clear the screen
  61. rect(0,0, sw,9, false, 12) --The top bar
  62. color(1) print(Title, 1,2, sw,"center") --Draw the title.
  63. drawProgress() --Draw the bottom bar.
  64.  
  65. --Display a log message
  66. local function display(text,col)
  67.   --Push the text up
  68.   screenshot(0,9+fh+2,sw,sh-9-fh-2-9):image():draw(0,9)
  69.   --Clear the last line
  70.   rect(0,sh-8-fh-3,sw,fh+2,false,5)
  71.   --Display the new message
  72.   color(col or 7) print(tostring(text),1,sh-9-fh-2)
  73.   --Make sure that it's shown to the user
  74.   flip()
  75. end
  76.  
  77. --Display a crash message, but doesn't end the program.
  78. local function crash(...)
  79.   cprint("[CRASH]",...)
  80.  
  81.   printCursor(0,th+1) color(8)
  82.   print(table.concat({...}," ")) flip()
  83. end
  84.  
  85. --Display a red message
  86. local function warn(...)
  87.   cprint("[WARNING]",...)
  88.   display(table.concat({...}," "), 8)
  89. end
  90.  
  91. --Display a blue message
  92. local function status(...)
  93.   cprint("[STATUS]",...)
  94.   display(table.concat({...}," "), 15)
  95. end
  96.  
  97. --Display a light grey message
  98. local function info(...)
  99.   cprint("[INFO]",...)
  100.   display(table.concat({...}," "), 7)
  101. end
  102.  
  103. --Download a url.
  104. local function download(url)
  105.  
  106.   --Send the web request
  107.   local ticket = WEB.send(url,{
  108.     headers = {
  109.       ["User-Agent"] = "LIKO-12" --Github requires a User-Agent.
  110.     }
  111.   })
  112.  
  113.   local attemps = 1 --The current attemp number
  114.  
  115.   for event, id, url, data, errnum, errmsg, errline in pullEvent do
  116.     if event == "webrequest" then
  117.       if id == ticket then --This is our request !
  118.         if not data then --Too bad !
  119.           warn("Attemp #"..attemps.." Failed: ",errmsg)
  120.          
  121.           attemps = attemps + 1
  122.           if attemps > DownloadAttempsCount then
  123.             crash("Failed to download after "..attemps.." attemps: "..tostring(errmsg)) return
  124.           end
  125.          
  126.           sleep(DownloadAttempsDelay) --The time between each attemp.
  127.          
  128.           ticket = WEB.send(url) --Attemp Again
  129.         else --We got something !
  130.           data.code = tonumber(data.code)
  131.           if data.code >= 200 and data.code < 400 then
  132.             return data.body --Success
  133.           else
  134.             crash("Bad response code: "..data.code) return -- :(
  135.           end
  136.         end
  137.       end
  138.     elseif event == "keypressed" then
  139.       if id == "escape" then
  140.         crash("Installation Terminated") return
  141.       end
  142.     end
  143.   end
  144.  
  145. end
  146.  
  147. --Download a url, and decode it's body pretending it's JSON data.
  148. local function downloadJSON(url)
  149.   local data = download(url)
  150.   if not data then return end
  151.  
  152.   local ok, t = pcall(json.decode,json,data)
  153.   if not ok then
  154.     crash("Failed to decode JSON: "..tostring(t))
  155.     return
  156.   end
  157.  
  158.   return t
  159. end
  160.  
  161. --Check if the path is in the blacklist
  162. function isBlackListed(path)
  163.   for k, item in ipairs(blacklist) do
  164.     if item == path then
  165.       return true
  166.     end
  167.   end
  168.   return false
  169. end
  170.  
  171. --The downloading process--
  172.  
  173. status("Determining Latest Version")
  174. local releases = downloadJSON("https://api.github.com/repos/"..GithubUsername.."/"..GithubReponame.."/releases") if not releases then return end
  175. local latestReleaseTag = releases[1].tag_name
  176. if FilterPreReleases then
  177.   for k, v in ipairs(releases) do
  178.     if not v.prerelease then
  179.       latestReleaseTag = v.tag_name
  180.       break
  181.     end
  182.   end
  183. end
  184. info("Latest Version:",latestReleaseTag)
  185.  
  186. status("Optaining Latest Version URL")
  187. local refs = downloadJSON("https://api.github.com/repos/"..GithubUsername.."/"..GithubReponame.."/git/refs/tags/"..latestReleaseTag) if not refs then return end
  188. local latestReleaseSha = refs.object.sha
  189. info("SHA:", latestReleaseSha)
  190.  
  191. status("Downloading File Listing")
  192. local tree = downloadJSON("https://api.github.com/repos/"..GithubUsername.."/"..GithubReponame.."/git/trees/"..latestReleaseSha.."?recursive=1")
  193. if tree then tree = tree.tree else return end
  194.  
  195. local TotalFiles, TotalBytes = 0, 0
  196. for k,v in ipairs(tree) do
  197.   if not isBlackListed("/"..v.path) and v.size then
  198.     TotalBytes = TotalBytes + v.size
  199.     TotalFiles = TotalFiles + 1
  200.   end
  201. end
  202. info("Total Files:",TotalFiles)
  203.  
  204. status("Downloading "..math.floor(TotalBytes/1024+0.5).."KB") drawProgress(0)
  205. fs.newDirectory(TempDir) --Create the download temp folder
  206.  
  207. local DownloadedBytes, DownloadedFiles = 0, 0
  208. function downloadBlob(v,k)
  209.   if isBlackListed("/"..v.path) then return end
  210.   if v.type == "tree" then --Folder
  211.     cprint("[LOG]","New Directory: "..v.path)
  212.     display("New Directory: "..v.path, 7)
  213.     fs.newDirectory(TempDir..v.path)
  214.   else --File
  215.     cprint("[LOG]","File ("..(DownloadedFiles+1).."/"..TotalFiles.."): "..v.path)
  216.     display("File ("..(DownloadedFiles+1).."/"..TotalFiles.."): "..v.path, 6)
  217.     local data = download("https://raw.github.com/"..GithubUsername.."/"..GithubReponame.."/"..latestReleaseTag.."/"..(v.path):gsub(" ","%%20"))
  218.     if not data then return true end
  219.     fs.write(TempDir..v.path,data)
  220.     DownloadedFiles = DownloadedFiles + 1
  221.     DownloadedBytes = DownloadedBytes + v.size
  222.   end
  223. end
  224.  
  225. for k,v in ipairs(tree) do
  226.   if downloadBlob(v,k) then return end
  227.   drawProgress(DownloadedBytes/TotalBytes)
  228. end
  229.  
  230. drawProgress()
  231. status("Download completed, Installing...")
  232. info("Entered the no going back stage !")
  233.  
  234. --The installing script
  235.  
  236. status("Formating the disk drives")
  237.  
  238. local function index(path, list)
  239.   local path = path or "C:/"
  240.   local list = list or {}
  241.  
  242.   local items = fs.directoryItems(path)
  243.   for id, item in ipairs(items) do
  244.     if fs.isDirectory(path..item) then
  245.       index(path..item.."/", list)
  246.       table.insert(list,path..item)
  247.     else
  248.       table.insert(list,path..item)
  249.     end
  250.   end
  251.  
  252.   return list
  253. end
  254.  
  255. local toDelete = index("C:/"); index("D:/",toDelete);drawProgress(0)
  256. info("Deleting "..(#toDelete-TotalFiles).." Files & Folders")
  257.  
  258. for k,v in ipairs(toDelete) do
  259.   if v:sub(1,8) ~= "C:/.temp" then
  260.     fs.remove(v) info("Removed",v)
  261.   end
  262.   drawProgress(k/#toDelete)
  263. end
  264.  
  265. drawProgress()
  266. status("Installing CraftOS...")
  267.  
  268. local CPath = TempDir.."drives/C/"
  269. local DPath = TempDir.."drives/D/"
  270.  
  271. local toCopyD = index(DPath); drawProgress(0)
  272. info("Copying "..(#toCopyD).." Files & Folders")
  273.  
  274. for k=#toCopyD,1,-1 do
  275.   local from, to = toCopyD[k], "D:/"..toCopyD[k]:sub(DPath:len()+1,-1)
  276.   if fs.isDirectory(from) then
  277.     fs.newDirectory(to) info("New Directory:",to)
  278.   else
  279.     local data = fs.read(from)
  280.     fs.write(to,data) info("Copied File:",to)
  281.   end
  282.   drawProgress(1 - k/#toCopyD)
  283. end
  284.  
  285. local toCopyC = index(CPath); drawProgress(0)
  286. info("Copying "..(#toCopyC).." Files & Folders")
  287.  
  288. for k=#toCopyC,1,-1 do
  289.   local from, to = toCopyC[k], "C:/"..toCopyC[k]:sub(CPath:len()+1,-1)
  290.   if fs.isDirectory(from) then
  291.     fs.newDirectory(to) info("New Directory:",to)
  292.   else
  293.     local data = fs.read(from)
  294.     fs.write(to,data) info("Copied File:",to)
  295.   end
  296.   drawProgress(1 - k/#toCopyC)
  297. end
  298.  
  299. status("Installation Complete !") drawProgress()
  300.  
  301. for i=5,1,-1 do
  302.   info("Rebooting in "..i) clearEStack() sleep(1)
  303. end
  304.  
  305. reboot()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement