Mercurial > repo
comparison share/lua/5.2/luarocks/util.lua @ 1132:d137f631bad5
<GreyKnight> (cd luabuild/luarocks-2.0.12; make install)
author | HackBot |
---|---|
date | Fri, 14 Dec 2012 22:24:27 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1131:ff65dfb63263 | 1132:d137f631bad5 |
---|---|
1 | |
2 --- Assorted utilities for managing tables, plus a scheduler for rollback functions. | |
3 -- Does not requires modules directly (only as locals | |
4 -- inside specific functions) to avoid interdependencies, | |
5 -- as this is used in the bootstrapping stage of luarocks.cfg. | |
6 | |
7 local global_env = _G | |
8 | |
9 module("luarocks.util", package.seeall) | |
10 | |
11 local scheduled_functions = {} | |
12 | |
13 --- Schedule a function to be executed upon program termination. | |
14 -- This is useful for actions such as deleting temporary directories | |
15 -- or failure rollbacks. | |
16 -- @param f function: Function to be executed. | |
17 -- @param ... arguments to be passed to function. | |
18 -- @return table: A token representing the scheduled execution, | |
19 -- which can be used to remove the item later from the list. | |
20 function schedule_function(f, ...) | |
21 assert(type(f) == "function") | |
22 | |
23 local item = { fn = f, args = {...} } | |
24 table.insert(scheduled_functions, item) | |
25 return item | |
26 end | |
27 | |
28 --- Unschedule a function. | |
29 -- This is useful for cancelling a rollback of a completed operation. | |
30 -- @param item table: The token representing the scheduled function that was | |
31 -- returned from the schedule_function call. | |
32 function remove_scheduled_function(item) | |
33 for k, v in pairs(scheduled_functions) do | |
34 if v == item then | |
35 table.remove(scheduled_functions, k) | |
36 return | |
37 end | |
38 end | |
39 end | |
40 | |
41 --- Execute scheduled functions. | |
42 -- Some calls create temporary files and/or directories and register | |
43 -- corresponding cleanup functions. Calling this function will run | |
44 -- these function, erasing temporaries. | |
45 -- Functions are executed in the inverse order they were scheduled. | |
46 function run_scheduled_functions() | |
47 local fs = require("luarocks.fs") | |
48 fs.change_dir_to_root() | |
49 for i = #scheduled_functions, 1, -1 do | |
50 local item = scheduled_functions[i] | |
51 item.fn(unpack(item.args)) | |
52 end | |
53 end | |
54 | |
55 --- Extract flags from an arguments list. | |
56 -- Given string arguments, extract flag arguments into a flags set. | |
57 -- For example, given "foo", "--tux=beep", "--bla", "bar", "--baz", | |
58 -- it would return the following: | |
59 -- {["bla"] = true, ["tux"] = "beep", ["baz"] = true}, "foo", "bar". | |
60 function parse_flags(...) | |
61 local args = {...} | |
62 local flags = {} | |
63 for i = #args, 1, -1 do | |
64 local flag = args[i]:match("^%-%-(.*)") | |
65 if flag then | |
66 local var,val = flag:match("([a-z_%-]*)=(.*)") | |
67 if val then | |
68 flags[var] = val | |
69 else | |
70 flags[flag] = true | |
71 end | |
72 table.remove(args, i) | |
73 end | |
74 end | |
75 return flags, unpack(args) | |
76 end | |
77 | |
78 --- Merges contents of src on top of dst's contents. | |
79 -- @param dst Destination table, which will receive src's contents. | |
80 -- @param src Table which provides new contents to dst. | |
81 -- @see platform_overrides | |
82 function deep_merge(dst, src) | |
83 for k, v in pairs(src) do | |
84 if type(v) == "table" then | |
85 if not dst[k] then | |
86 dst[k] = {} | |
87 end | |
88 if type(dst[k]) == "table" then | |
89 deep_merge(dst[k], v) | |
90 else | |
91 dst[k] = v | |
92 end | |
93 else | |
94 dst[k] = v | |
95 end | |
96 end | |
97 end | |
98 | |
99 --- Perform platform-specific overrides on a table. | |
100 -- Overrides values of table with the contents of the appropriate | |
101 -- subset of its "platforms" field. The "platforms" field should | |
102 -- be a table containing subtables keyed with strings representing | |
103 -- platform names. Names that match the contents of the global | |
104 -- cfg.platforms setting are used. For example, if | |
105 -- cfg.platforms= {"foo"}, then the fields of | |
106 -- tbl.platforms.foo will overwrite those of tbl with the same | |
107 -- names. For table values, the operation is performed recursively | |
108 -- (tbl.platforms.foo.x.y.z overrides tbl.x.y.z; other contents of | |
109 -- tbl.x are preserved). | |
110 -- @param tbl table or nil: Table which may contain a "platforms" field; | |
111 -- if it doesn't (or if nil is passed), this function does nothing. | |
112 function platform_overrides(tbl) | |
113 assert(type(tbl) == "table" or not tbl) | |
114 | |
115 local cfg = require("luarocks.cfg") | |
116 | |
117 if not tbl then return end | |
118 | |
119 if tbl.platforms then | |
120 for _, platform in ipairs(cfg.platforms) do | |
121 local platform_tbl = tbl.platforms[platform] | |
122 if platform_tbl then | |
123 deep_merge(tbl, platform_tbl) | |
124 end | |
125 end | |
126 end | |
127 tbl.platforms = nil | |
128 end | |
129 | |
130 local var_format_pattern = "%$%((%a[%a%d_]+)%)" | |
131 | |
132 --- Create a new shallow copy of a table: a new table with | |
133 -- the same keys and values. Keys point to the same objects as | |
134 -- the original table (ie, does not copy recursively). | |
135 -- @param tbl table: the input table | |
136 -- @return table: a new table with the same contents. | |
137 local function make_shallow_copy(tbl) | |
138 local copy = {} | |
139 for k,v in pairs(tbl) do | |
140 copy[k] = v | |
141 end | |
142 return copy | |
143 end | |
144 | |
145 -- Check if a set of needed variables are referenced | |
146 -- somewhere in a list of definitions, warning the user | |
147 -- about any unused ones. Each key in needed_set should | |
148 -- appear as a $(XYZ) variable at least once as a | |
149 -- substring of some value of var_defs. | |
150 -- @param var_defs: a table with string keys and string | |
151 -- values, containing variable definitions. | |
152 -- @param needed_set: a set where keys are the names of | |
153 -- needed variables. | |
154 -- @param msg string: the warning message to display. | |
155 function warn_if_not_used(var_defs, needed_set, msg) | |
156 needed_set = make_shallow_copy(needed_set) | |
157 for var,val in pairs(var_defs) do | |
158 for used in val:gmatch(var_format_pattern) do | |
159 needed_set[used] = nil | |
160 end | |
161 end | |
162 for var,_ in pairs(needed_set) do | |
163 warning(msg:format(var)) | |
164 end | |
165 end | |
166 | |
167 -- Output any entries that might remain in $(XYZ) format, | |
168 -- warning the user that substitutions have failed. | |
169 -- @param line string: the input string | |
170 local function warn_failed_matches(line) | |
171 local any_failed = false | |
172 if line:match(var_format_pattern) then | |
173 for unmatched in line:gmatch(var_format_pattern) do | |
174 warning("unmatched variable " .. unmatched) | |
175 any_failed = true | |
176 end | |
177 end | |
178 return any_failed | |
179 end | |
180 | |
181 --- Perform make-style variable substitutions on string values of a table. | |
182 -- For every string value tbl.x which contains a substring of the format | |
183 -- "$(XYZ)" will have this substring replaced by vars["XYZ"], if that field | |
184 -- exists in vars. Only string values are processed; this function | |
185 -- does not scan subtables recursively. | |
186 -- @param tbl table: Table to have its string values modified. | |
187 -- @param vars table: Table containing string-string key-value pairs | |
188 -- representing variables to replace in the strings values of tbl. | |
189 function variable_substitutions(tbl, vars) | |
190 assert(type(tbl) == "table") | |
191 assert(type(vars) == "table") | |
192 | |
193 local updated = {} | |
194 for k, v in pairs(tbl) do | |
195 if type(v) == "string" then | |
196 updated[k] = v:gsub(var_format_pattern, vars) | |
197 if warn_failed_matches(updated[k]) then | |
198 updated[k] = updated[k]:gsub(var_format_pattern, "") | |
199 end | |
200 end | |
201 end | |
202 for k, v in pairs(updated) do | |
203 tbl[k] = v | |
204 end | |
205 end | |
206 | |
207 --- Return an array of keys of a table. | |
208 -- @param tbl table: The input table. | |
209 -- @return table: The array of keys. | |
210 function keys(tbl) | |
211 local ks = {} | |
212 for k,_ in pairs(tbl) do | |
213 table.insert(ks, k) | |
214 end | |
215 return ks | |
216 end | |
217 | |
218 local function default_sort(a, b) | |
219 local ta = type(a) | |
220 local tb = type(b) | |
221 if ta == "number" and tb == "number" then | |
222 return a < b | |
223 elseif ta == "number" then | |
224 return true | |
225 elseif tb == "number" then | |
226 return false | |
227 else | |
228 return tostring(a) < tostring(b) | |
229 end | |
230 end | |
231 | |
232 -- The iterator function used internally by util.sortedpairs. | |
233 -- @param tbl table: The table to be iterated. | |
234 -- @param sort_function function or nil: An optional comparison function | |
235 -- to be used by table.sort when sorting keys. | |
236 -- @see sortedpairs | |
237 local function sortedpairs_iterator(tbl, sort_function) | |
238 local ks = keys(tbl) | |
239 if not sort_function or type(sort_function) == "function" then | |
240 table.sort(ks, sort_function or default_sort) | |
241 for _, k in ipairs(ks) do | |
242 coroutine.yield(k, tbl[k]) | |
243 end | |
244 else | |
245 local order = sort_function | |
246 local done = {} | |
247 for _, k in ipairs(order) do | |
248 local sub_order | |
249 if type(k) == "table" then | |
250 sub_order = k[2] | |
251 k = k[1] | |
252 end | |
253 if tbl[k] then | |
254 done[k] = true | |
255 coroutine.yield(k, tbl[k], sub_order) | |
256 end | |
257 end | |
258 table.sort(ks, default_sort) | |
259 for _, k in ipairs(ks) do | |
260 if not done[k] then | |
261 coroutine.yield(k, tbl[k]) | |
262 end | |
263 end | |
264 end | |
265 end | |
266 | |
267 --- A table iterator generator that returns elements sorted by key, | |
268 -- to be used in "for" loops. | |
269 -- @param tbl table: The table to be iterated. | |
270 -- @param sort_function function or table or nil: An optional comparison function | |
271 -- to be used by table.sort when sorting keys, or an array listing an explicit order | |
272 -- for keys. If a value itself is an array, it is taken so that the first element | |
273 -- is a string representing the field name, and the second element is a priority table | |
274 -- for that key. | |
275 -- @return function: the iterator function. | |
276 function sortedpairs(tbl, sort_function) | |
277 return coroutine.wrap(function() sortedpairs_iterator(tbl, sort_function) end) | |
278 end | |
279 | |
280 function starts_with(s, prefix) | |
281 return s:sub(1,#prefix) == prefix | |
282 end | |
283 | |
284 --- Print a line to standard output | |
285 function printout(...) | |
286 io.stdout:write(table.concat({...},"\t")) | |
287 io.stdout:write("\n") | |
288 end | |
289 | |
290 --- Print a line to standard error | |
291 function printerr(...) | |
292 io.stderr:write(table.concat({...},"\t")) | |
293 io.stderr:write("\n") | |
294 end | |
295 | |
296 --- Display a warning message. | |
297 -- @param msg string: the warning message | |
298 function warning(msg) | |
299 printerr("Warning: "..msg) | |
300 end | |
301 | |
302 function title(msg, porcelain, underline) | |
303 if porcelain then return end | |
304 printout() | |
305 printout(msg) | |
306 printout((underline or "-"):rep(#msg)) | |
307 printout() | |
308 end | |
309 | |
310 -- from http://lua-users.org/wiki/SplitJoin | |
311 -- by PhilippeLhoste | |
312 function split_string(str, delim, maxNb) | |
313 -- Eliminate bad cases... | |
314 if string.find(str, delim) == nil then | |
315 return { str } | |
316 end | |
317 if maxNb == nil or maxNb < 1 then | |
318 maxNb = 0 -- No limit | |
319 end | |
320 local result = {} | |
321 local pat = "(.-)" .. delim .. "()" | |
322 local nb = 0 | |
323 local lastPos | |
324 for part, pos in string.gmatch(str, pat) do | |
325 nb = nb + 1 | |
326 result[nb] = part | |
327 lastPos = pos | |
328 if nb == maxNb then break end | |
329 end | |
330 -- Handle the last field | |
331 if nb ~= maxNb then | |
332 result[nb + 1] = string.sub(str, lastPos) | |
333 end | |
334 return result | |
335 end | |
336 | |
337 --- Remove repeated entries from a path-style string. | |
338 -- Example: given ("a;b;c;a;b;d", ";"), returns "a;b;c;d". | |
339 -- @param list string: A path string (from $PATH or package.path) | |
340 -- @param sep string: The separator | |
341 function remove_path_dupes(list, sep) | |
342 assert(type(list) == "string") | |
343 assert(type(sep) == "string") | |
344 local parts = split_string(list, sep) | |
345 local final, entries = {}, {} | |
346 for _, part in ipairs(parts) do | |
347 if not entries[part] then | |
348 table.insert(final, part) | |
349 entries[part] = true | |
350 end | |
351 end | |
352 return table.concat(final, sep) | |
353 end | |
354 | |
355 --- | |
356 -- Formats tables with cycles recursively to any depth. | |
357 -- References to other tables are shown as values. | |
358 -- Self references are indicated. | |
359 -- The string returned is "Lua code", which can be procesed | |
360 -- (in the case in which indent is composed by spaces or "--"). | |
361 -- Userdata and function keys and values are shown as strings, | |
362 -- which logically are exactly not equivalent to the original code. | |
363 -- This routine can serve for pretty formating tables with | |
364 -- proper indentations, apart from printing them: | |
365 -- io.write(table.show(t, "t")) -- a typical use | |
366 -- Written by Julio Manuel Fernandez-Diaz, | |
367 -- Heavily based on "Saving tables with cycles", PIL2, p. 113. | |
368 -- @param t table: is the table. | |
369 -- @param name string: is the name of the table (optional) | |
370 -- @param indent string: is a first indentation (optional). | |
371 -- @return string: the pretty-printed table | |
372 function show_table(t, name, indent) | |
373 local cart -- a container | |
374 local autoref -- for self references | |
375 | |
376 local function isemptytable(t) return next(t) == nil end | |
377 | |
378 local function basicSerialize (o) | |
379 local so = tostring(o) | |
380 if type(o) == "function" then | |
381 local info = debug.getinfo(o, "S") | |
382 -- info.name is nil because o is not a calling level | |
383 if info.what == "C" then | |
384 return ("%q"):format(so .. ", C function") | |
385 else | |
386 -- the information is defined through lines | |
387 return ("%q"):format(so .. ", defined in (" .. info.linedefined .. "-" .. info.lastlinedefined .. ")" .. info.source) | |
388 end | |
389 elseif type(o) == "number" then | |
390 return so | |
391 else | |
392 return ("%q"):format(so) | |
393 end | |
394 end | |
395 | |
396 local function addtocart (value, name, indent, saved, field) | |
397 indent = indent or "" | |
398 saved = saved or {} | |
399 field = field or name | |
400 | |
401 cart = cart .. indent .. field | |
402 | |
403 if type(value) ~= "table" then | |
404 cart = cart .. " = " .. basicSerialize(value) .. ";\n" | |
405 else | |
406 if saved[value] then | |
407 cart = cart .. " = {}; -- " .. saved[value] .. " (self reference)\n" | |
408 autoref = autoref .. name .. " = " .. saved[value] .. ";\n" | |
409 else | |
410 saved[value] = name | |
411 --if tablecount(value) == 0 then | |
412 if isemptytable(value) then | |
413 cart = cart .. " = {};\n" | |
414 else | |
415 cart = cart .. " = {\n" | |
416 for k, v in pairs(value) do | |
417 k = basicSerialize(k) | |
418 local fname = ("%s[%s]"):format(name, k) | |
419 field = ("[%s]"):format(k) | |
420 -- three spaces between levels | |
421 addtocart(v, fname, indent .. " ", saved, field) | |
422 end | |
423 cart = cart .. indent .. "};\n" | |
424 end | |
425 end | |
426 end | |
427 end | |
428 | |
429 name = name or "__unnamed__" | |
430 if type(t) ~= "table" then | |
431 return name .. " = " .. basicSerialize(t) | |
432 end | |
433 cart, autoref = "", "" | |
434 addtocart(t, name, indent) | |
435 return cart .. autoref | |
436 end |