aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorV1K1NGbg <victor@ilchev.com>2024-06-12 02:45:29 +0200
committerV1K1NGbg <victor@ilchev.com>2024-08-05 20:49:17 +0300
commit3bab28f0f51aa39f3d704afac920257a6c9cb095 (patch)
tree26e70b4a9e6cce106f623b3739465439a9f0dcd0
parentd53493179d3e16b3f2cc22470483c2926c457751 (diff)
downloadluarocks-3bab28f0f51aa39f3d704afac920257a6c9cb095.tar.gz
luarocks-3bab28f0f51aa39f3d704afac920257a6c9cb095.tar.bz2
luarocks-3bab28f0f51aa39f3d704afac920257a6c9cb095.zip
some more errors fixed
-rw-r--r--src/luarocks/core/cfg-original.lua940
-rw-r--r--src/luarocks/core/cfg.d.tl7
-rw-r--r--src/luarocks/core/cfg.lua372
-rw-r--r--src/luarocks/core/cfg.tl982
-rw-r--r--src/luarocks/core/persist.lua22
-rw-r--r--src/luarocks/core/persist.tl33
-rw-r--r--src/luarocks/core/sysdetect.tl22
-rw-r--r--src/luarocks/core/util.lua65
-rw-r--r--src/luarocks/core/util.tl120
9 files changed, 281 insertions, 2282 deletions
diff --git a/src/luarocks/core/cfg-original.lua b/src/luarocks/core/cfg-original.lua
deleted file mode 100644
index 6d8fe55b..00000000
--- a/src/luarocks/core/cfg-original.lua
+++ /dev/null
@@ -1,940 +0,0 @@
1
2--- Configuration for LuaRocks.
3-- Tries to load the user's configuration file and
4-- defines defaults for unset values. See the
5-- <a href="http://luarocks.org/en/Config_file_format">config
6-- file format documentation</a> for details.
7--
8-- End-users shouldn't edit this file. They can override any defaults
9-- set in this file using their system-wide or user-specific configuration
10-- files. Run `luarocks` with no arguments to see the locations of
11-- these files in your platform.
12
13local table, pairs, require, os, pcall, ipairs, package, type, assert =
14 table, pairs, require, os, pcall, ipairs, package, type, assert
15
16local dir = require("luarocks.core.dir")
17local util = require("luarocks.core.util")
18local persist = require("luarocks.core.persist")
19local sysdetect = require("luarocks.core.sysdetect")
20local vers = require("luarocks.core.vers")
21
22--------------------------------------------------------------------------------
23
24local program_version = "dev"
25
26local is_windows = package.config:sub(1,1) == "\\"
27
28-- Set order for platform overrides.
29-- More general platform identifiers should be listed first,
30-- more specific ones later.
31local platform_order = {
32 -- Unixes
33 "unix",
34 "bsd",
35 "solaris",
36 "netbsd",
37 "openbsd",
38 "freebsd",
39 "dragonfly",
40 "linux",
41 "macosx",
42 "cygwin",
43 "msys",
44 "haiku",
45 -- Windows
46 "windows",
47 "win32",
48 "mingw",
49 "mingw32",
50 "msys2_mingw_w64",
51}
52
53local function detect_sysconfdir()
54 if not debug then
55 return
56 end
57 local src = debug.getinfo(1, "S").source
58 if not src then
59 return
60 end
61 src = dir.normalize(src)
62 if src:sub(1, 1) == "@" then
63 src = src:sub(2)
64 end
65 local basedir = src:match("^(.*)[\\/]luarocks[\\/]core[\\/]cfg.lua$")
66 if not basedir then
67 return
68 end
69 -- If installed in a Unix-like tree, use a Unix-like sysconfdir
70 local installdir = basedir:match("^(.*)[\\/]share[\\/]lua[\\/][^/]*$")
71 if installdir then
72 if installdir == "/usr" then
73 return "/etc/luarocks"
74 end
75 return dir.path(installdir, "etc", "luarocks")
76 end
77 -- Otherwise, use base directory of sources
78 return basedir
79end
80
81local load_config_file
82do
83 -- Create global environment for the config files;
84 local function env_for_config_file(cfg, platforms)
85 local platforms_copy = {}
86 for k,v in pairs(platforms) do
87 platforms_copy[k] = v
88 end
89
90 local e
91 e = {
92 home = cfg.home,
93 lua_version = cfg.lua_version,
94 platforms = platforms_copy,
95 processor = cfg.target_cpu, -- remains for compat reasons
96 target_cpu = cfg.target_cpu, -- replaces `processor`
97 os_getenv = os.getenv,
98 variables = cfg.variables or {},
99 dump_env = function()
100 -- debug function, calling it from a config file will show all
101 -- available globals to that config file
102 print(util.show_table(e, "global environment"))
103 end,
104 }
105 return e
106 end
107
108 -- Merge values from config files read into the `cfg` table
109 local function merge_overrides(cfg, overrides)
110 -- remove some stuff we do not want to integrate
111 overrides.os_getenv = nil
112 overrides.dump_env = nil
113 -- remove tables to be copied verbatim instead of deeply merged
114 if overrides.rocks_trees then cfg.rocks_trees = nil end
115 if overrides.rocks_servers then cfg.rocks_servers = nil end
116 -- perform actual merge
117 util.deep_merge(cfg, overrides)
118 end
119
120 local function update_platforms(platforms, overrides)
121 if overrides[1] then
122 for k, _ in pairs(platforms) do
123 platforms[k] = nil
124 end
125 for _, v in ipairs(overrides) do
126 platforms[v] = true
127 end
128 -- set some fallback default in case the user provides an incomplete configuration.
129 -- LuaRocks expects a set of defaults to be available.
130 if not (platforms.unix or platforms.windows) then
131 platforms[is_windows and "windows" or "unix"] = true
132 end
133 end
134 end
135
136 -- Load config file and merge its contents into the `cfg` module table.
137 -- @return filepath of successfully loaded file or nil if it failed
138 load_config_file = function(cfg, platforms, filepath)
139 local result, err, errcode = persist.load_into_table(filepath, env_for_config_file(cfg, platforms))
140 if (not result) and errcode ~= "open" then
141 -- errcode is either "load" or "run"; bad config file, so error out
142 return nil, err, "config"
143 end
144 if result then
145 -- success in loading and running, merge contents and exit
146 update_platforms(platforms, result.platforms)
147 result.platforms = nil
148 merge_overrides(cfg, result)
149 return filepath
150 end
151 return nil -- nothing was loaded
152 end
153end
154
155local platform_sets = {
156 freebsd = { unix = true, bsd = true, freebsd = true },
157 openbsd = { unix = true, bsd = true, openbsd = true },
158 dragonfly = { unix = true, bsd = true, dragonfly = true },
159 solaris = { unix = true, solaris = true },
160 windows = { windows = true, win32 = true },
161 cygwin = { unix = true, cygwin = true },
162 macosx = { unix = true, bsd = true, macosx = true, macos = true },
163 netbsd = { unix = true, bsd = true, netbsd = true },
164 haiku = { unix = true, haiku = true },
165 linux = { unix = true, linux = true },
166 mingw = { windows = true, win32 = true, mingw32 = true, mingw = true },
167 msys = { unix = true, cygwin = true, msys = true },
168 msys2_mingw_w64 = { windows = true, win32 = true, mingw32 = true, mingw = true, msys = true, msys2_mingw_w64 = true },
169}
170
171local function make_platforms(system)
172 -- fallback to Unix in unknown systems
173 return platform_sets[system] or { unix = true }
174end
175
176--------------------------------------------------------------------------------
177
178local function make_defaults(lua_version, target_cpu, platforms, home)
179
180 -- Configure defaults:
181 local defaults = {
182
183 local_by_default = false,
184 accept_unknown_fields = false,
185 fs_use_modules = true,
186 hooks_enabled = true,
187 deps_mode = "one",
188 no_manifest = false,
189 check_certificates = false,
190
191 cache_timeout = 60,
192 cache_fail_timeout = 86400,
193
194 lua_modules_path = dir.path("share", "lua", lua_version),
195 lib_modules_path = dir.path("lib", "lua", lua_version),
196 rocks_subdir = dir.path("lib", "luarocks", "rocks-"..lua_version),
197
198 arch = "unknown",
199 lib_extension = "unknown",
200 obj_extension = "unknown",
201 link_lua_explicitly = false,
202
203 rocks_servers = {
204 {
205 "https://luarocks.org",
206 "https://raw.githubusercontent.com/rocks-moonscript-org/moonrocks-mirror/master/",
207 "https://loadk.com/luarocks/",
208 }
209 },
210 disabled_servers = {},
211
212 upload = {
213 server = "https://luarocks.org",
214 tool_version = "1.0.0",
215 api_version = "1",
216 },
217
218 lua_extension = "lua",
219 connection_timeout = 30, -- 0 = no timeout
220
221 variables = {
222 MAKE = os.getenv("MAKE") or "make",
223 CC = os.getenv("CC") or "cc",
224 LD = os.getenv("CC") or "ld",
225 AR = os.getenv("AR") or "ar",
226 RANLIB = os.getenv("RANLIB") or "ranlib",
227
228 CVS = "cvs",
229 GIT = "git",
230 SSCM = "sscm",
231 SVN = "svn",
232 HG = "hg",
233
234 GPG = "gpg",
235
236 RSYNC = "rsync",
237 WGET = "wget",
238 SCP = "scp",
239 CURL = "curl",
240
241 PWD = "pwd",
242 MKDIR = "mkdir",
243 RMDIR = "rmdir",
244 CP = "cp",
245 LN = "ln",
246 LS = "ls",
247 RM = "rm",
248 FIND = "find",
249 CHMOD = "chmod",
250 ICACLS = "icacls",
251 MKTEMP = "mktemp",
252
253 ZIP = "zip",
254 UNZIP = "unzip -n",
255 GUNZIP = "gunzip",
256 BUNZIP2 = "bunzip2",
257 TAR = "tar",
258
259 MD5SUM = "md5sum",
260 OPENSSL = "openssl",
261 MD5 = "md5",
262 TOUCH = "touch",
263
264 CMAKE = "cmake",
265 SEVENZ = "7z",
266
267 RSYNCFLAGS = "--exclude=.git -Oavz",
268 CURLNOCERTFLAG = "",
269 WGETNOCERTFLAG = "",
270 },
271
272 external_deps_subdirs = {
273 bin = "bin",
274 lib = "lib",
275 include = "include"
276 },
277 runtime_external_deps_subdirs = {
278 bin = "bin",
279 lib = "lib",
280 include = "include"
281 },
282 }
283
284 if platforms.windows then
285
286 defaults.arch = "win32-"..target_cpu
287 defaults.lib_extension = "dll"
288 defaults.external_lib_extension = "dll"
289 defaults.static_lib_extension = "lib"
290 defaults.obj_extension = "obj"
291 defaults.external_deps_dirs = {
292 dir.path("c:", "external"),
293 dir.path("c:", "windows", "system32"),
294 }
295
296 defaults.makefile = "Makefile.win"
297 defaults.variables.PWD = "echo %cd%"
298 defaults.variables.MKDIR = "md"
299 defaults.variables.MAKE = os.getenv("MAKE") or "nmake"
300 defaults.variables.CC = os.getenv("CC") or "cl"
301 defaults.variables.RC = os.getenv("WINDRES") or "rc"
302 defaults.variables.LD = os.getenv("LINK") or "link"
303 defaults.variables.MT = os.getenv("MT") or "mt"
304 defaults.variables.AR = os.getenv("AR") or "lib"
305 defaults.variables.CFLAGS = os.getenv("CFLAGS") or "/nologo /MD /O2"
306 defaults.variables.LDFLAGS = os.getenv("LDFLAGS")
307 defaults.variables.LIBFLAG = "/nologo /dll"
308
309 defaults.external_deps_patterns = {
310 bin = { "?.exe", "?.bat" },
311 lib = { "?.lib", "lib?.lib", "?.dll", "lib?.dll" },
312 include = { "?.h" }
313 }
314 defaults.runtime_external_deps_patterns = {
315 bin = { "?.exe", "?.bat" },
316 lib = { "?.dll", "lib?.dll" },
317 include = { "?.h" }
318 }
319 defaults.export_path_separator = ";"
320 defaults.wrapper_suffix = ".bat"
321
322 local localappdata = os.getenv("LOCALAPPDATA")
323 if not localappdata then
324 -- for Windows versions below Vista
325 localappdata = dir.path((os.getenv("USERPROFILE") or dir.path("c:", "Users", "All Users")), "Local Settings", "Application Data")
326 end
327 defaults.local_cache = dir.path(localappdata, "LuaRocks", "Cache")
328 defaults.web_browser = "start"
329
330 defaults.external_deps_subdirs.lib = { "lib", "", "bin" }
331 defaults.runtime_external_deps_subdirs.lib = { "lib", "", "bin" }
332 defaults.link_lua_explicitly = true
333 defaults.fs_use_modules = false
334 end
335
336 if platforms.mingw32 then
337 defaults.obj_extension = "o"
338 defaults.static_lib_extension = "a"
339 defaults.external_deps_dirs = {
340 dir.path("c:", "external"),
341 dir.path("c:", "mingw"),
342 dir.path("c:", "windows", "system32"),
343 }
344 defaults.cmake_generator = "MinGW Makefiles"
345 defaults.variables.MAKE = os.getenv("MAKE") or "mingw32-make"
346 if target_cpu == "x86_64" then
347 defaults.variables.CC = os.getenv("CC") or "x86_64-w64-mingw32-gcc"
348 defaults.variables.LD = os.getenv("CC") or "x86_64-w64-mingw32-gcc"
349 else
350 defaults.variables.CC = os.getenv("CC") or "mingw32-gcc"
351 defaults.variables.LD = os.getenv("CC") or "mingw32-gcc"
352 end
353 defaults.variables.AR = os.getenv("AR") or "ar"
354 defaults.variables.RC = os.getenv("WINDRES") or "windres"
355 defaults.variables.RANLIB = os.getenv("RANLIB") or "ranlib"
356 defaults.variables.CFLAGS = os.getenv("CFLAGS") or "-O2"
357 defaults.variables.LDFLAGS = os.getenv("LDFLAGS")
358 defaults.variables.LIBFLAG = "-shared"
359 defaults.makefile = "Makefile"
360 defaults.external_deps_patterns = {
361 bin = { "?.exe", "?.bat" },
362 -- mingw lookup list from http://stackoverflow.com/a/15853231/1793220
363 -- ...should we keep ?.lib at the end? It's not in the above list.
364 lib = { "lib?.dll.a", "?.dll.a", "lib?.a", "cyg?.dll", "lib?.dll", "?.dll", "?.lib" },
365 include = { "?.h" }
366 }
367 defaults.runtime_external_deps_patterns = {
368 bin = { "?.exe", "?.bat" },
369 lib = { "cyg?.dll", "?.dll", "lib?.dll" },
370 include = { "?.h" }
371 }
372 defaults.link_lua_explicitly = true
373 end
374
375 if platforms.unix then
376 defaults.lib_extension = "so"
377 defaults.static_lib_extension = "a"
378 defaults.external_lib_extension = "so"
379 defaults.obj_extension = "o"
380 defaults.external_deps_dirs = { "/usr/local", "/usr", "/" }
381
382 defaults.variables.CFLAGS = os.getenv("CFLAGS") or "-O2"
383 -- we pass -fPIC via CFLAGS because of old Makefile-based Lua projects
384 -- which didn't have -fPIC in their Makefiles but which honor CFLAGS
385 if not defaults.variables.CFLAGS:match("-fPIC") then
386 defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC"
387 end
388
389 defaults.variables.LDFLAGS = os.getenv("LDFLAGS")
390
391 defaults.cmake_generator = "Unix Makefiles"
392 defaults.variables.CC = os.getenv("CC") or "gcc"
393 defaults.variables.LD = os.getenv("CC") or "gcc"
394 defaults.gcc_rpath = true
395 defaults.variables.LIBFLAG = "-shared"
396 defaults.variables.TEST = "test"
397
398 defaults.external_deps_patterns = {
399 bin = { "?" },
400 lib = { "lib?.a", "lib?.so", "lib?.so.*" },
401 include = { "?.h" }
402 }
403 defaults.runtime_external_deps_patterns = {
404 bin = { "?" },
405 lib = { "lib?.so", "lib?.so.*" },
406 include = { "?.h" }
407 }
408 defaults.export_path_separator = ":"
409 defaults.wrapper_suffix = ""
410 local xdg_cache_home = os.getenv("XDG_CACHE_HOME") or home.."/.cache"
411 defaults.local_cache = xdg_cache_home.."/luarocks"
412 defaults.web_browser = "xdg-open"
413 end
414
415 if platforms.cygwin then
416 defaults.lib_extension = "so" -- can be overridden in the config file for mingw builds
417 defaults.arch = "cygwin-"..target_cpu
418 defaults.cmake_generator = "Unix Makefiles"
419 defaults.variables.CC = "echo -llua | xargs " .. (os.getenv("CC") or "gcc")
420 defaults.variables.LD = "echo -llua | xargs " .. (os.getenv("CC") or "gcc")
421 defaults.variables.LIBFLAG = "-shared"
422 defaults.link_lua_explicitly = true
423 end
424
425 if platforms.msys then
426 -- msys is basically cygwin made out of mingw, meaning the subsytem is unixish
427 -- enough, yet we can freely mix with native win32
428 defaults.external_deps_patterns = {
429 bin = { "?.exe", "?.bat", "?" },
430 lib = { "lib?.so", "lib?.so.*", "lib?.dll.a", "?.dll.a",
431 "lib?.a", "lib?.dll", "?.dll", "?.lib" },
432 include = { "?.h" }
433 }
434 defaults.runtime_external_deps_patterns = {
435 bin = { "?.exe", "?.bat" },
436 lib = { "lib?.so", "?.dll", "lib?.dll" },
437 include = { "?.h" }
438 }
439 if platforms.mingw then
440 -- MSYS2 can build Windows programs that depend on
441 -- msys-2.0.dll (based on Cygwin) but MSYS2 is also designed
442 -- for building native Windows programs by MinGW. These
443 -- programs don't depend on msys-2.0.dll.
444 local pipe = io.popen("cygpath --windows %MINGW_PREFIX%")
445 local mingw_prefix = pipe:read("*l")
446 pipe:close()
447 defaults.external_deps_dirs = {
448 mingw_prefix,
449 dir.path("c:", "windows", "system32"),
450 }
451 defaults.makefile = "Makefile"
452 defaults.cmake_generator = "MSYS Makefiles"
453 defaults.local_cache = dir.path(home, ".cache", "luarocks")
454 defaults.variables.MAKE = os.getenv("MAKE") or "make"
455 defaults.variables.CC = os.getenv("CC") or "gcc"
456 defaults.variables.RC = os.getenv("WINDRES") or "windres"
457 defaults.variables.LD = os.getenv("CC") or "gcc"
458 defaults.variables.MT = os.getenv("MT") or nil
459 defaults.variables.AR = os.getenv("AR") or "ar"
460 defaults.variables.RANLIB = os.getenv("RANLIB") or "ranlib"
461
462 defaults.variables.CFLAGS = os.getenv("CFLAGS") or "-O2 -fPIC"
463 if not defaults.variables.CFLAGS:match("-fPIC") then
464 defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC"
465 end
466
467 defaults.variables.LIBFLAG = "-shared"
468 end
469 end
470
471 if platforms.bsd then
472 defaults.variables.MAKE = "gmake"
473 defaults.gcc_rpath = false
474 defaults.variables.CC = os.getenv("CC") or "cc"
475 defaults.variables.LD = os.getenv("CC") or defaults.variables.CC
476 end
477
478 if platforms.macosx then
479 defaults.variables.MAKE = os.getenv("MAKE") or "make"
480 defaults.external_lib_extension = "dylib"
481 defaults.arch = "macosx-"..target_cpu
482 defaults.variables.LIBFLAG = "-bundle -undefined dynamic_lookup -all_load"
483 local version = util.popen_read("sw_vers -productVersion")
484 if not (version:match("^%d+%.%d+%.%d+$") or version:match("^%d+%.%d+$")) then
485 version = "10.3"
486 end
487 version = vers.parse_version(version)
488 if version >= vers.parse_version("11.0") then
489 version = vers.parse_version("11.0")
490 elseif version >= vers.parse_version("10.10") then
491 version = vers.parse_version("10.8")
492 elseif version >= vers.parse_version("10.5") then
493 version = vers.parse_version("10.5")
494 else
495 defaults.gcc_rpath = false
496 end
497 defaults.variables.CC = "env MACOSX_DEPLOYMENT_TARGET="..tostring(version).." gcc"
498 defaults.variables.LD = "env MACOSX_DEPLOYMENT_TARGET="..tostring(version).." gcc"
499 defaults.web_browser = "open"
500
501 -- XCode SDK
502 local sdk_path = util.popen_read("xcrun --show-sdk-path 2>/dev/null")
503 if sdk_path then
504 table.insert(defaults.external_deps_dirs, sdk_path .. "/usr")
505 table.insert(defaults.external_deps_patterns.lib, 1, "lib?.tbd")
506 table.insert(defaults.runtime_external_deps_patterns.lib, 1, "lib?.tbd")
507 end
508
509 -- Homebrew
510 table.insert(defaults.external_deps_dirs, "/usr/local/opt")
511 defaults.external_deps_subdirs.lib = { "lib", "" }
512 defaults.runtime_external_deps_subdirs.lib = { "lib", "" }
513 table.insert(defaults.external_deps_patterns.lib, 1, "/?/lib/lib?.dylib")
514 table.insert(defaults.runtime_external_deps_patterns.lib, 1, "/?/lib/lib?.dylib")
515 end
516
517 if platforms.linux then
518 defaults.arch = "linux-"..target_cpu
519
520 local gcc_arch = util.popen_read("gcc -print-multiarch 2>/dev/null")
521 if gcc_arch and gcc_arch ~= "" then
522 defaults.external_deps_subdirs.lib = { "lib/" .. gcc_arch, "lib64", "lib" }
523 defaults.runtime_external_deps_subdirs.lib = { "lib/" .. gcc_arch, "lib64", "lib" }
524 else
525 defaults.external_deps_subdirs.lib = { "lib64", "lib" }
526 defaults.runtime_external_deps_subdirs.lib = { "lib64", "lib" }
527 end
528 end
529
530 if platforms.freebsd then
531 defaults.arch = "freebsd-"..target_cpu
532 elseif platforms.dragonfly then
533 defaults.arch = "dragonfly-"..target_cpu
534 elseif platforms.openbsd then
535 defaults.arch = "openbsd-"..target_cpu
536 elseif platforms.netbsd then
537 defaults.arch = "netbsd-"..target_cpu
538 elseif platforms.solaris then
539 defaults.arch = "solaris-"..target_cpu
540 defaults.variables.MAKE = "gmake"
541 end
542
543 -- Expose some more values detected by LuaRocks for use by rockspec authors.
544 defaults.variables.LIB_EXTENSION = defaults.lib_extension
545 defaults.variables.OBJ_EXTENSION = defaults.obj_extension
546
547 return defaults
548end
549
550local function use_defaults(cfg, defaults)
551
552 -- Populate variables with values from their 'defaults' counterparts
553 -- if they were not already set by user.
554 if not cfg.variables then
555 cfg.variables = {}
556 end
557 for k,v in pairs(defaults.variables) do
558 if not cfg.variables[k] then
559 cfg.variables[k] = v
560 end
561 end
562
563 util.deep_merge_under(cfg, defaults)
564
565 -- FIXME get rid of this
566 if not cfg.check_certificates then
567 cfg.variables.CURLNOCERTFLAG = "-k"
568 cfg.variables.WGETNOCERTFLAG = "--no-check-certificate"
569 end
570end
571
572--------------------------------------------------------------------------------
573
574local cfg = {}
575
576--- Initializes the LuaRocks configuration for variables, paths
577-- and OS detection.
578-- @param detected table containing information detected about the
579-- environment. All fields below are optional:
580-- * lua_version (in x.y format, e.g. "5.3")
581-- * lua_bindir (e.g. "/usr/local/bin")
582-- * lua_dir (e.g. "/usr/local")
583-- * lua (e.g. "/usr/local/bin/lua-5.3")
584-- * project_dir (a string with the path of the project directory
585-- when using per-project environments, as created with `luarocks init`)
586-- @param warning a logging function for warnings that takes a string
587-- @return true on success; nil and an error message on failure.
588function cfg.init(detected, warning)
589 detected = detected or {}
590
591 local exit_ok = true
592 local exit_err = nil
593 local exit_what = nil
594
595 local hc_ok, hardcoded = pcall(require, "luarocks.core.hardcoded")
596 if not hc_ok then
597 hardcoded = {}
598 end
599
600 local init = cfg.init
601
602 ----------------------------------------
603 -- Reset the cfg table.
604 ----------------------------------------
605
606 for k, _ in pairs(cfg) do
607 cfg[k] = nil
608 end
609
610 cfg.program_version = program_version
611
612 if hardcoded.IS_BINARY then
613 cfg.is_binary = true
614 end
615
616 -- Use detected values as defaults, overridable via config files or CLI args
617
618 local hardcoded_lua = hardcoded.LUA
619 local hardcoded_lua_dir = hardcoded.LUA_DIR
620 local hardcoded_lua_bindir = hardcoded.LUA_BINDIR
621 local hardcoded_lua_incdir = hardcoded.LUA_INCDIR
622 local hardcoded_lua_libdir = hardcoded.LUA_LIBDIR
623 local hardcoded_lua_version = hardcoded.LUA_VERSION or _VERSION:sub(5)
624
625 -- if --lua-version or --lua-dir are passed from the CLI,
626 -- don't use the hardcoded paths at all
627 if detected.given_lua_version or detected.given_lua_dir then
628 hardcoded_lua = nil
629 hardcoded_lua_dir = nil
630 hardcoded_lua_bindir = nil
631 hardcoded_lua_incdir = nil
632 hardcoded_lua_libdir = nil
633 hardcoded_lua_version = nil
634 end
635
636 cfg.lua_version = detected.lua_version or hardcoded_lua_version
637 cfg.project_dir = (not hardcoded.FORCE_CONFIG) and detected.project_dir
638
639 do
640 local lua = detected.lua or hardcoded_lua
641 local lua_dir = detected.lua_dir or hardcoded_lua_dir
642 local lua_bindir = detected.lua_bindir or hardcoded_lua_bindir
643 cfg.variables = {
644 LUA = lua,
645 LUA_DIR = lua_dir,
646 LUA_BINDIR = lua_bindir,
647 LUA_LIBDIR = hardcoded_lua_libdir,
648 LUA_INCDIR = hardcoded_lua_incdir,
649 }
650 end
651
652 cfg.init = init
653
654 ----------------------------------------
655 -- System detection.
656 ----------------------------------------
657
658 -- A proper build of LuaRocks will hardcode the system
659 -- and proc values with hardcoded.SYSTEM and hardcoded.PROCESSOR.
660 -- If that is not available, we try to identify the system.
661 local system, processor = sysdetect.detect()
662 if hardcoded.SYSTEM then
663 system = hardcoded.SYSTEM
664 end
665 if hardcoded.PROCESSOR then
666 processor = hardcoded.PROCESSOR
667 end
668
669 if system == "windows" then
670 if os.getenv("VCINSTALLDIR") then
671 -- running from the Development Command prompt for VS 2017
672 system = "windows"
673 else
674 local msystem = os.getenv("MSYSTEM")
675 if msystem == nil then
676 system = "mingw"
677 elseif msystem == "MSYS" then
678 system = "msys"
679 else
680 -- MINGW32 or MINGW64
681 system = "msys2_mingw_w64"
682 end
683 end
684 end
685
686 cfg.target_cpu = processor
687
688 local platforms = make_platforms(system)
689
690 ----------------------------------------
691 -- Platform is determined.
692 -- Let's load the config files.
693 ----------------------------------------
694
695 local sys_config_file
696 local home_config_file
697 local project_config_file
698
699 local config_file_name = "config-"..cfg.lua_version..".lua"
700
701 do
702 local sysconfdir = os.getenv("LUAROCKS_SYSCONFDIR") or hardcoded.SYSCONFDIR
703 if platforms.windows and not platforms.msys2_mingw_w64 then
704 cfg.home = os.getenv("APPDATA") or "c:"
705 cfg.home_tree = dir.path(cfg.home, "luarocks")
706 cfg.sysconfdir = sysconfdir or dir.path((os.getenv("PROGRAMFILES") or "c:"), "luarocks")
707 else
708 cfg.home = os.getenv("HOME") or ""
709 cfg.home_tree = dir.path(cfg.home, ".luarocks")
710 cfg.sysconfdir = sysconfdir or detect_sysconfdir() or "/etc/luarocks"
711 end
712 end
713
714 -- Load system configuration file
715 sys_config_file = dir.path(cfg.sysconfdir, config_file_name)
716 local sys_config_ok, err = load_config_file(cfg, platforms, sys_config_file)
717 if err then
718 exit_ok, exit_err, exit_what = nil, err, "config"
719 end
720
721 -- Load user configuration file (if allowed)
722 local home_config_ok
723 local project_config_ok
724 if not hardcoded.FORCE_CONFIG then
725 local env_var = "LUAROCKS_CONFIG_" .. cfg.lua_version:gsub("%.", "_")
726 local env_value = os.getenv(env_var)
727 if not env_value then
728 env_var = "LUAROCKS_CONFIG"
729 env_value = os.getenv(env_var)
730 end
731 -- first try environment provided file, so we can explicitly warn when it is missing
732 if env_value then
733 local env_ok, err = load_config_file(cfg, platforms, env_value)
734 if err then
735 exit_ok, exit_err, exit_what = nil, err, "config"
736 elseif warning and not env_ok then
737 warning("Warning: could not load configuration file `"..env_value.."` given in environment variable "..env_var.."\n")
738 end
739 if env_ok then
740 home_config_ok = true
741 home_config_file = env_value
742 end
743 end
744
745 -- try XDG config home
746 if platforms.unix and not home_config_ok then
747 local xdg_config_home = os.getenv("XDG_CONFIG_HOME") or dir.path(cfg.home, ".config")
748 cfg.homeconfdir = dir.path(xdg_config_home, "luarocks")
749 home_config_file = dir.path(cfg.homeconfdir, config_file_name)
750 home_config_ok, err = load_config_file(cfg, platforms, home_config_file)
751 if err then
752 exit_ok, exit_err, exit_what = nil, err, "config"
753 end
754 end
755
756 -- try the alternative defaults if there was no environment specified file or it didn't work
757 if not home_config_ok then
758 cfg.homeconfdir = cfg.home_tree
759 home_config_file = dir.path(cfg.homeconfdir, config_file_name)
760 home_config_ok, err = load_config_file(cfg, platforms, home_config_file)
761 if err then
762 exit_ok, exit_err, exit_what = nil, err, "config"
763 end
764 end
765
766 -- finally, use the project-specific config file if any
767 if cfg.project_dir then
768 project_config_file = dir.path(cfg.project_dir, ".luarocks", config_file_name)
769 project_config_ok, err = load_config_file(cfg, platforms, project_config_file)
770 if err then
771 exit_ok, exit_err, exit_what = nil, err, "config"
772 end
773 end
774 end
775
776 -- backwards compatibility:
777 if cfg.lua_interpreter and cfg.variables.LUA_BINDIR and not cfg.variables.LUA then
778 cfg.variables.LUA = dir.path(cfg.variables.LUA_BINDIR, cfg.lua_interpreter)
779 end
780
781 ----------------------------------------
782 -- Config files are loaded.
783 -- Let's finish up the cfg table.
784 ----------------------------------------
785
786 -- Settings given via the CLI (i.e. --lua-dir) take precedence over config files.
787 cfg.project_dir = detected.given_project_dir or cfg.project_dir
788 cfg.lua_version = detected.given_lua_version or cfg.lua_version
789 if detected.given_lua_dir then
790 cfg.variables.LUA = detected.lua
791 cfg.variables.LUA_DIR = detected.given_lua_dir
792 cfg.variables.LUA_BINDIR = detected.lua_bindir
793 cfg.variables.LUA_LIBDIR = nil
794 cfg.variables.LUA_INCDIR = nil
795 end
796
797 -- Build a default list of rocks trees if not given
798 if cfg.rocks_trees == nil then
799 cfg.rocks_trees = {}
800 if cfg.home_tree then
801 table.insert(cfg.rocks_trees, { name = "user", root = cfg.home_tree } )
802 end
803 if hardcoded.PREFIX and hardcoded.PREFIX ~= cfg.home_tree then
804 table.insert(cfg.rocks_trees, { name = "system", root = hardcoded.PREFIX } )
805 end
806 end
807
808 local defaults = make_defaults(cfg.lua_version, processor, platforms, cfg.home)
809
810 if platforms.windows and hardcoded.WIN_TOOLS then
811 local tools = { "SEVENZ", "CP", "FIND", "LS", "MD5SUM", "WGET", }
812 for _, tool in ipairs(tools) do
813 defaults.variables[tool] = '"' .. dir.path(hardcoded.WIN_TOOLS, defaults.variables[tool] .. '.exe') .. '"'
814 end
815 else
816 defaults.fs_use_modules = true
817 end
818
819 -- if only cfg.variables.LUA is given in config files,
820 -- derive LUA_BINDIR and LUA_DIR from them.
821 if cfg.variables.LUA and not cfg.variables.LUA_BINDIR then
822 cfg.variables.LUA_BINDIR = cfg.variables.LUA:match("^(.*)[\\/][^\\/]*$")
823 if not cfg.variables.LUA_DIR then
824 cfg.variables.LUA_DIR = cfg.variables.LUA_BINDIR:gsub("[\\/]bin$", "") or cfg.variables.LUA_BINDIR
825 end
826 end
827
828 use_defaults(cfg, defaults)
829
830 cfg.user_agent = "LuaRocks/"..cfg.program_version.." "..cfg.arch
831
832 cfg.config_files = {
833 project = cfg.project_dir and {
834 file = project_config_file,
835 found = not not project_config_ok,
836 },
837 system = {
838 file = sys_config_file,
839 found = not not sys_config_ok,
840 },
841 user = {
842 file = home_config_file,
843 found = not not home_config_ok,
844 },
845 nearest = project_config_ok
846 and project_config_file
847 or (home_config_ok
848 and home_config_file
849 or sys_config_file),
850 }
851
852 cfg.cache = {}
853
854 ----------------------------------------
855 -- Attributes of cfg are set.
856 -- Let's add some methods.
857 ----------------------------------------
858
859 do
860 local function make_paths_from_tree(tree)
861 local lua_path, lib_path, bin_path
862 if type(tree) == "string" then
863 lua_path = dir.path(tree, cfg.lua_modules_path)
864 lib_path = dir.path(tree, cfg.lib_modules_path)
865 bin_path = dir.path(tree, "bin")
866 else
867 lua_path = tree.lua_dir or dir.path(tree.root, cfg.lua_modules_path)
868 lib_path = tree.lib_dir or dir.path(tree.root, cfg.lib_modules_path)
869 bin_path = tree.bin_dir or dir.path(tree.root, "bin")
870 end
871 return lua_path, lib_path, bin_path
872 end
873
874 function cfg.package_paths(current)
875 local new_path, new_cpath, new_bin = {}, {}, {}
876 local function add_tree_to_paths(tree)
877 local lua_path, lib_path, bin_path = make_paths_from_tree(tree)
878 table.insert(new_path, dir.path(lua_path, "?.lua"))
879 table.insert(new_path, dir.path(lua_path, "?", "init.lua"))
880 table.insert(new_cpath, dir.path(lib_path, "?."..cfg.lib_extension))
881 table.insert(new_bin, bin_path)
882 end
883 if current then
884 add_tree_to_paths(current)
885 end
886 for _,tree in ipairs(cfg.rocks_trees) do
887 add_tree_to_paths(tree)
888 end
889 return table.concat(new_path, ";"), table.concat(new_cpath, ";"), table.concat(new_bin, cfg.export_path_separator)
890 end
891 end
892
893 function cfg.init_package_paths()
894 local lr_path, lr_cpath, lr_bin = cfg.package_paths()
895 package.path = util.cleanup_path(package.path .. ";" .. lr_path, ";", cfg.lua_version, true)
896 package.cpath = util.cleanup_path(package.cpath .. ";" .. lr_cpath, ";", cfg.lua_version, true)
897 end
898
899 --- Check if platform was detected
900 -- @param name string: The platform name to check.
901 -- @return boolean: true if LuaRocks is currently running on queried platform.
902 function cfg.is_platform(name)
903 assert(type(name) == "string")
904 return platforms[name]
905 end
906
907 -- @param direction (optional) "least-specific-first" (default) or "most-specific-first"
908 function cfg.each_platform(direction)
909 direction = direction or "least-specific-first"
910 local i, delta
911 if direction == "least-specific-first" then
912 i = 0
913 delta = 1
914 else
915 i = #platform_order + 1
916 delta = -1
917 end
918 return function()
919 local p
920 repeat
921 i = i + delta
922 p = platform_order[i]
923 until (not p) or platforms[p]
924 return p
925 end
926 end
927
928 function cfg.print_platforms()
929 local platform_keys = {}
930 for k,_ in pairs(platforms) do
931 table.insert(platform_keys, k)
932 end
933 table.sort(platform_keys)
934 return table.concat(platform_keys, ", ")
935 end
936
937 return exit_ok, exit_err, exit_what
938end
939
940return cfg
diff --git a/src/luarocks/core/cfg.d.tl b/src/luarocks/core/cfg.d.tl
new file mode 100644
index 00000000..09815260
--- /dev/null
+++ b/src/luarocks/core/cfg.d.tl
@@ -0,0 +1,7 @@
1local record cfg
2 detect_sysconfdir: function(): string
3 make_platforms: function(system: string): {any: boolean}
4 make_defaults: function(lua_version: string, target_cpu: string, platforms: {any: any}, home: string): {any: any}
5 use_defaults: function(cfg, defaults: {any: any})
6 --!
7end \ No newline at end of file
diff --git a/src/luarocks/core/cfg.lua b/src/luarocks/core/cfg.lua
index 4ae9bd6e..6d8fe55b 100644
--- a/src/luarocks/core/cfg.lua
+++ b/src/luarocks/core/cfg.lua
@@ -1,17 +1,17 @@
1local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local assert = _tl_compat and _tl_compat.assert or assert; local debug = _tl_compat and _tl_compat.debug or debug; local io = _tl_compat and _tl_compat.io or io; local ipairs = _tl_compat and _tl_compat.ipairs or ipairs; local os = _tl_compat and _tl_compat.os or os; local package = _tl_compat and _tl_compat.package or package; local pairs = _tl_compat and _tl_compat.pairs or pairs; local pcall = _tl_compat and _tl_compat.pcall or pcall; local string = _tl_compat and _tl_compat.string or string; local table = _tl_compat and _tl_compat.table or table
2 1
2--- Configuration for LuaRocks.
3-- Tries to load the user's configuration file and
4-- defines defaults for unset values. See the
5-- <a href="http://luarocks.org/en/Config_file_format">config
6-- file format documentation</a> for details.
7--
8-- End-users shouldn't edit this file. They can override any defaults
9-- set in this file using their system-wide or user-specific configuration
10-- files. Run `luarocks` with no arguments to see the locations of
11-- these files in your platform.
3 12
4 13local table, pairs, require, os, pcall, ipairs, package, type, assert =
5 14 table, pairs, require, os, pcall, ipairs, package, type, assert
6
7
8
9
10
11
12
13local table, pairs, require, os, pcall, ipairs, package, type, assert =
14table, pairs, require, os, pcall, ipairs, package, type, assert
15 15
16local dir = require("luarocks.core.dir") 16local dir = require("luarocks.core.dir")
17local util = require("luarocks.core.util") 17local util = require("luarocks.core.util")
@@ -19,21 +19,17 @@ local persist = require("luarocks.core.persist")
19local sysdetect = require("luarocks.core.sysdetect") 19local sysdetect = require("luarocks.core.sysdetect")
20local vers = require("luarocks.core.vers") 20local vers = require("luarocks.core.vers")
21 21
22local cfg = {} 22--------------------------------------------------------------------------------
23
24
25
26
27 23
28local program_version = "dev" 24local program_version = "dev"
29 25
30local is_windows = package.config:sub(1, 1) == "\\" 26local is_windows = package.config:sub(1,1) == "\\"
31
32
33
34 27
28-- Set order for platform overrides.
29-- More general platform identifiers should be listed first,
30-- more specific ones later.
35local platform_order = { 31local platform_order = {
36 32 -- Unixes
37 "unix", 33 "unix",
38 "bsd", 34 "bsd",
39 "solaris", 35 "solaris",
@@ -46,7 +42,7 @@ local platform_order = {
46 "cygwin", 42 "cygwin",
47 "msys", 43 "msys",
48 "haiku", 44 "haiku",
49 45 -- Windows
50 "windows", 46 "windows",
51 "win32", 47 "win32",
52 "mingw", 48 "mingw",
@@ -54,17 +50,6 @@ local platform_order = {
54 "msys2_mingw_w64", 50 "msys2_mingw_w64",
55} 51}
56 52
57
58
59
60
61
62
63
64
65
66
67
68local function detect_sysconfdir() 53local function detect_sysconfdir()
69 if not debug then 54 if not debug then
70 return 55 return
@@ -81,7 +66,7 @@ local function detect_sysconfdir()
81 if not basedir then 66 if not basedir then
82 return 67 return
83 end 68 end
84 69 -- If installed in a Unix-like tree, use a Unix-like sysconfdir
85 local installdir = basedir:match("^(.*)[\\/]share[\\/]lua[\\/][^/]*$") 70 local installdir = basedir:match("^(.*)[\\/]share[\\/]lua[\\/][^/]*$")
86 if installdir then 71 if installdir then
87 if installdir == "/usr" then 72 if installdir == "/usr" then
@@ -89,16 +74,16 @@ local function detect_sysconfdir()
89 end 74 end
90 return dir.path(installdir, "etc", "luarocks") 75 return dir.path(installdir, "etc", "luarocks")
91 end 76 end
92 77 -- Otherwise, use base directory of sources
93 return basedir 78 return basedir
94end 79end
95 80
96 81local load_config_file
97do 82do
98 83 -- Create global environment for the config files;
99 local function env_for_config_file(cfg, platforms) 84 local function env_for_config_file(cfg, platforms)
100 local platforms_copy = {} 85 local platforms_copy = {}
101 for k, v in pairs(platforms) do 86 for k,v in pairs(platforms) do
102 platforms_copy[k] = v 87 platforms_copy[k] = v
103 end 88 end
104 89
@@ -107,28 +92,28 @@ do
107 home = cfg.home, 92 home = cfg.home,
108 lua_version = cfg.lua_version, 93 lua_version = cfg.lua_version,
109 platforms = platforms_copy, 94 platforms = platforms_copy,
110 processor = cfg.target_cpu, 95 processor = cfg.target_cpu, -- remains for compat reasons
111 target_cpu = cfg.target_cpu, 96 target_cpu = cfg.target_cpu, -- replaces `processor`
112 os_getenv = os.getenv, 97 os_getenv = os.getenv,
113 variables = cfg.variables or {}, 98 variables = cfg.variables or {},
114 dump_env = function() 99 dump_env = function()
115 100 -- debug function, calling it from a config file will show all
116 101 -- available globals to that config file
117 print(util.show_table(e, "global environment")) 102 print(util.show_table(e, "global environment"))
118 end, 103 end,
119 } 104 }
120 return e 105 return e
121 end 106 end
122 107
123 108 -- Merge values from config files read into the `cfg` table
124 local function merge_overrides(cfg, overrides) 109 local function merge_overrides(cfg, overrides)
125 110 -- remove some stuff we do not want to integrate
126 overrides.os_getenv = nil 111 overrides.os_getenv = nil
127 overrides.dump_env = nil 112 overrides.dump_env = nil
128 113 -- remove tables to be copied verbatim instead of deeply merged
129 if overrides.rocks_trees then cfg.rocks_trees = nil end 114 if overrides.rocks_trees then cfg.rocks_trees = nil end
130 if overrides.rocks_servers then cfg.rocks_servers = nil end 115 if overrides.rocks_servers then cfg.rocks_servers = nil end
131 116 -- perform actual merge
132 util.deep_merge(cfg, overrides) 117 util.deep_merge(cfg, overrides)
133 end 118 end
134 119
@@ -140,30 +125,30 @@ do
140 for _, v in ipairs(overrides) do 125 for _, v in ipairs(overrides) do
141 platforms[v] = true 126 platforms[v] = true
142 end 127 end
143 128 -- set some fallback default in case the user provides an incomplete configuration.
144 129 -- LuaRocks expects a set of defaults to be available.
145 if not (platforms.unix or platforms.windows) then 130 if not (platforms.unix or platforms.windows) then
146 platforms[is_windows and "windows" or "unix"] = true 131 platforms[is_windows and "windows" or "unix"] = true
147 end 132 end
148 end 133 end
149 end 134 end
150 135
151 136 -- Load config file and merge its contents into the `cfg` module table.
152 137 -- @return filepath of successfully loaded file or nil if it failed
153 local load_config_file = function(cfg, platforms, filepath) 138 load_config_file = function(cfg, platforms, filepath)
154 local result, err, errcode = persist.load_into_table(filepath, env_for_config_file(cfg, platforms)) 139 local result, err, errcode = persist.load_into_table(filepath, env_for_config_file(cfg, platforms))
155 if (not result) and errcode ~= "open" then 140 if (not result) and errcode ~= "open" then
156 141 -- errcode is either "load" or "run"; bad config file, so error out
157 return nil, err, "config" 142 return nil, err, "config"
158 end 143 end
159 if result then 144 if result then
160 145 -- success in loading and running, merge contents and exit
161 update_platforms(platforms, result.platforms) 146 update_platforms(platforms, result.platforms)
162 result.platforms = nil 147 result.platforms = nil
163 merge_overrides(cfg, result) 148 merge_overrides(cfg, result)
164 return filepath 149 return filepath
165 end 150 end
166 return nil 151 return nil -- nothing was loaded
167 end 152 end
168end 153end
169 154
@@ -184,15 +169,15 @@ local platform_sets = {
184} 169}
185 170
186local function make_platforms(system) 171local function make_platforms(system)
187 172 -- fallback to Unix in unknown systems
188 return platform_sets[system] or { unix = true } 173 return platform_sets[system] or { unix = true }
189end 174end
190 175
191 176--------------------------------------------------------------------------------
192 177
193local function make_defaults(lua_version, target_cpu, platforms, home) 178local function make_defaults(lua_version, target_cpu, platforms, home)
194 179
195 180 -- Configure defaults:
196 local defaults = { 181 local defaults = {
197 182
198 local_by_default = false, 183 local_by_default = false,
@@ -208,29 +193,19 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
208 193
209 lua_modules_path = dir.path("share", "lua", lua_version), 194 lua_modules_path = dir.path("share", "lua", lua_version),
210 lib_modules_path = dir.path("lib", "lua", lua_version), 195 lib_modules_path = dir.path("lib", "lua", lua_version),
211 rocks_subdir = dir.path("lib", "luarocks", "rocks-" .. lua_version), 196 rocks_subdir = dir.path("lib", "luarocks", "rocks-"..lua_version),
212 197
213 arch = "unknown", 198 arch = "unknown",
214 lib_extension = "unknown", 199 lib_extension = "unknown",
215 external_lib_extension = "unknown",
216 static_lib_extension = "unknown",
217 obj_extension = "unknown", 200 obj_extension = "unknown",
218 link_lua_explicitly = false, 201 link_lua_explicitly = false,
219 202
220 external_deps_dirs = {},
221 external_deps_patterns = {},
222 runtime_external_deps_patterns = {},
223
224 export_path_separator = "",
225 wrapper_suffix = "",
226
227
228 rocks_servers = { 203 rocks_servers = {
229 { 204 {
230 "https://luarocks.org", 205 "https://luarocks.org",
231 "https://raw.githubusercontent.com/rocks-moonscript-org/moonrocks-mirror/master/", 206 "https://raw.githubusercontent.com/rocks-moonscript-org/moonrocks-mirror/master/",
232 "https://loadk.com/luarocks/", 207 "https://loadk.com/luarocks/",
233 }, 208 }
234 }, 209 },
235 disabled_servers = {}, 210 disabled_servers = {},
236 211
@@ -241,13 +216,7 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
241 }, 216 },
242 217
243 lua_extension = "lua", 218 lua_extension = "lua",
244 connection_timeout = 30, 219 connection_timeout = 30, -- 0 = no timeout
245
246 makefile = "",
247 local_cache = "",
248 web_browser = "",
249 cmake_generator = "",
250 gcc_rpath = false,
251 220
252 variables = { 221 variables = {
253 MAKE = os.getenv("MAKE") or "make", 222 MAKE = os.getenv("MAKE") or "make",
@@ -298,30 +267,23 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
298 RSYNCFLAGS = "--exclude=.git -Oavz", 267 RSYNCFLAGS = "--exclude=.git -Oavz",
299 CURLNOCERTFLAG = "", 268 CURLNOCERTFLAG = "",
300 WGETNOCERTFLAG = "", 269 WGETNOCERTFLAG = "",
301
302 RC = "",
303 MT = "",
304 CFLAGS = "",
305 LDFLAGS = "",
306 LIBFLAG = "",
307 TEST = "",
308 }, 270 },
309 271
310 external_deps_subdirs = { 272 external_deps_subdirs = {
311 bin = "bin", 273 bin = "bin",
312 lib = "lib", 274 lib = "lib",
313 include = "include", 275 include = "include"
314 }, 276 },
315 runtime_external_deps_subdirs = { 277 runtime_external_deps_subdirs = {
316 bin = "bin", 278 bin = "bin",
317 lib = "lib", 279 lib = "lib",
318 include = "include", 280 include = "include"
319 }, 281 },
320 } 282 }
321 283
322 if platforms.windows then 284 if platforms.windows then
323 285
324 defaults.arch = "win32-" .. target_cpu 286 defaults.arch = "win32-"..target_cpu
325 defaults.lib_extension = "dll" 287 defaults.lib_extension = "dll"
326 defaults.external_lib_extension = "dll" 288 defaults.external_lib_extension = "dll"
327 defaults.static_lib_extension = "lib" 289 defaults.static_lib_extension = "lib"
@@ -347,19 +309,19 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
347 defaults.external_deps_patterns = { 309 defaults.external_deps_patterns = {
348 bin = { "?.exe", "?.bat" }, 310 bin = { "?.exe", "?.bat" },
349 lib = { "?.lib", "lib?.lib", "?.dll", "lib?.dll" }, 311 lib = { "?.lib", "lib?.lib", "?.dll", "lib?.dll" },
350 include = { "?.h" }, 312 include = { "?.h" }
351 } 313 }
352 defaults.runtime_external_deps_patterns = { 314 defaults.runtime_external_deps_patterns = {
353 bin = { "?.exe", "?.bat" }, 315 bin = { "?.exe", "?.bat" },
354 lib = { "?.dll", "lib?.dll" }, 316 lib = { "?.dll", "lib?.dll" },
355 include = { "?.h" }, 317 include = { "?.h" }
356 } 318 }
357 defaults.export_path_separator = ";" 319 defaults.export_path_separator = ";"
358 defaults.wrapper_suffix = ".bat" 320 defaults.wrapper_suffix = ".bat"
359 321
360 local localappdata = os.getenv("LOCALAPPDATA") 322 local localappdata = os.getenv("LOCALAPPDATA")
361 if not localappdata then 323 if not localappdata then
362 324 -- for Windows versions below Vista
363 localappdata = dir.path((os.getenv("USERPROFILE") or dir.path("c:", "Users", "All Users")), "Local Settings", "Application Data") 325 localappdata = dir.path((os.getenv("USERPROFILE") or dir.path("c:", "Users", "All Users")), "Local Settings", "Application Data")
364 end 326 end
365 defaults.local_cache = dir.path(localappdata, "LuaRocks", "Cache") 327 defaults.local_cache = dir.path(localappdata, "LuaRocks", "Cache")
@@ -397,15 +359,15 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
397 defaults.makefile = "Makefile" 359 defaults.makefile = "Makefile"
398 defaults.external_deps_patterns = { 360 defaults.external_deps_patterns = {
399 bin = { "?.exe", "?.bat" }, 361 bin = { "?.exe", "?.bat" },
400 362 -- mingw lookup list from http://stackoverflow.com/a/15853231/1793220
401 363 -- ...should we keep ?.lib at the end? It's not in the above list.
402 lib = { "lib?.dll.a", "?.dll.a", "lib?.a", "cyg?.dll", "lib?.dll", "?.dll", "?.lib" }, 364 lib = { "lib?.dll.a", "?.dll.a", "lib?.a", "cyg?.dll", "lib?.dll", "?.dll", "?.lib" },
403 include = { "?.h" }, 365 include = { "?.h" }
404 } 366 }
405 defaults.runtime_external_deps_patterns = { 367 defaults.runtime_external_deps_patterns = {
406 bin = { "?.exe", "?.bat" }, 368 bin = { "?.exe", "?.bat" },
407 lib = { "cyg?.dll", "?.dll", "lib?.dll" }, 369 lib = { "cyg?.dll", "?.dll", "lib?.dll" },
408 include = { "?.h" }, 370 include = { "?.h" }
409 } 371 }
410 defaults.link_lua_explicitly = true 372 defaults.link_lua_explicitly = true
411 end 373 end
@@ -418,10 +380,10 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
418 defaults.external_deps_dirs = { "/usr/local", "/usr", "/" } 380 defaults.external_deps_dirs = { "/usr/local", "/usr", "/" }
419 381
420 defaults.variables.CFLAGS = os.getenv("CFLAGS") or "-O2" 382 defaults.variables.CFLAGS = os.getenv("CFLAGS") or "-O2"
421 383 -- we pass -fPIC via CFLAGS because of old Makefile-based Lua projects
422 384 -- which didn't have -fPIC in their Makefiles but which honor CFLAGS
423 if not defaults.variables.CFLAGS:match("-fPIC") then 385 if not defaults.variables.CFLAGS:match("-fPIC") then
424 defaults.variables.CFLAGS = defaults.variables.CFLAGS .. " -fPIC" 386 defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC"
425 end 387 end
426 388
427 defaults.variables.LDFLAGS = os.getenv("LDFLAGS") 389 defaults.variables.LDFLAGS = os.getenv("LDFLAGS")
@@ -436,23 +398,23 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
436 defaults.external_deps_patterns = { 398 defaults.external_deps_patterns = {
437 bin = { "?" }, 399 bin = { "?" },
438 lib = { "lib?.a", "lib?.so", "lib?.so.*" }, 400 lib = { "lib?.a", "lib?.so", "lib?.so.*" },
439 include = { "?.h" }, 401 include = { "?.h" }
440 } 402 }
441 defaults.runtime_external_deps_patterns = { 403 defaults.runtime_external_deps_patterns = {
442 bin = { "?" }, 404 bin = { "?" },
443 lib = { "lib?.so", "lib?.so.*" }, 405 lib = { "lib?.so", "lib?.so.*" },
444 include = { "?.h" }, 406 include = { "?.h" }
445 } 407 }
446 defaults.export_path_separator = ":" 408 defaults.export_path_separator = ":"
447 defaults.wrapper_suffix = "" 409 defaults.wrapper_suffix = ""
448 local xdg_cache_home = os.getenv("XDG_CACHE_HOME") or home .. "/.cache" 410 local xdg_cache_home = os.getenv("XDG_CACHE_HOME") or home.."/.cache"
449 defaults.local_cache = xdg_cache_home .. "/luarocks" 411 defaults.local_cache = xdg_cache_home.."/luarocks"
450 defaults.web_browser = "xdg-open" 412 defaults.web_browser = "xdg-open"
451 end 413 end
452 414
453 if platforms.cygwin then 415 if platforms.cygwin then
454 defaults.lib_extension = "so" 416 defaults.lib_extension = "so" -- can be overridden in the config file for mingw builds
455 defaults.arch = "cygwin-" .. target_cpu 417 defaults.arch = "cygwin-"..target_cpu
456 defaults.cmake_generator = "Unix Makefiles" 418 defaults.cmake_generator = "Unix Makefiles"
457 defaults.variables.CC = "echo -llua | xargs " .. (os.getenv("CC") or "gcc") 419 defaults.variables.CC = "echo -llua | xargs " .. (os.getenv("CC") or "gcc")
458 defaults.variables.LD = "echo -llua | xargs " .. (os.getenv("CC") or "gcc") 420 defaults.variables.LD = "echo -llua | xargs " .. (os.getenv("CC") or "gcc")
@@ -461,24 +423,24 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
461 end 423 end
462 424
463 if platforms.msys then 425 if platforms.msys then
464 426 -- msys is basically cygwin made out of mingw, meaning the subsytem is unixish
465 427 -- enough, yet we can freely mix with native win32
466 defaults.external_deps_patterns = { 428 defaults.external_deps_patterns = {
467 bin = { "?.exe", "?.bat", "?" }, 429 bin = { "?.exe", "?.bat", "?" },
468 lib = { "lib?.so", "lib?.so.*", "lib?.dll.a", "?.dll.a", 430 lib = { "lib?.so", "lib?.so.*", "lib?.dll.a", "?.dll.a",
469"lib?.a", "lib?.dll", "?.dll", "?.lib", }, 431 "lib?.a", "lib?.dll", "?.dll", "?.lib" },
470 include = { "?.h" }, 432 include = { "?.h" }
471 } 433 }
472 defaults.runtime_external_deps_patterns = { 434 defaults.runtime_external_deps_patterns = {
473 bin = { "?.exe", "?.bat" }, 435 bin = { "?.exe", "?.bat" },
474 lib = { "lib?.so", "?.dll", "lib?.dll" }, 436 lib = { "lib?.so", "?.dll", "lib?.dll" },
475 include = { "?.h" }, 437 include = { "?.h" }
476 } 438 }
477 if platforms.mingw then 439 if platforms.mingw then
478 440 -- MSYS2 can build Windows programs that depend on
479 441 -- msys-2.0.dll (based on Cygwin) but MSYS2 is also designed
480 442 -- for building native Windows programs by MinGW. These
481 443 -- programs don't depend on msys-2.0.dll.
482 local pipe = io.popen("cygpath --windows %MINGW_PREFIX%") 444 local pipe = io.popen("cygpath --windows %MINGW_PREFIX%")
483 local mingw_prefix = pipe:read("*l") 445 local mingw_prefix = pipe:read("*l")
484 pipe:close() 446 pipe:close()
@@ -499,7 +461,7 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
499 461
500 defaults.variables.CFLAGS = os.getenv("CFLAGS") or "-O2 -fPIC" 462 defaults.variables.CFLAGS = os.getenv("CFLAGS") or "-O2 -fPIC"
501 if not defaults.variables.CFLAGS:match("-fPIC") then 463 if not defaults.variables.CFLAGS:match("-fPIC") then
502 defaults.variables.CFLAGS = defaults.variables.CFLAGS .. " -fPIC" 464 defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC"
503 end 465 end
504 466
505 defaults.variables.LIBFLAG = "-shared" 467 defaults.variables.LIBFLAG = "-shared"
@@ -516,7 +478,7 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
516 if platforms.macosx then 478 if platforms.macosx then
517 defaults.variables.MAKE = os.getenv("MAKE") or "make" 479 defaults.variables.MAKE = os.getenv("MAKE") or "make"
518 defaults.external_lib_extension = "dylib" 480 defaults.external_lib_extension = "dylib"
519 defaults.arch = "macosx-" .. target_cpu 481 defaults.arch = "macosx-"..target_cpu
520 defaults.variables.LIBFLAG = "-bundle -undefined dynamic_lookup -all_load" 482 defaults.variables.LIBFLAG = "-bundle -undefined dynamic_lookup -all_load"
521 local version = util.popen_read("sw_vers -productVersion") 483 local version = util.popen_read("sw_vers -productVersion")
522 if not (version:match("^%d+%.%d+%.%d+$") or version:match("^%d+%.%d+$")) then 484 if not (version:match("^%d+%.%d+%.%d+$") or version:match("^%d+%.%d+$")) then
@@ -532,11 +494,11 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
532 else 494 else
533 defaults.gcc_rpath = false 495 defaults.gcc_rpath = false
534 end 496 end
535 defaults.variables.CC = "env MACOSX_DEPLOYMENT_TARGET=" .. tostring(version) .. " gcc" 497 defaults.variables.CC = "env MACOSX_DEPLOYMENT_TARGET="..tostring(version).." gcc"
536 defaults.variables.LD = "env MACOSX_DEPLOYMENT_TARGET=" .. tostring(version) .. " gcc" 498 defaults.variables.LD = "env MACOSX_DEPLOYMENT_TARGET="..tostring(version).." gcc"
537 defaults.web_browser = "open" 499 defaults.web_browser = "open"
538 500
539 501 -- XCode SDK
540 local sdk_path = util.popen_read("xcrun --show-sdk-path 2>/dev/null") 502 local sdk_path = util.popen_read("xcrun --show-sdk-path 2>/dev/null")
541 if sdk_path then 503 if sdk_path then
542 table.insert(defaults.external_deps_dirs, sdk_path .. "/usr") 504 table.insert(defaults.external_deps_dirs, sdk_path .. "/usr")
@@ -544,7 +506,7 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
544 table.insert(defaults.runtime_external_deps_patterns.lib, 1, "lib?.tbd") 506 table.insert(defaults.runtime_external_deps_patterns.lib, 1, "lib?.tbd")
545 end 507 end
546 508
547 509 -- Homebrew
548 table.insert(defaults.external_deps_dirs, "/usr/local/opt") 510 table.insert(defaults.external_deps_dirs, "/usr/local/opt")
549 defaults.external_deps_subdirs.lib = { "lib", "" } 511 defaults.external_deps_subdirs.lib = { "lib", "" }
550 defaults.runtime_external_deps_subdirs.lib = { "lib", "" } 512 defaults.runtime_external_deps_subdirs.lib = { "lib", "" }
@@ -553,7 +515,7 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
553 end 515 end
554 516
555 if platforms.linux then 517 if platforms.linux then
556 defaults.arch = "linux-" .. target_cpu 518 defaults.arch = "linux-"..target_cpu
557 519
558 local gcc_arch = util.popen_read("gcc -print-multiarch 2>/dev/null") 520 local gcc_arch = util.popen_read("gcc -print-multiarch 2>/dev/null")
559 if gcc_arch and gcc_arch ~= "" then 521 if gcc_arch and gcc_arch ~= "" then
@@ -566,19 +528,19 @@ local function make_defaults(lua_version, target_cpu, platforms, home)
566 end 528 end
567 529
568 if platforms.freebsd then 530 if platforms.freebsd then
569 defaults.arch = "freebsd-" .. target_cpu 531 defaults.arch = "freebsd-"..target_cpu
570 elseif platforms.dragonfly then 532 elseif platforms.dragonfly then
571 defaults.arch = "dragonfly-" .. target_cpu 533 defaults.arch = "dragonfly-"..target_cpu
572 elseif platforms.openbsd then 534 elseif platforms.openbsd then
573 defaults.arch = "openbsd-" .. target_cpu 535 defaults.arch = "openbsd-"..target_cpu
574 elseif platforms.netbsd then 536 elseif platforms.netbsd then
575 defaults.arch = "netbsd-" .. target_cpu 537 defaults.arch = "netbsd-"..target_cpu
576 elseif platforms.solaris then 538 elseif platforms.solaris then
577 defaults.arch = "solaris-" .. target_cpu 539 defaults.arch = "solaris-"..target_cpu
578 defaults.variables.MAKE = "gmake" 540 defaults.variables.MAKE = "gmake"
579 end 541 end
580 542
581 543 -- Expose some more values detected by LuaRocks for use by rockspec authors.
582 defaults.variables.LIB_EXTENSION = defaults.lib_extension 544 defaults.variables.LIB_EXTENSION = defaults.lib_extension
583 defaults.variables.OBJ_EXTENSION = defaults.obj_extension 545 defaults.variables.OBJ_EXTENSION = defaults.obj_extension
584 546
@@ -587,12 +549,12 @@ end
587 549
588local function use_defaults(cfg, defaults) 550local function use_defaults(cfg, defaults)
589 551
590 552 -- Populate variables with values from their 'defaults' counterparts
591 553 -- if they were not already set by user.
592 if not cfg.variables then 554 if not cfg.variables then
593 cfg.variables = {} 555 cfg.variables = {}
594 end 556 end
595 for k, v in pairs(defaults.variables) do 557 for k,v in pairs(defaults.variables) do
596 if not cfg.variables[k] then 558 if not cfg.variables[k] then
597 cfg.variables[k] = v 559 cfg.variables[k] = v
598 end 560 end
@@ -600,29 +562,29 @@ local function use_defaults(cfg, defaults)
600 562
601 util.deep_merge_under(cfg, defaults) 563 util.deep_merge_under(cfg, defaults)
602 564
603 565 -- FIXME get rid of this
604 if not cfg.check_certificates then 566 if not cfg.check_certificates then
605 cfg.variables.CURLNOCERTFLAG = "-k" 567 cfg.variables.CURLNOCERTFLAG = "-k"
606 cfg.variables.WGETNOCERTFLAG = "--no-check-certificate" 568 cfg.variables.WGETNOCERTFLAG = "--no-check-certificate"
607 end 569 end
608end 570end
609 571
610 572--------------------------------------------------------------------------------
611 573
612local cfg = {} 574local cfg = {}
613 575
614 576--- Initializes the LuaRocks configuration for variables, paths
615 577-- and OS detection.
616 578-- @param detected table containing information detected about the
617 579-- environment. All fields below are optional:
618 580-- * lua_version (in x.y format, e.g. "5.3")
619 581-- * lua_bindir (e.g. "/usr/local/bin")
620 582-- * lua_dir (e.g. "/usr/local")
621 583-- * lua (e.g. "/usr/local/bin/lua-5.3")
622 584-- * project_dir (a string with the path of the project directory
623 585-- when using per-project environments, as created with `luarocks init`)
624 586-- @param warning a logging function for warnings that takes a string
625 587-- @return true on success; nil and an error message on failure.
626function cfg.init(detected, warning) 588function cfg.init(detected, warning)
627 detected = detected or {} 589 detected = detected or {}
628 590
@@ -637,9 +599,9 @@ function cfg.init(detected, warning)
637 599
638 local init = cfg.init 600 local init = cfg.init
639 601
640 602 ----------------------------------------
641 603 -- Reset the cfg table.
642 604 ----------------------------------------
643 605
644 for k, _ in pairs(cfg) do 606 for k, _ in pairs(cfg) do
645 cfg[k] = nil 607 cfg[k] = nil
@@ -651,7 +613,7 @@ function cfg.init(detected, warning)
651 cfg.is_binary = true 613 cfg.is_binary = true
652 end 614 end
653 615
654 616 -- Use detected values as defaults, overridable via config files or CLI args
655 617
656 local hardcoded_lua = hardcoded.LUA 618 local hardcoded_lua = hardcoded.LUA
657 local hardcoded_lua_dir = hardcoded.LUA_DIR 619 local hardcoded_lua_dir = hardcoded.LUA_DIR
@@ -660,8 +622,8 @@ function cfg.init(detected, warning)
660 local hardcoded_lua_libdir = hardcoded.LUA_LIBDIR 622 local hardcoded_lua_libdir = hardcoded.LUA_LIBDIR
661 local hardcoded_lua_version = hardcoded.LUA_VERSION or _VERSION:sub(5) 623 local hardcoded_lua_version = hardcoded.LUA_VERSION or _VERSION:sub(5)
662 624
663 625 -- if --lua-version or --lua-dir are passed from the CLI,
664 626 -- don't use the hardcoded paths at all
665 if detected.given_lua_version or detected.given_lua_dir then 627 if detected.given_lua_version or detected.given_lua_dir then
666 hardcoded_lua = nil 628 hardcoded_lua = nil
667 hardcoded_lua_dir = nil 629 hardcoded_lua_dir = nil
@@ -689,13 +651,13 @@ function cfg.init(detected, warning)
689 651
690 cfg.init = init 652 cfg.init = init
691 653
654 ----------------------------------------
655 -- System detection.
656 ----------------------------------------
692 657
693 658 -- A proper build of LuaRocks will hardcode the system
694 659 -- and proc values with hardcoded.SYSTEM and hardcoded.PROCESSOR.
695 660 -- If that is not available, we try to identify the system.
696
697
698
699 local system, processor = sysdetect.detect() 661 local system, processor = sysdetect.detect()
700 if hardcoded.SYSTEM then 662 if hardcoded.SYSTEM then
701 system = hardcoded.SYSTEM 663 system = hardcoded.SYSTEM
@@ -706,7 +668,7 @@ function cfg.init(detected, warning)
706 668
707 if system == "windows" then 669 if system == "windows" then
708 if os.getenv("VCINSTALLDIR") then 670 if os.getenv("VCINSTALLDIR") then
709 671 -- running from the Development Command prompt for VS 2017
710 system = "windows" 672 system = "windows"
711 else 673 else
712 local msystem = os.getenv("MSYSTEM") 674 local msystem = os.getenv("MSYSTEM")
@@ -715,7 +677,7 @@ function cfg.init(detected, warning)
715 elseif msystem == "MSYS" then 677 elseif msystem == "MSYS" then
716 system = "msys" 678 system = "msys"
717 else 679 else
718 680 -- MINGW32 or MINGW64
719 system = "msys2_mingw_w64" 681 system = "msys2_mingw_w64"
720 end 682 end
721 end 683 end
@@ -725,16 +687,16 @@ function cfg.init(detected, warning)
725 687
726 local platforms = make_platforms(system) 688 local platforms = make_platforms(system)
727 689
728 690 ----------------------------------------
729 691 -- Platform is determined.
730 692 -- Let's load the config files.
731 693 ----------------------------------------
732 694
733 local sys_config_file 695 local sys_config_file
734 local home_config_file 696 local home_config_file
735 local project_config_file 697 local project_config_file
736 698
737 local config_file_name = "config-" .. cfg.lua_version .. ".lua" 699 local config_file_name = "config-"..cfg.lua_version..".lua"
738 700
739 do 701 do
740 local sysconfdir = os.getenv("LUAROCKS_SYSCONFDIR") or hardcoded.SYSCONFDIR 702 local sysconfdir = os.getenv("LUAROCKS_SYSCONFDIR") or hardcoded.SYSCONFDIR
@@ -749,30 +711,30 @@ function cfg.init(detected, warning)
749 end 711 end
750 end 712 end
751 713
752 714 -- Load system configuration file
753 sys_config_file = dir.path(cfg.sysconfdir, config_file_name) 715 sys_config_file = dir.path(cfg.sysconfdir, config_file_name)
754 local sys_config_ok, err = load_config_file(cfg, platforms, sys_config_file) 716 local sys_config_ok, err = load_config_file(cfg, platforms, sys_config_file)
755 if err then 717 if err then
756 exit_ok, exit_err, exit_what = nil, err, "config" 718 exit_ok, exit_err, exit_what = nil, err, "config"
757 end 719 end
758 720
759 721 -- Load user configuration file (if allowed)
760 local home_config_ok 722 local home_config_ok
761 local project_config_ok 723 local project_config_ok
762 if not hardcoded.FORCE_CONFIG then 724 if not hardcoded.FORCE_CONFIG then
763 local env_var = "LUAROCKS_CONFIG_" .. cfg.lua_version:gsub("%.", "_") 725 local env_var = "LUAROCKS_CONFIG_" .. cfg.lua_version:gsub("%.", "_")
764 local env_value = os.getenv(env_var) 726 local env_value = os.getenv(env_var)
765 if not env_value then 727 if not env_value then
766 env_var = "LUAROCKS_CONFIG" 728 env_var = "LUAROCKS_CONFIG"
767 env_value = os.getenv(env_var) 729 env_value = os.getenv(env_var)
768 end 730 end
769 731 -- first try environment provided file, so we can explicitly warn when it is missing
770 if env_value then 732 if env_value then
771 local env_ok, err = load_config_file(cfg, platforms, env_value) 733 local env_ok, err = load_config_file(cfg, platforms, env_value)
772 if err then 734 if err then
773 exit_ok, exit_err, exit_what = nil, err, "config" 735 exit_ok, exit_err, exit_what = nil, err, "config"
774 elseif warning and not env_ok then 736 elseif warning and not env_ok then
775 warning("Warning: could not load configuration file `" .. env_value .. "` given in environment variable " .. env_var .. "\n") 737 warning("Warning: could not load configuration file `"..env_value.."` given in environment variable "..env_var.."\n")
776 end 738 end
777 if env_ok then 739 if env_ok then
778 home_config_ok = true 740 home_config_ok = true
@@ -780,7 +742,7 @@ function cfg.init(detected, warning)
780 end 742 end
781 end 743 end
782 744
783 745 -- try XDG config home
784 if platforms.unix and not home_config_ok then 746 if platforms.unix and not home_config_ok then
785 local xdg_config_home = os.getenv("XDG_CONFIG_HOME") or dir.path(cfg.home, ".config") 747 local xdg_config_home = os.getenv("XDG_CONFIG_HOME") or dir.path(cfg.home, ".config")
786 cfg.homeconfdir = dir.path(xdg_config_home, "luarocks") 748 cfg.homeconfdir = dir.path(xdg_config_home, "luarocks")
@@ -791,7 +753,7 @@ function cfg.init(detected, warning)
791 end 753 end
792 end 754 end
793 755
794 756 -- try the alternative defaults if there was no environment specified file or it didn't work
795 if not home_config_ok then 757 if not home_config_ok then
796 cfg.homeconfdir = cfg.home_tree 758 cfg.homeconfdir = cfg.home_tree
797 home_config_file = dir.path(cfg.homeconfdir, config_file_name) 759 home_config_file = dir.path(cfg.homeconfdir, config_file_name)
@@ -801,7 +763,7 @@ function cfg.init(detected, warning)
801 end 763 end
802 end 764 end
803 765
804 766 -- finally, use the project-specific config file if any
805 if cfg.project_dir then 767 if cfg.project_dir then
806 project_config_file = dir.path(cfg.project_dir, ".luarocks", config_file_name) 768 project_config_file = dir.path(cfg.project_dir, ".luarocks", config_file_name)
807 project_config_ok, err = load_config_file(cfg, platforms, project_config_file) 769 project_config_ok, err = load_config_file(cfg, platforms, project_config_file)
@@ -811,17 +773,17 @@ function cfg.init(detected, warning)
811 end 773 end
812 end 774 end
813 775
814 776 -- backwards compatibility:
815 if cfg.lua_interpreter and cfg.variables.LUA_BINDIR and not cfg.variables.LUA then 777 if cfg.lua_interpreter and cfg.variables.LUA_BINDIR and not cfg.variables.LUA then
816 cfg.variables.LUA = dir.path(cfg.variables.LUA_BINDIR, cfg.lua_interpreter) 778 cfg.variables.LUA = dir.path(cfg.variables.LUA_BINDIR, cfg.lua_interpreter)
817 end 779 end
818 780
781 ----------------------------------------
782 -- Config files are loaded.
783 -- Let's finish up the cfg table.
784 ----------------------------------------
819 785
820 786 -- Settings given via the CLI (i.e. --lua-dir) take precedence over config files.
821
822
823
824
825 cfg.project_dir = detected.given_project_dir or cfg.project_dir 787 cfg.project_dir = detected.given_project_dir or cfg.project_dir
826 cfg.lua_version = detected.given_lua_version or cfg.lua_version 788 cfg.lua_version = detected.given_lua_version or cfg.lua_version
827 if detected.given_lua_dir then 789 if detected.given_lua_dir then
@@ -832,21 +794,21 @@ function cfg.init(detected, warning)
832 cfg.variables.LUA_INCDIR = nil 794 cfg.variables.LUA_INCDIR = nil
833 end 795 end
834 796
835 797 -- Build a default list of rocks trees if not given
836 if cfg.rocks_trees == nil then 798 if cfg.rocks_trees == nil then
837 cfg.rocks_trees = {} 799 cfg.rocks_trees = {}
838 if cfg.home_tree then 800 if cfg.home_tree then
839 table.insert(cfg.rocks_trees, { name = "user", root = cfg.home_tree }) 801 table.insert(cfg.rocks_trees, { name = "user", root = cfg.home_tree } )
840 end 802 end
841 if hardcoded.PREFIX and hardcoded.PREFIX ~= cfg.home_tree then 803 if hardcoded.PREFIX and hardcoded.PREFIX ~= cfg.home_tree then
842 table.insert(cfg.rocks_trees, { name = "system", root = hardcoded.PREFIX }) 804 table.insert(cfg.rocks_trees, { name = "system", root = hardcoded.PREFIX } )
843 end 805 end
844 end 806 end
845 807
846 local defaults = make_defaults(cfg.lua_version, processor, platforms, cfg.home) 808 local defaults = make_defaults(cfg.lua_version, processor, platforms, cfg.home)
847 809
848 if platforms.windows and hardcoded.WIN_TOOLS then 810 if platforms.windows and hardcoded.WIN_TOOLS then
849 local tools = { "SEVENZ", "CP", "FIND", "LS", "MD5SUM", "WGET" } 811 local tools = { "SEVENZ", "CP", "FIND", "LS", "MD5SUM", "WGET", }
850 for _, tool in ipairs(tools) do 812 for _, tool in ipairs(tools) do
851 defaults.variables[tool] = '"' .. dir.path(hardcoded.WIN_TOOLS, defaults.variables[tool] .. '.exe') .. '"' 813 defaults.variables[tool] = '"' .. dir.path(hardcoded.WIN_TOOLS, defaults.variables[tool] .. '.exe') .. '"'
852 end 814 end
@@ -854,8 +816,8 @@ function cfg.init(detected, warning)
854 defaults.fs_use_modules = true 816 defaults.fs_use_modules = true
855 end 817 end
856 818
857 819 -- if only cfg.variables.LUA is given in config files,
858 820 -- derive LUA_BINDIR and LUA_DIR from them.
859 if cfg.variables.LUA and not cfg.variables.LUA_BINDIR then 821 if cfg.variables.LUA and not cfg.variables.LUA_BINDIR then
860 cfg.variables.LUA_BINDIR = cfg.variables.LUA:match("^(.*)[\\/][^\\/]*$") 822 cfg.variables.LUA_BINDIR = cfg.variables.LUA:match("^(.*)[\\/][^\\/]*$")
861 if not cfg.variables.LUA_DIR then 823 if not cfg.variables.LUA_DIR then
@@ -865,7 +827,7 @@ function cfg.init(detected, warning)
865 827
866 use_defaults(cfg, defaults) 828 use_defaults(cfg, defaults)
867 829
868 cfg.user_agent = "LuaRocks/" .. cfg.program_version .. " " .. cfg.arch 830 cfg.user_agent = "LuaRocks/"..cfg.program_version.." "..cfg.arch
869 831
870 cfg.config_files = { 832 cfg.config_files = {
871 project = cfg.project_dir and { 833 project = cfg.project_dir and {
@@ -880,19 +842,19 @@ function cfg.init(detected, warning)
880 file = home_config_file, 842 file = home_config_file,
881 found = not not home_config_ok, 843 found = not not home_config_ok,
882 }, 844 },
883 nearest = project_config_ok and 845 nearest = project_config_ok
884 project_config_file or 846 and project_config_file
885 (home_config_ok and 847 or (home_config_ok
886 home_config_file or 848 and home_config_file
887 sys_config_file), 849 or sys_config_file),
888 } 850 }
889 851
890 cfg.cache = {} 852 cfg.cache = {}
891 853
892 854 ----------------------------------------
893 855 -- Attributes of cfg are set.
894 856 -- Let's add some methods.
895 857 ----------------------------------------
896 858
897 do 859 do
898 local function make_paths_from_tree(tree) 860 local function make_paths_from_tree(tree)
@@ -913,15 +875,15 @@ function cfg.init(detected, warning)
913 local new_path, new_cpath, new_bin = {}, {}, {} 875 local new_path, new_cpath, new_bin = {}, {}, {}
914 local function add_tree_to_paths(tree) 876 local function add_tree_to_paths(tree)
915 local lua_path, lib_path, bin_path = make_paths_from_tree(tree) 877 local lua_path, lib_path, bin_path = make_paths_from_tree(tree)
916 table.insert(new_path, dir.path(lua_path, "?.lua")) 878 table.insert(new_path, dir.path(lua_path, "?.lua"))
917 table.insert(new_path, dir.path(lua_path, "?", "init.lua")) 879 table.insert(new_path, dir.path(lua_path, "?", "init.lua"))
918 table.insert(new_cpath, dir.path(lib_path, "?." .. cfg.lib_extension)) 880 table.insert(new_cpath, dir.path(lib_path, "?."..cfg.lib_extension))
919 table.insert(new_bin, bin_path) 881 table.insert(new_bin, bin_path)
920 end 882 end
921 if current then 883 if current then
922 add_tree_to_paths(current) 884 add_tree_to_paths(current)
923 end 885 end
924 for _, tree in ipairs(cfg.rocks_trees) do 886 for _,tree in ipairs(cfg.rocks_trees) do
925 add_tree_to_paths(tree) 887 add_tree_to_paths(tree)
926 end 888 end
927 return table.concat(new_path, ";"), table.concat(new_cpath, ";"), table.concat(new_bin, cfg.export_path_separator) 889 return table.concat(new_path, ";"), table.concat(new_cpath, ";"), table.concat(new_bin, cfg.export_path_separator)
@@ -934,15 +896,15 @@ function cfg.init(detected, warning)
934 package.cpath = util.cleanup_path(package.cpath .. ";" .. lr_cpath, ";", cfg.lua_version, true) 896 package.cpath = util.cleanup_path(package.cpath .. ";" .. lr_cpath, ";", cfg.lua_version, true)
935 end 897 end
936 898
937 899 --- Check if platform was detected
938 900 -- @param name string: The platform name to check.
939 901 -- @return boolean: true if LuaRocks is currently running on queried platform.
940 function cfg.is_platform(name) 902 function cfg.is_platform(name)
941 assert(type(name) == "string") 903 assert(type(name) == "string")
942 return platforms[name] 904 return platforms[name]
943 end 905 end
944 906
945 907 -- @param direction (optional) "least-specific-first" (default) or "most-specific-first"
946 function cfg.each_platform(direction) 908 function cfg.each_platform(direction)
947 direction = direction or "least-specific-first" 909 direction = direction or "least-specific-first"
948 local i, delta 910 local i, delta
@@ -965,7 +927,7 @@ function cfg.init(detected, warning)
965 927
966 function cfg.print_platforms() 928 function cfg.print_platforms()
967 local platform_keys = {} 929 local platform_keys = {}
968 for k, _ in pairs(platforms) do 930 for k,_ in pairs(platforms) do
969 table.insert(platform_keys, k) 931 table.insert(platform_keys, k)
970 end 932 end
971 table.sort(platform_keys) 933 table.sort(platform_keys)
diff --git a/src/luarocks/core/cfg.tl b/src/luarocks/core/cfg.tl
deleted file mode 100644
index 3613e9dc..00000000
--- a/src/luarocks/core/cfg.tl
+++ /dev/null
@@ -1,982 +0,0 @@
1
2--- Configuration for LuaRocks.
3-- Tries to load the user's configuration file and
4-- defines defaults for unset values. See the
5-- <a href="http://luarocks.org/en/Config_file_format">config
6-- file format documentation</a> for details.
7--
8-- End-users shouldn't edit this file. They can override any defaults
9-- set in this file using their system-wide or user-specific configuration
10-- files. Run `luarocks` with no arguments to see the locations of
11-- these files in your platform.
12
13local table, pairs, require, os, pcall, ipairs, package, type, assert = --!
14 table, pairs, require, os, pcall, ipairs, package, type, assert
15
16local dir = require("luarocks.core.dir") --!
17local util = require("luarocks.core.util")
18local persist = require("luarocks.core.persist")
19local sysdetect = require("luarocks.core.sysdetect")
20local vers = require("luarocks.core.vers")
21
22local record cfg
23 detect_sysconfdir: function(): string
24 make_platforms: function(system: string): {any: boolean}
25 make_defaults: function(lua_version: string, target_cpu: string, platforms: {any: any}, home: string): {any: any}
26 use_defaults: function(cfg, defaults: {any: any})
27 --!
28end
29
30--------------------------------------------------------------------------------
31
32local program_version = "dev" --!
33
34local is_windows = package.config:sub(1,1) == "\\" --!
35
36-- Set order for platform overrides.
37-- More general platform identifiers should be listed first,
38-- more specific ones later.
39local platform_order = {
40 -- Unixes
41 "unix",
42 "bsd",
43 "solaris",
44 "netbsd",
45 "openbsd",
46 "freebsd",
47 "dragonfly",
48 "linux",
49 "macosx",
50 "cygwin",
51 "msys",
52 "haiku",
53 -- Windows
54 "windows",
55 "win32",
56 "mingw",
57 "mingw32",
58 "msys2_mingw_w64",
59}
60
61local type Config = record --!
62 home: any
63 lua_version: any
64 target_cpu: any
65 variables: {any: any}
66 os_getenv: any
67 rocks_trees: any
68 rocks_servers: any
69 dump_env: function()
70end
71
72local function detect_sysconfdir()
73 if not debug then
74 return
75 end
76 local src = debug.getinfo(1, "S").source
77 if not src then
78 return
79 end
80 src = dir.normalize(src)
81 if src:sub(1, 1) == "@" then
82 src = src:sub(2)
83 end
84 local basedir = src:match("^(.*)[\\/]luarocks[\\/]core[\\/]cfg.lua$")
85 if not basedir then
86 return
87 end
88 -- If installed in a Unix-like tree, use a Unix-like sysconfdir
89 local installdir = basedir:match("^(.*)[\\/]share[\\/]lua[\\/][^/]*$")
90 if installdir then
91 if installdir == "/usr" then
92 return "/etc/luarocks" --!
93 end
94 return dir.path(installdir, "etc", "luarocks")
95 end
96 -- Otherwise, use base directory of sources
97 return basedir
98end
99
100-- local load_config_file --!
101do
102 -- Create global environment for the config files;
103 local function env_for_config_file(cfg: Config, platforms: {any: any}): {any: any} --!
104 local platforms_copy = {}
105 for k,v in pairs(platforms) do
106 platforms_copy[k] = v
107 end
108
109 local e: {any: any} --!
110 e = {
111 home = cfg.home,
112 lua_version = cfg.lua_version,
113 platforms = platforms_copy,
114 processor = cfg.target_cpu, -- remains for compat reasons
115 target_cpu = cfg.target_cpu, -- replaces `processor`
116 os_getenv = os.getenv,
117 variables = cfg.variables or {},
118 dump_env = function()
119 -- debug function, calling it from a config file will show all
120 -- available globals to that config file
121 print(util.show_table(e, "global environment"))
122 end,
123 }
124 return e
125 end
126
127 -- Merge values from config files read into the `cfg` table
128 local function merge_overrides(cfg: Config, overrides: Config)
129 -- remove some stuff we do not want to integrate
130 overrides.os_getenv = nil
131 overrides.dump_env = nil
132 -- remove tables to be copied verbatim instead of deeply merged
133 if overrides.rocks_trees then cfg.rocks_trees = nil end
134 if overrides.rocks_servers then cfg.rocks_servers = nil end
135 -- perform actual merge
136 util.deep_merge(cfg, overrides)
137 end
138
139 local function update_platforms(platforms: {any: any}, overrides: {any: any})
140 if overrides[1] then
141 for k, _ in pairs(platforms) do
142 platforms[k] = nil
143 end
144 for _, v in ipairs(overrides) do
145 platforms[v] = true
146 end
147 -- set some fallback default in case the user provides an incomplete configuration.
148 -- LuaRocks expects a set of defaults to be available.
149 if not (platforms.unix or platforms.windows) then
150 platforms[is_windows and "windows" or "unix"] = true
151 end
152 end
153 end
154
155 -- Load config file and merge its contents into the `cfg` module table.
156 -- @return filepath of successfully loaded file or nil if it failed
157 local load_config_file = function(cfg: Config, platforms: {any: any}, filepath: string): string --!
158 local result, err, errcode = persist.load_into_table(filepath, env_for_config_file(cfg, platforms))
159 if (not result) and errcode ~= "open" then
160 -- errcode is either "load" or "run"; bad config file, so error out
161 return nil, err, "config"
162 end
163 if result then
164 -- success in loading and running, merge contents and exit
165 update_platforms(platforms, result.platforms)
166 result.platforms = nil
167 merge_overrides(cfg, result)
168 return filepath
169 end
170 return nil -- nothing was loaded
171 end
172end
173
174local platform_sets = {
175 freebsd = { unix = true, bsd = true, freebsd = true },
176 openbsd = { unix = true, bsd = true, openbsd = true },
177 dragonfly = { unix = true, bsd = true, dragonfly = true },
178 solaris = { unix = true, solaris = true },
179 windows = { windows = true, win32 = true },
180 cygwin = { unix = true, cygwin = true },
181 macosx = { unix = true, bsd = true, macosx = true, macos = true },
182 netbsd = { unix = true, bsd = true, netbsd = true },
183 haiku = { unix = true, haiku = true },
184 linux = { unix = true, linux = true },
185 mingw = { windows = true, win32 = true, mingw32 = true, mingw = true },
186 msys = { unix = true, cygwin = true, msys = true },
187 msys2_mingw_w64 = { windows = true, win32 = true, mingw32 = true, mingw = true, msys = true, msys2_mingw_w64 = true },
188}
189
190local function make_platforms(system: string): {any: boolean} --! :System
191 -- fallback to Unix in unknown systems
192 return platform_sets[system] or { unix = true }
193end
194
195--------------------------------------------------------------------------------
196
197local function make_defaults(lua_version: string, target_cpu: string, platforms: {any: any}, home: string): {any: any} --!
198
199 -- Configure defaults:
200 local defaults = {
201
202 local_by_default = false,
203 accept_unknown_fields = false,
204 fs_use_modules = true,
205 hooks_enabled = true,
206 deps_mode = "one",
207 no_manifest = false,
208 check_certificates = false,
209
210 cache_timeout = 60,
211 cache_fail_timeout = 86400,
212
213 lua_modules_path = dir.path("share", "lua", lua_version),
214 lib_modules_path = dir.path("lib", "lua", lua_version),
215 rocks_subdir = dir.path("lib", "luarocks", "rocks-"..lua_version),
216
217 arch = "unknown",
218 lib_extension = "unknown",
219 external_lib_extension = "unknown", --?
220 static_lib_extension = "unknown", --?
221 obj_extension = "unknown",
222 link_lua_explicitly = false,
223
224 external_deps_dirs = {}, --?
225 external_deps_patterns = {}, --?
226 runtime_external_deps_patterns = {}, --?
227
228 export_path_separator = "", --?
229 wrapper_suffix = "", --?
230
231
232 rocks_servers = {
233 {
234 "https://luarocks.org",
235 "https://raw.githubusercontent.com/rocks-moonscript-org/moonrocks-mirror/master/",
236 "https://loadk.com/luarocks/",
237 }
238 },
239 disabled_servers = {},
240
241 upload = {
242 server = "https://luarocks.org",
243 tool_version = "1.0.0",
244 api_version = "1",
245 },
246
247 lua_extension = "lua",
248 connection_timeout = 30, -- 0 = no timeout
249
250 makefile = "", --?
251 local_cache = "" , --?
252 web_browser = "", --?
253 cmake_generator = "", --?
254 gcc_rpath = false, --?
255
256 variables = {
257 MAKE = os.getenv("MAKE") or "make",
258 CC = os.getenv("CC") or "cc",
259 LD = os.getenv("CC") or "ld",
260 AR = os.getenv("AR") or "ar",
261 RANLIB = os.getenv("RANLIB") or "ranlib",
262
263 CVS = "cvs",
264 GIT = "git",
265 SSCM = "sscm",
266 SVN = "svn",
267 HG = "hg",
268
269 GPG = "gpg",
270
271 RSYNC = "rsync",
272 WGET = "wget",
273 SCP = "scp",
274 CURL = "curl",
275
276 PWD = "pwd",
277 MKDIR = "mkdir",
278 RMDIR = "rmdir",
279 CP = "cp",
280 LN = "ln",
281 LS = "ls",
282 RM = "rm",
283 FIND = "find",
284 CHMOD = "chmod",
285 ICACLS = "icacls",
286 MKTEMP = "mktemp",
287
288 ZIP = "zip",
289 UNZIP = "unzip -n",
290 GUNZIP = "gunzip",
291 BUNZIP2 = "bunzip2",
292 TAR = "tar",
293
294 MD5SUM = "md5sum",
295 OPENSSL = "openssl",
296 MD5 = "md5",
297 TOUCH = "touch",
298
299 CMAKE = "cmake",
300 SEVENZ = "7z",
301
302 RSYNCFLAGS = "--exclude=.git -Oavz",
303 CURLNOCERTFLAG = "",
304 WGETNOCERTFLAG = "",
305
306 RC = "", --?
307 MT = "", --?
308 CFLAGS = "", --?
309 LDFLAGS = "", --?
310 LIBFLAG = "", --?
311 TEST = "", --?
312 },
313
314 external_deps_subdirs = {
315 bin = "bin",
316 lib = "lib",
317 include = "include"
318 },
319 runtime_external_deps_subdirs = {
320 bin = "bin",
321 lib = "lib",
322 include = "include"
323 },
324 }
325
326 if platforms.windows then
327
328 defaults.arch = "win32-"..target_cpu
329 defaults.lib_extension = "dll"
330 defaults.external_lib_extension = "dll"
331 defaults.static_lib_extension = "lib"
332 defaults.obj_extension = "obj"
333 defaults.external_deps_dirs = {
334 dir.path("c:", "external"),
335 dir.path("c:", "windows", "system32"),
336 }
337
338 defaults.makefile = "Makefile.win"
339 defaults.variables.PWD = "echo %cd%"
340 defaults.variables.MKDIR = "md"
341 defaults.variables.MAKE = os.getenv("MAKE") or "nmake"
342 defaults.variables.CC = os.getenv("CC") or "cl"
343 defaults.variables.RC = os.getenv("WINDRES") or "rc"
344 defaults.variables.LD = os.getenv("LINK") or "link"
345 defaults.variables.MT = os.getenv("MT") or "mt"
346 defaults.variables.AR = os.getenv("AR") or "lib"
347 defaults.variables.CFLAGS = os.getenv("CFLAGS") or "/nologo /MD /O2"
348 defaults.variables.LDFLAGS = os.getenv("LDFLAGS")
349 defaults.variables.LIBFLAG = "/nologo /dll"
350
351 defaults.external_deps_patterns = {
352 bin = { "?.exe", "?.bat" },
353 lib = { "?.lib", "lib?.lib", "?.dll", "lib?.dll" },
354 include = { "?.h" }
355 }
356 defaults.runtime_external_deps_patterns = {
357 bin = { "?.exe", "?.bat" },
358 lib = { "?.dll", "lib?.dll" },
359 include = { "?.h" }
360 }
361 defaults.export_path_separator = ";"
362 defaults.wrapper_suffix = ".bat"
363
364 local localappdata = os.getenv("LOCALAPPDATA")
365 if not localappdata then
366 -- for Windows versions below Vista
367 localappdata = dir.path((os.getenv("USERPROFILE") or dir.path("c:", "Users", "All Users")), "Local Settings", "Application Data")
368 end
369 defaults.local_cache = dir.path(localappdata, "LuaRocks", "Cache")
370 defaults.web_browser = "start"
371
372 defaults.external_deps_subdirs.lib = { "lib", "", "bin" }
373 defaults.runtime_external_deps_subdirs.lib = { "lib", "", "bin" }
374 defaults.link_lua_explicitly = true
375 defaults.fs_use_modules = false
376 end
377
378 if platforms.mingw32 then
379 defaults.obj_extension = "o"
380 defaults.static_lib_extension = "a"
381 defaults.external_deps_dirs = {
382 dir.path("c:", "external"),
383 dir.path("c:", "mingw"),
384 dir.path("c:", "windows", "system32"),
385 }
386 defaults.cmake_generator = "MinGW Makefiles"
387 defaults.variables.MAKE = os.getenv("MAKE") or "mingw32-make"
388 if target_cpu == "x86_64" then
389 defaults.variables.CC = os.getenv("CC") or "x86_64-w64-mingw32-gcc"
390 defaults.variables.LD = os.getenv("CC") or "x86_64-w64-mingw32-gcc"
391 else
392 defaults.variables.CC = os.getenv("CC") or "mingw32-gcc"
393 defaults.variables.LD = os.getenv("CC") or "mingw32-gcc"
394 end
395 defaults.variables.AR = os.getenv("AR") or "ar"
396 defaults.variables.RC = os.getenv("WINDRES") or "windres"
397 defaults.variables.RANLIB = os.getenv("RANLIB") or "ranlib"
398 defaults.variables.CFLAGS = os.getenv("CFLAGS") or "-O2"
399 defaults.variables.LDFLAGS = os.getenv("LDFLAGS")
400 defaults.variables.LIBFLAG = "-shared"
401 defaults.makefile = "Makefile"
402 defaults.external_deps_patterns = {
403 bin = { "?.exe", "?.bat" },
404 -- mingw lookup list from http://stackoverflow.com/a/15853231/1793220
405 -- ...should we keep ?.lib at the end? It's not in the above list.
406 lib = { "lib?.dll.a", "?.dll.a", "lib?.a", "cyg?.dll", "lib?.dll", "?.dll", "?.lib" },
407 include = { "?.h" }
408 }
409 defaults.runtime_external_deps_patterns = {
410 bin = { "?.exe", "?.bat" },
411 lib = { "cyg?.dll", "?.dll", "lib?.dll" },
412 include = { "?.h" }
413 }
414 defaults.link_lua_explicitly = true
415 end
416
417 if platforms.unix then
418 defaults.lib_extension = "so"
419 defaults.static_lib_extension = "a"
420 defaults.external_lib_extension = "so"
421 defaults.obj_extension = "o"
422 defaults.external_deps_dirs = { "/usr/local", "/usr", "/" }
423
424 defaults.variables.CFLAGS = os.getenv("CFLAGS") or "-O2"
425 -- we pass -fPIC via CFLAGS because of old Makefile-based Lua projects
426 -- which didn't have -fPIC in their Makefiles but which honor CFLAGS
427 if not defaults.variables.CFLAGS:match("-fPIC") then
428 defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC"
429 end
430
431 defaults.variables.LDFLAGS = os.getenv("LDFLAGS")
432
433 defaults.cmake_generator = "Unix Makefiles"
434 defaults.variables.CC = os.getenv("CC") or "gcc"
435 defaults.variables.LD = os.getenv("CC") or "gcc"
436 defaults.gcc_rpath = true
437 defaults.variables.LIBFLAG = "-shared"
438 defaults.variables.TEST = "test"
439
440 defaults.external_deps_patterns = {
441 bin = { "?" },
442 lib = { "lib?.a", "lib?.so", "lib?.so.*" },
443 include = { "?.h" }
444 }
445 defaults.runtime_external_deps_patterns = {
446 bin = { "?" },
447 lib = { "lib?.so", "lib?.so.*" },
448 include = { "?.h" }
449 }
450 defaults.export_path_separator = ":"
451 defaults.wrapper_suffix = ""
452 local xdg_cache_home = os.getenv("XDG_CACHE_HOME") or home.."/.cache"
453 defaults.local_cache = xdg_cache_home.."/luarocks"
454 defaults.web_browser = "xdg-open"
455 end
456
457 if platforms.cygwin then
458 defaults.lib_extension = "so" -- can be overridden in the config file for mingw builds
459 defaults.arch = "cygwin-"..target_cpu
460 defaults.cmake_generator = "Unix Makefiles"
461 defaults.variables.CC = "echo -llua | xargs " .. (os.getenv("CC") or "gcc")
462 defaults.variables.LD = "echo -llua | xargs " .. (os.getenv("CC") or "gcc")
463 defaults.variables.LIBFLAG = "-shared"
464 defaults.link_lua_explicitly = true
465 end
466
467 if platforms.msys then
468 -- msys is basically cygwin made out of mingw, meaning the subsytem is unixish
469 -- enough, yet we can freely mix with native win32
470 defaults.external_deps_patterns = {
471 bin = { "?.exe", "?.bat", "?" },
472 lib = { "lib?.so", "lib?.so.*", "lib?.dll.a", "?.dll.a",
473 "lib?.a", "lib?.dll", "?.dll", "?.lib" },
474 include = { "?.h" }
475 }
476 defaults.runtime_external_deps_patterns = {
477 bin = { "?.exe", "?.bat" },
478 lib = { "lib?.so", "?.dll", "lib?.dll" },
479 include = { "?.h" }
480 }
481 if platforms.mingw then
482 -- MSYS2 can build Windows programs that depend on
483 -- msys-2.0.dll (based on Cygwin) but MSYS2 is also designed
484 -- for building native Windows programs by MinGW. These
485 -- programs don't depend on msys-2.0.dll.
486 local pipe = io.popen("cygpath --windows %MINGW_PREFIX%")
487 local mingw_prefix = pipe:read("*l")
488 pipe:close()
489 defaults.external_deps_dirs = {
490 mingw_prefix,
491 dir.path("c:", "windows", "system32"),
492 }
493 defaults.makefile = "Makefile"
494 defaults.cmake_generator = "MSYS Makefiles"
495 defaults.local_cache = dir.path(home, ".cache", "luarocks")
496 defaults.variables.MAKE = os.getenv("MAKE") or "make"
497 defaults.variables.CC = os.getenv("CC") or "gcc"
498 defaults.variables.RC = os.getenv("WINDRES") or "windres"
499 defaults.variables.LD = os.getenv("CC") or "gcc"
500 defaults.variables.MT = os.getenv("MT") or nil
501 defaults.variables.AR = os.getenv("AR") or "ar"
502 defaults.variables.RANLIB = os.getenv("RANLIB") or "ranlib"
503
504 defaults.variables.CFLAGS = os.getenv("CFLAGS") or "-O2 -fPIC"
505 if not defaults.variables.CFLAGS:match("-fPIC") then
506 defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC"
507 end
508
509 defaults.variables.LIBFLAG = "-shared"
510 end
511 end
512
513 if platforms.bsd then
514 defaults.variables.MAKE = "gmake"
515 defaults.gcc_rpath = false
516 defaults.variables.CC = os.getenv("CC") or "cc"
517 defaults.variables.LD = os.getenv("CC") or defaults.variables.CC
518 end
519
520 if platforms.macosx then
521 defaults.variables.MAKE = os.getenv("MAKE") or "make"
522 defaults.external_lib_extension = "dylib"
523 defaults.arch = "macosx-"..target_cpu
524 defaults.variables.LIBFLAG = "-bundle -undefined dynamic_lookup -all_load"
525 local version = util.popen_read("sw_vers -productVersion")
526 if not (version:match("^%d+%.%d+%.%d+$") or version:match("^%d+%.%d+$")) then
527 version = "10.3"
528 end
529 version = vers.parse_version(version)
530 if version >= vers.parse_version("11.0") then
531 version = vers.parse_version("11.0")
532 elseif version >= vers.parse_version("10.10") then
533 version = vers.parse_version("10.8")
534 elseif version >= vers.parse_version("10.5") then
535 version = vers.parse_version("10.5")
536 else
537 defaults.gcc_rpath = false
538 end
539 defaults.variables.CC = "env MACOSX_DEPLOYMENT_TARGET="..tostring(version).." gcc"
540 defaults.variables.LD = "env MACOSX_DEPLOYMENT_TARGET="..tostring(version).." gcc"
541 defaults.web_browser = "open"
542
543 -- XCode SDK
544 local sdk_path = util.popen_read("xcrun --show-sdk-path 2>/dev/null")
545 if sdk_path then
546 table.insert(defaults.external_deps_dirs, sdk_path .. "/usr")
547 table.insert(defaults.external_deps_patterns.lib, 1, "lib?.tbd")
548 table.insert(defaults.runtime_external_deps_patterns.lib, 1, "lib?.tbd")
549 end
550
551 -- Homebrew
552 table.insert(defaults.external_deps_dirs, "/usr/local/opt")
553 defaults.external_deps_subdirs.lib = { "lib", "" }
554 defaults.runtime_external_deps_subdirs.lib = { "lib", "" }
555 table.insert(defaults.external_deps_patterns.lib, 1, "/?/lib/lib?.dylib")
556 table.insert(defaults.runtime_external_deps_patterns.lib, 1, "/?/lib/lib?.dylib")
557 end
558
559 if platforms.linux then
560 defaults.arch = "linux-"..target_cpu
561
562 local gcc_arch = util.popen_read("gcc -print-multiarch 2>/dev/null")
563 if gcc_arch and gcc_arch ~= "" then
564 defaults.external_deps_subdirs.lib = { "lib/" .. gcc_arch, "lib64", "lib" }
565 defaults.runtime_external_deps_subdirs.lib = { "lib/" .. gcc_arch, "lib64", "lib" }
566 else
567 defaults.external_deps_subdirs.lib = { "lib64", "lib" }
568 defaults.runtime_external_deps_subdirs.lib = { "lib64", "lib" }
569 end
570 end
571
572 if platforms.freebsd then
573 defaults.arch = "freebsd-"..target_cpu
574 elseif platforms.dragonfly then
575 defaults.arch = "dragonfly-"..target_cpu
576 elseif platforms.openbsd then
577 defaults.arch = "openbsd-"..target_cpu
578 elseif platforms.netbsd then
579 defaults.arch = "netbsd-"..target_cpu
580 elseif platforms.solaris then
581 defaults.arch = "solaris-"..target_cpu
582 defaults.variables.MAKE = "gmake"
583 end
584
585 -- Expose some more values detected by LuaRocks for use by rockspec authors.
586 defaults.variables.LIB_EXTENSION = defaults.lib_extension
587 defaults.variables.OBJ_EXTENSION = defaults.obj_extension
588
589 return defaults
590end
591
592local function use_defaults(cfg, defaults)
593
594 -- Populate variables with values from their 'defaults' counterparts
595 -- if they were not already set by user.
596 if not cfg.variables then
597 cfg.variables = {}
598 end
599 for k,v in pairs(defaults.variables) do
600 if not cfg.variables[k] then
601 cfg.variables[k] = v
602 end
603 end
604
605 util.deep_merge_under(cfg, defaults)
606
607 -- FIXME get rid of this
608 if not cfg.check_certificates then
609 cfg.variables.CURLNOCERTFLAG = "-k"
610 cfg.variables.WGETNOCERTFLAG = "--no-check-certificate"
611 end
612end
613
614--------------------------------------------------------------------------------
615
616local cfg = {}
617
618--- Initializes the LuaRocks configuration for variables, paths
619-- and OS detection.
620-- @param detected table containing information detected about the
621-- environment. All fields below are optional:
622-- * lua_version (in x.y format, e.g. "5.3")
623-- * lua_bindir (e.g. "/usr/local/bin")
624-- * lua_dir (e.g. "/usr/local")
625-- * lua (e.g. "/usr/local/bin/lua-5.3")
626-- * project_dir (a string with the path of the project directory
627-- when using per-project environments, as created with `luarocks init`)
628-- @param warning a logging function for warnings that takes a string
629-- @return true on success; nil and an error message on failure.
630function cfg.init(detected, warning)
631 detected = detected or {}
632
633 local exit_ok = true
634 local exit_err = nil
635 local exit_what = nil
636
637 local hc_ok, hardcoded = pcall(require, "luarocks.core.hardcoded")
638 if not hc_ok then
639 hardcoded = {}
640 end
641
642 local init = cfg.init
643
644 ----------------------------------------
645 -- Reset the cfg table.
646 ----------------------------------------
647
648 for k, _ in pairs(cfg) do
649 cfg[k] = nil
650 end
651
652 cfg.program_version = program_version
653
654 if hardcoded.IS_BINARY then
655 cfg.is_binary = true
656 end
657
658 -- Use detected values as defaults, overridable via config files or CLI args
659
660 local hardcoded_lua = hardcoded.LUA
661 local hardcoded_lua_dir = hardcoded.LUA_DIR
662 local hardcoded_lua_bindir = hardcoded.LUA_BINDIR
663 local hardcoded_lua_incdir = hardcoded.LUA_INCDIR
664 local hardcoded_lua_libdir = hardcoded.LUA_LIBDIR
665 local hardcoded_lua_version = hardcoded.LUA_VERSION or _VERSION:sub(5)
666
667 -- if --lua-version or --lua-dir are passed from the CLI,
668 -- don't use the hardcoded paths at all
669 if detected.given_lua_version or detected.given_lua_dir then
670 hardcoded_lua = nil
671 hardcoded_lua_dir = nil
672 hardcoded_lua_bindir = nil
673 hardcoded_lua_incdir = nil
674 hardcoded_lua_libdir = nil
675 hardcoded_lua_version = nil
676 end
677
678 cfg.lua_version = detected.lua_version or hardcoded_lua_version
679 cfg.project_dir = (not hardcoded.FORCE_CONFIG) and detected.project_dir
680
681 do
682 local lua = detected.lua or hardcoded_lua
683 local lua_dir = detected.lua_dir or hardcoded_lua_dir
684 local lua_bindir = detected.lua_bindir or hardcoded_lua_bindir
685 cfg.variables = {
686 LUA = lua,
687 LUA_DIR = lua_dir,
688 LUA_BINDIR = lua_bindir,
689 LUA_LIBDIR = hardcoded_lua_libdir,
690 LUA_INCDIR = hardcoded_lua_incdir,
691 }
692 end
693
694 cfg.init = init
695
696 ----------------------------------------
697 -- System detection.
698 ----------------------------------------
699
700 -- A proper build of LuaRocks will hardcode the system
701 -- and proc values with hardcoded.SYSTEM and hardcoded.PROCESSOR.
702 -- If that is not available, we try to identify the system.
703 local system, processor = sysdetect.detect()
704 if hardcoded.SYSTEM then
705 system = hardcoded.SYSTEM
706 end
707 if hardcoded.PROCESSOR then
708 processor = hardcoded.PROCESSOR
709 end
710
711 if system == "windows" then
712 if os.getenv("VCINSTALLDIR") then
713 -- running from the Development Command prompt for VS 2017
714 system = "windows"
715 else
716 local msystem = os.getenv("MSYSTEM")
717 if msystem == nil then
718 system = "mingw"
719 elseif msystem == "MSYS" then
720 system = "msys"
721 else
722 -- MINGW32 or MINGW64
723 system = "msys2_mingw_w64"
724 end
725 end
726 end
727
728 cfg.target_cpu = processor
729
730 local platforms = make_platforms(system)
731
732 ----------------------------------------
733 -- Platform is determined.
734 -- Let's load the config files.
735 ----------------------------------------
736
737 local sys_config_file
738 local home_config_file
739 local project_config_file
740
741 local config_file_name = "config-"..cfg.lua_version..".lua"
742
743 do
744 local sysconfdir = os.getenv("LUAROCKS_SYSCONFDIR") or hardcoded.SYSCONFDIR
745 if platforms.windows and not platforms.msys2_mingw_w64 then
746 cfg.home = os.getenv("APPDATA") or "c:"
747 cfg.home_tree = dir.path(cfg.home, "luarocks")
748 cfg.sysconfdir = sysconfdir or dir.path((os.getenv("PROGRAMFILES") or "c:"), "luarocks")
749 else
750 cfg.home = os.getenv("HOME") or ""
751 cfg.home_tree = dir.path(cfg.home, ".luarocks")
752 cfg.sysconfdir = sysconfdir or detect_sysconfdir() or "/etc/luarocks"
753 end
754 end
755
756 -- Load system configuration file
757 sys_config_file = dir.path(cfg.sysconfdir, config_file_name)
758 local sys_config_ok, err = load_config_file(cfg, platforms, sys_config_file)
759 if err then
760 exit_ok, exit_err, exit_what = nil, err, "config"
761 end
762
763 -- Load user configuration file (if allowed)
764 local home_config_ok
765 local project_config_ok
766 if not hardcoded.FORCE_CONFIG then
767 local env_var = "LUAROCKS_CONFIG_" .. cfg.lua_version:gsub("%.", "_")
768 local env_value = os.getenv(env_var)
769 if not env_value then
770 env_var = "LUAROCKS_CONFIG"
771 env_value = os.getenv(env_var)
772 end
773 -- first try environment provided file, so we can explicitly warn when it is missing
774 if env_value then
775 local env_ok, err = load_config_file(cfg, platforms, env_value)
776 if err then
777 exit_ok, exit_err, exit_what = nil, err, "config"
778 elseif warning and not env_ok then
779 warning("Warning: could not load configuration file `"..env_value.."` given in environment variable "..env_var.."\n")
780 end
781 if env_ok then
782 home_config_ok = true
783 home_config_file = env_value
784 end
785 end
786
787 -- try XDG config home
788 if platforms.unix and not home_config_ok then
789 local xdg_config_home = os.getenv("XDG_CONFIG_HOME") or dir.path(cfg.home, ".config")
790 cfg.homeconfdir = dir.path(xdg_config_home, "luarocks")
791 home_config_file = dir.path(cfg.homeconfdir, config_file_name)
792 home_config_ok, err = load_config_file(cfg, platforms, home_config_file)
793 if err then
794 exit_ok, exit_err, exit_what = nil, err, "config"
795 end
796 end
797
798 -- try the alternative defaults if there was no environment specified file or it didn't work
799 if not home_config_ok then
800 cfg.homeconfdir = cfg.home_tree
801 home_config_file = dir.path(cfg.homeconfdir, config_file_name)
802 home_config_ok, err = load_config_file(cfg, platforms, home_config_file)
803 if err then
804 exit_ok, exit_err, exit_what = nil, err, "config"
805 end
806 end
807
808 -- finally, use the project-specific config file if any
809 if cfg.project_dir then
810 project_config_file = dir.path(cfg.project_dir, ".luarocks", config_file_name)
811 project_config_ok, err = load_config_file(cfg, platforms, project_config_file)
812 if err then
813 exit_ok, exit_err, exit_what = nil, err, "config"
814 end
815 end
816 end
817
818 -- backwards compatibility:
819 if cfg.lua_interpreter and cfg.variables.LUA_BINDIR and not cfg.variables.LUA then
820 cfg.variables.LUA = dir.path(cfg.variables.LUA_BINDIR, cfg.lua_interpreter)
821 end
822
823 ----------------------------------------
824 -- Config files are loaded.
825 -- Let's finish up the cfg table.
826 ----------------------------------------
827
828 -- Settings given via the CLI (i.e. --lua-dir) take precedence over config files.
829 cfg.project_dir = detected.given_project_dir or cfg.project_dir
830 cfg.lua_version = detected.given_lua_version or cfg.lua_version
831 if detected.given_lua_dir then
832 cfg.variables.LUA = detected.lua
833 cfg.variables.LUA_DIR = detected.given_lua_dir
834 cfg.variables.LUA_BINDIR = detected.lua_bindir
835 cfg.variables.LUA_LIBDIR = nil
836 cfg.variables.LUA_INCDIR = nil
837 end
838
839 -- Build a default list of rocks trees if not given
840 if cfg.rocks_trees == nil then
841 cfg.rocks_trees = {}
842 if cfg.home_tree then
843 table.insert(cfg.rocks_trees, { name = "user", root = cfg.home_tree } )
844 end
845 if hardcoded.PREFIX and hardcoded.PREFIX ~= cfg.home_tree then
846 table.insert(cfg.rocks_trees, { name = "system", root = hardcoded.PREFIX } )
847 end
848 end
849
850 local defaults = make_defaults(cfg.lua_version, processor, platforms, cfg.home)
851
852 if platforms.windows and hardcoded.WIN_TOOLS then
853 local tools = { "SEVENZ", "CP", "FIND", "LS", "MD5SUM", "WGET", }
854 for _, tool in ipairs(tools) do
855 defaults.variables[tool] = '"' .. dir.path(hardcoded.WIN_TOOLS, defaults.variables[tool] .. '.exe') .. '"'
856 end
857 else
858 defaults.fs_use_modules = true
859 end
860
861 -- if only cfg.variables.LUA is given in config files,
862 -- derive LUA_BINDIR and LUA_DIR from them.
863 if cfg.variables.LUA and not cfg.variables.LUA_BINDIR then
864 cfg.variables.LUA_BINDIR = cfg.variables.LUA:match("^(.*)[\\/][^\\/]*$")
865 if not cfg.variables.LUA_DIR then
866 cfg.variables.LUA_DIR = cfg.variables.LUA_BINDIR:gsub("[\\/]bin$", "") or cfg.variables.LUA_BINDIR
867 end
868 end
869
870 use_defaults(cfg, defaults)
871
872 cfg.user_agent = "LuaRocks/"..cfg.program_version.." "..cfg.arch
873
874 cfg.config_files = {
875 project = cfg.project_dir and {
876 file = project_config_file,
877 found = not not project_config_ok,
878 },
879 system = {
880 file = sys_config_file,
881 found = not not sys_config_ok,
882 },
883 user = {
884 file = home_config_file,
885 found = not not home_config_ok,
886 },
887 nearest = project_config_ok
888 and project_config_file
889 or (home_config_ok
890 and home_config_file
891 or sys_config_file),
892 }
893
894 cfg.cache = {}
895
896 ----------------------------------------
897 -- Attributes of cfg are set.
898 -- Let's add some methods.
899 ----------------------------------------
900
901 do
902 local function make_paths_from_tree(tree)
903 local lua_path, lib_path, bin_path
904 if type(tree) == "string" then
905 lua_path = dir.path(tree, cfg.lua_modules_path)
906 lib_path = dir.path(tree, cfg.lib_modules_path)
907 bin_path = dir.path(tree, "bin")
908 else
909 lua_path = tree.lua_dir or dir.path(tree.root, cfg.lua_modules_path)
910 lib_path = tree.lib_dir or dir.path(tree.root, cfg.lib_modules_path)
911 bin_path = tree.bin_dir or dir.path(tree.root, "bin")
912 end
913 return lua_path, lib_path, bin_path
914 end
915
916 function cfg.package_paths(current)
917 local new_path, new_cpath, new_bin = {}, {}, {}
918 local function add_tree_to_paths(tree)
919 local lua_path, lib_path, bin_path = make_paths_from_tree(tree)
920 table.insert(new_path, dir.path(lua_path, "?.lua"))
921 table.insert(new_path, dir.path(lua_path, "?", "init.lua"))
922 table.insert(new_cpath, dir.path(lib_path, "?."..cfg.lib_extension))
923 table.insert(new_bin, bin_path)
924 end
925 if current then
926 add_tree_to_paths(current)
927 end
928 for _,tree in ipairs(cfg.rocks_trees) do
929 add_tree_to_paths(tree)
930 end
931 return table.concat(new_path, ";"), table.concat(new_cpath, ";"), table.concat(new_bin, cfg.export_path_separator)
932 end
933 end
934
935 function cfg.init_package_paths()
936 local lr_path, lr_cpath, lr_bin = cfg.package_paths()
937 package.path = util.cleanup_path(package.path .. ";" .. lr_path, ";", cfg.lua_version, true)
938 package.cpath = util.cleanup_path(package.cpath .. ";" .. lr_cpath, ";", cfg.lua_version, true)
939 end
940
941 --- Check if platform was detected
942 -- @param name string: The platform name to check.
943 -- @return boolean: true if LuaRocks is currently running on queried platform.
944 function cfg.is_platform(name)
945 assert(type(name) == "string")
946 return platforms[name]
947 end
948
949 -- @param direction (optional) "least-specific-first" (default) or "most-specific-first"
950 function cfg.each_platform(direction)
951 direction = direction or "least-specific-first"
952 local i, delta
953 if direction == "least-specific-first" then
954 i = 0
955 delta = 1
956 else
957 i = #platform_order + 1
958 delta = -1
959 end
960 return function()
961 local p
962 repeat
963 i = i + delta
964 p = platform_order[i]
965 until (not p) or platforms[p]
966 return p
967 end
968 end
969
970 function cfg.print_platforms()
971 local platform_keys = {}
972 for k,_ in pairs(platforms) do
973 table.insert(platform_keys, k)
974 end
975 table.sort(platform_keys)
976 return table.concat(platform_keys, ", ")
977 end
978
979 return exit_ok, exit_err, exit_what
980end
981
982return cfg
diff --git a/src/luarocks/core/persist.lua b/src/luarocks/core/persist.lua
index 1435bd54..258a42c0 100644
--- a/src/luarocks/core/persist.lua
+++ b/src/luarocks/core/persist.lua
@@ -1,4 +1,4 @@
1local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local assert = _tl_compat and _tl_compat.assert or assert; local io = _tl_compat and _tl_compat.io or io; local load = _tl_compat and _tl_compat.load or load; local pcall = _tl_compat and _tl_compat.pcall or pcall; local string = _tl_compat and _tl_compat.string or string 1local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local io = _tl_compat and _tl_compat.io or io; local load = _tl_compat and _tl_compat.load or load; local pcall = _tl_compat and _tl_compat.pcall or pcall; local string = _tl_compat and _tl_compat.string or string
2local persist = {} 2local persist = {}
3 3
4 4
@@ -8,6 +8,8 @@ local persist = {}
8 8
9 9
10 10
11
12
11function persist.run_file(filename, env) 13function persist.run_file(filename, env)
12 local fd, open_err = io.open(filename) 14 local fd, open_err = io.open(filename)
13 if not fd then 15 if not fd then
@@ -20,17 +22,9 @@ function persist.run_file(filename, env)
20 end 22 end
21 str = str:gsub("^#![^\n]*\n", "") 23 str = str:gsub("^#![^\n]*\n", "")
22 local chunk, ran, err 24 local chunk, ran, err
23 if _VERSION == "Lua 5.1" then 25 chunk, err = load(str, filename, "t", env)
24 chunk, err = loadstring(str, filename) 26 if chunk then
25 if chunk then 27 ran, err = pcall(chunk)
26 setfenv(chunk, env)
27 ran, err = pcall(chunk)
28 end
29 else
30 chunk, err = load(str, filename, "t", env)
31 if chunk then
32 ran, err = pcall(chunk)
33 end
34 end 28 end
35 if not chunk then 29 if not chunk then
36 return nil, "Error loading file: " .. tostring(err), "load" 30 return nil, "Error loading file: " .. tostring(err), "load"
@@ -52,8 +46,6 @@ end
52 46
53 47
54function persist.load_into_table(filename, tbl) 48function persist.load_into_table(filename, tbl)
55 assert(type(filename) == "string")
56 assert(type(tbl) == "table" or not tbl)
57 49
58 local result = tbl or {} 50 local result = tbl or {}
59 local globals = {} 51 local globals = {}
@@ -70,7 +62,7 @@ function persist.load_into_table(filename, tbl)
70 setmetatable(result, save_mt) 62 setmetatable(result, save_mt)
71 63
72 if not ok then 64 if not ok then
73 return nil, err, errcode 65 return nil, tostring(err), errcode
74 end 66 end
75 return result, globals 67 return result, globals
76end 68end
diff --git a/src/luarocks/core/persist.tl b/src/luarocks/core/persist.tl
index 26eb5dff..f89a95c1 100644
--- a/src/luarocks/core/persist.tl
+++ b/src/luarocks/core/persist.tl
@@ -1,10 +1,7 @@
1 1
2local record persist 2local record persist
3 run_file: function(filename: string, env: {string:any}): boolean, any | nil, string, string
4 load_into_table: function(filename: string, tbl: {string:any}) : table, table | nil, string, string
5end 3end
6 4
7local require = nil --!
8-------------------------------------------------------------------------------- 5--------------------------------------------------------------------------------
9 6
10--- Load and run a Lua file in an environment. 7--- Load and run a Lua file in an environment.
@@ -13,7 +10,7 @@ local require = nil --!
13-- @return (true, any) or (nil, string, string): true and the return value 10-- @return (true, any) or (nil, string, string): true and the return value
14-- of the file, or nil, an error message and an error code ("open", "load" 11-- of the file, or nil, an error message and an error code ("open", "load"
15-- or "run") in case of errors. 12-- or "run") in case of errors.
16function persist.run_file(filename: string, env: {string:any}): boolean, any | nil, string, string 13function persist.run_file(filename: string, env: {string:any}): boolean, any | string, string
17 local fd, open_err: FILE, any = io.open(filename) 14 local fd, open_err: FILE, any = io.open(filename)
18 if not fd then 15 if not fd then
19 return nil, open_err, "open" 16 return nil, open_err, "open"
@@ -25,23 +22,15 @@ function persist.run_file(filename: string, env: {string:any}): boolean, any | n
25 end 22 end
26 str = str:gsub("^#![^\n]*\n", "") 23 str = str:gsub("^#![^\n]*\n", "")
27 local chunk, ran, err: function(any):(any), boolean, any 24 local chunk, ran, err: function(any):(any), boolean, any
28 if _VERSION == "Lua 5.1" then -- Lua 5.1 25 chunk, err = load(str, filename, "t", env)
29 chunk, err = loadstring(str, filename) --! 26 if chunk then
30 if chunk then 27 ran, err = pcall(chunk)
31 setfenv(chunk, env) --!
32 ran, err = pcall(chunk)
33 end
34 else -- Lua 5.2
35 chunk, err = load(str, filename, "t", env)
36 if chunk then
37 ran, err = pcall(chunk)
38 end
39 end 28 end
40 if not chunk then 29 if not chunk then
41 return nil, "Error loading file: "..tostring(err), "load" --? tostring 30 return nil, "Error loading file: "..tostring(err), "load"
42 end 31 end
43 if not ran then 32 if not ran then
44 return nil, "Error running file: "..tostring(err), "run" --? tostring 33 return nil, "Error running file: "..tostring(err), "run"
45 end 34 end
46 return true, err 35 return true, err
47end 36end
@@ -56,12 +45,10 @@ end
56-- or nil, an error message and an error code ("open"; couldn't open the file, 45-- or nil, an error message and an error code ("open"; couldn't open the file,
57-- "load"; compile-time error, or "run"; run-time error) 46-- "load"; compile-time error, or "run"; run-time error)
58-- in case of errors. 47-- in case of errors.
59function persist.load_into_table(filename: string, tbl: {string:any}) : table, table | nil, string, string 48function persist.load_into_table(filename: string, tbl: {string:any}) : table, table | string, string
60 assert(type(filename) == "string") --? needed
61 assert(type(tbl) == "table" or not tbl) --? needed
62 49
63 local result: {string:any} = tbl or {} 50 local result: {string:any} = tbl or {}
64 local globals: table = {} --? {string:boolean} 51 local globals = {}
65 local globals_mt = { 52 local globals_mt = {
66 __index = function(_, k: string) 53 __index = function(_, k: string)
67 globals[k] = true 54 globals[k] = true
@@ -70,12 +57,12 @@ function persist.load_into_table(filename: string, tbl: {string:any}) : table, t
70 local save_mt = getmetatable(result) 57 local save_mt = getmetatable(result)
71 setmetatable(result, globals_mt) 58 setmetatable(result, globals_mt)
72 59
73 local ok, err, errcode = persist.run_file(filename, result) --? boolean, string, string 60 local ok, err, errcode = persist.run_file(filename, result)
74 61
75 setmetatable(result, save_mt) 62 setmetatable(result, save_mt)
76 63
77 if not ok then 64 if not ok then
78 return nil, err, errcode --! table | nil???? 65 return nil, tostring(err), errcode
79 end 66 end
80 return result, globals 67 return result, globals
81end 68end
diff --git a/src/luarocks/core/sysdetect.tl b/src/luarocks/core/sysdetect.tl
index e783a012..a19a5f24 100644
--- a/src/luarocks/core/sysdetect.tl
+++ b/src/luarocks/core/sysdetect.tl
@@ -46,26 +46,12 @@ local record sysdetect
46 "cygwin" 46 "cygwin"
47 "macosx" 47 "macosx"
48 end 48 end
49
50 hex: function(s: string): string --?
51 read_int8: function(fd: FILE): integer
52 bytes2number: function(s: string, endian: Endian): integer
53 read: function(fd: FILE, bytes: integer, endian: Endian): integer
54 read_int32le: function(fd: FILE): integer
55 read_elf_section_headers: function(fd: FILE, hdr: ElfHeader): {string: ElfSection}
56 detect_elf_system: function(fd: FILE, hdr: ElfHeader, sections: {string:ElfSection}): System
57 read_elf_header: function(fd: FILE): ElfHeader, Processor
58 detect_elf: function(fd: FILE): System, Processor
59 detect_mach: function(magic: string, fd: FILE): System, Processor
60 detect_pe: function(fd: FILE): System, Processor
61 detect_file: function(file: string): System, Processor --? systemdetect.detect_file?
62 detect: function(input_file: string): System, Processor
63end 49end
64 50
65local type System = sysdetect.System --? ? 51local type System = sysdetect.System
66local type Processor = sysdetect.Processor --? ? 52local type Processor = sysdetect.Processor
67 53
68local enum Endian --? in the registry and a line for type ? 54local enum Endian
69 "little" 55 "little"
70 "big" 56 "big"
71end 57end
@@ -270,7 +256,7 @@ local function detect_elf_system(fd: FILE, hdr: ElfHeader, sections: {string:Elf
270 local idx = 0 256 local idx = 0
271 for _ = 0, gnu_version_r.sh_info - 1 do 257 for _ = 0, gnu_version_r.sh_info - 1 do
272 fd:seek("set", gnu_version_r.sh_offset + idx) 258 fd:seek("set", gnu_version_r.sh_offset + idx)
273 assert(read(fd, 2, endian)) -- vn_version --? 259 assert(read(fd, 2, endian)) -- vn_version
274 local vn_cnt = read(fd, 2, endian) 260 local vn_cnt = read(fd, 2, endian)
275 local vn_file = read(fd, 4, endian) 261 local vn_file = read(fd, 4, endian)
276 local vn_next = read(fd, 2, endian) 262 local vn_next = read(fd, 2, endian)
diff --git a/src/luarocks/core/util.lua b/src/luarocks/core/util.lua
index 44c9e63b..f8c7ac71 100644
--- a/src/luarocks/core/util.lua
+++ b/src/luarocks/core/util.lua
@@ -1,7 +1,7 @@
1local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local assert = _tl_compat and _tl_compat.assert or assert; local debug = _tl_compat and _tl_compat.debug or debug; local io = _tl_compat and _tl_compat.io or io; local ipairs = _tl_compat and _tl_compat.ipairs or ipairs; local math = _tl_compat and _tl_compat.math or math; local os = _tl_compat and _tl_compat.os or os; local package = _tl_compat and _tl_compat.package or package; local pairs = _tl_compat and _tl_compat.pairs or pairs; local string = _tl_compat and _tl_compat.string or string; local table = _tl_compat and _tl_compat.table or table 1local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local debug = _tl_compat and _tl_compat.debug or debug; local io = _tl_compat and _tl_compat.io or io; local ipairs = _tl_compat and _tl_compat.ipairs or ipairs; local math = _tl_compat and _tl_compat.math or math; local os = _tl_compat and _tl_compat.os or os; local package = _tl_compat and _tl_compat.package or package; local pairs = _tl_compat and _tl_compat.pairs or pairs; local string = _tl_compat and _tl_compat.string or string; local table = _tl_compat and _tl_compat.table or table
2local util = {} 2local util = {}
3 3
4local require = nil 4
5 5
6 6
7local dir_sep = package.config:sub(1, 1) 7local dir_sep = package.config:sub(1, 1)
@@ -80,7 +80,7 @@ function util.show_table(t, tname, top_indent)
80 80
81 cart = cart .. indent .. field 81 cart = cart .. indent .. field
82 82
83 if type(value) ~= "table" then 83 if not (type(value) == "table") then
84 cart = cart .. " = " .. basic_serialize(value) .. ";\n" 84 cart = cart .. " = " .. basic_serialize(value) .. ";\n"
85 else 85 else
86 if saved[value] then 86 if saved[value] then
@@ -156,6 +156,34 @@ end
156 156
157 157
158 158
159function util.split_string(str, delim, maxNb)
160
161 if string.find(str, delim) == nil then
162 return { str }
163 end
164 if maxNb == nil or maxNb < 1 then
165 maxNb = 0
166 end
167 local result = {}
168 local pat = "(.-)" .. delim .. "()"
169 local nb = 0
170 local lastPos
171 for part, pos in string.gmatch(str, pat) do
172 nb = nb + 1
173 result[nb] = part
174 lastPos = tonumber(pos)
175 if nb == maxNb then break end
176 end
177
178 if nb ~= maxNb then
179 result[nb + 1] = string.sub(str, lastPos)
180 end
181 return result
182end
183
184
185
186
159 187
160 188
161 189
@@ -164,8 +192,6 @@ end
164 192
165 193
166function util.cleanup_path(list, sep, lua_version, keep_first) 194function util.cleanup_path(list, sep, lua_version, keep_first)
167 assert(type(list) == "string")
168 assert(type(sep) == "string")
169 195
170 list = list:gsub(dir_sep, "/") 196 list = list:gsub(dir_sep, "/")
171 197
@@ -200,33 +226,6 @@ end
200 226
201 227
202 228
203function util.split_string(str, delim, maxNb)
204
205 if string.find(str, delim) == nil then
206 return { str }
207 end
208 if maxNb == nil or maxNb < 1 then
209 maxNb = 0
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
222 if nb ~= maxNb then
223 result[nb + 1] = string.sub(str, lastPos)
224 end
225 return result
226end
227
228
229
230 229
231function util.keys(tbl) 230function util.keys(tbl)
232 local ks = {} 231 local ks = {}
@@ -278,7 +277,7 @@ function util.sortedpairs(tbl, sort_function)
278 local keys = util.keys(tbl) 277 local keys = util.keys(tbl)
279 local sub_orders = {} 278 local sub_orders = {}
280 279
281 if type(sort_function) == "function" then 280 if (type(sort_function) == "function") and (type(sort_function) == "function") then
282 table.sort(keys, sort_function) 281 table.sort(keys, sort_function)
283 else 282 else
284 local order = sort_function 283 local order = sort_function
diff --git a/src/luarocks/core/util.tl b/src/luarocks/core/util.tl
index c7f02de2..738bb8a8 100644
--- a/src/luarocks/core/util.tl
+++ b/src/luarocks/core/util.tl
@@ -1,18 +1,7 @@
1 1
2local record util 2local record util
3 popen_read: function(cmd: string, spec: string): string --? util.popen_read
4 show_table: function(t: {any:any}, tname: string, top_indent: string): string
5 deep_merge: function(dst: {integer: any}, src: {integer: any})
6 deep_merge_under: function(dst: {integer: any}, src: {integer: any})
7 cleanup_path: function(list: string, sep: string, lua_version: string, keep_first: boolean): string
8 split_string: function(str: string, delim: string, maxNb: number): {string}
9 keys: function(tbl: {any:any}): {any}
10 printerr: function(...: string | number)
11 warning: function(msg: string)
12 sortedpairs: function(tbl: {any: any}, sort_function: function<any>(any, any): boolean | {any:any} | nil): function
13end 3end
14 4
15local require = nil --!
16-------------------------------------------------------------------------------- 5--------------------------------------------------------------------------------
17 6
18local dir_sep = package.config:sub(1, 1) 7local dir_sep = package.config:sub(1, 1)
@@ -84,14 +73,14 @@ function util.show_table(t: {any:any}, tname: string, top_indent: string): strin
84 end 73 end
85 end 74 end
86 75
87 local function add_to_cart (value: {any:any}, name: string, indent: string, saved: {any: string}, field: string) --? <A,B> value: {A:B} 76 local function add_to_cart (value: any | {any:any}, name: string, indent: string, saved: {any: string}, field: string)
88 indent = indent or "" 77 indent = indent or ""
89 saved = saved or {} 78 saved = saved or {}
90 field = field or name 79 field = field or name
91 80
92 cart = cart .. indent .. field 81 cart = cart .. indent .. field
93 82
94 if type(value) ~= "table" then --? 1 83 if not value is {any: any} then
95 cart = cart .. " = " .. basic_serialize(value) .. ";\n" 84 cart = cart .. " = " .. basic_serialize(value) .. ";\n"
96 else 85 else
97 if saved[value] then 86 if saved[value] then
@@ -99,7 +88,7 @@ function util.show_table(t: {any:any}, tname: string, top_indent: string): strin
99 autoref = autoref .. name .. " = " .. saved[value] .. ";\n" 88 autoref = autoref .. name .. " = " .. saved[value] .. ";\n"
100 else 89 else
101 saved[value] = name 90 saved[value] = name
102 if is_empty_table(value) then --? 1 91 if is_empty_table(value) then
103 cart = cart .. " = {};\n" 92 cart = cart .. " = {};\n"
104 else 93 else
105 cart = cart .. " = {\n" 94 cart = cart .. " = {\n"
@@ -108,7 +97,7 @@ function util.show_table(t: {any:any}, tname: string, top_indent: string): strin
108 local fname = ("%s[%s]"):format(name, k) 97 local fname = ("%s[%s]"):format(name, k)
109 field = ("[%s]"):format(k) 98 field = ("[%s]"):format(k)
110 -- three spaces between levels 99 -- three spaces between levels
111 add_to_cart(v, fname, indent .. " ", saved, field) --! 100 add_to_cart(v, fname, indent .. " ", saved, field)
112 end 101 end
113 cart = cart .. indent .. "};\n" 102 cart = cart .. indent .. "};\n"
114 end 103 end
@@ -129,14 +118,14 @@ end
129-- (i.e. if an key from src already exists in dst, replace it). 118-- (i.e. if an key from src already exists in dst, replace it).
130-- @param dst Destination table, which will receive src's contents. 119-- @param dst Destination table, which will receive src's contents.
131-- @param src Table which provides new contents to dst. 120-- @param src Table which provides new contents to dst.
132function util.deep_merge(dst: {integer: any}, src: {integer: any}) --? {integer: {any:any}}, {integer: {any:any}} 121function util.deep_merge(dst: {any: any}, src: {any: any})
133 for k, v in pairs(src) do 122 for k, v in pairs(src) do
134 if type(v) == "table" then 123 if v is table then
135 if dst[k] == nil then 124 if dst[k] == nil then
136 dst[k] = {} 125 dst[k] = {}
137 end 126 end
138 if type(dst[k]) == "table" then 127 if dst[k] is {any: any} then --! "is" unavailable for table
139 util.deep_merge(dst[k], v) --! 128 util.deep_merge(dst[k], v)
140 else 129 else
141 dst[k] = v 130 dst[k] = v
142 end 131 end
@@ -150,13 +139,13 @@ end
150-- (i.e. if an key from src already exists in dst, do not replace it). 139-- (i.e. if an key from src already exists in dst, do not replace it).
151-- @param dst Destination table, which will receive src's contents. 140-- @param dst Destination table, which will receive src's contents.
152-- @param src Table which provides new contents to dst. 141-- @param src Table which provides new contents to dst.
153function util.deep_merge_under(dst: {integer: any}, src: {integer: any}) --? {integer: {any:any}}, {integer: {any:any}} 142function util.deep_merge_under(dst: {any: any}, src: {any: any})
154 for k, v in pairs(src) do 143 for k, v in pairs(src) do
155 if type(v) == "table" then 144 if type(v) == "table" then
156 if dst[k] == nil then 145 if dst[k] == nil then
157 dst[k] = {} 146 dst[k] = {}
158 end 147 end
159 if type(dst[k]) == "table" then 148 if dst[k] is {any: any} then --! "is" unavailable for table
160 util.deep_merge_under(dst[k], v) 149 util.deep_merge_under(dst[k], v)
161 end 150 end
162 elseif dst[k] == nil then 151 elseif dst[k] == nil then
@@ -165,6 +154,34 @@ function util.deep_merge_under(dst: {integer: any}, src: {integer: any}) --? {in
165 end 154 end
166end 155end
167 156
157-- from http://lua-users.org/wiki/SplitJoin
158-- by Philippe Lhoste
159function util.split_string(str: string, delim: string, maxNb: number): {string}
160 -- Eliminate bad cases...
161 if string.find(str, delim) == nil then
162 return { str }
163 end
164 if maxNb == nil or maxNb < 1 then
165 maxNb = 0 -- No limit
166 end
167 local result = {}
168 local pat = "(.-)" .. delim .. "()"
169 local nb = 0
170 local lastPos: number
171 for part, pos in string.gmatch(str, pat) do
172 nb = nb + 1
173 result[nb] = part
174 lastPos = tonumber(pos)
175 if nb == maxNb then break end
176 end
177 -- Handle the last field
178 if nb ~= maxNb then
179 result[nb + 1] = string.sub(str, lastPos)
180 end
181 return result
182end
183
184
168--- Clean up a path-style string ($PATH, $LUA_PATH/package.path, etc.), 185--- Clean up a path-style string ($PATH, $LUA_PATH/package.path, etc.),
169-- removing repeated entries and making sure only the relevant 186-- removing repeated entries and making sure only the relevant
170-- Lua version is used. 187-- Lua version is used.
@@ -175,14 +192,12 @@ end
175-- @param keep_first (optional) if true, keep first occurrence in case 192-- @param keep_first (optional) if true, keep first occurrence in case
176-- of duplicates; otherwise keep last occurrence. The default is false. 193-- of duplicates; otherwise keep last occurrence. The default is false.
177function util.cleanup_path(list: string, sep: string, lua_version: string, keep_first: boolean): string 194function util.cleanup_path(list: string, sep: string, lua_version: string, keep_first: boolean): string
178 assert(type(list) == "string") --?
179 assert(type(sep) == "string") --?
180 195
181 list = list:gsub(dir_sep, "/") 196 list = list:gsub(dir_sep, "/")
182 197
183 local parts = util.split_string(list, sep) --! 198 local parts = util.split_string(list, sep)
184 local final, entries = {}, {} 199 local final, entries = {}, {}
185 local start, stop, step: number, number, number 200 local start, stop, step: integer, integer, integer
186 201
187 if keep_first then 202 if keep_first then
188 start, stop, step = 1, #parts, 1 203 start, stop, step = 1, #parts, 1
@@ -193,9 +208,9 @@ function util.cleanup_path(list: string, sep: string, lua_version: string, keep_
193 for i = start, stop, step do 208 for i = start, stop, step do
194 local part = parts[i]:gsub("//", "/") 209 local part = parts[i]:gsub("//", "/")
195 if lua_version then 210 if lua_version then
196 part = part:gsub("/lua/([%d.]+)/", function(part_version) 211 part = part:gsub("/lua/([%d.]+)/", function(part_version: string): string
197 if part_version:sub(1, #lua_version) ~= lua_version then --! 212 if part_version:sub(1, #lua_version) ~= lua_version then
198 return "/lua/"..lua_version.."/" --! 213 return "/lua/"..lua_version.."/"
199 end 214 end
200 end) 215 end)
201 end 216 end
@@ -206,34 +221,7 @@ function util.cleanup_path(list: string, sep: string, lua_version: string, keep_
206 end 221 end
207 end 222 end
208 223
209 return (table.concat(final, sep):gsub("/", dir_sep)) --! 224 return (table.concat(final, sep):gsub("/", dir_sep))
210end
211
212-- from http://lua-users.org/wiki/SplitJoin
213-- by Philippe Lhoste
214function util.split_string(str: string, delim: string, maxNb: number): {string}
215 -- Eliminate bad cases...
216 if string.find(str, delim) == nil then
217 return { str }
218 end
219 if maxNb == nil or maxNb < 1 then
220 maxNb = 0 -- No limit
221 end
222 local result = {}
223 local pat = "(.-)" .. delim .. "()"
224 local nb = 0
225 local lastPos: any
226 for part, pos in string.gmatch(str, pat) do --! pos: number or string
227 nb = nb + 1
228 result[nb] = part
229 lastPos = pos --! number or string
230 if nb == maxNb then break end
231 end
232 -- Handle the last field
233 if nb ~= maxNb then
234 result[nb + 1] = string.sub(str, lastPos)
235 end
236 return result
237end 225end
238 226
239--- Return an array of keys of a table. 227--- Return an array of keys of a table.
@@ -284,24 +272,24 @@ end
284-- for that key, which is returned by the iterator as the third value after the key 272-- for that key, which is returned by the iterator as the third value after the key
285-- and the value. 273-- and the value.
286-- @return function: the iterator function. 274-- @return function: the iterator function.
287function util.sortedpairs(tbl: {any: any}, sort_function: function<any>(any, any): boolean | {any:any} | nil): function --? function<A>(A, A): boolean | {any:integer} | nil 275function util.sortedpairs(tbl: {any: any}, sort_function: function | {any} | nil): function(): any, any, any --! (function(any, any): boolean) | {any} | nil NOT function(any, any): (boolean | {any:any} | nil)
288 sort_function = sort_function or default_sort 276 sort_function = sort_function or default_sort
289 local keys = util.keys(tbl) 277 local keys = util.keys(tbl)
290 local sub_orders = {} 278 local sub_orders = {}
291 279
292 if type(sort_function) == "function" then 280 if (sort_function is function ) and (sort_function is function():boolean) then --? How to enforce boolean output?
293 table.sort(keys, sort_function) --! 281 table.sort(keys, sort_function)
294 else 282 else
295 local order = sort_function 283 local order = sort_function
296 local ordered_keys = {} 284 local ordered_keys = {}
297 local all_keys = keys 285 local all_keys = keys
298 keys = {} 286 keys = {}
299 287
300 for _, order_entry in ipairs(order) do --! 288 for _, order_entry in ipairs(order) do
301 local key, sub_order: any, any --! 289 local key, sub_order: any, any
302 if type(order_entry) == "table" then 290 if order_entry is {any: any} then
303 key = order_entry[1] --! 291 key = order_entry[1]
304 sub_order = order_entry[2] --! 292 sub_order = order_entry[2]
305 else 293 else
306 key = order_entry 294 key = order_entry
307 end 295 end
@@ -322,10 +310,10 @@ function util.sortedpairs(tbl: {any: any}, sort_function: function<any>(any, any
322 end 310 end
323 311
324 local i = 1 312 local i = 1
325 return function() 313 return function(): any, any, any
326 local key = keys[i] 314 local key = keys[i]
327 i = i + 1 315 i = i + 1
328 return key, tbl[key], sub_orders[key] --! 316 return key, tbl[key], sub_orders[key]
329 end 317 end
330end 318end
331 319