aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorV1K1NGbg <victor@ilchev.com>2024-08-19 17:42:28 +0300
committerV1K1NGbg <victor@ilchev.com>2024-08-19 17:42:28 +0300
commitf17c209b891e53cf510e13e31a40dbc4fa918049 (patch)
tree8416b832c3c28abd8e3d1032df0b7c2793d65478
parente46a1edb5b5c75e10b2d199a64817743fc29dbee (diff)
downloadluarocks-f17c209b891e53cf510e13e31a40dbc4fa918049.tar.gz
luarocks-f17c209b891e53cf510e13e31a40dbc4fa918049.tar.bz2
luarocks-f17c209b891e53cf510e13e31a40dbc4fa918049.zip
cmd build
-rw-r--r--src/luarocks/build.tl3
-rw-r--r--src/luarocks/cmd-original.lua781
-rw-r--r--src/luarocks/cmd.lua415
-rw-r--r--src/luarocks/cmd.tl10
-rw-r--r--src/luarocks/cmd/build-original.lua199
-rw-r--r--src/luarocks/cmd/build.lua101
-rw-r--r--src/luarocks/cmd/build.tl17
-rw-r--r--src/luarocks/cmd/install.tl2
-rw-r--r--src/luarocks/cmd/make.tl2
-rw-r--r--src/luarocks/cmd/show.tl13
-rw-r--r--src/luarocks/cmd/upload.tl26
-rw-r--r--src/luarocks/deps.tl7
-rw-r--r--src/luarocks/test/busted.tl1
13 files changed, 1285 insertions, 292 deletions
diff --git a/src/luarocks/build.tl b/src/luarocks/build.tl
index ffbc4f01..b3594225 100644
--- a/src/luarocks/build.tl
+++ b/src/luarocks/build.tl
@@ -403,8 +403,7 @@ end
403-- @param rockspec rockspec: the rockspec to build 403-- @param rockspec rockspec: the rockspec to build
404-- @param opts table: build options table 404-- @param opts table: build options table
405-- @param cwd string or nil: The current working directory 405-- @param cwd string or nil: The current working directory
406-- @return (string, string) or (nil, string, [string]): Name and version of 406-- @return: Name and version of installed rock if succeeded or nil and an error message.
407-- installed rock if succeeded or nil and an error message followed by an error code.
408function build.build_rockspec(rockspec: Rockspec, opts: BOpts, cwd: string): string, string 407function build.build_rockspec(rockspec: Rockspec, opts: BOpts, cwd: string): string, string
409 408
410 cwd = cwd or dir.path(".") 409 cwd = cwd or dir.path(".")
diff --git a/src/luarocks/cmd-original.lua b/src/luarocks/cmd-original.lua
new file mode 100644
index 00000000..7710dc68
--- /dev/null
+++ b/src/luarocks/cmd-original.lua
@@ -0,0 +1,781 @@
1
2--- Functions for command-line scripts.
3local cmd = {}
4
5local manif = require("luarocks.manif")
6local config = require("luarocks.config")
7local util = require("luarocks.util")
8local path = require("luarocks.path")
9local cfg = require("luarocks.core.cfg")
10local dir = require("luarocks.dir")
11local fun = require("luarocks.fun")
12local fs = require("luarocks.fs")
13local argparse = require("luarocks.vendor.argparse")
14
15local unpack = table.unpack or unpack
16local pack = table.pack or function(...) return { n = select("#", ...), ... } end
17
18local hc_ok, hardcoded = pcall(require, "luarocks.core.hardcoded")
19if not hc_ok then
20 hardcoded = {}
21end
22
23local program = util.this_program("luarocks")
24
25cmd.errorcodes = {
26 OK = 0,
27 UNSPECIFIED = 1,
28 PERMISSIONDENIED = 2,
29 CONFIGFILE = 3,
30 LOCK = 4,
31 CRASH = 99
32}
33
34local function check_popen()
35 local popen_ok, popen_result = pcall(io.popen, "")
36 if popen_ok then
37 if popen_result then
38 popen_result:close()
39 end
40 else
41 io.stderr:write("Your version of Lua does not support io.popen,\n")
42 io.stderr:write("which is required by LuaRocks. Please check your Lua installation.\n")
43 os.exit(cmd.errorcodes.UNSPECIFIED)
44 end
45end
46
47local process_tree_args
48do
49 local function replace_tree(args, root, tree)
50 root = dir.normalize(root)
51 args.tree = root
52 path.use_tree(tree or root)
53 end
54
55 local function strip_trailing_slashes()
56 if type(cfg.root_dir) == "string" then
57 cfg.root_dir = cfg.root_dir:gsub("/+$", "")
58 else
59 cfg.root_dir.root = cfg.root_dir.root:gsub("/+$", "")
60 end
61 cfg.rocks_dir = cfg.rocks_dir:gsub("/+$", "")
62 cfg.deploy_bin_dir = cfg.deploy_bin_dir:gsub("/+$", "")
63 cfg.deploy_lua_dir = cfg.deploy_lua_dir:gsub("/+$", "")
64 cfg.deploy_lib_dir = cfg.deploy_lib_dir:gsub("/+$", "")
65 end
66
67 local function set_named_tree(args, name)
68 for _, tree in ipairs(cfg.rocks_trees) do
69 if type(tree) == "table" and name == tree.name then
70 if not tree.root then
71 return nil, "Configuration error: tree '"..tree.name.."' has no 'root' field."
72 end
73 replace_tree(args, tree.root, tree)
74 return true
75 end
76 end
77 return false
78 end
79
80 process_tree_args = function(args, project_dir)
81
82 if args.global then
83 local ok, err = set_named_tree(args, "system")
84 if not ok then
85 return nil, err
86 end
87 elseif args.tree then
88 local named = set_named_tree(args, args.tree)
89 if not named then
90 local root_dir = fs.absolute_name(args.tree)
91 replace_tree(args, root_dir)
92 if (args.deps_mode or cfg.deps_mode) ~= "order" then
93 table.insert(cfg.rocks_trees, 1, { name = "arg", root = root_dir } )
94 end
95 end
96 elseif args["local"] then
97 if fs.is_superuser() then
98 return nil, "The --local flag is meant for operating in a user's home directory.\n"..
99 "You are running as a superuser, which is intended for system-wide operation.\n"..
100 "To force using the superuser's home, use --tree explicitly."
101 else
102 local ok, err = set_named_tree(args, "user")
103 if not ok then
104 return nil, err
105 end
106 end
107 elseif args.project_tree then
108 local tree = args.project_tree
109 table.insert(cfg.rocks_trees, 1, { name = "project", root = tree } )
110 manif.load_rocks_tree_manifests()
111 path.use_tree(tree)
112 elseif project_dir then
113 local project_tree = project_dir .. "/lua_modules"
114 table.insert(cfg.rocks_trees, 1, { name = "project", root = project_tree } )
115 manif.load_rocks_tree_manifests()
116 path.use_tree(project_tree)
117 elseif cfg.local_by_default then
118 local ok, err = set_named_tree(args, "user")
119 if not ok then
120 return nil, err
121 end
122 else
123 local trees = cfg.rocks_trees
124 path.use_tree(trees[#trees])
125 end
126
127 strip_trailing_slashes()
128
129 cfg.variables.ROCKS_TREE = cfg.rocks_dir
130 cfg.variables.SCRIPTS_DIR = cfg.deploy_bin_dir
131
132 return true
133 end
134end
135
136local function process_server_args(args)
137 if args.server then
138 local protocol, pathname = dir.split_url(args.server)
139 table.insert(cfg.rocks_servers, 1, protocol.."://"..pathname)
140 end
141
142 if args.dev then
143 local append_dev = function(s) return dir.path(s, "dev") end
144 local dev_servers = fun.traverse(cfg.rocks_servers, append_dev)
145 cfg.rocks_servers = fun.concat(dev_servers, cfg.rocks_servers)
146 end
147
148 if args.only_server then
149 if args.dev then
150 return nil, "--only-server cannot be used with --dev"
151 end
152 if args.server then
153 return nil, "--only-server cannot be used with --server"
154 end
155 cfg.rocks_servers = { args.only_server }
156 end
157
158 return true
159end
160
161local function error_handler(err)
162 if not debug then
163 return err
164 end
165 local mode = "Arch.: " .. (cfg and cfg.arch or "unknown")
166 if package.config:sub(1, 1) == "\\" then
167 if cfg and cfg.fs_use_modules then
168 mode = mode .. " (fs_use_modules = true)"
169 end
170 end
171 if cfg and cfg.is_binary then
172 mode = mode .. " (binary)"
173 end
174 return debug.traceback("LuaRocks "..cfg.program_version..
175 " bug (please report at https://github.com/luarocks/luarocks/issues).\n"..
176 mode.."\n"..err, 2)
177end
178
179--- Display an error message and exit.
180-- @param message string: The error message.
181-- @param exitcode number: the exitcode to use
182local function die(message, exitcode)
183 assert(type(message) == "string", "bad error, expected string, got: " .. type(message))
184 assert(exitcode == nil or type(exitcode) == "number", "bad error, expected number, got: " .. type(exitcode) .. " - " .. tostring(exitcode))
185 util.printerr("\nError: "..message)
186
187 local ok, err = xpcall(util.run_scheduled_functions, error_handler)
188 if not ok then
189 util.printerr("\nError: "..err)
190 exitcode = cmd.errorcodes.CRASH
191 end
192
193 os.exit(exitcode or cmd.errorcodes.UNSPECIFIED)
194end
195
196local function search_lua(lua_version, verbose, search_at)
197 if search_at then
198 return util.find_lua(search_at, lua_version, verbose)
199 end
200
201 local path_sep = (package.config:sub(1, 1) == "\\" and ";" or ":")
202 local all_tried = {}
203 for bindir in (os.getenv("PATH") or ""):gmatch("[^"..path_sep.."]+") do
204 local searchdir = (bindir:gsub("[\\/]+bin[\\/]?$", ""))
205 local detected, tried = util.find_lua(searchdir, lua_version)
206 if detected then
207 return detected
208 else
209 table.insert(all_tried, tried)
210 end
211 end
212 return nil, "Could not find " ..
213 (lua_version and "Lua " .. lua_version or "Lua") ..
214 " in PATH." ..
215 (verbose and " Tried:\n" .. table.concat(all_tried, "\n") or "")
216end
217
218local init_config
219do
220 local detect_config_via_args
221 do
222 local function find_project_dir(project_tree)
223 if project_tree then
224 return project_tree:gsub("[/\\][^/\\]+$", ""), true
225 else
226 local try = "."
227 for _ = 1, 10 do -- FIXME detect when root dir was hit instead
228 if util.exists(try .. "/.luarocks") and util.exists(try .. "/lua_modules") then
229 return dir.normalize(try), false
230 elseif util.exists(try .. "/.luarocks-no-project") then
231 break
232 end
233 try = try .. "/.."
234 end
235 end
236 return nil
237 end
238
239 local function find_default_lua_version(args, project_dir)
240 if hardcoded.FORCE_CONFIG then
241 return nil
242 end
243
244 local dirs = {}
245 if project_dir then
246 table.insert(dirs, dir.path(project_dir, ".luarocks"))
247 end
248 if cfg.homeconfdir then
249 table.insert(dirs, cfg.homeconfdir)
250 end
251 table.insert(dirs, cfg.sysconfdir)
252 for _, d in ipairs(dirs) do
253 local f = dir.path(d, "default-lua-version.lua")
254 local mod, err = loadfile(f, "t")
255 if mod then
256 local pok, ver = pcall(mod)
257 if pok and type(ver) == "string" and ver:match("%d+.%d+") then
258 if args.verbose then
259 util.printout("Defaulting to Lua " .. ver .. " based on " .. f .. " ...")
260 end
261 return ver
262 end
263 end
264 end
265 return nil
266 end
267
268 local function find_version_from_config(dirname)
269 return fun.find(util.lua_versions("descending"), function(v)
270 if util.exists(dir.path(dirname, ".luarocks", "config-"..v..".lua")) then
271 return v
272 end
273 end)
274 end
275
276 local function detect_lua_via_args(args, project_dir)
277 local lua_version = args.lua_version
278 or find_default_lua_version(args, project_dir)
279 or (project_dir and find_version_from_config(project_dir))
280
281 if args.lua_dir then
282 local detected, err = util.find_lua(args.lua_dir, lua_version)
283 if not detected then
284 local suggestion = (not args.lua_version)
285 and "\nYou may want to specify a different Lua version with --lua-version\n"
286 or ""
287 die(err .. suggestion)
288 end
289 return detected
290 end
291
292 if lua_version then
293 local detected = search_lua(lua_version)
294 if detected then
295 return detected
296 end
297 return {
298 lua_version = lua_version,
299 }
300 end
301
302 return {}
303 end
304
305 detect_config_via_args = function(args)
306 local project_dir, given
307 if not args.no_project then
308 project_dir, given = find_project_dir(args.project_tree)
309 end
310
311 local detected = detect_lua_via_args(args, project_dir)
312 if args.lua_version then
313 detected.given_lua_version = args.lua_version
314 end
315 if args.lua_dir then
316 detected.given_lua_dir = args.lua_dir
317 end
318 if given then
319 detected.given_project_dir = project_dir
320 end
321 detected.project_dir = project_dir
322 return detected
323 end
324 end
325
326 init_config = function(args)
327 local detected = detect_config_via_args(args)
328
329 local ok, err = cfg.init(detected, util.warning)
330 if not ok then
331 return nil, err
332 end
333
334 return (detected.lua_dir ~= nil)
335 end
336end
337
338local variables_help = [[
339Variables:
340 Variables from the "variables" table of the configuration file can be
341 overridden with VAR=VALUE assignments.
342
343]]
344
345local lua_example = package.config:sub(1, 1) == "\\"
346 and "<d:\\path\\lua.exe>"
347 or "</path/lua>"
348
349local function show_status(file, status, err)
350 return (file and file .. " " or "") .. (status and "(ok)" or ("(" .. (err or "not found") ..")"))
351end
352
353local function use_to_fix_location(key, what)
354 local buf = " ****************************************\n"
355 buf = buf .. " Use the command\n\n"
356 buf = buf .. " luarocks config " .. key .. " " .. (what or "<dir>") .. "\n\n"
357 buf = buf .. " to fix the location\n"
358 buf = buf .. " ****************************************\n"
359 return buf
360end
361
362local function get_config_text(cfg) -- luacheck: ignore 431
363 local deps = require("luarocks.deps")
364
365 local libdir_ok = deps.check_lua_libdir(cfg.variables)
366 local incdir_ok = deps.check_lua_incdir(cfg.variables)
367 local lua_ok = cfg.variables.LUA and fs.exists(cfg.variables.LUA)
368
369 local buf = "Configuration:\n"
370 buf = buf.." Lua:\n"
371 buf = buf.." Version : "..cfg.lua_version.."\n"
372 if cfg.luajit_version then
373 buf = buf.." LuaJIT : "..cfg.luajit_version.."\n"
374 end
375 buf = buf.." LUA : "..show_status(cfg.variables.LUA, lua_ok, "interpreter not found").."\n"
376 if not lua_ok then
377 buf = buf .. use_to_fix_location("variables.LUA", lua_example)
378 end
379 buf = buf.." LUA_INCDIR : "..show_status(cfg.variables.LUA_INCDIR, incdir_ok, "lua.h not found").."\n"
380 if lua_ok and not incdir_ok then
381 buf = buf .. use_to_fix_location("variables.LUA_INCDIR")
382 end
383 buf = buf.." LUA_LIBDIR : "..show_status(cfg.variables.LUA_LIBDIR, libdir_ok, "Lua library itself not found").."\n"
384 if lua_ok and not libdir_ok then
385 buf = buf .. use_to_fix_location("variables.LUA_LIBDIR")
386 end
387
388 buf = buf.."\n Configuration files:\n"
389 local conf = cfg.config_files
390 buf = buf.." System : "..show_status(fs.absolute_name(conf.system.file), conf.system.found).."\n"
391 if conf.user.file then
392 buf = buf.." User : "..show_status(fs.absolute_name(conf.user.file), conf.user.found).."\n"
393 else
394 buf = buf.." User : disabled in this LuaRocks installation.\n"
395 end
396 if conf.project then
397 buf = buf.." Project : "..show_status(fs.absolute_name(conf.project.file), conf.project.found).."\n"
398 end
399 buf = buf.."\n Rocks trees in use: \n"
400 for _, tree in ipairs(cfg.rocks_trees) do
401 if type(tree) == "string" then
402 buf = buf.." "..fs.absolute_name(tree)
403 else
404 local name = tree.name and " (\""..tree.name.."\")" or ""
405 buf = buf.." "..fs.absolute_name(tree.root)..name
406 end
407 buf = buf .. "\n"
408 end
409
410 return buf
411end
412
413local function get_parser(description, cmd_modules)
414 local basename = dir.base_name(program)
415 local parser = argparse(
416 basename, "LuaRocks "..cfg.program_version..", the Lua package manager\n\n"..
417 program.." - "..description, variables_help.."Run '"..basename..
418 "' without any arguments to see the configuration.")
419 :help_max_width(80)
420 :add_help_command()
421 :add_complete_command({
422 help_max_width = 100,
423 summary = "Output a shell completion script.",
424 description = [[
425Output a shell completion script.
426
427Enabling completions for Bash:
428
429 Add the following line to your ~/.bashrc:
430 source <(]]..basename..[[ completion bash)
431 or save the completion script to the local completion directory:
432 ]]..basename..[[ completion bash > ~/.local/share/bash-completion/completions/]]..basename..[[
433
434
435Enabling completions for Zsh:
436
437 Save the completion script to a file in your $fpath.
438 You can add a new directory to your $fpath by adding e.g.
439 fpath=(~/.zfunc $fpath)
440 to your ~/.zshrc.
441 Then run:
442 ]]..basename..[[ completion zsh > ~/.zfunc/_]]..basename..[[
443
444
445Enabling completion for Fish:
446
447 Add the following line to your ~/.config/fish/config.fish:
448 ]]..basename..[[ completion fish | source
449 or save the completion script to the local completion directory:
450 ]]..basename..[[ completion fish > ~/.config/fish/completions/]]..basename..[[.fish
451]]})
452 :command_target("command")
453 :require_command(false)
454
455 parser:flag("--version", "Show version info and exit.")
456 :action(function()
457 util.printout(program.." "..cfg.program_version)
458 util.printout(description)
459 util.printout()
460 os.exit(cmd.errorcodes.OK)
461 end)
462 parser:flag("--dev", "Enable the sub-repositories in rocks servers for "..
463 "rockspecs of in-development versions.")
464 parser:option("--server", "Fetch rocks/rockspecs from this server "..
465 "(takes priority over config file).")
466 :hidden_name("--from")
467 parser:option("--only-server", "Fetch rocks/rockspecs from this server only "..
468 "(overrides any entries in the config file).")
469 :argname("<server>")
470 :hidden_name("--only-from")
471 parser:option("--only-sources", "Restrict downloads to paths matching the given URL.")
472 :argname("<url>")
473 :hidden_name("--only-sources-from")
474 parser:option("--namespace", "Specify the rocks server namespace to use.")
475 :convert(string.lower)
476 parser:option("--lua-dir", "Which Lua installation to use.")
477 :argname("<prefix>")
478 parser:option("--lua-version", "Which Lua version to use.")
479 :argname("<ver>")
480 :convert(function(s) return (s:match("^%d+%.%d+$")) end)
481 parser:option("--tree", "Which tree to operate on.")
482 :hidden_name("--to")
483 parser:flag("--local", "Use the tree in the user's home directory.\n"..
484 "To enable it, see '"..program.." help path'.")
485 parser:flag("--global", "Use the system tree when `local_by_default` is `true`.")
486 parser:flag("--no-project", "Do not use project tree even if running from a project folder.")
487 parser:flag("--force-lock", "Attempt to overwrite the lock for commands " ..
488 "that require exclusive access, such as 'install'")
489 parser:flag("--verbose", "Display verbose output of commands executed.")
490 parser:option("--timeout", "Timeout on network operations, in seconds.\n"..
491 "0 means no timeout (wait forever). Default is "..
492 tostring(cfg.connection_timeout)..".")
493 :argname("<seconds>")
494 :convert(tonumber)
495
496 -- Used internally to force the use of a particular project tree
497 parser:option("--project-tree"):hidden(true)
498
499 for _, module in util.sortedpairs(cmd_modules) do
500 module.add_to_parser(parser)
501 end
502
503 return parser
504end
505
506local function get_first_arg()
507 if not arg then
508 return
509 end
510 local first_arg = arg[0]
511 local i = -1
512 while arg[i] do
513 first_arg = arg[i]
514 i = i -1
515 end
516 return first_arg
517end
518
519--- Main command-line processor.
520-- Parses input arguments and calls the appropriate driver function
521-- to execute the action requested on the command-line, forwarding
522-- to it any additional arguments passed by the user.
523-- @param description string: Short summary description of the program.
524-- @param commands table: contains the loaded modules representing commands.
525-- @param external_namespace string: where to look for external commands.
526-- @param ... string: Arguments given on the command-line.
527function cmd.run_command(description, commands, external_namespace, ...)
528
529 check_popen()
530
531 -- Preliminary initialization
532 cfg.init()
533
534 fs.init()
535
536 for _, module_name in ipairs(fs.modules(external_namespace)) do
537 if not commands[module_name] then
538 commands[module_name] = external_namespace.."."..module_name
539 end
540 end
541
542 local cmd_modules = {}
543 for name, module in pairs(commands) do
544 local pok, mod = pcall(require, module)
545 if pok and type(mod) == "table" then
546 local original_command = mod.command
547 if original_command then
548 if not mod.add_to_parser then
549 mod.add_to_parser = function(parser)
550 parser:command(name, mod.help, util.see_also())
551 :summary(mod.help_summary)
552 :handle_options(false)
553 :argument("input")
554 :args("*")
555 end
556
557 mod.command = function(args)
558 return original_command(args, unpack(args.input))
559 end
560 end
561 cmd_modules[name] = mod
562 else
563 util.warning("command module " .. module .. " does not implement command(), skipping")
564 end
565 else
566 util.warning("failed to load command module " .. module .. ": " .. mod)
567 end
568 end
569
570 local function process_cmdline_vars(...)
571 local args = pack(...)
572 local cmdline_vars = {}
573 local last = args.n
574 for i = 1, args.n do
575 if args[i] == "--" then
576 last = i - 1
577 break
578 end
579 end
580 for i = last, 1, -1 do
581 local arg = args[i]
582 if arg:match("^[^-][^=]*=") then
583 local var, val = arg:match("^([A-Z_][A-Z0-9_]*)=(.*)")
584 if val then
585 cmdline_vars[var] = val
586 table.remove(args, i)
587 else
588 die("Invalid assignment: "..arg)
589 end
590 end
591 end
592
593 return args, cmdline_vars
594 end
595
596 local args, cmdline_vars = process_cmdline_vars(...)
597 local parser = get_parser(description, cmd_modules)
598 args = parser:parse(args)
599
600 -- Compatibility for old flag
601 if args.nodeps then
602 args.deps_mode = "none"
603 end
604
605 if args.timeout then -- setting it in the config file will kick-in earlier in the process
606 cfg.connection_timeout = args.timeout
607 end
608
609 if args.command == "config" then
610 if args.key == "lua_version" and args.value then
611 args.lua_version = args.value
612 elseif args.key == "lua_dir" and args.value then
613 args.lua_dir = args.value
614 end
615 end
616
617 -----------------------------------------------------------------------------
618 local lua_found, err = init_config(args)
619 if err then
620 die(err)
621 end
622 -----------------------------------------------------------------------------
623
624 -- Now that the config is fully loaded, reinitialize fs using the full
625 -- feature set.
626 fs.init()
627
628 -- if the Lua interpreter wasn't explicitly found before cfg.init,
629 -- try again now.
630 local tried
631 if not lua_found then
632 local detected
633 detected, tried = search_lua(cfg.lua_version, args.verbose, cfg.variables.LUA_DIR)
634 if detected then
635 lua_found = true
636 cfg.variables.LUA = detected.lua
637 cfg.variables.LUA_DIR = detected.lua_dir
638 cfg.variables.LUA_BINDIR = detected.lua_bindir
639 if args.lua_dir then
640 cfg.variables.LUA_INCDIR = nil
641 cfg.variables.LUA_LIBDIR = nil
642 end
643 else
644 cfg.variables.LUA = nil
645 cfg.variables.LUA_DIR = nil
646 cfg.variables.LUA_BINDIR = nil
647 cfg.variables.LUA_INCDIR = nil
648 cfg.variables.LUA_LIBDIR = nil
649 end
650 end
651
652 if lua_found then
653 assert(cfg.variables.LUA)
654 else
655 -- Fallback producing _some_ Lua configuration based on the running interpreter.
656 -- Most likely won't produce correct results when running from the standalone binary,
657 -- so eventually we need to drop this and outright fail if Lua is not found
658 -- or explictly configured
659 if not cfg.variables.LUA then
660 local first_arg = get_first_arg()
661 local bin_dir = dir.dir_name(fs.absolute_name(first_arg))
662 local exe = dir.base_name(first_arg)
663 exe = exe:match("rocks") and ("lua" .. (cfg.arch:match("win") and ".exe" or "")) or exe
664 local full_path = dir.path(bin_dir, exe)
665 if util.check_lua_version(full_path, cfg.lua_version) then
666 cfg.variables.LUA = dir.path(bin_dir, exe)
667 cfg.variables.LUA_DIR = bin_dir:gsub("[/\\]bin[/\\]?$", "")
668 cfg.variables.LUA_BINDIR = bin_dir
669 cfg.variables.LUA_INCDIR = nil
670 cfg.variables.LUA_LIBDIR = nil
671 end
672 end
673 end
674
675 cfg.lua_found = lua_found
676
677 if cfg.project_dir then
678 cfg.project_dir = fs.absolute_name(cfg.project_dir)
679 end
680
681 if args.verbose then
682 cfg.verbose = true
683 print(("-"):rep(79))
684 print("Current configuration:")
685 print(("-"):rep(79))
686 print(config.to_string(cfg))
687 print(("-"):rep(79))
688 fs.verbose()
689 end
690
691 if (not fs.current_dir()) or fs.current_dir() == "" then
692 die("Current directory does not exist. Please run LuaRocks from an existing directory.")
693 end
694
695 local ok, err = process_tree_args(args, cfg.project_dir)
696 if not ok then
697 die(err)
698 end
699
700 ok, err = process_server_args(args)
701 if not ok then
702 die(err)
703 end
704
705 if args.only_sources then
706 cfg.only_sources_from = args.only_sources
707 end
708
709 for k, v in pairs(cmdline_vars) do
710 cfg.variables[k] = v
711 end
712
713 -- if running as superuser, use system cache dir
714 if fs.is_superuser() then
715 cfg.local_cache = dir.path(fs.system_cache_dir(), "luarocks")
716 end
717
718 if args.no_manifest then
719 cfg.no_manifest = true
720 end
721
722 if not args.command then
723 parser:epilog(variables_help..get_config_text(cfg))
724 util.printout()
725 util.printout(parser:get_help())
726 util.printout()
727 os.exit(cmd.errorcodes.OK)
728 end
729
730 if not cfg.variables["LUA"] and args.command ~= "config" and args.command ~= "help" then
731 local flag = (not cfg.project_tree)
732 and "--local "
733 or ""
734 if args.lua_version then
735 flag = "--lua-version=" .. args.lua_version .. " " .. flag
736 end
737 die((tried or "Lua interpreter not found.") ..
738 "\nPlease set your Lua interpreter with:\n\n" ..
739 " luarocks " .. flag.. "config variables.LUA " .. lua_example .. "\n")
740 end
741
742 local cmd_mod = cmd_modules[args.command]
743
744 local lock
745 if cmd_mod.needs_lock and cmd_mod.needs_lock(args) then
746 local ok, err = fs.check_command_permissions(args)
747 if not ok then
748 die(err, cmd.errorcodes.PERMISSIONDENIED)
749 end
750
751 lock, err = fs.lock_access(path.root_dir(cfg.root_dir), args.force_lock)
752 if not lock then
753 err = args.force_lock
754 and ("failed to force the lock" .. (err and ": " .. err or ""))
755 or (err and err ~= "File exists")
756 and err
757 or "try --force-lock to overwrite the lock"
758
759 die("command '" .. args.command .. "' " ..
760 "requires exclusive write access to " .. path.root_dir(cfg.root_dir) .. " - " ..
761 err, cmd.errorcodes.LOCK)
762 end
763 end
764
765 local call_ok, ok, err, exitcode = xpcall(function()
766 return cmd_mod.command(args)
767 end, error_handler)
768
769 if lock then
770 fs.unlock_access(lock)
771 end
772
773 if not call_ok then
774 die(ok, cmd.errorcodes.CRASH)
775 elseif not ok then
776 die(err, exitcode)
777 end
778 util.run_scheduled_functions()
779end
780
781return cmd
diff --git a/src/luarocks/cmd.lua b/src/luarocks/cmd.lua
index 7710dc68..3cf565bf 100644
--- a/src/luarocks/cmd.lua
+++ b/src/luarocks/cmd.lua
@@ -1,6 +1,16 @@
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 loadfile = _tl_compat and _tl_compat.loadfile or loadfile; 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; local _tl_table_unpack = unpack or table.unpack; local xpcall = _tl_compat and _tl_compat.xpcall or xpcall
2
3local cmd = {Module = {}, }
4
5
6
7
8
9
10
11
12
1 13
2--- Functions for command-line scripts.
3local cmd = {}
4 14
5local manif = require("luarocks.manif") 15local manif = require("luarocks.manif")
6local config = require("luarocks.config") 16local config = require("luarocks.config")
@@ -12,8 +22,22 @@ local fun = require("luarocks.fun")
12local fs = require("luarocks.fs") 22local fs = require("luarocks.fs")
13local argparse = require("luarocks.vendor.argparse") 23local argparse = require("luarocks.vendor.argparse")
14 24
15local unpack = table.unpack or unpack 25
16local pack = table.pack or function(...) return { n = select("#", ...), ... } end 26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
17 41
18local hc_ok, hardcoded = pcall(require, "luarocks.core.hardcoded") 42local hc_ok, hardcoded = pcall(require, "luarocks.core.hardcoded")
19if not hc_ok then 43if not hc_ok then
@@ -28,7 +52,7 @@ cmd.errorcodes = {
28 PERMISSIONDENIED = 2, 52 PERMISSIONDENIED = 2,
29 CONFIGFILE = 3, 53 CONFIGFILE = 3,
30 LOCK = 4, 54 LOCK = 4,
31 CRASH = 99 55 CRASH = 99,
32} 56}
33 57
34local function check_popen() 58local function check_popen()
@@ -53,10 +77,11 @@ do
53 end 77 end
54 78
55 local function strip_trailing_slashes() 79 local function strip_trailing_slashes()
56 if type(cfg.root_dir) == "string" then 80 local cfg_root_dir = cfg.root_dir
57 cfg.root_dir = cfg.root_dir:gsub("/+$", "") 81 if type(cfg_root_dir) == "string" then
82 cfg.root_dir = (cfg.root_dir):gsub("/+$", "")
58 else 83 else
59 cfg.root_dir.root = cfg.root_dir.root:gsub("/+$", "") 84 (cfg.root_dir).root = (cfg.root_dir).root:gsub("/+$", "")
60 end 85 end
61 cfg.rocks_dir = cfg.rocks_dir:gsub("/+$", "") 86 cfg.rocks_dir = cfg.rocks_dir:gsub("/+$", "")
62 cfg.deploy_bin_dir = cfg.deploy_bin_dir:gsub("/+$", "") 87 cfg.deploy_bin_dir = cfg.deploy_bin_dir:gsub("/+$", "")
@@ -68,7 +93,7 @@ do
68 for _, tree in ipairs(cfg.rocks_trees) do 93 for _, tree in ipairs(cfg.rocks_trees) do
69 if type(tree) == "table" and name == tree.name then 94 if type(tree) == "table" and name == tree.name then
70 if not tree.root then 95 if not tree.root then
71 return nil, "Configuration error: tree '"..tree.name.."' has no 'root' field." 96 return nil, "Configuration error: tree '" .. tree.name .. "' has no 'root' field."
72 end 97 end
73 replace_tree(args, tree.root, tree) 98 replace_tree(args, tree.root, tree)
74 return true 99 return true
@@ -90,14 +115,14 @@ do
90 local root_dir = fs.absolute_name(args.tree) 115 local root_dir = fs.absolute_name(args.tree)
91 replace_tree(args, root_dir) 116 replace_tree(args, root_dir)
92 if (args.deps_mode or cfg.deps_mode) ~= "order" then 117 if (args.deps_mode or cfg.deps_mode) ~= "order" then
93 table.insert(cfg.rocks_trees, 1, { name = "arg", root = root_dir } ) 118 table.insert(cfg.rocks_trees, 1, { name = "arg", root = root_dir })
94 end 119 end
95 end 120 end
96 elseif args["local"] then 121 elseif args["local"] then
97 if fs.is_superuser() then 122 if fs.is_superuser() then
98 return nil, "The --local flag is meant for operating in a user's home directory.\n".. 123 return nil, "The --local flag is meant for operating in a user's home directory.\n" ..
99 "You are running as a superuser, which is intended for system-wide operation.\n".. 124 "You are running as a superuser, which is intended for system-wide operation.\n" ..
100 "To force using the superuser's home, use --tree explicitly." 125 "To force using the superuser's home, use --tree explicitly."
101 else 126 else
102 local ok, err = set_named_tree(args, "user") 127 local ok, err = set_named_tree(args, "user")
103 if not ok then 128 if not ok then
@@ -106,12 +131,12 @@ do
106 end 131 end
107 elseif args.project_tree then 132 elseif args.project_tree then
108 local tree = args.project_tree 133 local tree = args.project_tree
109 table.insert(cfg.rocks_trees, 1, { name = "project", root = tree } ) 134 table.insert(cfg.rocks_trees, 1, { name = "project", root = tree })
110 manif.load_rocks_tree_manifests() 135 manif.load_rocks_tree_manifests()
111 path.use_tree(tree) 136 path.use_tree(tree)
112 elseif project_dir then 137 elseif project_dir then
113 local project_tree = project_dir .. "/lua_modules" 138 local project_tree = project_dir .. "/lua_modules"
114 table.insert(cfg.rocks_trees, 1, { name = "project", root = project_tree } ) 139 table.insert(cfg.rocks_trees, 1, { name = "project", root = project_tree })
115 manif.load_rocks_tree_manifests() 140 manif.load_rocks_tree_manifests()
116 path.use_tree(project_tree) 141 path.use_tree(project_tree)
117 elseif cfg.local_by_default then 142 elseif cfg.local_by_default then
@@ -136,13 +161,19 @@ end
136local function process_server_args(args) 161local function process_server_args(args)
137 if args.server then 162 if args.server then
138 local protocol, pathname = dir.split_url(args.server) 163 local protocol, pathname = dir.split_url(args.server)
139 table.insert(cfg.rocks_servers, 1, protocol.."://"..pathname) 164 table.insert(cfg.rocks_servers, 1, protocol .. "://" .. pathname)
140 end 165 end
141 166
142 if args.dev then 167 if args.dev then
143 local append_dev = function(s) return dir.path(s, "dev") end 168 for i, server in ipairs(cfg.rocks_servers) do
144 local dev_servers = fun.traverse(cfg.rocks_servers, append_dev) 169 if type(server) == "string" then
145 cfg.rocks_servers = fun.concat(dev_servers, cfg.rocks_servers) 170 cfg.rocks_servers[i] = dir.path(server, "dev")
171 else
172 for j, mirror in ipairs(server) do
173 server[j] = dir.path(mirror, "dev")
174 end
175 end
176 end
146 end 177 end
147 178
148 if args.only_server then 179 if args.only_server then
@@ -171,22 +202,22 @@ local function error_handler(err)
171 if cfg and cfg.is_binary then 202 if cfg and cfg.is_binary then
172 mode = mode .. " (binary)" 203 mode = mode .. " (binary)"
173 end 204 end
174 return debug.traceback("LuaRocks "..cfg.program_version.. 205 return debug.traceback("LuaRocks " .. cfg.program_version ..
175 " bug (please report at https://github.com/luarocks/luarocks/issues).\n".. 206 " bug (please report at https://github.com/luarocks/luarocks/issues).\n" ..
176 mode.."\n"..err, 2) 207 mode .. "\n" .. err, 2)
177end 208end
178 209
179--- Display an error message and exit. 210
180-- @param message string: The error message. 211
181-- @param exitcode number: the exitcode to use 212
182local function die(message, exitcode) 213local function die(message, exitcode)
183 assert(type(message) == "string", "bad error, expected string, got: " .. type(message)) 214 assert(type(message) == "string", "bad error, expected string, got: " .. type(message))
184 assert(exitcode == nil or type(exitcode) == "number", "bad error, expected number, got: " .. type(exitcode) .. " - " .. tostring(exitcode)) 215 assert(exitcode == nil or type(exitcode) == "number", "bad error, expected number, got: " .. type(exitcode) .. " - " .. tostring(exitcode))
185 util.printerr("\nError: "..message) 216 util.printerr("\nError: " .. message)
186 217
187 local ok, err = xpcall(util.run_scheduled_functions, error_handler) 218 local ok, err = xpcall(util.run_scheduled_functions, error_handler)
188 if not ok then 219 if not ok then
189 util.printerr("\nError: "..err) 220 util.printerr("\nError: " .. err)
190 exitcode = cmd.errorcodes.CRASH 221 exitcode = cmd.errorcodes.CRASH
191 end 222 end
192 223
@@ -200,7 +231,7 @@ local function search_lua(lua_version, verbose, search_at)
200 231
201 local path_sep = (package.config:sub(1, 1) == "\\" and ";" or ":") 232 local path_sep = (package.config:sub(1, 1) == "\\" and ";" or ":")
202 local all_tried = {} 233 local all_tried = {}
203 for bindir in (os.getenv("PATH") or ""):gmatch("[^"..path_sep.."]+") do 234 for bindir in (os.getenv("PATH") or ""):gmatch("[^" .. path_sep .. "]+") do
204 local searchdir = (bindir:gsub("[\\/]+bin[\\/]?$", "")) 235 local searchdir = (bindir:gsub("[\\/]+bin[\\/]?$", ""))
205 local detected, tried = util.find_lua(searchdir, lua_version) 236 local detected, tried = util.find_lua(searchdir, lua_version)
206 if detected then 237 if detected then
@@ -210,9 +241,9 @@ local function search_lua(lua_version, verbose, search_at)
210 end 241 end
211 end 242 end
212 return nil, "Could not find " .. 243 return nil, "Could not find " ..
213 (lua_version and "Lua " .. lua_version or "Lua") .. 244 (lua_version and "Lua " .. lua_version or "Lua") ..
214 " in PATH." .. 245 " in PATH." ..
215 (verbose and " Tried:\n" .. table.concat(all_tried, "\n") or "") 246 (verbose and " Tried:\n" .. table.concat(all_tried, "\n") or "")
216end 247end
217 248
218local init_config 249local init_config
@@ -224,7 +255,7 @@ do
224 return project_tree:gsub("[/\\][^/\\]+$", ""), true 255 return project_tree:gsub("[/\\][^/\\]+$", ""), true
225 else 256 else
226 local try = "." 257 local try = "."
227 for _ = 1, 10 do -- FIXME detect when root dir was hit instead 258 for _ = 1, 10 do
228 if util.exists(try .. "/.luarocks") and util.exists(try .. "/lua_modules") then 259 if util.exists(try .. "/.luarocks") and util.exists(try .. "/lua_modules") then
229 return dir.normalize(try), false 260 return dir.normalize(try), false
230 elseif util.exists(try .. "/.luarocks-no-project") then 261 elseif util.exists(try .. "/.luarocks-no-project") then
@@ -251,7 +282,7 @@ do
251 table.insert(dirs, cfg.sysconfdir) 282 table.insert(dirs, cfg.sysconfdir)
252 for _, d in ipairs(dirs) do 283 for _, d in ipairs(dirs) do
253 local f = dir.path(d, "default-lua-version.lua") 284 local f = dir.path(d, "default-lua-version.lua")
254 local mod, err = loadfile(f, "t") 285 local mod, _ = loadfile(f, "t")
255 if mod then 286 if mod then
256 local pok, ver = pcall(mod) 287 local pok, ver = pcall(mod)
257 if pok and type(ver) == "string" and ver:match("%d+.%d+") then 288 if pok and type(ver) == "string" and ver:match("%d+.%d+") then
@@ -267,23 +298,23 @@ do
267 298
268 local function find_version_from_config(dirname) 299 local function find_version_from_config(dirname)
269 return fun.find(util.lua_versions("descending"), function(v) 300 return fun.find(util.lua_versions("descending"), function(v)
270 if util.exists(dir.path(dirname, ".luarocks", "config-"..v..".lua")) then 301 if util.exists(dir.path(dirname, ".luarocks", "config-" .. v .. ".lua")) then
271 return v 302 return v
272 end 303 end
273 end) 304 end)
274 end 305 end
275 306
276 local function detect_lua_via_args(args, project_dir) 307 local function detect_lua_via_args(args, project_dir)
277 local lua_version = args.lua_version 308 local lua_version = args.lua_version or
278 or find_default_lua_version(args, project_dir) 309 find_default_lua_version(args, project_dir) or
279 or (project_dir and find_version_from_config(project_dir)) 310 (project_dir and find_version_from_config(project_dir))
280 311
281 if args.lua_dir then 312 if args.lua_dir then
282 local detected, err = util.find_lua(args.lua_dir, lua_version) 313 local detected, err = util.find_lua(args.lua_dir, lua_version)
283 if not detected then 314 if not detected then
284 local suggestion = (not args.lua_version) 315 local suggestion = (not args.lua_version) and
285 and "\nYou may want to specify a different Lua version with --lua-version\n" 316 "\nYou may want to specify a different Lua version with --lua-version\n" or
286 or "" 317 ""
287 die(err .. suggestion) 318 die(err .. suggestion)
288 end 319 end
289 return detected 320 return detected
@@ -342,16 +373,16 @@ Variables:
342 373
343]] 374]]
344 375
345local lua_example = package.config:sub(1, 1) == "\\" 376local lua_example = package.config:sub(1, 1) == "\\" and
346 and "<d:\\path\\lua.exe>" 377"<d:\\path\\lua.exe>" or
347 or "</path/lua>" 378"</path/lua>"
348 379
349local function show_status(file, status, err) 380local function show_status(file, status, err)
350 return (file and file .. " " or "") .. (status and "(ok)" or ("(" .. (err or "not found") ..")")) 381 return (file and file .. " " or "") .. (status and "(ok)" or ("(" .. (err or "not found") .. ")"))
351end 382end
352 383
353local function use_to_fix_location(key, what) 384local function use_to_fix_location(key, what)
354 local buf = " ****************************************\n" 385 local buf = " ****************************************\n"
355 buf = buf .. " Use the command\n\n" 386 buf = buf .. " Use the command\n\n"
356 buf = buf .. " luarocks config " .. key .. " " .. (what or "<dir>") .. "\n\n" 387 buf = buf .. " luarocks config " .. key .. " " .. (what or "<dir>") .. "\n\n"
357 buf = buf .. " to fix the location\n" 388 buf = buf .. " to fix the location\n"
@@ -359,7 +390,7 @@ local function use_to_fix_location(key, what)
359 return buf 390 return buf
360end 391end
361 392
362local function get_config_text(cfg) -- luacheck: ignore 431 393local function get_config_text(cfg)
363 local deps = require("luarocks.deps") 394 local deps = require("luarocks.deps")
364 395
365 local libdir_ok = deps.check_lua_libdir(cfg.variables) 396 local libdir_ok = deps.check_lua_libdir(cfg.variables)
@@ -367,42 +398,42 @@ local function get_config_text(cfg) -- luacheck: ignore 431
367 local lua_ok = cfg.variables.LUA and fs.exists(cfg.variables.LUA) 398 local lua_ok = cfg.variables.LUA and fs.exists(cfg.variables.LUA)
368 399
369 local buf = "Configuration:\n" 400 local buf = "Configuration:\n"
370 buf = buf.." Lua:\n" 401 buf = buf .. " Lua:\n"
371 buf = buf.." Version : "..cfg.lua_version.."\n" 402 buf = buf .. " Version : " .. cfg.lua_version .. "\n"
372 if cfg.luajit_version then 403 if cfg.luajit_version then
373 buf = buf.." LuaJIT : "..cfg.luajit_version.."\n" 404 buf = buf .. " LuaJIT : " .. cfg.luajit_version .. "\n"
374 end 405 end
375 buf = buf.." LUA : "..show_status(cfg.variables.LUA, lua_ok, "interpreter not found").."\n" 406 buf = buf .. " LUA : " .. show_status(cfg.variables.LUA, lua_ok, "interpreter not found") .. "\n"
376 if not lua_ok then 407 if not lua_ok then
377 buf = buf .. use_to_fix_location("variables.LUA", lua_example) 408 buf = buf .. use_to_fix_location("variables.LUA", lua_example)
378 end 409 end
379 buf = buf.." LUA_INCDIR : "..show_status(cfg.variables.LUA_INCDIR, incdir_ok, "lua.h not found").."\n" 410 buf = buf .. " LUA_INCDIR : " .. show_status(cfg.variables.LUA_INCDIR, incdir_ok, "lua.h not found") .. "\n"
380 if lua_ok and not incdir_ok then 411 if lua_ok and not incdir_ok then
381 buf = buf .. use_to_fix_location("variables.LUA_INCDIR") 412 buf = buf .. use_to_fix_location("variables.LUA_INCDIR")
382 end 413 end
383 buf = buf.." LUA_LIBDIR : "..show_status(cfg.variables.LUA_LIBDIR, libdir_ok, "Lua library itself not found").."\n" 414 buf = buf .. " LUA_LIBDIR : " .. show_status(cfg.variables.LUA_LIBDIR, libdir_ok, "Lua library itself not found") .. "\n"
384 if lua_ok and not libdir_ok then 415 if lua_ok and not libdir_ok then
385 buf = buf .. use_to_fix_location("variables.LUA_LIBDIR") 416 buf = buf .. use_to_fix_location("variables.LUA_LIBDIR")
386 end 417 end
387 418
388 buf = buf.."\n Configuration files:\n" 419 buf = buf .. "\n Configuration files:\n"
389 local conf = cfg.config_files 420 local conf = cfg.config_files
390 buf = buf.." System : "..show_status(fs.absolute_name(conf.system.file), conf.system.found).."\n" 421 buf = buf .. " System : " .. show_status(fs.absolute_name(conf.system.file), conf.system.found) .. "\n"
391 if conf.user.file then 422 if conf.user.file then
392 buf = buf.." User : "..show_status(fs.absolute_name(conf.user.file), conf.user.found).."\n" 423 buf = buf .. " User : " .. show_status(fs.absolute_name(conf.user.file), conf.user.found) .. "\n"
393 else 424 else
394 buf = buf.." User : disabled in this LuaRocks installation.\n" 425 buf = buf .. " User : disabled in this LuaRocks installation.\n"
395 end 426 end
396 if conf.project then 427 if conf.project then
397 buf = buf.." Project : "..show_status(fs.absolute_name(conf.project.file), conf.project.found).."\n" 428 buf = buf .. " Project : " .. show_status(fs.absolute_name(conf.project.file), conf.project.found) .. "\n"
398 end 429 end
399 buf = buf.."\n Rocks trees in use: \n" 430 buf = buf .. "\n Rocks trees in use: \n"
400 for _, tree in ipairs(cfg.rocks_trees) do 431 for _, tree in ipairs(cfg.rocks_trees) do
401 if type(tree) == "string" then 432 if type(tree) == "string" then
402 buf = buf.." "..fs.absolute_name(tree) 433 buf = buf .. " " .. fs.absolute_name(tree)
403 else 434 else
404 local name = tree.name and " (\""..tree.name.."\")" or "" 435 local name = tree.name and " (\"" .. tree.name .. "\")" or ""
405 buf = buf.." "..fs.absolute_name(tree.root)..name 436 buf = buf .. " " .. fs.absolute_name(tree.root) .. name
406 end 437 end
407 buf = buf .. "\n" 438 buf = buf .. "\n"
408 end 439 end
@@ -413,23 +444,23 @@ end
413local function get_parser(description, cmd_modules) 444local function get_parser(description, cmd_modules)
414 local basename = dir.base_name(program) 445 local basename = dir.base_name(program)
415 local parser = argparse( 446 local parser = argparse(
416 basename, "LuaRocks "..cfg.program_version..", the Lua package manager\n\n".. 447 basename, "LuaRocks " .. cfg.program_version .. ", the Lua package manager\n\n" ..
417 program.." - "..description, variables_help.."Run '"..basename.. 448 program .. " - " .. description, variables_help .. "Run '" .. basename ..
418 "' without any arguments to see the configuration.") 449 "' without any arguments to see the configuration."):
419 :help_max_width(80) 450 help_max_width(80):
420 :add_help_command() 451 add_help_command():
421 :add_complete_command({ 452 add_complete_command({
422 help_max_width = 100, 453 help_max_width = 100,
423 summary = "Output a shell completion script.", 454 summary = "Output a shell completion script.",
424 description = [[ 455 description = [[
425Output a shell completion script. 456Output a shell completion script.
426 457
427Enabling completions for Bash: 458Enabling completions for Bash:
428 459
429 Add the following line to your ~/.bashrc: 460 Add the following line to your ~/.bashrc:
430 source <(]]..basename..[[ completion bash) 461 source <(]] .. basename .. [[ completion bash)
431 or save the completion script to the local completion directory: 462 or save the completion script to the local completion directory:
432 ]]..basename..[[ completion bash > ~/.local/share/bash-completion/completions/]]..basename..[[ 463 ]] .. basename .. [[ completion bash > ~/.local/share/bash-completion/completions/]] .. basename .. [[
433 464
434 465
435Enabling completions for Zsh: 466Enabling completions for Zsh:
@@ -439,61 +470,61 @@ Enabling completions for Zsh:
439 fpath=(~/.zfunc $fpath) 470 fpath=(~/.zfunc $fpath)
440 to your ~/.zshrc. 471 to your ~/.zshrc.
441 Then run: 472 Then run:
442 ]]..basename..[[ completion zsh > ~/.zfunc/_]]..basename..[[ 473 ]] .. basename .. [[ completion zsh > ~/.zfunc/_]] .. basename .. [[
443 474
444 475
445Enabling completion for Fish: 476Enabling completion for Fish:
446 477
447 Add the following line to your ~/.config/fish/config.fish: 478 Add the following line to your ~/.config/fish/config.fish:
448 ]]..basename..[[ completion fish | source 479 ]] .. basename .. [[ completion fish | source
449 or save the completion script to the local completion directory: 480 or save the completion script to the local completion directory:
450 ]]..basename..[[ completion fish > ~/.config/fish/completions/]]..basename..[[.fish 481 ]] .. basename .. [[ completion fish > ~/.config/fish/completions/]] .. basename .. [[.fish
451]]}) 482]], }):
452 :command_target("command") 483 command_target("command"):
453 :require_command(false) 484 require_command(false)
454 485
455 parser:flag("--version", "Show version info and exit.") 486 parser:flag("--version", "Show version info and exit."):
456 :action(function() 487 action(function()
457 util.printout(program.." "..cfg.program_version) 488 util.printout(program .. " " .. cfg.program_version)
458 util.printout(description) 489 util.printout(description)
459 util.printout() 490 util.printout()
460 os.exit(cmd.errorcodes.OK) 491 os.exit(cmd.errorcodes.OK)
461 end) 492 end)
462 parser:flag("--dev", "Enable the sub-repositories in rocks servers for ".. 493 parser:flag("--dev", "Enable the sub-repositories in rocks servers for " ..
463 "rockspecs of in-development versions.") 494 "rockspecs of in-development versions.")
464 parser:option("--server", "Fetch rocks/rockspecs from this server ".. 495 parser:option("--server", "Fetch rocks/rockspecs from this server " ..
465 "(takes priority over config file).") 496 "(takes priority over config file)."):
466 :hidden_name("--from") 497 hidden_name("--from")
467 parser:option("--only-server", "Fetch rocks/rockspecs from this server only ".. 498 parser:option("--only-server", "Fetch rocks/rockspecs from this server only " ..
468 "(overrides any entries in the config file).") 499 "(overrides any entries in the config file)."):
469 :argname("<server>") 500 argname("<server>"):
470 :hidden_name("--only-from") 501 hidden_name("--only-from")
471 parser:option("--only-sources", "Restrict downloads to paths matching the given URL.") 502 parser:option("--only-sources", "Restrict downloads to paths matching the given URL."):
472 :argname("<url>") 503 argname("<url>"):
473 :hidden_name("--only-sources-from") 504 hidden_name("--only-sources-from")
474 parser:option("--namespace", "Specify the rocks server namespace to use.") 505 parser:option("--namespace", "Specify the rocks server namespace to use."):
475 :convert(string.lower) 506 convert(string.lower)
476 parser:option("--lua-dir", "Which Lua installation to use.") 507 parser:option("--lua-dir", "Which Lua installation to use."):
477 :argname("<prefix>") 508 argname("<prefix>")
478 parser:option("--lua-version", "Which Lua version to use.") 509 parser:option("--lua-version", "Which Lua version to use."):
479 :argname("<ver>") 510 argname("<ver>"):
480 :convert(function(s) return (s:match("^%d+%.%d+$")) end) 511 convert(function(s) return (s:match("^%d+%.%d+$")) end)
481 parser:option("--tree", "Which tree to operate on.") 512 parser:option("--tree", "Which tree to operate on."):
482 :hidden_name("--to") 513 hidden_name("--to")
483 parser:flag("--local", "Use the tree in the user's home directory.\n".. 514 parser:flag("--local", "Use the tree in the user's home directory.\n" ..
484 "To enable it, see '"..program.." help path'.") 515 "To enable it, see '" .. program .. " help path'.")
485 parser:flag("--global", "Use the system tree when `local_by_default` is `true`.") 516 parser:flag("--global", "Use the system tree when `local_by_default` is `true`.")
486 parser:flag("--no-project", "Do not use project tree even if running from a project folder.") 517 parser:flag("--no-project", "Do not use project tree even if running from a project folder.")
487 parser:flag("--force-lock", "Attempt to overwrite the lock for commands " .. 518 parser:flag("--force-lock", "Attempt to overwrite the lock for commands " ..
488 "that require exclusive access, such as 'install'") 519 "that require exclusive access, such as 'install'")
489 parser:flag("--verbose", "Display verbose output of commands executed.") 520 parser:flag("--verbose", "Display verbose output of commands executed.")
490 parser:option("--timeout", "Timeout on network operations, in seconds.\n".. 521 parser:option("--timeout", "Timeout on network operations, in seconds.\n" ..
491 "0 means no timeout (wait forever). Default is ".. 522 "0 means no timeout (wait forever). Default is " ..
492 tostring(cfg.connection_timeout)..".") 523 tostring(cfg.connection_timeout) .. "."):
493 :argname("<seconds>") 524 argname("<seconds>"):
494 :convert(tonumber) 525 convert(tonumber)
526
495 527
496 -- Used internally to force the use of a particular project tree
497 parser:option("--project-tree"):hidden(true) 528 parser:option("--project-tree"):hidden(true)
498 529
499 for _, module in util.sortedpairs(cmd_modules) do 530 for _, module in util.sortedpairs(cmd_modules) do
@@ -511,31 +542,31 @@ local function get_first_arg()
511 local i = -1 542 local i = -1
512 while arg[i] do 543 while arg[i] do
513 first_arg = arg[i] 544 first_arg = arg[i]
514 i = i -1 545 i = i - 1
515 end 546 end
516 return first_arg 547 return first_arg
517end 548end
518 549
519--- Main command-line processor. 550
520-- Parses input arguments and calls the appropriate driver function 551
521-- to execute the action requested on the command-line, forwarding 552
522-- to it any additional arguments passed by the user. 553
523-- @param description string: Short summary description of the program. 554
524-- @param commands table: contains the loaded modules representing commands. 555
525-- @param external_namespace string: where to look for external commands. 556
526-- @param ... string: Arguments given on the command-line. 557
527function cmd.run_command(description, commands, external_namespace, ...) 558function cmd.run_command(description, commands, external_namespace, ...)
528 559
529 check_popen() 560 check_popen()
530 561
531 -- Preliminary initialization 562
532 cfg.init() 563 cfg.init()
533 564
534 fs.init() 565 fs.init()
535 566
536 for _, module_name in ipairs(fs.modules(external_namespace)) do 567 for _, module_name in ipairs(fs.modules(external_namespace)) do
537 if not commands[module_name] then 568 if not commands[module_name] then
538 commands[module_name] = external_namespace.."."..module_name 569 commands[module_name] = external_namespace .. "." .. module_name
539 end 570 end
540 end 571 end
541 572
@@ -547,15 +578,15 @@ function cmd.run_command(description, commands, external_namespace, ...)
547 if original_command then 578 if original_command then
548 if not mod.add_to_parser then 579 if not mod.add_to_parser then
549 mod.add_to_parser = function(parser) 580 mod.add_to_parser = function(parser)
550 parser:command(name, mod.help, util.see_also()) 581 parser:command(name, mod.help, util.see_also()):
551 :summary(mod.help_summary) 582 summary(mod.help_summary):
552 :handle_options(false) 583 handle_options(false):
553 :argument("input") 584 argument("input"):
554 :args("*") 585 args("*")
555 end 586 end
556 587
557 mod.command = function(args) 588 mod.command = function(args)
558 return original_command(args, unpack(args.input)) 589 return original_command(args, _tl_table_unpack(args.input))
559 end 590 end
560 end 591 end
561 cmd_modules[name] = mod 592 cmd_modules[name] = mod
@@ -563,12 +594,12 @@ function cmd.run_command(description, commands, external_namespace, ...)
563 util.warning("command module " .. module .. " does not implement command(), skipping") 594 util.warning("command module " .. module .. " does not implement command(), skipping")
564 end 595 end
565 else 596 else
566 util.warning("failed to load command module " .. module .. ": " .. mod) 597 util.warning("failed to load command module " .. module .. ": " .. tostring(mod))
567 end 598 end
568 end 599 end
569 600
570 local function process_cmdline_vars(...) 601 local function process_cmdline_vars(...)
571 local args = pack(...) 602 local args = table.pack(...)
572 local cmdline_vars = {} 603 local cmdline_vars = {}
573 local last = args.n 604 local last = args.n
574 for i = 1, args.n do 605 for i = 1, args.n do
@@ -585,7 +616,7 @@ function cmd.run_command(description, commands, external_namespace, ...)
585 cmdline_vars[var] = val 616 cmdline_vars[var] = val
586 table.remove(args, i) 617 table.remove(args, i)
587 else 618 else
588 die("Invalid assignment: "..arg) 619 die("Invalid assignment: " .. arg)
589 end 620 end
590 end 621 end
591 end 622 end
@@ -595,48 +626,48 @@ function cmd.run_command(description, commands, external_namespace, ...)
595 626
596 local args, cmdline_vars = process_cmdline_vars(...) 627 local args, cmdline_vars = process_cmdline_vars(...)
597 local parser = get_parser(description, cmd_modules) 628 local parser = get_parser(description, cmd_modules)
598 args = parser:parse(args) 629 local argsp = parser:parse(args)
630
599 631
600 -- Compatibility for old flag 632 if argsp.nodeps then
601 if args.nodeps then 633 argsp.deps_mode = "none"
602 args.deps_mode = "none"
603 end 634 end
604 635
605 if args.timeout then -- setting it in the config file will kick-in earlier in the process 636 if argsp.timeout then
606 cfg.connection_timeout = args.timeout 637 cfg.connection_timeout = argsp.timeout
607 end 638 end
608 639
609 if args.command == "config" then 640 if argsp.command == "config" then
610 if args.key == "lua_version" and args.value then 641 if argsp.key == "lua_version" and argsp.value then
611 args.lua_version = args.value 642 argsp.lua_version = argsp.value
612 elseif args.key == "lua_dir" and args.value then 643 elseif argsp.key == "lua_dir" and argsp.value then
613 args.lua_dir = args.value 644 argsp.lua_dir = argsp.value
614 end 645 end
615 end 646 end
616 647
617 ----------------------------------------------------------------------------- 648
618 local lua_found, err = init_config(args) 649 local lua_found, err = init_config(argsp)
619 if err then 650 if err then
620 die(err) 651 die(err)
621 end 652 end
622 -----------------------------------------------------------------------------
623 653
624 -- Now that the config is fully loaded, reinitialize fs using the full 654
625 -- feature set. 655
656
626 fs.init() 657 fs.init()
627 658
628 -- if the Lua interpreter wasn't explicitly found before cfg.init, 659
629 -- try again now. 660
630 local tried 661 local tried
631 if not lua_found then 662 if not lua_found then
632 local detected 663 local detected
633 detected, tried = search_lua(cfg.lua_version, args.verbose, cfg.variables.LUA_DIR) 664 detected, tried = search_lua(cfg.lua_version, argsp.verbose, cfg.variables.LUA_DIR)
634 if detected then 665 if detected then
635 lua_found = true 666 lua_found = true
636 cfg.variables.LUA = detected.lua 667 cfg.variables.LUA = detected.lua
637 cfg.variables.LUA_DIR = detected.lua_dir 668 cfg.variables.LUA_DIR = detected.lua_dir
638 cfg.variables.LUA_BINDIR = detected.lua_bindir 669 cfg.variables.LUA_BINDIR = detected.lua_bindir
639 if args.lua_dir then 670 if argsp.lua_dir then
640 cfg.variables.LUA_INCDIR = nil 671 cfg.variables.LUA_INCDIR = nil
641 cfg.variables.LUA_LIBDIR = nil 672 cfg.variables.LUA_LIBDIR = nil
642 end 673 end
@@ -652,10 +683,10 @@ function cmd.run_command(description, commands, external_namespace, ...)
652 if lua_found then 683 if lua_found then
653 assert(cfg.variables.LUA) 684 assert(cfg.variables.LUA)
654 else 685 else
655 -- Fallback producing _some_ Lua configuration based on the running interpreter. 686
656 -- Most likely won't produce correct results when running from the standalone binary, 687
657 -- so eventually we need to drop this and outright fail if Lua is not found 688
658 -- or explictly configured 689
659 if not cfg.variables.LUA then 690 if not cfg.variables.LUA then
660 local first_arg = get_first_arg() 691 local first_arg = get_first_arg()
661 local bin_dir = dir.dir_name(fs.absolute_name(first_arg)) 692 local bin_dir = dir.dir_name(fs.absolute_name(first_arg))
@@ -678,7 +709,7 @@ function cmd.run_command(description, commands, external_namespace, ...)
678 cfg.project_dir = fs.absolute_name(cfg.project_dir) 709 cfg.project_dir = fs.absolute_name(cfg.project_dir)
679 end 710 end
680 711
681 if args.verbose then 712 if argsp.verbose then
682 cfg.verbose = true 713 cfg.verbose = true
683 print(("-"):rep(79)) 714 print(("-"):rep(79))
684 print("Current configuration:") 715 print("Current configuration:")
@@ -692,78 +723,78 @@ function cmd.run_command(description, commands, external_namespace, ...)
692 die("Current directory does not exist. Please run LuaRocks from an existing directory.") 723 die("Current directory does not exist. Please run LuaRocks from an existing directory.")
693 end 724 end
694 725
695 local ok, err = process_tree_args(args, cfg.project_dir) 726 local ok, err = process_tree_args(argsp, cfg.project_dir)
696 if not ok then 727 if not ok then
697 die(err) 728 die(err)
698 end 729 end
699 730
700 ok, err = process_server_args(args) 731 ok, err = process_server_args(argsp)
701 if not ok then 732 if not ok then
702 die(err) 733 die(err)
703 end 734 end
704 735
705 if args.only_sources then 736 if argsp.only_sources then
706 cfg.only_sources_from = args.only_sources 737 cfg.only_sources_from = argsp.only_sources
707 end 738 end
708 739
709 for k, v in pairs(cmdline_vars) do 740 for k, v in pairs(cmdline_vars) do
710 cfg.variables[k] = v 741 cfg.variables[k] = v
711 end 742 end
712 743
713 -- if running as superuser, use system cache dir 744
714 if fs.is_superuser() then 745 if fs.is_superuser() then
715 cfg.local_cache = dir.path(fs.system_cache_dir(), "luarocks") 746 cfg.local_cache = dir.path(fs.system_cache_dir(), "luarocks")
716 end 747 end
717 748
718 if args.no_manifest then 749 if argsp.no_manifest then
719 cfg.no_manifest = true 750 cfg.no_manifest = true
720 end 751 end
721 752
722 if not args.command then 753 if not argsp.command then
723 parser:epilog(variables_help..get_config_text(cfg)) 754 parser:epilog(variables_help .. get_config_text(cfg))
724 util.printout() 755 util.printout()
725 util.printout(parser:get_help()) 756 util.printout(parser:get_help())
726 util.printout() 757 util.printout()
727 os.exit(cmd.errorcodes.OK) 758 os.exit(cmd.errorcodes.OK)
728 end 759 end
729 760
730 if not cfg.variables["LUA"] and args.command ~= "config" and args.command ~= "help" then 761 if not cfg.variables["LUA"] and argsp.command ~= "config" and argsp.command ~= "help" then
731 local flag = (not cfg.project_tree) 762 local flag = (not cfg.project_tree) and
732 and "--local " 763 "--local " or
733 or "" 764 ""
734 if args.lua_version then 765 if argsp.lua_version then
735 flag = "--lua-version=" .. args.lua_version .. " " .. flag 766 flag = "--lua-version=" .. argsp.lua_version .. " " .. flag
736 end 767 end
737 die((tried or "Lua interpreter not found.") .. 768 die((tried or "Lua interpreter not found.") ..
738 "\nPlease set your Lua interpreter with:\n\n" .. 769 "\nPlease set your Lua interpreter with:\n\n" ..
739 " luarocks " .. flag.. "config variables.LUA " .. lua_example .. "\n") 770 " luarocks " .. flag .. "config variables.LUA " .. lua_example .. "\n")
740 end 771 end
741 772
742 local cmd_mod = cmd_modules[args.command] 773 local cmd_mod = cmd_modules[argsp.command]
743 774
744 local lock 775 local lock
745 if cmd_mod.needs_lock and cmd_mod.needs_lock(args) then 776 if cmd_mod.needs_lock and cmd_mod.needs_lock(argsp) then
746 local ok, err = fs.check_command_permissions(args) 777 local ok, err = fs.check_command_permissions(argsp)
747 if not ok then 778 if not ok then
748 die(err, cmd.errorcodes.PERMISSIONDENIED) 779 die(err, cmd.errorcodes.PERMISSIONDENIED)
749 end 780 end
750 781
751 lock, err = fs.lock_access(path.root_dir(cfg.root_dir), args.force_lock) 782 lock, err = fs.lock_access(path.root_dir(cfg.root_dir), argsp.force_lock)
752 if not lock then 783 if not lock then
753 err = args.force_lock 784 err = argsp.force_lock and
754 and ("failed to force the lock" .. (err and ": " .. err or "")) 785 ("failed to force the lock" .. (err and ": " .. err or "")) or
755 or (err and err ~= "File exists") 786 (err and err ~= "File exists") and
756 and err 787 err or
757 or "try --force-lock to overwrite the lock" 788 "try --force-lock to overwrite the lock"
758 789
759 die("command '" .. args.command .. "' " .. 790 die("command '" .. argsp.command .. "' " ..
760 "requires exclusive write access to " .. path.root_dir(cfg.root_dir) .. " - " .. 791 "requires exclusive write access to " .. path.root_dir(cfg.root_dir) .. " - " ..
761 err, cmd.errorcodes.LOCK) 792 err, cmd.errorcodes.LOCK)
762 end 793 end
763 end 794 end
764 795
765 local call_ok, ok, err, exitcode = xpcall(function() 796 local call_ok, ok, err, exitcode = xpcall(function()
766 return cmd_mod.command(args) 797 return cmd_mod.command(argsp)
767 end, error_handler) 798 end, error_handler)
768 799
769 if lock then 800 if lock then
@@ -771,7 +802,7 @@ function cmd.run_command(description, commands, external_namespace, ...)
771 end 802 end
772 803
773 if not call_ok then 804 if not call_ok then
774 die(ok, cmd.errorcodes.CRASH) 805 die(tostring(ok), cmd.errorcodes.CRASH)
775 elseif not ok then 806 elseif not ok then
776 die(err, exitcode) 807 die(err, exitcode)
777 end 808 end
diff --git a/src/luarocks/cmd.tl b/src/luarocks/cmd.tl
index b9490e66..64abf6ce 100644
--- a/src/luarocks/cmd.tl
+++ b/src/luarocks/cmd.tl
@@ -5,7 +5,7 @@ local record cmd
5 5
6 record Module 6 record Module
7 add_to_parser: function(Parser) 7 add_to_parser: function(Parser)
8 command: function(Args): boolean, string 8 command: function(Args, ...: string): boolean, string, integer
9 needs_lock: function(Args): boolean 9 needs_lock: function(Args): boolean
10 help: string 10 help: string
11 help_summary: string 11 help_summary: string
@@ -585,7 +585,7 @@ function cmd.run_command(description: string, commands: {string: string}, extern
585 :args("*") 585 :args("*")
586 end 586 end
587 587
588 mod.command = function(args: Args): boolean, string 588 mod.command = function(args: Args): boolean, string, integer
589 return original_command(args, table.unpack(args.input)) 589 return original_command(args, table.unpack(args.input))
590 end 590 end
591 end 591 end
@@ -594,7 +594,7 @@ function cmd.run_command(description: string, commands: {string: string}, extern
594 util.warning("command module " .. module .. " does not implement command(), skipping") 594 util.warning("command module " .. module .. " does not implement command(), skipping")
595 end 595 end
596 else 596 else
597 util.warning("failed to load command module " .. module .. ": " .. mod) 597 util.warning("failed to load command module " .. module .. ": " .. tostring(mod))
598 end 598 end
599 end 599 end
600 600
@@ -793,7 +793,7 @@ function cmd.run_command(description: string, commands: {string: string}, extern
793 end 793 end
794 end 794 end
795 795
796 local call_ok, ok, err, exitcode = xpcall(function(): boolean, string 796 local call_ok, ok, err, exitcode = xpcall(function(): boolean, string, integer
797 return cmd_mod.command(argsp) 797 return cmd_mod.command(argsp)
798 end, error_handler) 798 end, error_handler)
799 799
@@ -802,7 +802,7 @@ function cmd.run_command(description: string, commands: {string: string}, extern
802 end 802 end
803 803
804 if not call_ok then 804 if not call_ok then
805 die(ok, cmd.errorcodes.CRASH) 805 die(tostring(ok), cmd.errorcodes.CRASH)
806 elseif not ok then 806 elseif not ok then
807 die(err, exitcode) 807 die(err, exitcode)
808 end 808 end
diff --git a/src/luarocks/cmd/build-original.lua b/src/luarocks/cmd/build-original.lua
new file mode 100644
index 00000000..6d719d5a
--- /dev/null
+++ b/src/luarocks/cmd/build-original.lua
@@ -0,0 +1,199 @@
1
2--- Module implementing the LuaRocks "build" command.
3-- Builds a rock, compiling its C parts if any.
4local cmd_build = {}
5
6local pack = require("luarocks.pack")
7local path = require("luarocks.path")
8local dir = require("luarocks.dir")
9local util = require("luarocks.util")
10local fetch = require("luarocks.fetch")
11local fs = require("luarocks.fs")
12local deps = require("luarocks.deps")
13local remove = require("luarocks.remove")
14local cfg = require("luarocks.core.cfg")
15local build = require("luarocks.build")
16local search = require("luarocks.search")
17local make = require("luarocks.cmd.make")
18local repos = require("luarocks.repos")
19
20function cmd_build.add_to_parser(parser)
21 local cmd = parser:command("build", "Build and install a rock, compiling its C parts if any.\n".. -- luacheck: ignore 431
22 "If the sources contain a luarocks.lock file, uses it as an authoritative source for "..
23 "exact version of dependencies.\n"..
24 "If no arguments are given, behaves as luarocks make.", util.see_also())
25 :summary("Build/compile a rock.")
26
27 cmd:argument("rock", "A rockspec file, a source rock file, or the name of "..
28 "a rock to be fetched from a repository.")
29 :args("?")
30 :action(util.namespaced_name_action)
31 cmd:argument("version", "Rock version.")
32 :args("?")
33
34 cmd:flag("--only-deps --deps-only", "Install only the dependencies of the rock.")
35 cmd:option("--branch", "Override the `source.branch` field in the loaded "..
36 "rockspec. Allows to specify a different branch to fetch. Particularly "..
37 'for "dev" rocks.')
38 :argname("<name>")
39 cmd:flag("--pin", "Create a luarocks.lock file listing the exact "..
40 "versions of each dependency found for this rock (recursively), "..
41 "and store it in the rock's directory. "..
42 "Ignores any existing luarocks.lock file in the rock's sources.")
43 make.cmd_options(cmd)
44end
45
46--- Build and install a rock.
47-- @param rock_filename string: local or remote filename of a rock.
48-- @param opts table: build options
49-- @return boolean or (nil, string, [string]): True if build was successful,
50-- or false and an error message and an optional error code.
51local function build_rock(rock_filename, opts)
52 assert(type(rock_filename) == "string")
53
54 local cwd = fs.absolute_name(dir.path("."))
55
56 local ok, err, errcode
57
58 local unpack_dir
59 unpack_dir, err, errcode = fetch.fetch_and_unpack_rock(rock_filename, nil, opts.verify)
60 if not unpack_dir then
61 return nil, err, errcode
62 end
63
64 local rockspec_filename = path.rockspec_name_from_rock(rock_filename)
65
66 ok, err = fs.change_dir(unpack_dir)
67 if not ok then return nil, err end
68
69 local rockspec
70 rockspec, err, errcode = fetch.load_rockspec(rockspec_filename)
71 if not rockspec then
72 return nil, err, errcode
73 end
74
75 ok, err, errcode = build.build_rockspec(rockspec, opts, cwd)
76
77 fs.pop_dir()
78 return ok, err, errcode
79end
80
81local function do_build(name, namespace, version, opts)
82 assert(type(name) == "string")
83 assert(type(namespace) == "string" or not namespace)
84 assert(version == nil or type(version) == "string")
85
86 local url, err
87 if name:match("%.rockspec$") or name:match("%.rock$") then
88 url = name
89 else
90 url, err = search.find_src_or_rockspec(name, namespace, version, opts.check_lua_versions)
91 if not url then
92 return nil, err
93 end
94 end
95
96 name, version = path.parse_name(url)
97 if name and repos.is_installed(name, version) then
98 if not opts.rebuild then
99 util.printout(name .. " " .. version .. " is already installed in " .. path.root_dir(cfg.root_dir))
100 util.printout("Use --force to reinstall.")
101 return name, version, "skip"
102 end
103 end
104
105 if url:match("%.rockspec$") then
106 local cwd = fs.absolute_name(dir.path("."))
107 local rockspec, err = fetch.load_rockspec(url, nil, opts.verify)
108 if not rockspec then
109 return nil, err
110 end
111 return build.build_rockspec(rockspec, opts, cwd)
112 end
113
114 if url:match("%.src%.rock$") then
115 opts.need_to_fetch = false
116 end
117
118 return build_rock(url, opts)
119end
120
121--- Driver function for "build" command.
122-- If a package name is given, forwards the request to "search" and,
123-- if returned a result, installs the matching rock.
124-- When passing a package name, a version number may also be given.
125-- @return boolean or (nil, string, exitcode): True if build was successful; nil and an
126-- error message otherwise. exitcode is optionally returned.
127function cmd_build.command(args)
128 if not args.rock then
129 return make.command(args)
130 end
131
132 local opts = {
133 need_to_fetch = true,
134 minimal_mode = false,
135 deps_mode = deps.get_deps_mode(args),
136 build_only_deps = not not (args.only_deps and not args.pack_binary_rock),
137 namespace = args.namespace,
138 branch = args.branch,
139 verify = not not args.verify,
140 check_lua_versions = not not args.check_lua_versions,
141 pin = not not args.pin,
142 rebuild = not not (args.force or args.force_fast),
143 no_install = false
144 }
145
146 if args.sign and not args.pack_binary_rock then
147 return nil, "In the build command, --sign is meant to be used only with --pack-binary-rock"
148 end
149
150 if args.pack_binary_rock then
151 return pack.pack_binary_rock(args.rock, args.namespace, args.version, args.sign, function()
152 local name, version = do_build(args.rock, args.namespace, args.version, opts)
153 if name and args.no_doc then
154 util.remove_doc_dir(name, version)
155 end
156 return name, version
157 end)
158 end
159
160 local name, version, skip = do_build(args.rock, args.namespace, args.version, opts)
161 if not name then
162 return nil, version
163 end
164 if skip == "skip" then
165 return name, version
166 end
167
168 if args.no_doc then
169 util.remove_doc_dir(name, version)
170 end
171
172 if opts.build_only_deps then
173 util.printout("Stopping after installing dependencies for " ..name.." "..version)
174 util.printout()
175 else
176 if (not args.keep) and not cfg.keep_other_versions then
177 local ok, err, warn = remove.remove_other_versions(name, version, args.force, args.force_fast)
178 if not ok then
179 return nil, err
180 elseif warn then
181 util.printerr(err)
182 end
183 end
184 end
185
186 if opts.deps_mode ~= "none" then
187 deps.check_dependencies(nil, deps.get_deps_mode(args))
188 end
189 return name, version
190end
191
192cmd_build.needs_lock = function(args)
193 if args.pack_binary_rock then
194 return false
195 end
196 return true
197end
198
199return cmd_build
diff --git a/src/luarocks/cmd/build.lua b/src/luarocks/cmd/build.lua
index 6d719d5a..6aa3afe0 100644
--- a/src/luarocks/cmd/build.lua
+++ b/src/luarocks/cmd/build.lua
@@ -1,8 +1,10 @@
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 string = _tl_compat and _tl_compat.string or string
2
1 3
2--- Module implementing the LuaRocks "build" command.
3-- Builds a rock, compiling its C parts if any.
4local cmd_build = {} 4local cmd_build = {}
5 5
6
7
6local pack = require("luarocks.pack") 8local pack = require("luarocks.pack")
7local path = require("luarocks.path") 9local path = require("luarocks.path")
8local dir = require("luarocks.dir") 10local dir = require("luarocks.dir")
@@ -17,39 +19,49 @@ local search = require("luarocks.search")
17local make = require("luarocks.cmd.make") 19local make = require("luarocks.cmd.make")
18local repos = require("luarocks.repos") 20local repos = require("luarocks.repos")
19 21
22local argparse = require("luarocks.vendor.argparse")
23
24
25
26
27
28
29
30
31
32
20function cmd_build.add_to_parser(parser) 33function cmd_build.add_to_parser(parser)
21 local cmd = parser:command("build", "Build and install a rock, compiling its C parts if any.\n".. -- luacheck: ignore 431 34 local cmd = parser:command("build", "Build and install a rock, compiling its C parts if any.\n" ..
22 "If the sources contain a luarocks.lock file, uses it as an authoritative source for ".. 35 "If the sources contain a luarocks.lock file, uses it as an authoritative source for " ..
23 "exact version of dependencies.\n".. 36 "exact version of dependencies.\n" ..
24 "If no arguments are given, behaves as luarocks make.", util.see_also()) 37 "If no arguments are given, behaves as luarocks make.", util.see_also()):
25 :summary("Build/compile a rock.") 38 summary("Build/compile a rock.")
26 39
27 cmd:argument("rock", "A rockspec file, a source rock file, or the name of ".. 40 cmd:argument("rock", "A rockspec file, a source rock file, or the name of " ..
28 "a rock to be fetched from a repository.") 41 "a rock to be fetched from a repository."):
29 :args("?") 42 args("?"):
30 :action(util.namespaced_name_action) 43 action(util.namespaced_name_action)
31 cmd:argument("version", "Rock version.") 44 cmd:argument("version", "Rock version."):
32 :args("?") 45 args("?")
33 46
34 cmd:flag("--only-deps --deps-only", "Install only the dependencies of the rock.") 47 cmd:flag("--only-deps --deps-only", "Install only the dependencies of the rock.")
35 cmd:option("--branch", "Override the `source.branch` field in the loaded ".. 48 cmd:option("--branch", "Override the `source.branch` field in the loaded " ..
36 "rockspec. Allows to specify a different branch to fetch. Particularly ".. 49 "rockspec. Allows to specify a different branch to fetch. Particularly " ..
37 'for "dev" rocks.') 50 'for "dev" rocks.'):
38 :argname("<name>") 51 argname("<name>")
39 cmd:flag("--pin", "Create a luarocks.lock file listing the exact ".. 52 cmd:flag("--pin", "Create a luarocks.lock file listing the exact " ..
40 "versions of each dependency found for this rock (recursively), ".. 53 "versions of each dependency found for this rock (recursively), " ..
41 "and store it in the rock's directory. ".. 54 "and store it in the rock's directory. " ..
42 "Ignores any existing luarocks.lock file in the rock's sources.") 55 "Ignores any existing luarocks.lock file in the rock's sources.")
43 make.cmd_options(cmd) 56 make.cmd_options(cmd)
44end 57end
45 58
46--- Build and install a rock. 59
47-- @param rock_filename string: local or remote filename of a rock. 60
48-- @param opts table: build options 61
49-- @return boolean or (nil, string, [string]): True if build was successful, 62
50-- or false and an error message and an optional error code. 63
51local function build_rock(rock_filename, opts) 64local function build_rock(rock_filename, opts)
52 assert(type(rock_filename) == "string")
53 65
54 local cwd = fs.absolute_name(dir.path(".")) 66 local cwd = fs.absolute_name(dir.path("."))
55 67
@@ -72,16 +84,15 @@ local function build_rock(rock_filename, opts)
72 return nil, err, errcode 84 return nil, err, errcode
73 end 85 end
74 86
75 ok, err, errcode = build.build_rockspec(rockspec, opts, cwd) 87 local n, v = build.build_rockspec(rockspec, opts, cwd)
88
89 ok, err, errcode = n ~= nil, v, nil
76 90
77 fs.pop_dir() 91 fs.pop_dir()
78 return ok, err, errcode 92 return ok, err, errcode
79end 93end
80 94
81local function do_build(name, namespace, version, opts) 95local function do_build(name, namespace, version, opts)
82 assert(type(name) == "string")
83 assert(type(namespace) == "string" or not namespace)
84 assert(version == nil or type(version) == "string")
85 96
86 local url, err 97 local url, err
87 if name:match("%.rockspec$") or name:match("%.rock$") then 98 if name:match("%.rockspec$") or name:match("%.rock$") then
@@ -115,15 +126,19 @@ local function do_build(name, namespace, version, opts)
115 opts.need_to_fetch = false 126 opts.need_to_fetch = false
116 end 127 end
117 128
118 return build_rock(url, opts) 129 local ok, err, errcode = build_rock(url, opts)
130 if not ok then
131 return nil, err, errcode
132 end
133 return name, version
119end 134end
120 135
121--- Driver function for "build" command. 136
122-- If a package name is given, forwards the request to "search" and, 137
123-- if returned a result, installs the matching rock. 138
124-- When passing a package name, a version number may also be given. 139
125-- @return boolean or (nil, string, exitcode): True if build was successful; nil and an 140
126-- error message otherwise. exitcode is optionally returned. 141
127function cmd_build.command(args) 142function cmd_build.command(args)
128 if not args.rock then 143 if not args.rock then
129 return make.command(args) 144 return make.command(args)
@@ -140,7 +155,7 @@ function cmd_build.command(args)
140 check_lua_versions = not not args.check_lua_versions, 155 check_lua_versions = not not args.check_lua_versions,
141 pin = not not args.pin, 156 pin = not not args.pin,
142 rebuild = not not (args.force or args.force_fast), 157 rebuild = not not (args.force or args.force_fast),
143 no_install = false 158 no_install = false,
144 } 159 }
145 160
146 if args.sign and not args.pack_binary_rock then 161 if args.sign and not args.pack_binary_rock then
@@ -162,7 +177,7 @@ function cmd_build.command(args)
162 return nil, version 177 return nil, version
163 end 178 end
164 if skip == "skip" then 179 if skip == "skip" then
165 return name, version 180 return name ~= nil, version
166 end 181 end
167 182
168 if args.no_doc then 183 if args.no_doc then
@@ -170,7 +185,7 @@ function cmd_build.command(args)
170 end 185 end
171 186
172 if opts.build_only_deps then 187 if opts.build_only_deps then
173 util.printout("Stopping after installing dependencies for " ..name.." "..version) 188 util.printout("Stopping after installing dependencies for " .. name .. " " .. version)
174 util.printout() 189 util.printout()
175 else 190 else
176 if (not args.keep) and not cfg.keep_other_versions then 191 if (not args.keep) and not cfg.keep_other_versions then
@@ -186,7 +201,7 @@ function cmd_build.command(args)
186 if opts.deps_mode ~= "none" then 201 if opts.deps_mode ~= "none" then
187 deps.check_dependencies(nil, deps.get_deps_mode(args)) 202 deps.check_dependencies(nil, deps.get_deps_mode(args))
188 end 203 end
189 return name, version 204 return name ~= nil, version
190end 205end
191 206
192cmd_build.needs_lock = function(args) 207cmd_build.needs_lock = function(args)
diff --git a/src/luarocks/cmd/build.tl b/src/luarocks/cmd/build.tl
index 9ec58c3e..96e2ec42 100644
--- a/src/luarocks/cmd/build.tl
+++ b/src/luarocks/cmd/build.tl
@@ -22,8 +22,7 @@ local repos = require("luarocks.repos")
22local argparse = require("luarocks.vendor.argparse") 22local argparse = require("luarocks.vendor.argparse")
23local type Parser = argparse.Parser 23local type Parser = argparse.Parser
24 24
25local type a = require("luarocks.core.types.args") 25local type Args = require("luarocks.core.types.args").Args
26local type Args = a.Args
27 26
28local type bo = require("luarocks.core.types.bopts") 27local type bo = require("luarocks.core.types.bopts")
29local type BOpts = bo.BOpts 28local type BOpts = bo.BOpts
@@ -85,7 +84,9 @@ local function build_rock(rock_filename: string, opts: BOpts): boolean, string,
85 return nil, err, errcode 84 return nil, err, errcode
86 end 85 end
87 86
88 ok, err, errcode = build.build_rockspec(rockspec, opts, cwd) 87 local n, v = build.build_rockspec(rockspec, opts, cwd)
88
89 ok, err, errcode = n ~= nil, v, nil
89 90
90 fs.pop_dir() 91 fs.pop_dir()
91 return ok, err, errcode 92 return ok, err, errcode
@@ -125,7 +126,11 @@ local function do_build(name: string, namespace: string, version: string, opts:
125 opts.need_to_fetch = false 126 opts.need_to_fetch = false
126 end 127 end
127 128
128 return build_rock(url, opts) 129 local ok, err, errcode = build_rock(url, opts)
130 if not ok then
131 return nil, err, errcode
132 end
133 return name, version
129end 134end
130 135
131--- Driver function for "build" command. 136--- Driver function for "build" command.
@@ -172,7 +177,7 @@ function cmd_build.command(args: Args): boolean, string, string
172 return nil, version 177 return nil, version
173 end 178 end
174 if skip == "skip" then 179 if skip == "skip" then
175 return name, version 180 return name ~= nil, version
176 end 181 end
177 182
178 if args.no_doc then 183 if args.no_doc then
@@ -196,7 +201,7 @@ function cmd_build.command(args: Args): boolean, string, string
196 if opts.deps_mode ~= "none" then 201 if opts.deps_mode ~= "none" then
197 deps.check_dependencies(nil, deps.get_deps_mode(args)) 202 deps.check_dependencies(nil, deps.get_deps_mode(args))
198 end 203 end
199 return name, version 204 return name ~= nil, version
200end 205end
201 206
202cmd_build.needs_lock = function(args: Args): boolean 207cmd_build.needs_lock = function(args: Args): boolean
diff --git a/src/luarocks/cmd/install.tl b/src/luarocks/cmd/install.tl
index 40f6c782..157ef772 100644
--- a/src/luarocks/cmd/install.tl
+++ b/src/luarocks/cmd/install.tl
@@ -259,4 +259,6 @@ install.needs_lock = function(args: Args): boolean
259 return true 259 return true
260end 260end
261 261
262deps.installer = install.command
263
262return install 264return install
diff --git a/src/luarocks/cmd/make.tl b/src/luarocks/cmd/make.tl
index f151c950..4d29c6d6 100644
--- a/src/luarocks/cmd/make.tl
+++ b/src/luarocks/cmd/make.tl
@@ -43,7 +43,7 @@ function make.cmd_options(parser: Parser)
43 "built. If the rockspec or src.rock is being downloaded, LuaRocks will ".. 43 "built. If the rockspec or src.rock is being downloaded, LuaRocks will "..
44 "attempt to download the signature as well. Otherwise, the signature ".. 44 "attempt to download the signature as well. Otherwise, the signature "..
45 "file should be already available locally in the same directory.\n".. 45 "file should be already available locally in the same directory.\n"..
46 "You need the signers public key in your local keyring for this ".. 46 "You need the signer's public key in your local keyring for this "..
47 "option to work properly.") 47 "option to work properly.")
48 parser:flag("--sign", "To be used with --pack-binary-rock. Also produce a ".. 48 parser:flag("--sign", "To be used with --pack-binary-rock. Also produce a "..
49 "signature file for the generated .rock file.") 49 "signature file for the generated .rock file.")
diff --git a/src/luarocks/cmd/show.tl b/src/luarocks/cmd/show.tl
index 4850b3af..1d6eddda 100644
--- a/src/luarocks/cmd/show.tl
+++ b/src/luarocks/cmd/show.tl
@@ -23,23 +23,10 @@ local type Return = show.Return
23 23
24local argparse = require("luarocks.vendor.argparse") 24local argparse = require("luarocks.vendor.argparse")
25local type Parser = argparse.Parser 25local type Parser = argparse.Parser
26local type Option = argparse.Option
27 26
28local type a = require("luarocks.core.types.args") 27local type a = require("luarocks.core.types.args")
29local type Args = a.Args 28local type Args = a.Args
30 29
31local type bo = require("luarocks.core.types.bopts")
32local type BOpts = bo.BOpts
33
34local type i = require("luarocks.core.types.installs")
35local type IOpts = i.IOpts
36
37local type p = require("luarocks.core.types.persist")
38local type PersistableTable = p.PersistableTable
39
40local type res = require("luarocks.core.types.result")
41local type Result = res.Result
42
43local type t = require("luarocks.core.types.tree") 30local type t = require("luarocks.core.types.tree")
44local type Tree = t.Tree 31local type Tree = t.Tree
45 32
diff --git a/src/luarocks/cmd/upload.tl b/src/luarocks/cmd/upload.tl
index 018d9f6e..ae02fc64 100644
--- a/src/luarocks/cmd/upload.tl
+++ b/src/luarocks/cmd/upload.tl
@@ -11,36 +11,10 @@ local Api = require("luarocks.upload.api")
11 11
12local argparse = require("luarocks.vendor.argparse") 12local argparse = require("luarocks.vendor.argparse")
13local type Parser = argparse.Parser 13local type Parser = argparse.Parser
14local type Option = argparse.Option
15 14
16local type a = require("luarocks.core.types.args") 15local type a = require("luarocks.core.types.args")
17local type Args = a.Args 16local type Args = a.Args
18 17
19local type bo = require("luarocks.core.types.bopts")
20local type BOpts = bo.BOpts
21
22local type i = require("luarocks.core.types.installs")
23local type IOpts = i.IOpts
24
25local type p = require("luarocks.core.types.persist")
26local type PersistableTable = p.PersistableTable
27
28local type res = require("luarocks.core.types.result")
29local type Result = res.Result
30
31local type t = require("luarocks.core.types.tree")
32local type Tree = t.Tree
33
34local type q = require("luarocks.core.types.query")
35local type Query = q.Query
36
37local type r = require("luarocks.core.types.rockspec")
38local type Rockspec = r.Rockspec
39local type Dependencies = r.Dependencies
40
41local type m = require("luarocks.core.types.manifest")
42local type Entry = m.Manifest.Entry
43
44function upload.add_to_parser(parser: Parser) 18function upload.add_to_parser(parser: Parser)
45 local cmd = parser:command("upload", "Pack a source rock file (.src.rock extension) ".. 19 local cmd = parser:command("upload", "Pack a source rock file (.src.rock extension) "..
46 "and upload it and the rockspec to the public rocks repository.", util.see_also()) 20 "and upload it and the rockspec to the public rocks repository.", util.see_also())
diff --git a/src/luarocks/deps.tl b/src/luarocks/deps.tl
index 1f5f24aa..58c0bd1c 100644
--- a/src/luarocks/deps.tl
+++ b/src/luarocks/deps.tl
@@ -1,6 +1,7 @@
1 1
2--- High-level dependency related functions. 2--- High-level dependency related functions.
3local record deps 3local record deps
4 installer: function(Args): boolean, string, string
4end 5end
5 6
6local cfg = require("luarocks.core.cfg") 7local cfg = require("luarocks.core.cfg")
@@ -41,8 +42,7 @@ local type dr = require("luarocks.core.types.dir")
41local type Dir = dr.Dir 42local type Dir = dr.Dir
42local type Dirs = dr.Dirs 43local type Dirs = dr.Dirs
43 44
44local type arg = require("luarocks.core.types.args") 45local type Args = require("luarocks.core.types.args").Args
45local type Args = arg.Args
46 46
47--- Generate a function that matches dep queries against the manifest, 47--- Generate a function that matches dep queries against the manifest,
48-- taking into account rocks_provided, the list of versions to skip, 48-- taking into account rocks_provided, the list of versions to skip,
@@ -229,7 +229,6 @@ function deps.fulfill_dependency(dep: Query, deps_mode: string, rocks_provided:
229 end 229 end
230 230
231 local search = require("luarocks.search") 231 local search = require("luarocks.search")
232 local install = require("luarocks.cmd.install")
233 232
234 local url, search_err = search.find_suitable_rock(dep) 233 local url, search_err = search.find_suitable_rock(dep)
235 if not url then 234 if not url then
@@ -242,7 +241,7 @@ function deps.fulfill_dependency(dep: Query, deps_mode: string, rocks_provided:
242 namespace = dep.namespace, 241 namespace = dep.namespace,
243 verify = verify, 242 verify = verify,
244 } 243 }
245 local ok, install_err, errcode = install.command(install_args) 244 local ok, install_err, errcode = deps.installer(install_args)
246 if not ok then 245 if not ok then
247 return nil, "Failed installing dependency: "..url.." - "..install_err, errcode 246 return nil, "Failed installing dependency: "..url.." - "..install_err, errcode
248 end 247 end
diff --git a/src/luarocks/test/busted.tl b/src/luarocks/test/busted.tl
index c0ac5503..01473f1f 100644
--- a/src/luarocks/test/busted.tl
+++ b/src/luarocks/test/busted.tl
@@ -7,6 +7,7 @@ local deps = require("luarocks.deps")
7local path = require("luarocks.path") 7local path = require("luarocks.path")
8local dir = require("luarocks.dir") 8local dir = require("luarocks.dir")
9local queries = require("luarocks.queries") 9local queries = require("luarocks.queries")
10local install = require("luarocks.cmd.install")
10 11
11local type r = require("luarocks.core.types.rockspec") 12local type r = require("luarocks.core.types.rockspec")
12local type Test = r.Test 13local type Test = r.Test