Grey-Echo 3b69cf992e This is an important refactor of the way documentation generation works
* Installs luarocks WITH it's executable (easy to install other rocks if necessary)
* Use Lua supplied with luarocks
* Create Utils/luadocumentor.bat, which works with RELATIVE PATH ! -> Everybody can generate the doc
* Updated launch files accordingly
2017-04-05 01:26:39 +02:00

285 lines
8.3 KiB
Lua

local api = {}
local cfg = require("luarocks.cfg")
local fs = require("luarocks.fs")
local util = require("luarocks.util")
local persist = require("luarocks.persist")
local multipart = require("luarocks.upload.multipart")
local Api = {}
local function upload_config_file()
local conf = cfg.which_config()
if not conf.user.file then
return nil
end
return (conf.user.file:gsub("/[^/]+$", "/upload_config.lua"))
end
function Api:load_config()
local upload_conf = upload_config_file()
if not upload_conf then return nil end
local cfg, err = persist.load_into_table(upload_conf)
return cfg
end
function Api:save_config()
-- Test configuration before saving it.
local res, err = self:raw_method("status")
if not res then
return nil, err
end
if res.errors then
util.printerr("Server says: " .. tostring(res.errors[1]))
return
end
local upload_conf = upload_config_file()
if not upload_conf then return nil end
persist.save_from_table(upload_conf, self.config)
fs.chmod(upload_conf, "0600")
end
function Api:check_version()
if not self._server_tool_version then
local tool_version = cfg.upload.tool_version
local res, err = self:request(tostring(self.config.server) .. "/api/tool_version", {
current = tool_version
})
if not res then
return nil, err
end
if not res.version then
return nil, "failed to fetch tool version"
end
self._server_tool_version = res.version
if res.force_update then
return nil, "Your upload client is too out of date to continue, please upgrade LuaRocks."
end
if res.version ~= tool_version then
util.printerr("Warning: Your LuaRocks is out of date, consider upgrading.")
end
end
return true
end
function Api:method(...)
local res, err = self:raw_method(...)
if not res then
return nil, err
end
if res.errors then
if res.errors[1] == "Invalid key" then
return nil, res.errors[1] .. " (use the --api-key flag to change)"
end
local msg = table.concat(res.errors, ", ")
return nil, "API Failed: " .. msg
end
return res
end
function Api:raw_method(path, ...)
self:check_version()
local url = tostring(self.config.server) .. "/api/" .. tostring(cfg.upload.api_version) .. "/" .. tostring(self.config.key) .. "/" .. tostring(path)
return self:request(url, ...)
end
local function encode_query_string(t, sep)
if sep == nil then
sep = "&"
end
local i = 0
local buf = { }
for k, v in pairs(t) do
if type(k) == "number" and type(v) == "table" then
k, v = v[1], v[2]
end
buf[i + 1] = multipart.url_escape(k)
buf[i + 2] = "="
buf[i + 3] = multipart.url_escape(v)
buf[i + 4] = sep
i = i + 4
end
buf[i] = nil
return table.concat(buf)
end
-- An ode to the multitude of JSON libraries out there...
local function require_json()
local list = { "cjson", "dkjson", "json" }
for _, lib in ipairs(list) do
local json_ok, json = pcall(require, lib)
if json_ok then
pcall(json.use_lpeg) -- optional feature in dkjson
return json_ok, json
end
end
local errmsg = "Failed loading "
for i, name in ipairs(list) do
if i == #list then
errmsg = errmsg .."and '"..name.."'. Use 'luarocks search <partial-name>' to search for a library and 'luarocks install <name>' to install one."
else
errmsg = errmsg .."'"..name.."', "
end
end
return nil, errmsg
end
local function redact_api_url(url)
url = tostring(url)
return (url:gsub(".*/api/[^/]+/[^/]+", "")) or ""
end
local ltn12_ok, ltn12 = pcall(require, "ltn12")
if not ltn12_ok then -- If not using LuaSocket and/or LuaSec...
function Api:request(url, params, post_params)
local vars = cfg.variables
local json_ok, json = require_json()
if not json_ok then return nil, "A JSON library is required for this command. "..json end
if cfg.downloader == "wget" then
local curl_ok, err = fs.is_tool_available(vars.CURL, "curl")
if not curl_ok then
return nil, err
end
end
if not self.config.key then
return nil, "Must have API key before performing any actions."
end
if params and next(params) then
url = url .. ("?" .. encode_query_string(params))
end
local method = "GET"
local out
local tmpfile = fs.tmpname()
if post_params then
method = "POST"
local curl_cmd = fs.Q(vars.CURL).." -f -k -L --silent --user-agent \""..cfg.user_agent.." via curl\" "
for k,v in pairs(post_params) do
local var = v
if type(v) == "table" then
var = "@"..v.fname
end
curl_cmd = curl_cmd .. "--form \""..k.."="..var.."\" "
end
if cfg.connection_timeout and cfg.connection_timeout > 0 then
curl_cmd = curl_cmd .. "--connect-timeout "..tonumber(cfg.connection_timeout).." "
end
local ok = fs.execute_string(curl_cmd..fs.Q(url).." -o "..fs.Q(tmpfile))
if not ok then
return nil, "API failure: " .. redact_api_url(url)
end
else
local ok, err = fs.download(url, tmpfile)
if not ok then
return nil, "API failure: " .. tostring(err) .. " - " .. redact_api_url(url)
end
end
local tmpfd = io.open(tmpfile)
if not tmpfd then
os.remove(tmpfile)
return nil, "API failure reading temporary file - " .. redact_api_url(url)
end
out = tmpfd:read("*a")
tmpfd:close()
os.remove(tmpfile)
if self.debug then
util.printout("[" .. tostring(method) .. " via curl] " .. redact_api_url(url) .. " ... ")
end
return json.decode(out)
end
else -- use LuaSocket and LuaSec
local warned_luasec = false
function Api:request(url, params, post_params)
local json_ok, json = require_json()
if not json_ok then return nil, "A JSON library is required for this command. "..json end
local server = tostring(self.config.server)
local http_ok, http
local via = "luasocket"
if server:match("^https://") then
http_ok, http = pcall(require, "ssl.https")
if http_ok then
via = "luasec"
else
if not warned_luasec then
util.printerr("LuaSec is not available; using plain HTTP. Install 'luasec' to enable HTTPS.")
warned_luasec = true
end
http_ok, http = pcall(require, "socket.http")
url = url:gsub("^https", "http")
via = "luasocket"
end
else
http_ok, http = pcall(require, "socket.http")
end
if not http_ok then
return nil, "Failed loading socket library!"
end
if not self.config.key then
return nil, "Must have API key before performing any actions."
end
local body
local headers = {}
if params and next(params) then
url = url .. ("?" .. encode_query_string(params))
end
if post_params then
local boundary
body, boundary = multipart.encode(post_params)
headers["Content-length"] = #body
headers["Content-type"] = "multipart/form-data; boundary=" .. tostring(boundary)
end
local method = post_params and "POST" or "GET"
if self.debug then
util.printout("[" .. tostring(method) .. " via "..via.."] " .. redact_api_url(url) .. " ... ")
end
local out = {}
local _, status = http.request({
url = url,
headers = headers,
method = method,
sink = ltn12.sink.table(out),
source = body and ltn12.source.string(body)
})
if self.debug then
util.printout(tostring(status))
end
if status ~= 200 then
return nil, "API returned " .. tostring(status) .. " - " .. redact_api_url(url)
end
return json.decode(table.concat(out))
end
end
function api.new(flags)
local self = {}
setmetatable(self, { __index = Api })
self.config = self:load_config() or {}
self.config.server = flags["server"] or self.config.server or cfg.upload.server
self.config.version = self.config.version or cfg.upload.version
self.config.key = flags["api-key"] or self.config.key
self.debug = flags["debug"]
if not self.config.key then
return nil, "You need an API key to upload rocks.\n" ..
"Navigate to "..self.config.server.."/settings to get a key\n" ..
"and then pass it through the --api-key=<key> flag."
end
if flags["api-key"] then
self:save_config()
end
return self
end
return api