diff options
author | V1K1NGbg <victor@ilchev.com> | 2024-08-01 10:00:47 +0300 |
---|---|---|
committer | V1K1NGbg <victor@ilchev.com> | 2024-08-05 20:51:31 +0300 |
commit | 17f3ebdcb213e64ea9081991b29f0dfc94b1f910 (patch) | |
tree | 798c5e5f15ac24a3345c70e7a7b4ba469b37fbfc | |
parent | c7d3e493ef15f0171617b489bb0304ba3545c2aa (diff) | |
download | luarocks-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.tl | 271 | ||||
-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 @@ | |||
1 | local record api | ||
2 | |||
3 | end | ||
4 | |||
5 | local cfg = require("luarocks.core.cfg") | ||
6 | local fs = require("luarocks.fs") | ||
7 | local dir = require("luarocks.dir") | ||
8 | local util = require("luarocks.util") | ||
9 | local persist = require("luarocks.persist") | ||
10 | local multipart = require("luarocks.upload.multipart") | ||
11 | local json = require("luarocks.vendor.dkjson") | ||
12 | local dir_sep = package.config:sub(1, 1) | ||
13 | |||
14 | local record Api | ||
15 | raw_method: function(Api, string) | ||
16 | record config | ||
17 | server: any --! why to string | ||
18 | end | ||
19 | end | ||
20 | |||
21 | local 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")) | ||
26 | end | ||
27 | |||
28 | function 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 | ||
33 | end | ||
34 | |||
35 | function 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") | ||
53 | end | ||
54 | |||
55 | function 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 | ||
76 | end | ||
77 | |||
78 | function 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 | ||
91 | end | ||
92 | |||
93 | function 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, ...) | ||
97 | end | ||
98 | |||
99 | local 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) | ||
117 | end | ||
118 | |||
119 | local function redact_api_url(url) | ||
120 | url = tostring(url) | ||
121 | return (url:gsub(".*/api/[^/]+/[^/]+", "")) or "" | ||
122 | end | ||
123 | |||
124 | local ltn12_ok, ltn12 = pcall(require, "ltn12") | ||
125 | if not ltn12_ok then -- If not using LuaSocket and/or LuaSec... | ||
126 | |||
127 | function 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) | ||
184 | end | ||
185 | |||
186 | else -- use LuaSocket and LuaSec | ||
187 | |||
188 | local warned_luasec = false | ||
189 | |||
190 | function 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) | ||
248 | end | ||
249 | |||
250 | end | ||
251 | |||
252 | function 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 | ||
269 | end | ||
270 | |||
271 | return 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 | |||