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