aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorV1K1NGbg <victor@ilchev.com>2024-08-01 10:00:47 +0300
committerV1K1NGbg <victor@ilchev.com>2024-08-05 20:51:31 +0300
commit17f3ebdcb213e64ea9081991b29f0dfc94b1f910 (patch)
tree798c5e5f15ac24a3345c70e7a7b4ba469b37fbfc
parentc7d3e493ef15f0171617b489bb0304ba3545c2aa (diff)
downloadluarocks-17f3ebdcb213e64ea9081991b29f0dfc94b1f910.tar.gz
luarocks-17f3ebdcb213e64ea9081991b29f0dfc94b1f910.tar.bz2
luarocks-17f3ebdcb213e64ea9081991b29f0dfc94b1f910.zip
api + multipart rename to have a constant passing action
-rw-r--r--src/luarocks/upload/api.tl271
-rw-r--r--src/luarocks/upload/multipart.lua (renamed from src/luarocks/upload/multipart-original.lua)0
2 files changed, 271 insertions, 0 deletions
diff --git a/src/luarocks/upload/api.tl b/src/luarocks/upload/api.tl
new file mode 100644
index 00000000..7c643c43
--- /dev/null
+++ b/src/luarocks/upload/api.tl
@@ -0,0 +1,271 @@
1local record api
2
3end
4
5local cfg = require("luarocks.core.cfg")
6local fs = require("luarocks.fs")
7local dir = require("luarocks.dir")
8local util = require("luarocks.util")
9local persist = require("luarocks.persist")
10local multipart = require("luarocks.upload.multipart")
11local json = require("luarocks.vendor.dkjson")
12local dir_sep = package.config:sub(1, 1)
13
14local record Api
15 raw_method: function(Api, string)
16 record config
17 server: any --! why to string
18 end
19end
20
21local function upload_config_file(): string
22 if not cfg.config_files.user.file then
23 return nil
24 end
25 return (cfg.config_files.user.file:gsub("[\\/][^\\/]+$", dir_sep .. "upload_config.lua"))
26end
27
28function Api:load_config(): {any: any} --? tighter bound?
29 local upload_conf = upload_config_file()
30 if not upload_conf then return nil end
31 local config = persist.load_into_table(upload_conf)
32 return config
33end
34
35function Api:save_config()
36 -- Test configuration before saving it.
37 local res, err = self:raw_method("status")
38 if not res then
39 return nil, err
40 end
41 if res.errors then
42 util.printerr("Server says: " .. tostring(res.errors[1]))
43 return
44 end
45 local upload_conf = upload_config_file()
46 if not upload_conf then return nil end
47 local ok, err = fs.make_dir(dir.dir_name(upload_conf))
48 if not ok then
49 return nil, err
50 end
51 persist.save_from_table(upload_conf, self.config)
52 fs.set_permissions(upload_conf, "read", "user")
53end
54
55function Api:check_version()
56 if not self._server_tool_version then
57 local tool_version = cfg.upload.tool_version
58 local res, err = self:request(tostring(self.config.server) .. "/api/tool_version", {
59 current = tool_version
60 })
61 if not res then
62 return nil, err
63 end
64 if not res.version then
65 return nil, "failed to fetch tool version"
66 end
67 self._server_tool_version = res.version
68 if res.force_update then
69 return nil, "Your upload client is too out of date to continue, please upgrade LuaRocks."
70 end
71 if res.version ~= tool_version then
72 util.warning("your LuaRocks is out of date, consider upgrading.")
73 end
74 end
75 return true
76end
77
78function Api:method(...)
79 local res, err = self:raw_method(...)
80 if not res then
81 return nil, err
82 end
83 if res.errors then
84 if res.errors[1] == "Invalid key" then
85 return nil, res.errors[1] .. " (use the --api-key flag to change)"
86 end
87 local msg = table.concat(res.errors, ", ")
88 return nil, "API Failed: " .. msg
89 end
90 return res
91end
92
93function Api.raw_method(self: Api, path, ...) --! path, ... type
94 self:check_version()
95 local url = tostring(self.config.server) .. "/api/" .. tostring(cfg.upload.api_version) .. "/" .. tostring(self.config.key) .. "/" .. tostring(path)
96 return self:request(url, ...)
97end
98
99local function encode_query_string(t, sep)
100 if sep == nil then
101 sep = "&"
102 end
103 local i = 0
104 local buf = { }
105 for k, v in pairs(t) do
106 if type(k) == "number" and type(v) == "table" then
107 k, v = v[1], v[2]
108 end
109 buf[i + 1] = multipart.url_escape(k)
110 buf[i + 2] = "="
111 buf[i + 3] = multipart.url_escape(v)
112 buf[i + 4] = sep
113 i = i + 4
114 end
115 buf[i] = nil
116 return table.concat(buf)
117end
118
119local function redact_api_url(url)
120 url = tostring(url)
121 return (url:gsub(".*/api/[^/]+/[^/]+", "")) or ""
122end
123
124local ltn12_ok, ltn12 = pcall(require, "ltn12")
125if not ltn12_ok then -- If not using LuaSocket and/or LuaSec...
126
127function Api.request(self: Api, url: string, params?, post_params?): {string : any}, string
128 local vars = cfg.variables
129
130 if fs.which_tool("downloader") == "wget" then
131 local curl_ok, err = fs.is_tool_available(vars.CURL, "curl")
132 if not curl_ok then
133 return nil, err
134 end
135 end
136
137 if not self.config.key then
138 return nil, "Must have API key before performing any actions."
139 end
140 if params and next(params) then
141 url = url .. ("?" .. encode_query_string(params))
142 end
143 local method = "GET"
144 local out
145 local tmpfile = fs.tmpname()
146 if post_params then
147 method = "POST"
148 local curl_cmd = vars.CURL.." "..vars.CURLNOCERTFLAG.." -f -L --silent --user-agent \""..cfg.user_agent.." via curl\" "
149 for k,v in pairs(post_params) do
150 local var = v
151 if type(v) == "table" then
152 var = "@"..v.fname
153 end
154 curl_cmd = curl_cmd .. "--form \""..k.."="..var.."\" "
155 end
156 if cfg.connection_timeout and cfg.connection_timeout > 0 then
157 curl_cmd = curl_cmd .. "--connect-timeout "..tonumber(cfg.connection_timeout).." "
158 end
159 local ok = fs.execute_string(curl_cmd..fs.Q(url).." -o "..fs.Q(tmpfile))
160 if not ok then
161 return nil, "API failure: " .. redact_api_url(url)
162 end
163 else
164 local ok, err = fs.download(url, tmpfile)
165 if not ok then
166 return nil, "API failure: " .. tostring(err) .. " - " .. redact_api_url(url)
167 end
168 end
169
170 local tmpfd = io.open(tmpfile)
171 if not tmpfd then
172 os.remove(tmpfile)
173 return nil, "API failure reading temporary file - " .. redact_api_url(url)
174 end
175 out = tmpfd:read("*a")
176 tmpfd:close()
177 os.remove(tmpfile)
178
179 if self.debug then
180 util.printout("[" .. tostring(method) .. " via curl] " .. redact_api_url(url) .. " ... ")
181 end
182
183 return json.decode(out)
184end
185
186else -- use LuaSocket and LuaSec
187
188local warned_luasec = false
189
190function Api:request(url, params, post_params)
191 local server = tostring(self.config.server)
192 local http_ok, http
193 local via = "luasocket"
194 if server:match("^https://") then
195 http_ok, http = pcall(require, "ssl.https")
196 if http_ok then
197 via = "luasec"
198 else
199 if not warned_luasec then
200 util.printerr("LuaSec is not available; using plain HTTP. Install 'luasec' to enable HTTPS.")
201 warned_luasec = true
202 end
203 http_ok, http = pcall(require, "socket.http")
204 url = url:gsub("^https", "http")
205 via = "luasocket"
206 end
207 else
208 http_ok, http = pcall(require, "socket.http")
209 end
210 if not http_ok then
211 return nil, "Failed loading socket library!"
212 end
213
214 if not self.config.key then
215 return nil, "Must have API key before performing any actions."
216 end
217 local body
218 local headers = {}
219 if params and next(params) then
220 url = url .. ("?" .. encode_query_string(params))
221 end
222 if post_params then
223 local boundary
224 body, boundary = multipart.encode(post_params)
225 headers["Content-length"] = #body
226 headers["Content-type"] = "multipart/form-data; boundary=" .. tostring(boundary)
227 end
228 local method = post_params and "POST" or "GET"
229 if self.debug then
230 util.printout("[" .. tostring(method) .. " via "..via.."] " .. redact_api_url(url) .. " ... ")
231 end
232 local out = {}
233 local _, status = http.request({
234 url = url,
235 headers = headers,
236 method = method,
237 sink = ltn12.sink.table(out),
238 source = body and ltn12.source.string(body)
239 })
240 if self.debug then
241 util.printout(tostring(status))
242 end
243 local pok, ret, err = pcall(json.decode, table.concat(out))
244 if pok and ret then
245 return ret
246 end
247 return nil, "API returned " .. tostring(status) .. " - " .. redact_api_url(url)
248end
249
250end
251
252function api.new(args)
253 local self = {}
254 setmetatable(self, { __index = Api })
255 self.config = self:load_config() or {}
256 self.config.server = args.server or self.config.server or cfg.upload.server
257 self.config.version = self.config.version or cfg.upload.version
258 self.config.key = args.temp_key or args.api_key or self.config.key
259 self.debug = args.debug
260 if not self.config.key then
261 return nil, "You need an API key to upload rocks.\n" ..
262 "Navigate to "..self.config.server.."/settings to get a key\n" ..
263 "and then pass it through the --api-key=<key> flag."
264 end
265 if args.api_key then
266 self:save_config()
267 end
268 return self
269end
270
271return api
diff --git a/src/luarocks/upload/multipart-original.lua b/src/luarocks/upload/multipart.lua
index 790e368f..790e368f 100644
--- a/src/luarocks/upload/multipart-original.lua
+++ b/src/luarocks/upload/multipart.lua