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 /src | |
| parent | c3822ad23d588f69931ebc98d870ba2e2e29eece (diff) | |
| download | luarocks-9c9252f3873a89f9642aa6c7ff9d5e914c4042cd.tar.gz luarocks-9c9252f3873a89f9642aa6c7ff9d5e914c4042cd.tar.bz2 luarocks-9c9252f3873a89f9642aa6c7ff9d5e914c4042cd.zip | |
Teal: convert luarocks.core.util
Diffstat (limited to 'src')
| -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 | ||
