aboutsummaryrefslogtreecommitdiff
path: root/src/luarocks/remove.tl
diff options
context:
space:
mode:
Diffstat (limited to 'src/luarocks/remove.tl')
-rw-r--r--src/luarocks/remove.tl140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/luarocks/remove.tl b/src/luarocks/remove.tl
new file mode 100644
index 00000000..11d270a9
--- /dev/null
+++ b/src/luarocks/remove.tl
@@ -0,0 +1,140 @@
1
2local record remove
3end
4
5local search = require("luarocks.search")
6local deps = require("luarocks.deps")
7local fetch = require("luarocks.fetch")
8local repos = require("luarocks.repos")
9local repo_writer = require("luarocks.repo_writer")
10local path = require("luarocks.path")
11local util = require("luarocks.util")
12local cfg = require("luarocks.core.cfg")
13local manif = require("luarocks.manif")
14local queries = require("luarocks.queries")
15
16local type Result = require("luarocks.core.types.result").Result
17
18--- Obtain a list of packages that depend on the given set of packages
19-- (where all packages of the set are versions of one program).
20-- @param name string: the name of a program
21-- @param versions array of string: the versions to be deleted.
22-- @return array of string: an empty table if no packages depend on any
23-- of the given list, or an array of strings in "name/version" format.
24local function check_dependents(name: string, versions: {string: {Result}}, deps_mode: string): {Result}
25 local dependents: {Result} = {}
26
27 local skip_set = {}
28 skip_set[name] = {}
29 for version, _ in pairs(versions) do
30 skip_set[name][version] = true
31 end
32
33 local local_rocks = {}
34 local query_all = queries.all()
35 search.local_manifest_search(local_rocks, cfg.rocks_dir, query_all)
36 local_rocks[name] = nil
37 for rock_name, rock_versions in pairs(local_rocks) do
38 for rock_version, _ in pairs(rock_versions) do
39 local rockspec, err = fetch.load_rockspec(path.rockspec_file(rock_name, rock_version))
40 if rockspec then
41 local _, missing = deps.match_deps(rockspec.dependencies.queries, rockspec.rocks_provided, deps_mode, skip_set)
42 if missing[name] then
43 table.insert(dependents, { name = rock_name, version = rock_version })
44 end
45 end
46 end
47 end
48
49 return dependents
50end
51
52--- Delete given versions of a program.
53-- @param name string: the name of a program
54-- @param versions array of string: the versions to be deleted.
55-- @param deps_mode: string: Which trees to check dependencies for:
56-- "one" for the current default tree, "all" for all trees,
57-- "order" for all trees with priority >= the current default, "none" for no trees.
58-- @return boolean or (nil, string): true on success or nil and an error message.
59local function delete_versions(name: string, versions: {string: any}, deps_mode: string): boolean, string
60
61 for version, _ in pairs(versions) do
62 util.printout("Removing "..name.." "..version.."...")
63 local ok, err = repo_writer.delete_version(name, version, deps_mode)
64 if not ok then return nil, err end
65 end
66
67 return true
68end
69
70function remove.remove_search_results(results: {string : {string : {Result}}}, name: string, deps_mode: string, force: boolean, fast: boolean): boolean, string
71 local versions = results[name]
72
73 local version = next(versions)
74 local second = next(versions, version)
75
76 local dependents = {}
77 if not fast then
78 util.printout("Checking stability of dependencies in the absence of")
79 util.printout(name.." "..table.concat((util.keys(versions) as {string | number}), ", ").."...")
80 util.printout()
81 dependents = check_dependents(name, versions, deps_mode)
82 end
83
84 if #dependents > 0 then
85 if force or fast then
86 util.printerr("The following packages may be broken by this forced removal:")
87 for _, dependent in ipairs(dependents) do
88 util.printerr(dependent.name.." "..dependent.version)
89 end
90 util.printerr()
91 else
92 if not second then
93 util.printerr("Will not remove "..name.." "..version..".")
94 util.printerr("Removing it would break dependencies for: ")
95 else
96 util.printerr("Will not remove installed versions of "..name..".")
97 util.printerr("Removing them would break dependencies for: ")
98 end
99 for _, dependent in ipairs(dependents) do
100 util.printerr(dependent.name.." "..dependent.version)
101 end
102 util.printerr()
103 util.printerr("Use --force to force removal (warning: this may break modules).")
104 return nil, "Failed removing."
105 end
106 end
107
108 local ok, err = delete_versions(name, versions, deps_mode)
109 if not ok then return nil, err end
110
111 util.printout("Removal successful.")
112 return true
113end
114
115function remove.remove_other_versions(name: string, version: string, force: boolean, fast: boolean): boolean, string, string
116 local results = {}
117 local query = queries.new(name, nil, version, false, nil, "~=")
118 search.local_manifest_search(results, cfg.rocks_dir, query)
119 local warn: string
120 if results[name] then
121 local ok, err = remove.remove_search_results(results, name, cfg.deps_mode, force, fast)
122 if not ok then -- downgrade failure to a warning
123 warn = err
124 end
125 end
126
127 if not fast then
128 -- since we're not using --keep, this means that all files of the rock being installed
129 -- should be available as non-versioned variants. Double-check that:
130 local rock_manifest, load_err = manif.load_rock_manifest(name, version)
131 local ok, err = repos.check_everything_is_installed(name, version, rock_manifest, cfg.root_dir, false)
132 if not ok then
133 return nil, err
134 end
135 end
136
137 return true, nil, warn
138end
139
140return remove