diff options
author | V1K1NGbg <victor@ilchev.com> | 2024-08-22 17:49:06 -0300 |
---|---|---|
committer | Hisham Muhammad <hisham@gobolinux.org> | 2024-10-21 13:30:51 -0300 |
commit | 9c9252f3873a89f9642aa6c7ff9d5e914c4042cd (patch) | |
tree | 25b8822a8a0d5ff18ba66946c4f94ec41bb422b9 | |
parent | c3822ad23d588f69931ebc98d870ba2e2e29eece (diff) | |
download | luarocks-9c9252f3873a89f9642aa6c7ff9d5e914c4042cd.tar.gz luarocks-9c9252f3873a89f9642aa6c7ff9d5e914c4042cd.tar.bz2 luarocks-9c9252f3873a89f9642aa6c7ff9d5e914c4042cd.zip |
Teal: convert luarocks.core.util
-rw-r--r-- | src/luarocks/core/util.tl (renamed from src/luarocks/core/util.lua) | 193 |
1 files changed, 103 insertions, 90 deletions
diff --git a/src/luarocks/core/util.lua b/src/luarocks/core/util.tl index e9abdd34..a9be2d43 100644 --- a/src/luarocks/core/util.lua +++ b/src/luarocks/core/util.tl | |||
@@ -1,9 +1,12 @@ | |||
1 | 1 | ||
2 | local util = {} | 2 | local record util |
3 | end | ||
3 | 4 | ||
4 | local require = nil | ||
5 | -------------------------------------------------------------------------------- | 5 | -------------------------------------------------------------------------------- |
6 | 6 | ||
7 | local type Ordering = require("luarocks.core.types.ordering").Ordering | ||
8 | local type SortBy = require("luarocks.core.types.ordering").SortBy | ||
9 | |||
7 | local dir_sep = package.config:sub(1, 1) | 10 | local dir_sep = package.config:sub(1, 1) |
8 | 11 | ||
9 | --- Run a process and read a its output. | 12 | --- Run a process and read a its output. |
@@ -13,8 +16,8 @@ local dir_sep = package.config:sub(1, 1) | |||
13 | -- @param spec string: "*l" by default, to read a single line. | 16 | -- @param spec string: "*l" by default, to read a single line. |
14 | -- May be used to read more, passing, for instance, "*a". | 17 | -- May be used to read more, passing, for instance, "*a". |
15 | -- @return string: the output of the program. | 18 | -- @return string: the output of the program. |
16 | function util.popen_read(cmd, spec) | 19 | function util.popen_read(cmd: string, spec?: string): string |
17 | local tmpfile = (dir_sep == "\\") | 20 | local tmpfile: string = (dir_sep == "\\") |
18 | and (os.getenv("TMP") .. "/luarocks-" .. tostring(math.floor(math.random() * 10000))) | 21 | and (os.getenv("TMP") .. "/luarocks-" .. tostring(math.floor(math.random() * 10000))) |
19 | or os.tmpname() | 22 | or os.tmpname() |
20 | os.execute(cmd .. " > " .. tmpfile) | 23 | os.execute(cmd .. " > " .. tmpfile) |
@@ -46,15 +49,15 @@ end | |||
46 | -- @param tname string: is the name of the table (optional) | 49 | -- @param tname string: is the name of the table (optional) |
47 | -- @param top_indent string: is a first indentation (optional). | 50 | -- @param top_indent string: is a first indentation (optional). |
48 | -- @return string: the pretty-printed table | 51 | -- @return string: the pretty-printed table |
49 | function util.show_table(t, tname, top_indent) | 52 | function util.show_table(t: {any:any}, tname: string, top_indent: string): string |
50 | local cart -- a container | 53 | local cart: string -- a container |
51 | local autoref -- for self references | 54 | local autoref: string -- for self references |
52 | 55 | ||
53 | local function is_empty_table(tbl) return next(tbl) == nil end | 56 | local function is_empty_table(tbl: {any:any}): boolean return next(tbl) == nil end |
54 | 57 | ||
55 | local function basic_serialize(o) | 58 | local function basic_serialize(o: any): string |
56 | local so = tostring(o) | 59 | local so = tostring(o) |
57 | if type(o) == "function" then | 60 | if o is function then |
58 | local info = debug and debug.getinfo(o, "S") | 61 | local info = debug and debug.getinfo(o, "S") |
59 | if not info then | 62 | if not info then |
60 | return ("%q"):format(so) | 63 | return ("%q"):format(so) |
@@ -66,21 +69,21 @@ function util.show_table(t, tname, top_indent) | |||
66 | -- the information is defined through lines | 69 | -- the information is defined through lines |
67 | return ("%q"):format(so .. ", defined in (" .. info.linedefined .. "-" .. info.lastlinedefined .. ")" .. info.source) | 70 | return ("%q"):format(so .. ", defined in (" .. info.linedefined .. "-" .. info.lastlinedefined .. ")" .. info.source) |
68 | end | 71 | end |
69 | elseif type(o) == "number" then | 72 | elseif o is number then |
70 | return so | 73 | return so |
71 | else | 74 | else |
72 | return ("%q"):format(so) | 75 | return ("%q"):format(so) |
73 | end | 76 | end |
74 | end | 77 | end |
75 | 78 | ||
76 | local function add_to_cart(value, name, indent, saved, field) | 79 | local function add_to_cart (value: any | {any:any}, name: string, indent: string, saved?: {any: string}, field?: string) |
77 | indent = indent or "" | 80 | indent = indent or "" |
78 | saved = saved or {} | 81 | saved = saved or {} |
79 | field = field or name | 82 | field = field or name |
80 | 83 | ||
81 | cart = cart .. indent .. field | 84 | cart = cart .. indent .. field |
82 | 85 | ||
83 | if type(value) ~= "table" then | 86 | if not value is {any: any} then |
84 | cart = cart .. " = " .. basic_serialize(value) .. ";\n" | 87 | cart = cart .. " = " .. basic_serialize(value) .. ";\n" |
85 | else | 88 | else |
86 | if saved[value] then | 89 | if saved[value] then |
@@ -106,7 +109,7 @@ function util.show_table(t, tname, top_indent) | |||
106 | end | 109 | end |
107 | 110 | ||
108 | tname = tname or "__unnamed__" | 111 | tname = tname or "__unnamed__" |
109 | if type(t) ~= "table" then | 112 | if not t is {any:any} then |
110 | return tname .. " = " .. basic_serialize(t) | 113 | return tname .. " = " .. basic_serialize(t) |
111 | end | 114 | end |
112 | cart, autoref = "", "" | 115 | cart, autoref = "", "" |
@@ -114,18 +117,29 @@ function util.show_table(t, tname, top_indent) | |||
114 | return cart .. autoref | 117 | return cart .. autoref |
115 | end | 118 | end |
116 | 119 | ||
120 | --- Produce a Lua pattern that matches precisely the given string | ||
121 | -- (this is suitable to be concatenating to other patterns, | ||
122 | -- so it does not include beginning- and end-of-string markers (^$) | ||
123 | -- @param s string: The input string | ||
124 | -- @return string: The equivalent pattern | ||
125 | function util.matchquote(s: string): string | ||
126 | return (s:gsub("[?%-+*%[%].%%()$^]","%%%1")) | ||
127 | end | ||
128 | |||
117 | --- Merges contents of src on top of dst's contents | 129 | --- Merges contents of src on top of dst's contents |
118 | -- (i.e. if an key from src already exists in dst, replace it). | 130 | -- (i.e. if an key from src already exists in dst, replace it). |
119 | -- @param dst Destination table, which will receive src's contents. | 131 | -- @param dst Destination table, which will receive src's contents. |
120 | -- @param src Table which provides new contents to dst. | 132 | -- @param src Table which provides new contents to dst. |
121 | function util.deep_merge(dst, src) | 133 | function util.deep_merge(dst: {any: any}, src: {any: any}) |
122 | for k, v in pairs(src) do | 134 | for k, v in pairs(src) do |
123 | if type(v) == "table" then | 135 | if v is {any: any} then |
124 | if dst[k] == nil then | 136 | local dstk: any | {any: any} = dst[k] |
137 | if dstk == nil then | ||
125 | dst[k] = {} | 138 | dst[k] = {} |
139 | dstk = dst[k] | ||
126 | end | 140 | end |
127 | if type(dst[k]) == "table" then | 141 | if dstk is {any: any} then |
128 | util.deep_merge(dst[k], v) | 142 | util.deep_merge(dstk, v) |
129 | else | 143 | else |
130 | dst[k] = v | 144 | dst[k] = v |
131 | end | 145 | end |
@@ -139,14 +153,16 @@ end | |||
139 | -- (i.e. if an key from src already exists in dst, do not replace it). | 153 | -- (i.e. if an key from src already exists in dst, do not replace it). |
140 | -- @param dst Destination table, which will receive src's contents. | 154 | -- @param dst Destination table, which will receive src's contents. |
141 | -- @param src Table which provides new contents to dst. | 155 | -- @param src Table which provides new contents to dst. |
142 | function util.deep_merge_under(dst, src) | 156 | function util.deep_merge_under(dst: {any: any}, src: {any: any}) |
143 | for k, v in pairs(src) do | 157 | for k, v in pairs(src) do |
144 | if type(v) == "table" then | 158 | if v is {any: any} then |
145 | if dst[k] == nil then | 159 | local dstk: any | {any: any} = dst[k] |
160 | if dstk == nil then | ||
146 | dst[k] = {} | 161 | dst[k] = {} |
162 | dstk = dst[k] | ||
147 | end | 163 | end |
148 | if type(dst[k]) == "table" then | 164 | if dstk is {any: any} then |
149 | util.deep_merge_under(dst[k], v) | 165 | util.deep_merge_under(dstk, v) |
150 | end | 166 | end |
151 | elseif dst[k] == nil then | 167 | elseif dst[k] == nil then |
152 | dst[k] = v | 168 | dst[k] = v |
@@ -154,6 +170,34 @@ function util.deep_merge_under(dst, src) | |||
154 | end | 170 | end |
155 | end | 171 | end |
156 | 172 | ||
173 | -- from http://lua-users.org/wiki/SplitJoin | ||
174 | -- by Philippe Lhoste | ||
175 | function util.split_string(str: string, delim: string, maxNb?: number): {string} | ||
176 | -- Eliminate bad cases... | ||
177 | if string.find(str, delim) == nil then | ||
178 | return { str } | ||
179 | end | ||
180 | if maxNb == nil or maxNb < 1 then | ||
181 | maxNb = 0 -- No limit | ||
182 | end | ||
183 | local result = {} | ||
184 | local pat = "(.-)" .. delim .. "()" | ||
185 | local nb = 0 | ||
186 | local lastPos: integer | ||
187 | for part, pos in string.gmatch(str, pat) do | ||
188 | nb = nb + 1 | ||
189 | result[nb] = part | ||
190 | lastPos = tonumber(pos) as integer | ||
191 | if nb == maxNb then break end | ||
192 | end | ||
193 | -- Handle the last field | ||
194 | if nb ~= maxNb then | ||
195 | result[nb + 1] = string.sub(str, lastPos) | ||
196 | end | ||
197 | return result | ||
198 | end | ||
199 | |||
200 | |||
157 | --- Clean up a path-style string ($PATH, $LUA_PATH/package.path, etc.), | 201 | --- Clean up a path-style string ($PATH, $LUA_PATH/package.path, etc.), |
158 | -- removing repeated entries and making sure only the relevant | 202 | -- removing repeated entries and making sure only the relevant |
159 | -- Lua version is used. | 203 | -- Lua version is used. |
@@ -163,15 +207,13 @@ end | |||
163 | -- @param lua_version (optional) string: The Lua version to use. | 207 | -- @param lua_version (optional) string: The Lua version to use. |
164 | -- @param keep_first (optional) if true, keep first occurrence in case | 208 | -- @param keep_first (optional) if true, keep first occurrence in case |
165 | -- of duplicates; otherwise keep last occurrence. The default is false. | 209 | -- of duplicates; otherwise keep last occurrence. The default is false. |
166 | function util.cleanup_path(list, sep, lua_version, keep_first) | 210 | function util.cleanup_path(list: string, sep: string, lua_version: string, keep_first: boolean): string |
167 | assert(type(list) == "string") | ||
168 | assert(type(sep) == "string") | ||
169 | 211 | ||
170 | list = list:gsub(dir_sep, "/") | 212 | list = list:gsub(dir_sep, "/") |
171 | 213 | ||
172 | local parts = util.split_string(list, sep) | 214 | local parts = util.split_string(list, sep) |
173 | local final, entries = {}, {} | 215 | local final, entries = {}, {} |
174 | local start, stop, step | 216 | local start, stop, step: integer, integer, integer |
175 | 217 | ||
176 | if keep_first then | 218 | if keep_first then |
177 | start, stop, step = 1, #parts, 1 | 219 | start, stop, step = 1, #parts, 1 |
@@ -182,7 +224,7 @@ function util.cleanup_path(list, sep, lua_version, keep_first) | |||
182 | for i = start, stop, step do | 224 | for i = start, stop, step do |
183 | local part = parts[i]:gsub("//", "/") | 225 | local part = parts[i]:gsub("//", "/") |
184 | if lua_version then | 226 | if lua_version then |
185 | part = part:gsub("/lua/([%d.]+)/", function(part_version) | 227 | part = part:gsub("/lua/([%d.]+)/", function(part_version: string): string |
186 | if part_version:sub(1, #lua_version) ~= lua_version then | 228 | if part_version:sub(1, #lua_version) ~= lua_version then |
187 | return "/lua/"..lua_version.."/" | 229 | return "/lua/"..lua_version.."/" |
188 | end | 230 | end |
@@ -198,37 +240,10 @@ function util.cleanup_path(list, sep, lua_version, keep_first) | |||
198 | return (table.concat(final, sep):gsub("/", dir_sep)) | 240 | return (table.concat(final, sep):gsub("/", dir_sep)) |
199 | end | 241 | end |
200 | 242 | ||
201 | -- from http://lua-users.org/wiki/SplitJoin | ||
202 | -- by Philippe Lhoste | ||
203 | function util.split_string(str, delim, maxNb) | ||
204 | -- Eliminate bad cases... | ||
205 | if string.find(str, delim) == nil then | ||
206 | return { str } | ||
207 | end | ||
208 | if maxNb == nil or maxNb < 1 then | ||
209 | maxNb = 0 -- No limit | ||
210 | end | ||
211 | local result = {} | ||
212 | local pat = "(.-)" .. delim .. "()" | ||
213 | local nb = 0 | ||
214 | local lastPos | ||
215 | for part, pos in string.gmatch(str, pat) do | ||
216 | nb = nb + 1 | ||
217 | result[nb] = part | ||
218 | lastPos = pos | ||
219 | if nb == maxNb then break end | ||
220 | end | ||
221 | -- Handle the last field | ||
222 | if nb ~= maxNb then | ||
223 | result[nb + 1] = string.sub(str, lastPos) | ||
224 | end | ||
225 | return result | ||
226 | end | ||
227 | |||
228 | --- Return an array of keys of a table. | 243 | --- Return an array of keys of a table. |
229 | -- @param tbl table: The input table. | 244 | -- @param tbl table: The input table. |
230 | -- @return table: The array of keys. | 245 | -- @return table: The array of keys. |
231 | function util.keys(tbl) | 246 | function util.keys<K, V>(tbl: {K: V}): {K} |
232 | local ks = {} | 247 | local ks = {} |
233 | for k,_ in pairs(tbl) do | 248 | for k,_ in pairs(tbl) do |
234 | table.insert(ks, k) | 249 | table.insert(ks, k) |
@@ -237,23 +252,23 @@ function util.keys(tbl) | |||
237 | end | 252 | end |
238 | 253 | ||
239 | --- Print a line to standard error | 254 | --- Print a line to standard error |
240 | function util.printerr(...) | 255 | function util.printerr(...: string | number) |
241 | io.stderr:write(table.concat({...},"\t")) | 256 | io.stderr:write(table.concat({...},"\t")) |
242 | io.stderr:write("\n") | 257 | io.stderr:write("\n") |
243 | end | 258 | end |
244 | 259 | ||
245 | --- Display a warning message. | 260 | --- Display a warning message. |
246 | -- @param msg string: the warning message | 261 | -- @param msg string: the warning message |
247 | function util.warning(msg) | 262 | function util.warning(msg: string) |
248 | util.printerr("Warning: "..msg) | 263 | util.printerr("Warning: "..msg) |
249 | end | 264 | end |
250 | 265 | ||
251 | --- Simple sort function used as a default for util.sortedpairs. | 266 | --- Simple sort function used as a default for util.sortedpairs. |
252 | local function default_sort(a, b) | 267 | local function default_sort(a: any, b: any): boolean |
253 | local ta = type(a) | 268 | local ta = type(a) |
254 | local tb = type(b) | 269 | local tb = type(b) |
255 | if ta == "number" and tb == "number" then | 270 | if ta == "number" and tb == "number" then |
256 | return a < b | 271 | return tonumber(a) < tonumber(b) |
257 | elseif ta == "number" then | 272 | elseif ta == "number" then |
258 | return true | 273 | return true |
259 | elseif tb == "number" then | 274 | elseif tb == "number" then |
@@ -273,48 +288,46 @@ end | |||
273 | -- for that key, which is returned by the iterator as the third value after the key | 288 | -- for that key, which is returned by the iterator as the third value after the key |
274 | -- and the value. | 289 | -- and the value. |
275 | -- @return function: the iterator function. | 290 | -- @return function: the iterator function. |
276 | function util.sortedpairs(tbl, sort_function) | 291 | function util.sortedpairs<K, V>(tbl: {K: V}, sort_by?: SortBy<K>): function(): K, V, Ordering<K> |
277 | sort_function = sort_function or default_sort | ||
278 | local keys = util.keys(tbl) | 292 | local keys = util.keys(tbl) |
279 | local sub_orders = {} | 293 | local sub_orders: {K: Ordering<K>} = nil |
280 | 294 | ||
281 | if type(sort_function) == "function" then | 295 | if sort_by == nil then |
282 | table.sort(keys, sort_function) | 296 | table.sort(keys, default_sort) |
297 | elseif sort_by is table.SortFunction<K> then | ||
298 | table.sort(keys, sort_by) | ||
283 | else | 299 | else |
284 | local order = sort_function | 300 | -- sort_by is Ordering<K> |
285 | local ordered_keys = {} | 301 | |
286 | local all_keys = keys | 302 | sub_orders = sort_by.sub_orders |
287 | keys = {} | 303 | |
288 | 304 | local seen_ordered_key: {K: boolean} = {} | |
289 | for _, order_entry in ipairs(order) do | 305 | |
290 | local key, sub_order | 306 | local my_ordered_keys: {K} = {} |
291 | if type(order_entry) == "table" then | 307 | |
292 | key = order_entry[1] | 308 | for _, key in ipairs(sort_by) do |
293 | sub_order = order_entry[2] | ||
294 | else | ||
295 | key = order_entry | ||
296 | end | ||
297 | |||
298 | if tbl[key] then | 309 | if tbl[key] then |
299 | ordered_keys[key] = true | 310 | seen_ordered_key[key] = true |
300 | sub_orders[key] = sub_order | 311 | table.insert(my_ordered_keys, key) |
301 | table.insert(keys, key) | ||
302 | end | 312 | end |
303 | end | 313 | end |
304 | 314 | ||
305 | table.sort(all_keys, default_sort) | 315 | table.sort(keys, default_sort) |
306 | for _, key in ipairs(all_keys) do | 316 | |
307 | if not ordered_keys[key] then | 317 | for _, key in ipairs(keys) do |
308 | table.insert(keys, key) | 318 | if not seen_ordered_key[key] then |
319 | table.insert(my_ordered_keys, key) | ||
309 | end | 320 | end |
310 | end | 321 | end |
322 | |||
323 | keys = my_ordered_keys | ||
311 | end | 324 | end |
312 | 325 | ||
313 | local i = 1 | 326 | local i = 1 |
314 | return function() | 327 | return function(): K, V, Ordering<K> |
315 | local key = keys[i] | 328 | local key = keys[i] |
316 | i = i + 1 | 329 | i = i + 1 |
317 | return key, tbl[key], sub_orders[key] | 330 | return key, tbl[key], sub_orders and sub_orders[key] |
318 | end | 331 | end |
319 | end | 332 | end |
320 | 333 | ||