aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHisham Muhammad <hisham@gobolinux.org>2021-03-16 14:55:11 -0300
committerHisham Muhammad <hisham@gobolinux.org>2021-03-19 13:15:53 -0300
commit2efec770b1b1b27a4b15c3b06a2f5fcadc0b546d (patch)
treef7c2e34abe3314658df0970dde6e1bc346c1e627
parent08ae98e309c3f09be00b547bab74a5fd875bfa36 (diff)
downloadluarocks-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.lua35
-rw-r--r--src/luarocks/cmd/build.lua4
-rw-r--r--src/luarocks/cmd/install.lua8
-rw-r--r--src/luarocks/cmd/make.lua8
-rw-r--r--src/luarocks/cmd/purge.lua4
-rw-r--r--src/luarocks/remove.lua20
-rw-r--r--src/luarocks/repos.lua59
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")
2local lfs = require("lfs") 2local lfs = require("lfs")
3local run = test_env.run 3local run = test_env.run
4local testing_paths = test_env.testing_paths 4local testing_paths = test_env.testing_paths
5local env_variables = test_env.env_variables
5 6
6test_env.unload_luarocks() 7test_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
15describe("luarocks remove #integration", function() 18describe("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")
7local path = require("luarocks.path") 7local path = require("luarocks.path")
8local util = require("luarocks.util") 8local util = require("luarocks.util")
9local cfg = require("luarocks.core.cfg") 9local cfg = require("luarocks.core.cfg")
10local manif = require("luarocks.manif")
10local queries = require("luarocks.queries") 11local 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
114end 130end
115 131
116return remove 132return 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
393end 393end
394 394
395--- Double check that all files referenced in `rock_manifest` are installed in `repo`.
396function 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
415end
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)
508end 535end
509 536
537local function add_to_double_checks(double_checks, name, version)
538 double_checks[name] = double_checks[name] or {}
539 double_checks[name][version] = true
540end
541
542local 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
557end
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))