aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
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
2local util = {} 2local record util
3end
3 4
4local require = nil
5-------------------------------------------------------------------------------- 5--------------------------------------------------------------------------------
6 6
7local type Ordering = require("luarocks.core.types.ordering").Ordering
8local type SortBy = require("luarocks.core.types.ordering").SortBy
9
7local dir_sep = package.config:sub(1, 1) 10local 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.
16function util.popen_read(cmd, spec) 19function 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
49function util.show_table(t, tname, top_indent) 52function 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
115end 118end
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
125function util.matchquote(s: string): string
126 return (s:gsub("[?%-+*%[%].%%()$^]","%%%1"))
127end
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.
121function util.deep_merge(dst, src) 133function 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.
142function util.deep_merge_under(dst, src) 156function 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
155end 171end
156 172
173-- from http://lua-users.org/wiki/SplitJoin
174-- by Philippe Lhoste
175function 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
198end
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.
166function util.cleanup_path(list, sep, lua_version, keep_first) 210function 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))
199end 241end
200 242
201-- from http://lua-users.org/wiki/SplitJoin
202-- by Philippe Lhoste
203function 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
226end
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.
231function util.keys(tbl) 246function 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)
237end 252end
238 253
239--- Print a line to standard error 254--- Print a line to standard error
240function util.printerr(...) 255function 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")
243end 258end
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
247function util.warning(msg) 262function util.warning(msg: string)
248 util.printerr("Warning: "..msg) 263 util.printerr("Warning: "..msg)
249end 264end
250 265
251--- Simple sort function used as a default for util.sortedpairs. 266--- Simple sort function used as a default for util.sortedpairs.
252local function default_sort(a, b) 267local 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.
276function util.sortedpairs(tbl, sort_function) 291function 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
319end 332end
320 333