Advertisement
Krutoy242

KrutoyTurtle Installer (debug version)

May 13th, 2014
346
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 20.00 KB | None | 0 0
  1. -- ********************************************************************************** --
  2. -- **                                                                              ** --
  3. -- **   Krutoy Turtle installer                                                    ** --
  4. -- **   ----------------------------------------------------                       ** --
  5. -- **   Most code from https://github.com/oeed/OneOS                               ** --
  6. -- **                                                                              ** --
  7. -- ********************************************************************************** --
  8.  
  9.  
  10. local isDebug = true
  11.  
  12.  
  13. -- If we using IDE, must load other files first
  14. IDE = false
  15. if not term then
  16.   IDE = true
  17.   dofile('other/ComputerCraft.lua')
  18.  
  19.   dofile('src/AStar.lua')
  20.   dofile('src/KTurtle.lua')
  21.   dofile('src/ZeroSwarm.lua')
  22.   dofile('src/KUI.lua')
  23. end
  24.  
  25.  
  26. do
  27.  
  28.  
  29. local _jstr = [[
  30.   local base = _G
  31.  
  32.   -----------------------------------------------------------------------------
  33.   -- Module declaration
  34.   -----------------------------------------------------------------------------
  35.  
  36.   -- Public functions
  37.  
  38.   -- Private functions
  39.   local decode_scanArray
  40.   local decode_scanComment
  41.   local decode_scanConstant
  42.   local decode_scanNumber
  43.   local decode_scanObject
  44.   local decode_scanString
  45.   local decode_scanWhitespace
  46.   local encodeString
  47.   local isArray
  48.   local isEncodable
  49.  
  50.   -----------------------------------------------------------------------------
  51.   -- PUBLIC FUNCTIONS
  52.   -----------------------------------------------------------------------------
  53.   --- Encodes an arbitrary Lua object / variable.
  54.   -- @param v The Lua object / variable to be JSON encoded.
  55.   -- @return String containing the JSON encoding in internal Lua string format (i.e. not unicode)
  56.   function encode (v)
  57.     -- Handle nil values
  58.     if v==nil then
  59.       return "null"
  60.     end
  61.    
  62.     local vtype = base.type(v)  
  63.  
  64.     -- Handle strings
  65.     if vtype=='string' then    
  66.       return '"' .. encodeString(v) .. '"'      -- Need to handle encoding in string
  67.     end
  68.    
  69.     -- Handle booleans
  70.     if vtype=='number' or vtype=='boolean' then
  71.       return base.tostring(v)
  72.     end
  73.    
  74.     -- Handle tables
  75.     if vtype=='table' then
  76.       local rval = {}
  77.       -- Consider arrays separately
  78.       local bArray, maxCount = isArray(v)
  79.       if bArray then
  80.         for i = 1,maxCount do
  81.           table.insert(rval, encode(v[i]))
  82.         end
  83.       else -- An object, not an array
  84.         for i,j in base.pairs(v) do
  85.           if isEncodable(i) and isEncodable(j) then
  86.             table.insert(rval, '"' .. encodeString(i) .. '":' .. encode(j))
  87.           end
  88.         end
  89.       end
  90.       if bArray then
  91.         return '[' .. table.concat(rval,',') ..']'
  92.       else
  93.         return '{' .. table.concat(rval,',') .. '}'
  94.       end
  95.     end
  96.    
  97.     -- Handle null values
  98.     if vtype=='function' and v==null then
  99.       return 'null'
  100.     end
  101.    
  102.     base.assert(false,'encode attempt to encode unsupported type ' .. vtype .. ':' .. base.tostring(v))
  103.   end
  104.  
  105.  
  106.   --- Decodes a JSON string and returns the decoded value as a Lua data structure / value.
  107.   -- @param s The string to scan.
  108.   -- @param [startPos] Optional starting position where the JSON string is located. Defaults to 1.
  109.   -- @param Lua object, number The object that was scanned, as a Lua table / string / number / boolean or nil,
  110.   -- and the position of the first character after
  111.   -- the scanned JSON object.
  112.   function decode(s, startPos)
  113.     startPos = startPos and startPos or 1
  114.     startPos = decode_scanWhitespace(s,startPos)
  115.     base.assert(startPos<=string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']')
  116.     local curChar = string.sub(s,startPos,startPos)
  117.     -- Object
  118.     if curChar=='{' then
  119.       return decode_scanObject(s,startPos)
  120.     end
  121.     -- Array
  122.     if curChar=='[' then
  123.       return decode_scanArray(s,startPos)
  124.     end
  125.     -- Number
  126.     if string.find("+-0123456789.e", curChar, 1, true) then
  127.       return decode_scanNumber(s,startPos)
  128.     end
  129.     -- String
  130.     if curChar=='"' or curChar=="'" then
  131.       return decode_scanString(s,startPos)
  132.     end
  133.     if string.sub(s,startPos,startPos+1)=='/*' then
  134.       return decode(s, decode_scanComment(s,startPos))
  135.     end
  136.     -- Otherwise, it must be a constant
  137.     return decode_scanConstant(s,startPos)
  138.   end
  139.  
  140.   --- The null function allows one to specify a null value in an associative array (which is otherwise
  141.   -- discarded if you set the value with 'nil' in Lua. Simply set t = { first=json.null }
  142.   function null()
  143.     return null -- so json.null() will also return null ;-)
  144.   end
  145.   -----------------------------------------------------------------------------
  146.   -- Internal, PRIVATE functions.
  147.   -- Following a Python-like convention, I have prefixed all these 'PRIVATE'
  148.   -- functions with an underscore.
  149.   -----------------------------------------------------------------------------
  150.  
  151.   --- Scans an array from JSON into a Lua object
  152.   -- startPos begins at the start of the array.
  153.   -- Returns the array and the next starting position
  154.   -- @param s The string being scanned.
  155.   -- @param startPos The starting position for the scan.
  156.   -- @return table, int The scanned array as a table, and the position of the next character to scan.
  157.   function decode_scanArray(s,startPos)
  158.     local array = {}   -- The return value
  159.     local stringLen = string.len(s)
  160.     base.assert(string.sub(s,startPos,startPos)=='[','decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\n'..s )
  161.     startPos = startPos + 1
  162.     -- Infinite loop for array elements
  163.     repeat
  164.       startPos = decode_scanWhitespace(s,startPos)
  165.       base.assert(startPos<=stringLen,'JSON String ended unexpectedly scanning array.')
  166.       local curChar = string.sub(s,startPos,startPos)
  167.       if (curChar==']') then
  168.         return array, startPos+1
  169.       end
  170.       if (curChar==',') then
  171.         startPos = decode_scanWhitespace(s,startPos+1)
  172.       end
  173.       base.assert(startPos<=stringLen, 'JSON String ended unexpectedly scanning array.')
  174.       object, startPos = decode(s,startPos)
  175.       table.insert(array,object)
  176.     until false
  177.   end
  178.  
  179.   --- Scans a comment and discards the comment.
  180.   -- Returns the position of the next character following the comment.
  181.   -- @param string s The JSON string to scan.
  182.   -- @param int startPos The starting position of the comment
  183.   function decode_scanComment(s, startPos)
  184.     base.assert( string.sub(s,startPos,startPos+1)=='/*', "decode_scanComment called but comment does not start at position " .. startPos)
  185.     local endPos = string.find(s,'*/',startPos+2)
  186.     base.assert(endPos~=nil, "Unterminated comment in string at " .. startPos)
  187.     return endPos+2  
  188.   end
  189.  
  190.   --- Scans for given constants: true, false or null
  191.   -- Returns the appropriate Lua type, and the position of the next character to read.
  192.   -- @param s The string being scanned.
  193.   -- @param startPos The position in the string at which to start scanning.
  194.   -- @return object, int The object (true, false or nil) and the position at which the next character should be
  195.   -- scanned.
  196.   function decode_scanConstant(s, startPos)
  197.     local consts = { ["true"] = true, ["false"] = false, ["null"] = nil }
  198.     local constNames = {"true","false","null"}
  199.  
  200.     for i,k in base.pairs(constNames) do
  201.       --print ("[" .. string.sub(s,startPos, startPos + string.len(k) -1) .."]", k)
  202.       if string.sub(s,startPos, startPos + string.len(k) -1 )==k then
  203.         return consts[k], startPos + string.len(k)
  204.       end
  205.     end
  206.     base.assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos)
  207.   end
  208.  
  209.   --- Scans a number from the JSON encoded string.
  210.   -- (in fact, also is able to scan numeric +- eqns, which is not
  211.   -- in the JSON spec.)
  212.   -- Returns the number, and the position of the next character
  213.   -- after the number.
  214.   -- @param s The string being scanned.
  215.   -- @param startPos The position at which to start scanning.
  216.   -- @return number, int The extracted number and the position of the next character to scan.
  217.   function decode_scanNumber(s,startPos)
  218.     local endPos = startPos+1
  219.     local stringLen = string.len(s)
  220.     local acceptableChars = "+-0123456789.e"
  221.     while (string.find(acceptableChars, string.sub(s,endPos,endPos), 1, true)
  222.      and endPos<=stringLen
  223.      ) do
  224.       endPos = endPos + 1
  225.     end
  226.     local stringValue = 'return ' .. string.sub(s,startPos, endPos-1)
  227.     local stringEval = base.loadstring(stringValue)
  228.     base.assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos)
  229.     return stringEval(), endPos
  230.   end
  231.  
  232.   --- Scans a JSON object into a Lua object.
  233.   -- startPos begins at the start of the object.
  234.   -- Returns the object and the next starting position.
  235.   -- @param s The string being scanned.
  236.   -- @param startPos The starting position of the scan.
  237.   -- @return table, int The scanned object as a table and the position of the next character to scan.
  238.   function decode_scanObject(s,startPos)
  239.     local object = {}
  240.     local stringLen = string.len(s)
  241.     local key, value
  242.     base.assert(string.sub(s,startPos,startPos)=='{','decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\n' .. s)
  243.     startPos = startPos + 1
  244.     repeat
  245.       startPos = decode_scanWhitespace(s,startPos)
  246.       base.assert(startPos<=stringLen, 'JSON string ended unexpectedly while scanning object.')
  247.       local curChar = string.sub(s,startPos,startPos)
  248.       if (curChar=='}') then
  249.         return object,startPos+1
  250.       end
  251.       if (curChar==',') then
  252.         startPos = decode_scanWhitespace(s,startPos+1)
  253.       end
  254.       base.assert(startPos<=stringLen, 'JSON string ended unexpectedly scanning object.')
  255.       -- Scan the key
  256.       key, startPos = decode(s,startPos)
  257.       base.assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
  258.       startPos = decode_scanWhitespace(s,startPos)
  259.       base.assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
  260.       base.assert(string.sub(s,startPos,startPos)==':','JSON object key-value assignment mal-formed at ' .. startPos)
  261.       startPos = decode_scanWhitespace(s,startPos+1)
  262.       base.assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
  263.       value, startPos = decode(s,startPos)
  264.       object[key]=value
  265.     until false  -- infinite loop while key-value pairs are found
  266.   end
  267.  
  268.   --- Scans a JSON string from the opening inverted comma or single quote to the
  269.   -- end of the string.
  270.   -- Returns the string extracted as a Lua string,
  271.   -- and the position of the next non-string character
  272.   -- (after the closing inverted comma or single quote).
  273.   -- @param s The string being scanned.
  274.   -- @param startPos The starting position of the scan.
  275.   -- @return string, int The extracted string as a Lua string, and the next character to parse.
  276.   function decode_scanString(s,startPos)
  277.     base.assert(startPos, 'decode_scanString(..) called without start position')
  278.     local startChar = string.sub(s,startPos,startPos)
  279.     base.assert(startChar=="'" or startChar=='"','decode_scanString called for a non-string')
  280.     local escaped = false
  281.     local endPos = startPos + 1
  282.     local bEnded = false
  283.     local stringLen = string.len(s)
  284.     repeat
  285.       local curChar = string.sub(s,endPos,endPos)
  286.       -- Character escaping is only used to escape the string delimiters
  287.       if not escaped then
  288.         if curChar=='\\' then
  289.           escaped = true
  290.         else
  291.           bEnded = curChar==startChar
  292.         end
  293.       else
  294.         -- If we're escaped, we accept the current character come what may
  295.         escaped = false
  296.       end
  297.       endPos = endPos + 1
  298.       base.assert(endPos <= stringLen+1, "String decoding failed: unterminated string at position " .. endPos)
  299.     until bEnded
  300.     local stringValue = 'return ' .. string.sub(s, startPos, endPos-1)
  301.     local stringEval = base.loadstring(stringValue)
  302.     base.assert(stringEval, 'Failed to load string [ ' .. stringValue .. '] in JSON4Lua.decode_scanString at position ' .. startPos .. ' : ' .. endPos)
  303.     return stringEval(), endPos  
  304.   end
  305.  
  306.   --- Scans a JSON string skipping all whitespace from the current start position.
  307.   -- Returns the position of the first non-whitespace character, or nil if the whole end of string is reached.
  308.   -- @param s The string being scanned
  309.   -- @param startPos The starting position where we should begin removing whitespace.
  310.   -- @return int The first position where non-whitespace was encountered, or string.len(s)+1 if the end of string
  311.   -- was reached.
  312.   function decode_scanWhitespace(s,startPos)
  313.     local whitespace=" \n\r\t"
  314.     local stringLen = string.len(s)
  315.     while ( string.find(whitespace, string.sub(s,startPos,startPos), 1, true)  and startPos <= stringLen) do
  316.       startPos = startPos + 1
  317.     end
  318.     return startPos
  319.   end
  320.  
  321.   --- Encodes a string to be JSON-compatible.
  322.   -- This just involves back-quoting inverted commas, back-quotes and newlines, I think ;-)
  323.   -- @param s The string to return as a JSON encoded (i.e. backquoted string)
  324.   -- @return The string appropriately escaped.
  325.   function encodeString(s)
  326.     s = string.gsub(s,'\\','\\\\')
  327.     s = string.gsub(s,'"','\\"')
  328.     s = string.gsub(s,"'","\\'")
  329.     s = string.gsub(s,'\n','\\n')
  330.     s = string.gsub(s,'\t','\\t')
  331.     return s
  332.   end
  333.  
  334.   -- Determines whether the given Lua type is an array or a table / dictionary.
  335.   -- We consider any table an array if it has indexes 1..n for its n items, and no
  336.   -- other data in the table.
  337.   -- I think this method is currently a little 'flaky', but can't think of a good way around it yet...
  338.   -- @param t The table to evaluate as an array
  339.   -- @return boolean, number True if the table can be represented as an array, false otherwise. If true,
  340.   -- the second returned value is the maximum
  341.   -- number of indexed elements in the array.
  342.   function isArray(t)
  343.     -- Next we count all the elements, ensuring that any non-indexed elements are not-encodable
  344.     -- (with the possible exception of 'n')
  345.     local maxIndex = 0
  346.     for k,v in base.pairs(t) do
  347.       if (base.type(k)=='number' and math.floor(k)==k and 1<=k) then   -- k,v is an indexed pair
  348.         if (not isEncodable(v)) then return false end   -- All array elements must be encodable
  349.         maxIndex = math.max(maxIndex,k)
  350.       else
  351.         if (k=='n') then
  352.           if v ~= table.getn(t) then return false end  -- False if n does not hold the number of elements
  353.         else -- Else of (k=='n')
  354.           if isEncodable(v) then return false end
  355.         end  -- End of (k~='n')
  356.       end -- End of k,v not an indexed pair
  357.     end  -- End of loop across all pairs
  358.     return true, maxIndex
  359.   end
  360.  
  361.   --- Determines whether the given Lua object / table / variable can be JSON encoded. The only
  362.   -- types that are JSON encodable are: string, boolean, number, nil, table and json.null.
  363.   -- In this implementation, all other types are ignored.
  364.   -- @param o The object to examine.
  365.   -- @return boolean True if the object should be JSON encoded, false if it should be ignored.
  366.   function isEncodable(o)
  367.     local t = base.type(o)
  368.     return (t=='string' or t=='boolean' or t=='number' or t=='nil' or t=='table') or (t=='function' and o==null)
  369.   end
  370. ]]
  371.  
  372. local function loadJSON()
  373.   local sName = 'JSON'
  374.    
  375.   local tEnv = {}
  376.   setmetatable( tEnv, { __index = _G } )
  377.   local fnAPI, err = loadstring(_jstr)
  378.   if fnAPI then
  379.     setfenv( fnAPI, tEnv )
  380.     fnAPI()
  381.   else
  382.     printError( err )
  383.     return false
  384.   end
  385.  
  386.   local tAPI = {}
  387.   for k,v in pairs( tEnv ) do
  388.     tAPI[k] =  v
  389.   end
  390.  
  391.   _G[sName] = tAPI
  392.   return true
  393. end
  394.  
  395. local mainTitle = 'KrutoyTurtle Installer'
  396. local subTitle = 'Please wait...'
  397.  
  398. local function Draw()
  399.   sleep(0)
  400.   term.clear()
  401.   local w, h = term.getSize()
  402.   term.setCursorPos((w-#mainTitle)/2, h/2-2)
  403.   term.write(mainTitle)
  404.   term.setCursorPos((w-#subTitle)/2, h/2)
  405.   term.write(subTitle)
  406. end
  407.  
  408. local tArgs = {...}
  409.  
  410. local Settings = {
  411.   InstallPath = '/', --Where the program's installed, don't always asume root
  412.   GitHubUsername = 'Krutoy242', --Your GitHub username as it appears in the URL
  413.   GitHubRepoName = 'OpenKrutoy', --The repo name as it appears in the URL
  414.   TotalBytes = 0, --Do not change this value (especially programatically)!
  415.   DownloadedBytes = 0, --Do not change this value (especially programatically)!
  416. }
  417.  
  418. loadJSON()
  419.  
  420. local function downloadJSON(path)
  421.   local _json = http.get(path)
  422.   if not _json then
  423.     error('Could not download, check your connection.')
  424.   end
  425.   return JSON.decode(_json.readAll())
  426. end
  427.  
  428. if http then
  429.   subTitle = 'HTTP enabled, attempting update...'
  430.   Draw()
  431. else
  432.   subTitle = 'HTTP is required to update.'
  433.   Draw()
  434.   error('')
  435. end
  436.  
  437.  
  438. local tree
  439. local gitRepo = 'https://api.github.com/repos/'..Settings.GitHubUsername..'/'..Settings.GitHubRepoName
  440. local rawRepo = 'https://raw.github.com/'..      Settings.GitHubUsername..'/'..Settings.GitHubRepoName
  441. local rawPath
  442. if isDebug then
  443.   subTitle = 'Debug mode enabled'
  444.   Draw()
  445.   tree = downloadJSON(gitRepo..'/contents/?recursive=1')
  446.   rawPath = 'master'
  447. else
  448.   subTitle = 'Determining Latest Version'
  449.   Draw()
  450.   local releases = downloadJSON(gitRepo..'/releases')
  451.   rawPath = releases[1].tag_name
  452.   subTitle = 'Optaining Latest Version URL'
  453.   Draw()
  454.   local refs = downloadJSON(gitRepo..'/git/refs')
  455.   local latestReleaseSha = ''
  456.   for i, v in ipairs(refs) do
  457.     if v.ref == 'refs/tags/'..rawPath then
  458.       latestReleaseSha = v.object.sha
  459.     end
  460.   end
  461.   tree = downloadJSON(gitRepo..'/git/trees/'..latestReleaseSha..'?recursive=1').tree
  462. end
  463.  
  464. subTitle = 'Downloading File Listing'
  465. Draw()
  466.  
  467.  
  468. local blacklist = {
  469.   '/.gitignore',
  470.   '/README.md',
  471.   '/TODO',
  472.   '/.version'
  473. }
  474.  
  475. local function isBlacklisted(path)
  476.   for i, item in ipairs(blacklist) do
  477.     if item == path then
  478.       return true
  479.     end
  480.   end
  481.   return false
  482. end
  483.  
  484. local tAPIsLoading = {}
  485. local function LoadAPI(_sAPI, sName)
  486.  
  487.   if tAPIsLoading[sName] == true then
  488.     printError( "API "..sName.." is already being loaded" )
  489.     return false
  490.   end
  491.   tAPIsLoading[sName] = true
  492.  
  493.   local tEnv = {}
  494.   setmetatable( tEnv, { __index = getfenv() } )
  495.   local fnAPI, err = loadstring( _sAPI, sName )
  496.   if fnAPI then
  497.     --setfenv( fnAPI, tEnv )
  498.     setfenv( fnAPI, getfenv() )
  499.     fnAPI()
  500.   else
  501.     printError( err )
  502.     tAPIsLoading[sName] = nil
  503.     return false
  504.   end
  505.  
  506.   local tAPI = {}
  507.   for k,v in pairs( tEnv ) do
  508.     tAPI[k] =  v
  509.   end
  510.  
  511.   getfenv()[sName] = tAPI
  512.  
  513.   tAPIsLoading[sName] = nil
  514.   return true
  515. end
  516.  
  517.  
  518. Settings.TotalFiles = 0
  519. Settings.TotalBytes = 0
  520. for i, v in ipairs(tree) do
  521.   if not isBlacklisted(Settings.InstallPath..v.path) and v.size then
  522.     Settings.TotalBytes = Settings.TotalBytes + v.size
  523.     Settings.TotalFiles = Settings.TotalFiles + 1
  524.   end
  525. end
  526.  
  527. Settings.DownloadedBytes = 0
  528. local function downloadBlob(v)
  529.   local fileName = Settings.InstallPath..v.path
  530.   if isBlacklisted(fileName) then
  531.     return
  532.   end
  533.   if v.type == 'tree' then
  534.  
  535.   else
  536.     local rawFilePath = (rawRepo..'/'..rawPath..fileName):gsub(' ','%%20')
  537.     local f = http.get(rawFilePath)
  538.     if not f then
  539.       error('Downloading failed, try again. '..fileName)
  540.     end
  541.     LoadAPI( f.readAll(), fileName )
  542.     local processPercent = math.floor(100*(Settings.DownloadedBytes/Settings.TotalBytes))
  543.     subTitle = '('..processPercent..'%) Downloaded: '..fileName
  544.     Draw()
  545.     if v.size then
  546.       Settings.DownloadedBytes = Settings.DownloadedBytes + v.size
  547.     end
  548.   end
  549. end
  550.  
  551. local downloads = {}
  552. for i, v in ipairs(tree) do
  553.   table.insert(downloads, function()downloadBlob(v)end)
  554. end
  555.  
  556. parallel.waitForAll(unpack(downloads))
  557.  
  558.  
  559. mainTitle = 'Installation Complete!'
  560. subTitle = 'Lunch...'
  561. Draw()
  562. end
  563.  
  564. main() -- Init function from KrutoyTurtle.lua
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement