diff options
author | Hisham Muhammad <hisham@gobolinux.org> | 2021-03-16 14:55:11 -0300 |
---|---|---|
committer | Hisham Muhammad <hisham@gobolinux.org> | 2021-03-19 13:15:53 -0300 |
commit | 2efec770b1b1b27a4b15c3b06a2f5fcadc0b546d (patch) | |
tree | f7c2e34abe3314658df0970dde6e1bc346c1e627 | |
parent | 08ae98e309c3f09be00b547bab74a5fd875bfa36 (diff) | |
download | luarocks-2efec770b1b1b27a4b15c3b06a2f5fcadc0b546d.tar.gz luarocks-2efec770b1b1b27a4b15c3b06a2f5fcadc0b546d.tar.bz2 luarocks-2efec770b1b1b27a4b15c3b06a2f5fcadc0b546d.zip |
repos: double-check that all files from a rock are installed
Ensure that `luarocks` fails if an installation does not successfully
deploy all files registered in the `rock_manifest`.
See #1276.
-rw-r--r-- | spec/remove_spec.lua | 35 | ||||
-rw-r--r-- | src/luarocks/cmd/build.lua | 4 | ||||
-rw-r--r-- | src/luarocks/cmd/install.lua | 8 | ||||
-rw-r--r-- | src/luarocks/cmd/make.lua | 8 | ||||
-rw-r--r-- | src/luarocks/cmd/purge.lua | 4 | ||||
-rw-r--r-- | src/luarocks/remove.lua | 20 | ||||
-rw-r--r-- | src/luarocks/repos.lua | 59 |
7 files changed, 129 insertions, 9 deletions
diff --git a/spec/remove_spec.lua b/spec/remove_spec.lua index 91b6a460..21a39696 100644 --- a/spec/remove_spec.lua +++ b/spec/remove_spec.lua | |||
@@ -2,6 +2,7 @@ local test_env = require("spec.util.test_env") | |||
2 | local lfs = require("lfs") | 2 | local lfs = require("lfs") |
3 | local run = test_env.run | 3 | local run = test_env.run |
4 | local testing_paths = test_env.testing_paths | 4 | local testing_paths = test_env.testing_paths |
5 | local env_variables = test_env.env_variables | ||
5 | 6 | ||
6 | test_env.unload_luarocks() | 7 | test_env.unload_luarocks() |
7 | 8 | ||
@@ -9,7 +10,9 @@ local extra_rocks = { | |||
9 | "/abelhas-1.1-1.src.rock", | 10 | "/abelhas-1.1-1.src.rock", |
10 | "/copas-2.0.1-1.src.rock", | 11 | "/copas-2.0.1-1.src.rock", |
11 | "/coxpcall-1.16.0-1.src.rock", | 12 | "/coxpcall-1.16.0-1.src.rock", |
12 | "/coxpcall-1.16.0-1.rockspec" | 13 | "/coxpcall-1.16.0-1.rockspec", |
14 | "/luafilesystem-1.7.0-1.src.rock", | ||
15 | "/luafilesystem-1.6.3-2.src.rock", | ||
13 | } | 16 | } |
14 | 17 | ||
15 | describe("luarocks remove #integration", function() | 18 | describe("luarocks remove #integration", function() |
@@ -80,6 +83,36 @@ describe("luarocks remove #integration", function() | |||
80 | assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/coxpcall")) | 83 | assert.is.falsy(lfs.attributes(testing_paths.testing_sys_rocks .. "/coxpcall")) |
81 | assert.is.falsy(output:find("Checking stability of dependencies")) | 84 | assert.is.falsy(output:find("Checking stability of dependencies")) |
82 | end) | 85 | end) |
86 | |||
87 | it("restores old versions", function() | ||
88 | assert.is_true(run.luarocks_bool("install luafilesystem 1.6.3")) | ||
89 | assert.is.truthy(lfs.attributes(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension)) | ||
90 | |||
91 | if test_env.TEST_TARGET_OS ~= "windows" then | ||
92 | local fd = io.open(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension, "r") | ||
93 | assert(fd:read("*a"):match("LuaFileSystem 1.6.3", 1, true)) | ||
94 | fd:close() | ||
95 | end | ||
96 | |||
97 | assert.is_true(run.luarocks_bool("install luafilesystem 1.7.0 --keep")) | ||
98 | assert.is.truthy(lfs.attributes(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension)) | ||
99 | assert.is.truthy(lfs.attributes(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/luafilesystem_1_6_3_2-lfs."..test_env.lib_extension)) | ||
100 | |||
101 | if test_env.TEST_TARGET_OS ~= "windows" then | ||
102 | local fd = io.open(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension, "r") | ||
103 | assert(fd:read("*a"):match("LuaFileSystem 1.7.0", 1, true)) | ||
104 | fd:close() | ||
105 | end | ||
106 | |||
107 | assert.is_true(run.luarocks_bool("remove luafilesystem 1.7.0")) | ||
108 | assert.is.truthy(lfs.attributes(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension)) | ||
109 | |||
110 | if test_env.TEST_TARGET_OS ~= "windows" then | ||
111 | local fd = io.open(testing_paths.testing_sys_tree .. "/lib/lua/"..env_variables.LUA_VERSION.."/lfs."..test_env.lib_extension, "r") | ||
112 | assert(fd:read("*a"):match("LuaFileSystem 1.6.3", 1, true)) | ||
113 | fd:close() | ||
114 | end | ||
115 | end) | ||
83 | end) | 116 | end) |
84 | 117 | ||
85 | it("#admin remove #ssh", function() | 118 | it("#admin remove #ssh", function() |
diff --git a/src/luarocks/cmd/build.lua b/src/luarocks/cmd/build.lua index 4500bcc9..6ad76b6e 100644 --- a/src/luarocks/cmd/build.lua +++ b/src/luarocks/cmd/build.lua | |||
@@ -165,8 +165,10 @@ function cmd_build.command(args) | |||
165 | util.printout() | 165 | util.printout() |
166 | else | 166 | else |
167 | if (not args.keep) and not cfg.keep_other_versions then | 167 | if (not args.keep) and not cfg.keep_other_versions then |
168 | local ok, err = remove.remove_other_versions(name, version, args.force, args.force_fast) | 168 | local ok, err, warn = remove.remove_other_versions(name, version, args.force, args.force_fast) |
169 | if not ok then | 169 | if not ok then |
170 | return nil, err | ||
171 | elseif warn then | ||
170 | util.printerr(err) | 172 | util.printerr(err) |
171 | end | 173 | end |
172 | end | 174 | end |
diff --git a/src/luarocks/cmd/install.lua b/src/luarocks/cmd/install.lua index da9e1ce3..0d6ad63f 100644 --- a/src/luarocks/cmd/install.lua +++ b/src/luarocks/cmd/install.lua | |||
@@ -195,8 +195,12 @@ local function install_rock_file(filename, opts) | |||
195 | end | 195 | end |
196 | 196 | ||
197 | if (not opts.keep) and not cfg.keep_other_versions then | 197 | if (not opts.keep) and not cfg.keep_other_versions then |
198 | local ok, err = remove.remove_other_versions(name, version, opts.force, opts.force_fast) | 198 | local ok, err, warn = remove.remove_other_versions(name, version, opts.force, opts.force_fast) |
199 | if not ok then util.printerr(err) end | 199 | if not ok then |
200 | return nil, err | ||
201 | elseif warn then | ||
202 | util.printerr(err) | ||
203 | end | ||
200 | end | 204 | end |
201 | 205 | ||
202 | writer.check_dependencies(nil, opts.deps_mode) | 206 | writer.check_dependencies(nil, opts.deps_mode) |
diff --git a/src/luarocks/cmd/make.lua b/src/luarocks/cmd/make.lua index a72e6817..8b313bb9 100644 --- a/src/luarocks/cmd/make.lua +++ b/src/luarocks/cmd/make.lua | |||
@@ -142,8 +142,12 @@ function make.command(args) | |||
142 | end | 142 | end |
143 | 143 | ||
144 | if (not args.keep) and not cfg.keep_other_versions then | 144 | if (not args.keep) and not cfg.keep_other_versions then |
145 | local ok, err = remove.remove_other_versions(name, version, args.force, args.force_fast) | 145 | local ok, err, warn = remove.remove_other_versions(name, version, args.force, args.force_fast) |
146 | if not ok then util.printerr(err) end | 146 | if not ok then |
147 | return nil, err | ||
148 | elseif warn then | ||
149 | util.printerr(warn) | ||
150 | end | ||
147 | end | 151 | end |
148 | 152 | ||
149 | writer.check_dependencies(nil, deps.get_deps_mode(args)) | 153 | writer.check_dependencies(nil, deps.get_deps_mode(args)) |
diff --git a/src/luarocks/cmd/purge.lua b/src/luarocks/cmd/purge.lua index 2b5873d7..c300e286 100644 --- a/src/luarocks/cmd/purge.lua +++ b/src/luarocks/cmd/purge.lua | |||
@@ -62,9 +62,11 @@ function purge.command(args) | |||
62 | for version, _ in util.sortedpairs(versions, sort) do | 62 | for version, _ in util.sortedpairs(versions, sort) do |
63 | if args.old_versions then | 63 | if args.old_versions then |
64 | util.printout("Keeping "..package.." "..version.."...") | 64 | util.printout("Keeping "..package.." "..version.."...") |
65 | local ok, err = remove.remove_other_versions(package, version, args.force, args.force_fast) | 65 | local ok, err, warn = remove.remove_other_versions(package, version, args.force, args.force_fast) |
66 | if not ok then | 66 | if not ok then |
67 | util.printerr(err) | 67 | util.printerr(err) |
68 | elseif warn then | ||
69 | util.printerr(err) | ||
68 | end | 70 | end |
69 | break | 71 | break |
70 | else | 72 | else |
diff --git a/src/luarocks/remove.lua b/src/luarocks/remove.lua index 9f816c7e..385930eb 100644 --- a/src/luarocks/remove.lua +++ b/src/luarocks/remove.lua | |||
@@ -7,6 +7,7 @@ local repos = require("luarocks.repos") | |||
7 | local path = require("luarocks.path") | 7 | local path = require("luarocks.path") |
8 | local util = require("luarocks.util") | 8 | local util = require("luarocks.util") |
9 | local cfg = require("luarocks.core.cfg") | 9 | local cfg = require("luarocks.core.cfg") |
10 | local manif = require("luarocks.manif") | ||
10 | local queries = require("luarocks.queries") | 11 | local queries = require("luarocks.queries") |
11 | 12 | ||
12 | --- Obtain a list of packages that depend on the given set of packages | 13 | --- Obtain a list of packages that depend on the given set of packages |
@@ -107,10 +108,25 @@ function remove.remove_other_versions(name, version, force, fast) | |||
107 | local results = {} | 108 | local results = {} |
108 | local query = queries.new(name, nil, version, false, nil, "~=") | 109 | local query = queries.new(name, nil, version, false, nil, "~=") |
109 | search.local_manifest_search(results, cfg.rocks_dir, query) | 110 | search.local_manifest_search(results, cfg.rocks_dir, query) |
111 | local warn | ||
110 | if results[name] then | 112 | if results[name] then |
111 | return remove.remove_search_results(results, name, cfg.deps_mode, force, fast) | 113 | local ok, err = remove.remove_search_results(results, name, cfg.deps_mode, force, fast) |
114 | if not ok then -- downgrade failure to a warning | ||
115 | warn = err | ||
116 | end | ||
112 | end | 117 | end |
113 | return true | 118 | |
119 | if not fast then | ||
120 | -- since we're not using --keep, this means that all files of the rock being installed | ||
121 | -- should be available as non-versioned variants. Double-check that: | ||
122 | local rock_manifest, load_err = manif.load_rock_manifest(name, version) | ||
123 | local ok, err = repos.check_everything_is_installed(name, version, rock_manifest, cfg.root_dir, false) | ||
124 | if not ok then | ||
125 | return nil, err | ||
126 | end | ||
127 | end | ||
128 | |||
129 | return true, nil, warn | ||
114 | end | 130 | end |
115 | 131 | ||
116 | return remove | 132 | return remove |
diff --git a/src/luarocks/repos.lua b/src/luarocks/repos.lua index 8eecf8fd..6827cd0f 100644 --- a/src/luarocks/repos.lua +++ b/src/luarocks/repos.lua | |||
@@ -392,6 +392,28 @@ local function rollback_ops(ops, op_fn, n) | |||
392 | end | 392 | end |
393 | end | 393 | end |
394 | 394 | ||
395 | --- Double check that all files referenced in `rock_manifest` are installed in `repo`. | ||
396 | function repos.check_everything_is_installed(name, version, rock_manifest, repo, accept_versioned) | ||
397 | local missing = {} | ||
398 | for _, category in ipairs({"bin", "lua", "lib"}) do | ||
399 | local suffix = (category == "bin") and cfg.wrapper_suffix or "" | ||
400 | if rock_manifest[category] then | ||
401 | repos.recurse_rock_manifest_entry(rock_manifest[category], function(file_path) | ||
402 | local paths = get_deploy_paths(name, version, category, file_path, repo) | ||
403 | if not (fs.exists(paths.nv .. suffix) or (accept_versioned and fs.exists(paths.v .. suffix))) then | ||
404 | table.insert(missing, paths.nv .. suffix) | ||
405 | end | ||
406 | end) | ||
407 | end | ||
408 | end | ||
409 | if #missing > 0 then | ||
410 | return nil, "failed deploying files. " .. | ||
411 | "The following files were not installed:\n" .. | ||
412 | table.concat(missing, "\n") | ||
413 | end | ||
414 | return true | ||
415 | end | ||
416 | |||
395 | --- Deploy a package from the rocks subdirectory. | 417 | --- Deploy a package from the rocks subdirectory. |
396 | -- @param name string: name of package | 418 | -- @param name string: name of package |
397 | -- @param version string: exact package version in string format | 419 | -- @param version string: exact package version in string format |
@@ -503,10 +525,37 @@ function repos.deploy_files(name, version, wrap_bin_scripts, deps_mode) | |||
503 | end | 525 | end |
504 | done_op_install() | 526 | done_op_install() |
505 | 527 | ||
528 | local ok, err = repos.check_everything_is_installed(name, version, rock_manifest, repo, true) | ||
529 | if not ok then | ||
530 | return nil, err | ||
531 | end | ||
532 | |||
506 | local writer = require("luarocks.manif.writer") | 533 | local writer = require("luarocks.manif.writer") |
507 | return writer.add_to_manifest(name, version, nil, deps_mode) | 534 | return writer.add_to_manifest(name, version, nil, deps_mode) |
508 | end | 535 | end |
509 | 536 | ||
537 | local function add_to_double_checks(double_checks, name, version) | ||
538 | double_checks[name] = double_checks[name] or {} | ||
539 | double_checks[name][version] = true | ||
540 | end | ||
541 | |||
542 | local function double_check_all(double_checks, repo) | ||
543 | local errs = {} | ||
544 | for next_name, versions in pairs(double_checks) do | ||
545 | for next_version in pairs(versions) do | ||
546 | local rock_manifest, load_err = manif.load_rock_manifest(next_name, next_version) | ||
547 | local ok, err = repos.check_everything_is_installed(next_name, next_version, rock_manifest, repo, true) | ||
548 | if not ok then | ||
549 | table.insert(errs, err) | ||
550 | end | ||
551 | end | ||
552 | end | ||
553 | if next(errs) then | ||
554 | return nil, table.concat(errs, "\n") | ||
555 | end | ||
556 | return true | ||
557 | end | ||
558 | |||
510 | --- Delete a package from the local repository. | 559 | --- Delete a package from the local repository. |
511 | -- @param name string: name of package | 560 | -- @param name string: name of package |
512 | -- @param version string: exact package version in string format | 561 | -- @param version string: exact package version in string format |
@@ -536,6 +585,8 @@ function repos.delete_version(name, version, deps_mode, quick) | |||
536 | local renames = {} | 585 | local renames = {} |
537 | local deletes = {} | 586 | local deletes = {} |
538 | 587 | ||
588 | local double_checks = {} | ||
589 | |||
539 | if rock_manifest.bin then | 590 | if rock_manifest.bin then |
540 | repos.recurse_rock_manifest_entry(rock_manifest.bin, function(file_path) | 591 | repos.recurse_rock_manifest_entry(rock_manifest.bin, function(file_path) |
541 | local paths = get_deploy_paths(name, version, "bin", file_path, repo) | 592 | local paths = get_deploy_paths(name, version, "bin", file_path, repo) |
@@ -547,6 +598,7 @@ function repos.delete_version(name, version, deps_mode, quick) | |||
547 | 598 | ||
548 | local next_name, next_version = manif.get_next_provider("command", item_name) | 599 | local next_name, next_version = manif.get_next_provider("command", item_name) |
549 | if next_name then | 600 | if next_name then |
601 | add_to_double_checks(double_checks, next_name, next_version) | ||
550 | local next_paths = get_deploy_paths(next_name, next_version, "lua", file_path, repo) | 602 | local next_paths = get_deploy_paths(next_name, next_version, "lua", file_path, repo) |
551 | table.insert(renames, { src = next_paths.v, dst = next_paths.nv, suffix = cfg.wrapper_suffix }) | 603 | table.insert(renames, { src = next_paths.v, dst = next_paths.nv, suffix = cfg.wrapper_suffix }) |
552 | end | 604 | end |
@@ -565,6 +617,7 @@ function repos.delete_version(name, version, deps_mode, quick) | |||
565 | 617 | ||
566 | local next_name, next_version = manif.get_next_provider("module", item_name) | 618 | local next_name, next_version = manif.get_next_provider("module", item_name) |
567 | if next_name then | 619 | if next_name then |
620 | add_to_double_checks(double_checks, next_name, next_version) | ||
568 | local next_lua_paths = get_deploy_paths(next_name, next_version, "lua", file_path, repo) | 621 | local next_lua_paths = get_deploy_paths(next_name, next_version, "lua", file_path, repo) |
569 | table.insert(renames, { src = next_lua_paths.v, dst = next_lua_paths.nv }) | 622 | table.insert(renames, { src = next_lua_paths.v, dst = next_lua_paths.nv }) |
570 | local next_lib_paths = get_deploy_paths(next_name, next_version, "lib", file_path:gsub("%.[^.]+$", ".lua"), repo) | 623 | local next_lib_paths = get_deploy_paths(next_name, next_version, "lib", file_path:gsub("%.[^.]+$", ".lua"), repo) |
@@ -585,6 +638,7 @@ function repos.delete_version(name, version, deps_mode, quick) | |||
585 | 638 | ||
586 | local next_name, next_version = manif.get_next_provider("module", item_name) | 639 | local next_name, next_version = manif.get_next_provider("module", item_name) |
587 | if next_name then | 640 | if next_name then |
641 | add_to_double_checks(double_checks, next_name, next_version) | ||
588 | local next_lua_paths = get_deploy_paths(next_name, next_version, "lua", file_path:gsub("%.[^.]+$", ".lua"), repo) | 642 | local next_lua_paths = get_deploy_paths(next_name, next_version, "lua", file_path:gsub("%.[^.]+$", ".lua"), repo) |
589 | table.insert(renames, { src = next_lua_paths.v, dst = next_lua_paths.nv }) | 643 | table.insert(renames, { src = next_lua_paths.v, dst = next_lua_paths.nv }) |
590 | local next_lib_paths = get_deploy_paths(next_name, next_version, "lib", file_path, repo) | 644 | local next_lib_paths = get_deploy_paths(next_name, next_version, "lib", file_path, repo) |
@@ -604,6 +658,11 @@ function repos.delete_version(name, version, deps_mode, quick) | |||
604 | for _, op in ipairs(renames) do | 658 | for _, op in ipairs(renames) do |
605 | op_rename(op) | 659 | op_rename(op) |
606 | end | 660 | end |
661 | |||
662 | local ok, err = double_check_all(double_checks, repo) | ||
663 | if not ok then | ||
664 | return nil, err | ||
665 | end | ||
607 | end | 666 | end |
608 | 667 | ||
609 | fs.delete(path.install_dir(name, version)) | 668 | fs.delete(path.install_dir(name, version)) |