NeOzay

git.lua

Aug 24th, 2021
1,094
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. local shell = require("shell")
  2. local term = require("term")
  3. local filesystem = require("filesystem")
  4. local component = require("component")
  5.  
  6. local github = require("github")
  7.  
  8. local gpu = component.gpu
  9. local screenw, screenl = gpu.getResolution()
  10.  
  11. local args, opts = shell.parse(...)
  12.  
  13. local _
  14.  
  15. if opts.b and opts.t then
  16.     error("")
  17. end
  18.  
  19. ---@return number,number
  20. local function getOffset()
  21.     local _, _, _, _, ox, oy = term.getViewport()
  22.     return ox, oy
  23. end
  24.  
  25. ---@param barsize number
  26. ---@return fun(percent:number):string @between 0 and 1
  27. local function newProgressbar(barsize)
  28.     local left = "["
  29.     local right = ("]%3d%%"):format(0)
  30.     local gap = barsize or 50 - #left - #right
  31.     local at
  32.     local tampon = 1
  33.     ---@type string[]
  34.     local bar = { left, ">", right }
  35.     for i = 1, gap do
  36.         table.insert(bar, #bar, " ")
  37.     end
  38.     ---@type
  39.     return coroutine.wrap(function(percent)
  40.         while true do
  41.  
  42.             right = ("]%3d%%"):format(tostring(percent * 100))
  43.             table.remove(bar)
  44.             table.insert(bar, right)
  45.  
  46.             at = math.floor(percent * (gap) + 0.5)
  47.             for i = tampon, gap + 2 do
  48.                 if i < at + 2 then
  49.                     table.insert(bar, 2, "=")
  50.                     table.remove(bar, #bar - 1)
  51.                 else
  52.                     tampon = i
  53.                     break
  54.                 end
  55.             end
  56.             percent = coroutine.yield(table.concat(bar))
  57.         end
  58.     end)
  59. end
  60.  
  61. ---@param initLine number
  62. ---@param drawFn fun(currentLine:number,text:string|number)
  63. local function newDisplay(initLine, drawFn)
  64.     ---@type number
  65.     local currentLine
  66.     if initLine == 1 then
  67.         currentLine = initLine
  68.         initLine = initLine + 1
  69.         term.setCursor(1, initLine)
  70.     else
  71.         currentLine = initLine - 1
  72.         term.setCursor(1, initLine)
  73.     end
  74.  
  75.     local state = false
  76.     return ---@param text string|number
  77.     function(text)
  78.         text = tostring(text)
  79.         local _, yo = getOffset()
  80.         if yo == 50 then
  81.             if state then
  82.                 currentLine = math.max(currentLine - 1, 1)
  83.             else
  84.                 state = true
  85.             end
  86.         end
  87.         drawFn(currentLine, text)
  88.     end
  89. end
  90.  
  91. local function sizeStr(bytes)
  92.     local unit = 1024
  93.     if bytes < unit then
  94.         return ("%s byte(s)"):format(bytes)
  95.     else
  96.         local multi = 10 ^ (1)
  97.         local KiB = math.floor((bytes / unit) * multi + 0.5) / multi
  98.         return ("%s KiB"):format(KiB)
  99.     end
  100. end
  101.  
  102. local function hasEnoughSpace(locate, repoSize)
  103.     -- The value reported by github underestimates the one reported by CC. This tries
  104.     -- to guess when this matters.
  105.  
  106.     local disk, _, _ = filesystem.get(locate)
  107.  
  108.     local maxSpace = disk.spaceTotal()
  109.  
  110.     local freeSpace = maxSpace - disk.spaceUsed()
  111.  
  112.     local sizeError = 0.2
  113.  
  114.     local function warnAndContinue()
  115.         io.stderr:write("Repository may be too large to download, attempt anyway? [Y/n]: ")
  116.         local validAnswers = { [''] = 'yes', y = 'yes', yes = 'yes', n = 'no', no = 'no' }
  117.         local input = io.read()
  118.         while not validAnswers[input:lower()] do
  119.             print("Please type [y]es or [n]o")
  120.             input = io.read()
  121.         end
  122.         return validAnswers[input:lower()] == 'yes'
  123.     end
  124.     local errStr = "Repository is %s, but only %s are free on this computer. Aborting!"
  125.     errStr = errStr:format(sizeStr(repoSize), sizeStr(freeSpace))
  126.     if repoSize > freeSpace then
  127.         error(errStr)
  128.     elseif repoSize * (1 + sizeError) > freeSpace then
  129.         if not warnAndContinue() then
  130.             error(errStr)
  131.         end
  132.     else
  133.         return true
  134.     end
  135. end
  136.  
  137. if args[1] == "clone" then
  138.     local user, repoName = args[2]:match('^(.-)/(.+)$')
  139.     local dest = shell.resolve(args[3] or repoName)
  140.     local treeName = opts.b or opts.t or "master"
  141.     local auth
  142.     if opts.a then
  143.         auth = github.Auth.get(opts.a)
  144.     end
  145.     local repo = github.repo(user, repoName, auth)
  146.  
  147.     local tree = repo:tree(treeName)
  148.  
  149.     local repoSize = tree.size
  150.     local size = 0
  151.     hasEnoughSpace(dest, repoSize)
  152.  
  153.     local progressbar = newProgressbar(screenw - #"Downloading:")
  154.  
  155.     print("Downloading:" .. progressbar(0))
  156.     local _, oy = getOffset()
  157.     local display = newDisplay(oy,
  158.             function(line, text)
  159.                 gpu.fill(1, line, screenl, 1, " ")
  160.                 gpu.set(1, line, text)
  161.             end)
  162.  
  163.     tree:cloneTo(dest, function(item)
  164.         print(item:fullPath())
  165.         if getmetatable(item) == github.Blob then
  166.             size = size + item.size
  167.             display(progressbar(size / repoSize))
  168.         end
  169.     end)
  170.     return
  171. end
  172.  
  173. if args[1] == "auth" then
  174.     local user, token = args[2], args[3]
  175.     if not user then return error("No user specified.") end
  176.  
  177.     if args.d then
  178.         github.Auth.delete(user)
  179.         print(('Deleted github token for user %s'):format(user))
  180.     else
  181.         if not token then return error("No token specified.") end
  182.         local auth = github.Auth.new('oauth', user, token)
  183.         if auth:checkToken() then
  184.             auth:save()
  185.             print(('Saved github token for user %s'):format(auth.user))
  186.         else
  187.             return error("Invalid token!")
  188.         end
  189.     end
  190.  
  191.     return
  192. end
RAW Paste Data