JackMacWindows

gist.lua

Jan 21st, 2020
369
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 22.48 KB | None | 0 0
  1. -- gist.lua - Gist client for ComputerCraft
  2. -- Made by JackMacWindows for CraftOS-PC and CC: Tweaked
  3.  
  4. -- The following code consists of a JSON library.
  5.  
  6. local json
  7. do
  8.  
  9. --
  10. -- json.lua
  11. --
  12. -- Copyright (c) 2019 rxi
  13. --
  14. -- Permission is hereby granted, free of charge, to any person obtaining a copy of
  15. -- this software and associated documentation files (the "Software"), to deal in
  16. -- the Software without restriction, including without limitation the rights to
  17. -- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  18. -- of the Software, and to permit persons to whom the Software is furnished to do
  19. -- so, subject to the following conditions:
  20. --
  21. -- The above copyright notice and this permission notice shall be included in all
  22. -- copies or substantial portions of the Software.
  23. --
  24. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  25. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  26. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  27. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  28. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  29. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30. -- SOFTWARE.
  31. --
  32.  
  33. json = { _version = "0.1.2" }
  34.  
  35. -------------------------------------------------------------------------------
  36. -- Encode
  37. -------------------------------------------------------------------------------
  38.  
  39. local encode
  40.  
  41. local escape_char_map = {
  42.   [ "\\" ] = "\\\\",
  43.   [ "\"" ] = "\\\"",
  44.   [ "\b" ] = "\\b",
  45.   [ "\f" ] = "\\f",
  46.   [ "\n" ] = "\\n",
  47.   [ "\r" ] = "\\r",
  48.   [ "\t" ] = "\\t",
  49. }
  50.  
  51. local escape_char_map_inv = { [ "\\/" ] = "/" }
  52. for k, v in pairs(escape_char_map) do
  53.   escape_char_map_inv[v] = k
  54. end
  55.  
  56.  
  57. local function escape_char(c)
  58.   return escape_char_map[c] or string.format("\\u%04x", c:byte())
  59. end
  60.  
  61.  
  62. local function encode_nil(val)
  63.   return "null"
  64. end
  65.  
  66.  
  67. local function encode_table(val, stack)
  68.   local res = {}
  69.   stack = stack or {}
  70.  
  71.   -- Circular reference?
  72.   if stack[val] then error("circular reference") end
  73.  
  74.   stack[val] = true
  75.  
  76.   if rawget(val, 1) ~= nil or next(val) == nil then
  77.     -- Treat as array -- check keys are valid and it is not sparse
  78.     local n = 0
  79.     for k in pairs(val) do
  80.       if type(k) ~= "number" then
  81.         error("invalid table: mixed or invalid key types")
  82.       end
  83.       n = n + 1
  84.     end
  85.     if n ~= #val then
  86.       error("invalid table: sparse array")
  87.     end
  88.     -- Encode
  89.     for i, v in ipairs(val) do
  90.       table.insert(res, encode(v, stack))
  91.     end
  92.     stack[val] = nil
  93.     return "[" .. table.concat(res, ",") .. "]"
  94.  
  95.   else
  96.     -- Treat as an object
  97.     for k, v in pairs(val) do
  98.       if type(k) ~= "string" then
  99.         error("invalid table: mixed or invalid key types")
  100.       end
  101.       table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
  102.     end
  103.     stack[val] = nil
  104.     return "{" .. table.concat(res, ",") .. "}"
  105.   end
  106. end
  107.  
  108.  
  109. local function encode_string(val)
  110.   return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
  111. end
  112.  
  113.  
  114. local function encode_number(val)
  115.   -- Check for NaN, -inf and inf
  116.   if val ~= val or val <= -math.huge or val >= math.huge then
  117.     error("unexpected number value '" .. tostring(val) .. "'")
  118.   end
  119.   return string.format("%.14g", val)
  120. end
  121.  
  122.  
  123. local type_func_map = {
  124.   [ "nil"     ] = encode_nil,
  125.   [ "table"   ] = encode_table,
  126.   [ "string"  ] = encode_string,
  127.   [ "number"  ] = encode_number,
  128.   [ "boolean" ] = tostring,
  129. }
  130.  
  131.  
  132. encode = function(val, stack)
  133.   local t = type(val)
  134.   local f = type_func_map[t]
  135.   if f then
  136.     return f(val, stack)
  137.   end
  138.   error("unexpected type '" .. t .. "'")
  139. end
  140.  
  141.  
  142. function json.encode(val)
  143.   return ( encode(val) )
  144. end
  145.  
  146.  
  147. -------------------------------------------------------------------------------
  148. -- Decode
  149. -------------------------------------------------------------------------------
  150.  
  151. local parse
  152.  
  153. local function create_set(...)
  154.   local res = {}
  155.   for i = 1, select("#", ...) do
  156.     res[ select(i, ...) ] = true
  157.   end
  158.   return res
  159. end
  160.  
  161. local space_chars   = create_set(" ", "\t", "\r", "\n")
  162. local delim_chars   = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
  163. local escape_chars  = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
  164. local literals      = create_set("true", "false", "null")
  165.  
  166. local literal_map = {
  167.   [ "true"  ] = true,
  168.   [ "false" ] = false,
  169.   [ "null"  ] = nil,
  170. }
  171.  
  172.  
  173. local function next_char(str, idx, set, negate)
  174.   for i = idx, #str do
  175.     if set[str:sub(i, i)] ~= negate then
  176.       return i
  177.     end
  178.   end
  179.   return #str + 1
  180. end
  181.  
  182.  
  183. local function decode_error(str, idx, msg)
  184.   local line_count = 1
  185.   local col_count = 1
  186.   for i = 1, idx - 1 do
  187.     col_count = col_count + 1
  188.     if str:sub(i, i) == "\n" then
  189.       line_count = line_count + 1
  190.       col_count = 1
  191.     end
  192.   end
  193.   error( string.format("%s at line %d col %d", msg, line_count, col_count) )
  194. end
  195.  
  196.  
  197. local function codepoint_to_utf8(n)
  198.   -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
  199.   local f = math.floor
  200.   if n <= 0x7f then
  201.     return string.char(n)
  202.   elseif n <= 0x7ff then
  203.     return string.char(f(n / 64) + 192, n % 64 + 128)
  204.   elseif n <= 0xffff then
  205.     return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
  206.   elseif n <= 0x10ffff then
  207.     return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
  208.                        f(n % 4096 / 64) + 128, n % 64 + 128)
  209.   end
  210.   error( string.format("invalid unicode codepoint '%x'", n) )
  211. end
  212.  
  213.  
  214. local function parse_unicode_escape(s)
  215.   local n1 = tonumber( s:sub(3, 6),  16 )
  216.   local n2 = tonumber( s:sub(9, 12), 16 )
  217.   -- Surrogate pair?
  218.   if n2 then
  219.     return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
  220.   else
  221.     return codepoint_to_utf8(n1)
  222.   end
  223. end
  224.  
  225.  
  226. local function parse_string(str, i)
  227.   local has_unicode_escape = false
  228.   local has_surrogate_escape = false
  229.   local has_escape = false
  230.   local last
  231.   for j = i + 1, #str do
  232.     local x = str:byte(j)
  233.  
  234.     if x < 32 then
  235.       decode_error(str, j, "control character in string")
  236.     end
  237.  
  238.     if last == 92 then -- "\\" (escape char)
  239.       if x == 117 then -- "u" (unicode escape sequence)
  240.         local hex = str:sub(j + 1, j + 5)
  241.         if not hex:find("%x%x%x%x") then
  242.           decode_error(str, j, "invalid unicode escape in string")
  243.         end
  244.         if hex:find("^[dD][89aAbB]") then
  245.           has_surrogate_escape = true
  246.         else
  247.           has_unicode_escape = true
  248.         end
  249.       else
  250.         local c = string.char(x)
  251.         if not escape_chars[c] then
  252.           decode_error(str, j, "invalid escape char '" .. c .. "' in string")
  253.         end
  254.         has_escape = true
  255.       end
  256.       last = nil
  257.  
  258.     elseif x == 34 then -- '"' (end of string)
  259.       local s = str:sub(i + 1, j - 1)
  260.       if has_surrogate_escape then
  261.         s = s:gsub("\\u[dD][89aAbB]..\\u....", parse_unicode_escape)
  262.       end
  263.       if has_unicode_escape then
  264.         s = s:gsub("\\u....", parse_unicode_escape)
  265.       end
  266.       if has_escape then
  267.         s = s:gsub("\\.", escape_char_map_inv)
  268.       end
  269.       return s, j + 1
  270.  
  271.     else
  272.       last = x
  273.     end
  274.   end
  275.   decode_error(str, i, "expected closing quote for string")
  276. end
  277.  
  278.  
  279. local function parse_number(str, i)
  280.   local x = next_char(str, i, delim_chars)
  281.   local s = str:sub(i, x - 1)
  282.   local n = tonumber(s)
  283.   if not n then
  284.     decode_error(str, i, "invalid number '" .. s .. "'")
  285.   end
  286.   return n, x
  287. end
  288.  
  289.  
  290. local function parse_literal(str, i)
  291.   local x = next_char(str, i, delim_chars)
  292.   local word = str:sub(i, x - 1)
  293.   if not literals[word] then
  294.     decode_error(str, i, "invalid literal '" .. word .. "'")
  295.   end
  296.   return literal_map[word], x
  297. end
  298.  
  299.  
  300. local function parse_array(str, i)
  301.   local res = {}
  302.   local n = 1
  303.   i = i + 1
  304.   while 1 do
  305.     local x
  306.     i = next_char(str, i, space_chars, true)
  307.     -- Empty / end of array?
  308.     if str:sub(i, i) == "]" then
  309.       i = i + 1
  310.       break
  311.     end
  312.     -- Read token
  313.     x, i = parse(str, i)
  314.     res[n] = x
  315.     n = n + 1
  316.     -- Next token
  317.     i = next_char(str, i, space_chars, true)
  318.     local chr = str:sub(i, i)
  319.     i = i + 1
  320.     if chr == "]" then break end
  321.     if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
  322.   end
  323.   return res, i
  324. end
  325.  
  326.  
  327. local function parse_object(str, i)
  328.   local res = {}
  329.   i = i + 1
  330.   while 1 do
  331.     local key, val
  332.     i = next_char(str, i, space_chars, true)
  333.     -- Empty / end of object?
  334.     if str:sub(i, i) == "}" then
  335.       i = i + 1
  336.       break
  337.     end
  338.     -- Read key
  339.     if str:sub(i, i) ~= '"' then
  340.       decode_error(str, i, "expected string for key")
  341.     end
  342.     key, i = parse(str, i)
  343.     -- Read ':' delimiter
  344.     i = next_char(str, i, space_chars, true)
  345.     if str:sub(i, i) ~= ":" then
  346.       decode_error(str, i, "expected ':' after key")
  347.     end
  348.     i = next_char(str, i + 1, space_chars, true)
  349.     -- Read value
  350.     val, i = parse(str, i)
  351.     -- Set
  352.     res[key] = val
  353.     -- Next token
  354.     i = next_char(str, i, space_chars, true)
  355.     local chr = str:sub(i, i)
  356.     i = i + 1
  357.     if chr == "}" then break end
  358.     if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
  359.   end
  360.   return res, i
  361. end
  362.  
  363.  
  364. local char_func_map = {
  365.   [ '"' ] = parse_string,
  366.   [ "0" ] = parse_number,
  367.   [ "1" ] = parse_number,
  368.   [ "2" ] = parse_number,
  369.   [ "3" ] = parse_number,
  370.   [ "4" ] = parse_number,
  371.   [ "5" ] = parse_number,
  372.   [ "6" ] = parse_number,
  373.   [ "7" ] = parse_number,
  374.   [ "8" ] = parse_number,
  375.   [ "9" ] = parse_number,
  376.   [ "-" ] = parse_number,
  377.   [ "t" ] = parse_literal,
  378.   [ "f" ] = parse_literal,
  379.   [ "n" ] = parse_literal,
  380.   [ "[" ] = parse_array,
  381.   [ "{" ] = parse_object,
  382. }
  383.  
  384.  
  385. parse = function(str, idx)
  386.   local chr = str:sub(idx, idx)
  387.   local f = char_func_map[chr]
  388.   if f then
  389.     return f(str, idx)
  390.   end
  391.   decode_error(str, idx, "unexpected character '" .. chr .. "'")
  392. end
  393.  
  394.  
  395. function json.decode(str)
  396.   if type(str) ~= "string" then
  397.     error("expected argument of type string, got " .. type(str))
  398.   end
  399.   local res, idx = parse(str, next_char(str, 1, space_chars, true))
  400.   idx = next_char(str, idx, space_chars, true)
  401.   if idx <= #str then
  402.     decode_error(str, idx, "trailing garbage")
  403.   end
  404.   return res
  405. end
  406.  
  407. end -- end of libraries
  408.  
  409. -- Actual program
  410.  
  411. local function getGistFile(data)
  412.     if not data.truncated then return data.content else
  413.         local handle = http.get(data.raw_url)
  414.         if not handle then error("Could not connect to api.github.com.") end
  415.         if handle.getResponseCode() ~= 200 then handle.close(); error("Failed to download file data.") end
  416.         local d = handle.readAll()
  417.         handle.close()
  418.         return d
  419.     end
  420. end
  421.  
  422. -- ID can be either just the gist ID or a gist ID followed by a slash and a file name
  423. -- * If a file name is specified, retrieves that file
  424. -- * Otherwise, if there's only one file, retrieves that file
  425. -- * Otherwise, if there's a file named 'init.lua', retrieves 'init.lua'
  426. -- * Otherwise, if there's more than one file but only one *.lua file, retrieves the Lua file
  427. -- * Otherwise, retrieves the first Lua file alphabetically (with a warning)
  428. -- * Otherwise, fails
  429. local function getGistData(id)
  430.     local file, rev
  431.     if id:find("/") ~= nil then id, file = id:match("^([0-9A-Fa-f:]+)/(.+)$") end
  432.     if id:find(":") ~= nil then id = id:gsub(":", "/") end
  433.     write("Connecting to api.github.com... ")
  434.     local handle = http.get("https://api.github.com/gists/" .. id)
  435.     if handle == nil then print("Failed."); return nil end
  436.     if handle.getResponseCode() ~= 200 then print("Failed."); handle.close(); return nil end
  437.     local meta = json.decode(handle.readAll())
  438.     handle.close()
  439.     if meta == nil or meta.files == nil then print("Failed."); return nil end
  440.     print("Success.")
  441.     if file then return getGistFile(meta.files[file]), file
  442.     elseif next(meta.files, next(meta.files)) == nil then return getGistFile(meta.files[next(meta.files)]), next(meta.files)
  443.     elseif meta.files["init.lua"] ~= nil then return getGistFile(meta.files["init.lua"]), "init.lua"
  444.     else
  445.         local luaFiles = {}
  446.         for k in pairs(meta.files) do if k:match("%.lua$") then table.insert(luaFiles, k) end end
  447.         table.sort(luaFiles)
  448.         if #luaFiles == 0 then
  449.             print("Error: Could not find any Lua files to download!")
  450.             return nil
  451.         end
  452.         if #luaFiles > 1 then print("Warning: More than one Lua file detected, downloading the first one alphabetically.") end
  453.         return getGistFile(meta.files[luaFiles[1]]), luaFiles[1]
  454.     end
  455. end
  456.  
  457. local function setTextColor(c) if term.isColor() then term.setTextColor(c) elseif c == colors.white then term.setTextColor(c) else term.setTextColor(colors.lightGray) end end
  458.  
  459. local function requestAuth(headers)
  460.     if settings.get("gist.id") ~= nil then headers.Authorization = "token " .. settings.get("gist.id") else
  461.         setTextColor(colors.yellow)
  462.         write("You need to add a Personal Access Token (PAK) to upload Gists. Follow the instructions at ")
  463.         setTextColor(colors.blue)
  464.         write("https://tinyurl.com/GitHubPAK")
  465.         setTextColor(colors.yellow)
  466.         write(" to generate one. Make sure to check the '")
  467.         setTextColor(colors.blue)
  468.         write("gist")
  469.         setTextColor(colors.yellow)
  470.         print("' checkbox on step 7 (under 'Select scopes'). Once done, paste it here.")
  471.         setTextColor(colors.lime)
  472.         write("PAK: ")
  473.         setTextColor(colors.white)
  474.         local pak = read()
  475.         if pak == nil or pak == "" then error("Invalid PAK, please try again.") end
  476.         settings.set("gist.id", pak)
  477.         headers.Authorization = "token " .. pak
  478.     end
  479. end
  480.  
  481. local args = {...}
  482.  
  483. local helpstr = "Usages:\ngist put <filenames...> [-- description...]\ngist edit <id> <filenames...> [-- description]\ngist delete <id>\ngist get <id> <filename>\ngist run <id> [arguments...]\ngist info <id>"
  484.  
  485. if #args < 2 then
  486.     print(helpstr)
  487.     return 1
  488. end
  489.  
  490. if not http then
  491.     printError("Gist requires http API")
  492.     if _G.config ~= nil then printError("Set http_enable to true in the CraftOS-PC configuration")
  493.     else printError("Set http_enable to true in ComputerCraft.cfg") end
  494.     return 2
  495. end
  496.  
  497. if args[1] == "get" then
  498.     if #args < 3 then print(helpstr); return 1 end
  499.     local data = getGistData(args[2])
  500.     if data == nil then return 3 end
  501.     local file = fs.open(shell.resolve(args[3]), "w")
  502.     file.write(data)
  503.     file.close()
  504.     print("Downloaded as " .. shell.resolve(args[3]))
  505. elseif args[1] == "run" then
  506.     local data, name = getGistData(args[2])
  507.     if data == nil then return 3 end
  508.     local fn, err = load(data, name, "t", _ENV)
  509.     if fn == nil then error(err) end
  510.     local ok, msg = fn(table.unpack(args, 3))
  511.     if not ok then error(msg) end
  512. elseif args[1] == "put" then
  513.     local data = {files = {}, public = true}
  514.     local i = 2
  515.     while args[i] ~= nil and args[i] ~= "--" do
  516.         if data.files[fs.getName(args[i])] then error("Cannot upload files with duplicate names.") end
  517.         local file = fs.open(shell.resolve(args[i]), "r")
  518.         if file == nil then error("Could not read " .. shell.resolve(args[i]) .. ".") end
  519.         data.files[fs.getName(args[i])] = {content = file.readAll()}
  520.         file.close()
  521.         i=i+1
  522.     end
  523.     if args[i] == "--" then data.description = table.concat({table.unpack(args, i+1)}, " ") end
  524.     -- Get authorization
  525.     local headers = {["Content-Type"] = "application/json"}
  526.     requestAuth(headers)
  527.     local jsonfiles = ""
  528.     for k,v in pairs(data.files) do jsonfiles = jsonfiles .. (jsonfiles == "" and "" or ",\n") .. ("    \"%s\": {\n      \"content\": %s\n    }"):format(k, json.encode(v.content)) end
  529.     local jsondata = ([[{
  530.   "description": %s,
  531.   "public": true,
  532.   "files": {
  533. %s
  534.   }
  535. }]]):format(data.description and '"' .. data.description .. '"' or "null", jsonfiles)
  536.     write("Connecting to api.github.com... ")
  537.     local handle = http.post("https://api.github.com/gists", jsondata, headers)
  538.     if handle == nil then print("Failed."); return 3 end
  539.     local resp = json.decode(handle.readAll())
  540.     if handle.getResponseCode() ~= 201 or resp == nil then print("Failed: " .. handle.getResponseCode() .. ": " .. (resp and json.encode(resp) or "Unknown error")); handle.close(); return 3 end
  541.     handle.close()
  542.     print("Success. Uploaded as " .. resp.id .. "\nRun 'gist get " .. resp.id .. "' to download anywhere")
  543. elseif args[1] == "info" then
  544.     local id = args[2]
  545.     if id:find("/") ~= nil then id = id:match("^([0-9A-Fa-f:]+)/.+$") end
  546.     if id:find(":") ~= nil then id = id:gsub(":", "/") end
  547.     write("Connecting to api.github.com... ")
  548.     local handle = http.get("https://api.github.com/gists/" .. id)
  549.     if handle == nil then print("Failed."); return 3 end
  550.     if handle.getResponseCode() ~= 200 then print("Failed."); handle.close(); return 3 end
  551.     local meta = json.decode(handle.readAll())
  552.     handle.close()
  553.     if meta == nil or meta.files == nil then print("Failed."); return 3 end
  554.     local f = {}
  555.     for k in pairs(meta.files) do table.insert(f, k) end
  556.     table.sort(f)
  557.     print("Success.")
  558.     setTextColor(colors.yellow)
  559.     write("Description: ")
  560.     setTextColor(colors.white)
  561.     print(meta.description)
  562.     setTextColor(colors.yellow)
  563.     write("Author: ")
  564.     setTextColor(colors.white)
  565.     print(meta.owner.login)
  566.     setTextColor(colors.yellow)
  567.     write("Revisions: ")
  568.     setTextColor(colors.white)
  569.     print(#meta.history)
  570.     setTextColor(colors.yellow)
  571.     print("Files in this Gist:")
  572.     setTextColor(colors.white)
  573.     textutils.tabulate(f)
  574. elseif args[1] == "edit" then
  575.     if #args < 3 then print(helpstr); return 1 end
  576.     local data = {files = {}, public = true}
  577.     local id = args[2]
  578.     if id:find("/") ~= nil then id = id:match("^([0-9A-Fa-f:]+)/.+$") end
  579.     if id:find(":") ~= nil then id = id:gsub(":", "/") end
  580.     local i = 3
  581.     while args[i] ~= nil and args[i] ~= "--" do
  582.         if data.files[fs.getName(args[i])] then error("Cannot upload files with duplicate names.") end
  583.         local file = fs.open(shell.resolve(args[i]), "r")
  584.         if file == nil then data.files[fs.getName(args[i])] = {} else
  585.             data.files[fs.getName(args[i])] = {content = file.readAll()}
  586.             file.close()
  587.         end
  588.         i=i+1
  589.     end
  590.     if args[i] == "--" then data.description = table.concat({table.unpack(args, i+1)}, " ") else
  591.         write("Connecting to api.github.com... ")
  592.         local handle = http.get("https://api.github.com/gists/" .. id)
  593.         if handle == nil then print("Failed."); return 3 end
  594.         if handle.getResponseCode() ~= 200 then print("Failed."); handle.close(); return 3 end
  595.         local meta = json.decode(handle.readAll())
  596.         handle.close()
  597.         if meta == nil or meta.files == nil then print("Failed."); return 3 end
  598.         data.description = meta.description
  599.         print("Success.")
  600.     end
  601.     -- Get authorization
  602.     local headers = {["Content-Type"] = "application/json"}
  603.     requestAuth(headers)
  604.     local jsonfiles = ""
  605.     for k,v in pairs(data.files) do jsonfiles = jsonfiles .. (jsonfiles == "" and "" or ",\n") .. (v.content == nil and ("    \"%s\": null"):format(k) or ("    \"%s\": {\n      \"content\": %s\n    }"):format(k, json.encode(v.content))) end
  606.     local jsondata = ([[{
  607.   "description": %s,
  608.   "public": true,
  609.   "files": {
  610. %s
  611.   }
  612. }]]):format(data.description and '"' .. data.description .. '"' or "null", jsonfiles)
  613.     write("Connecting to api.github.com... ")
  614.     local handle
  615.     if http.patch ~= nil then handle = http.patch("https://api.github.com/gists/" .. id, jsondata, headers)
  616.     elseif http.websocket ~= nil then
  617.         local _url = "https://api.github.com/gists/" .. id
  618.         local ok, err = http.request(_url, jsondata, headers, false, "PATCH")
  619.         if ok then
  620.             while true do
  621.                 local event, param1, param2, param3 = os.pullEvent()
  622.                 if event == "http_success" and param1 == _url then
  623.                     handle = param2
  624.                     break
  625.                 elseif event == "http_failure" and param1 == _url then
  626.                     print("Failed: ", param2, param3)
  627.                     return 3
  628.                 end
  629.             end
  630.         else print("Failed: " .. err); return 3 end
  631.     else print("Failed: This version of ComputerCraft doesn't support the PATCH method. Update to CC: Tweaked or a compatible emulator (CraftOS-PC, CCEmuX) to use 'edit'."); return 3 end
  632.     if handle == nil then print("Failed."); return 3 end
  633.     local resp = json.decode(handle.readAll())
  634.     if handle.getResponseCode() ~= 200 or resp == nil then print("Failed: " .. handle.getResponseCode() .. ": " .. (resp and json.encode(resp) or "Unknown error")); handle.close(); return 3 end
  635.     handle.close()
  636.     print("Success. Uploaded as " .. resp.id .. "\nRun 'gist get " .. resp.id .. "' to download anywhere")
  637. elseif args[1] == "delete" then
  638.     local id = args[2]
  639.     if id:find("/") ~= nil or id:find(":") ~= nil then id = id:match("^([0-9A-Fa-f]+)") end
  640.     local headers = {}
  641.     requestAuth(headers)
  642.     local handle
  643.     write("Connecting to api.github.com... ")
  644.     if http.delete ~= nil then handle = http.delete("https://api.github.com/gists/" .. id, nil, headers)
  645.     elseif http.websocket ~= nil then
  646.         local _url = "https://api.github.com/gists/" .. id
  647.         local ok, err = http.request(_url, nil, headers, false, "DELETE")
  648.         if ok then
  649.             while true do
  650.                 local event, param1, param2, param3 = os.pullEvent()
  651.                 if event == "http_success" and param1 == _url then
  652.                     handle = param2
  653.                     break
  654.                 elseif event == "http_failure" and param1 == _url then
  655.                     print("Failed: ", param2, param3)
  656.                     return 3
  657.                 end
  658.             end
  659.         else print("Failed: " .. err); return 3 end
  660.     else print("Failed: This version of ComputerCraft doesn't support the PATCH method. Update to CC: Tweaked or a compatible emulator (CraftOS-PC, CCEmuX) to use 'edit'."); return 3 end
  661.     if handle == nil then print("Failed."); return 3 end
  662.     if handle.getResponseCode() ~= 204 then print("Failed: " .. handle.getResponseCode() .. "."); handle.close(); return 3 end
  663.     handle.close()
  664.     print("Success.")
  665.     print("The requested Gist has been deleted.")
  666. else print(helpstr); return 1 end
Add Comment
Please, Sign In to add comment