diff options
author | Hisham Muhammad <hisham@gobolinux.org> | 2018-09-03 19:53:18 +0200 |
---|---|---|
committer | Hisham Muhammad <hisham@gobolinux.org> | 2018-09-04 18:11:12 +0200 |
commit | c2fde487834c6d7505d7e803256e8764237d4476 (patch) | |
tree | 97253f34b90c463ca3bb2039e0aa1ab0855031fd /src | |
parent | d09f92a84d0a9267a066af2d6978f9a51e555f5f (diff) | |
download | luarocks-c2fde487834c6d7505d7e803256e8764237d4476.tar.gz luarocks-c2fde487834c6d7505d7e803256e8764237d4476.tar.bz2 luarocks-c2fde487834c6d7505d7e803256e8764237d4476.zip |
repos: fix upgrade and downgrade of files when module names clash
This reworks the logic of upgrading/downgrading multiple versions
of the same package (or different packages) when they have
different files that resolve to the same module name (foo.lua
and foo.so).
For a concrete example, this was hitting LuaSec downgrades.
Diffstat (limited to 'src')
-rw-r--r-- | src/luarocks/cmd/show.lua | 55 | ||||
-rw-r--r-- | src/luarocks/repos.lua | 394 |
2 files changed, 262 insertions, 187 deletions
diff --git a/src/luarocks/cmd/show.lua b/src/luarocks/cmd/show.lua index c90a6bea..bb0fdfd7 100644 --- a/src/luarocks/cmd/show.lua +++ b/src/luarocks/cmd/show.lua | |||
@@ -5,6 +5,7 @@ local show = {} | |||
5 | local queries = require("luarocks.queries") | 5 | local queries = require("luarocks.queries") |
6 | local search = require("luarocks.search") | 6 | local search = require("luarocks.search") |
7 | local dir = require("luarocks.core.dir") | 7 | local dir = require("luarocks.core.dir") |
8 | local fs = require("luarocks.fs") | ||
8 | local cfg = require("luarocks.core.cfg") | 9 | local cfg = require("luarocks.core.cfg") |
9 | local util = require("luarocks.util") | 10 | local util = require("luarocks.util") |
10 | local path = require("luarocks.path") | 11 | local path = require("luarocks.path") |
@@ -145,25 +146,52 @@ local function render(template, data) | |||
145 | return table.concat(out, "\n") | 146 | return table.concat(out, "\n") |
146 | end | 147 | end |
147 | 148 | ||
148 | local function files_to_list(name, version, item_set, item_type, repo) | 149 | local function adjust_path(name, version, basedir, pathname, suffix) |
149 | local ret = {} | 150 | pathname = dir.path(basedir, pathname) |
150 | for item_name in util.sortedpairs(item_set) do | 151 | local vpathname = path.versioned_name(pathname, basedir, name, version) |
151 | table.insert(ret, { name = item_name, file = repos.which(name, version, item_type, item_name, repo) }) | 152 | return (fs.exists(vpathname) |
152 | end | 153 | and vpathname |
153 | return ret | 154 | or pathname) .. (suffix or "") |
154 | end | 155 | end |
155 | 156 | ||
156 | local function modules_to_list(name, version, repo) | 157 | local function modules_to_list(name, version, repo) |
157 | local ret = {} | 158 | local ret = {} |
158 | local rock_manifest = manif.load_rock_manifest(name, version, repo) | 159 | local rock_manifest = manif.load_rock_manifest(name, version, repo) |
159 | 160 | ||
160 | local lua_dir = path.lua_dir(name, version, repo) | 161 | local lua_dir = path.deploy_lua_dir(repo) |
161 | local lib_dir = path.lib_dir(name, version, repo) | 162 | local lib_dir = path.deploy_lib_dir(repo) |
162 | repos.recurse_rock_manifest_entry(rock_manifest.lua, function(pathname, modname) | 163 | repos.recurse_rock_manifest_entry(rock_manifest.lua, function(pathname) |
163 | table.insert(ret, { name = modname, file = dir.path(lua_dir, pathname) }) | 164 | table.insert(ret, { |
165 | name = path.path_to_module(pathname), | ||
166 | file = adjust_path(name, version, lua_dir, pathname), | ||
167 | }) | ||
164 | end) | 168 | end) |
165 | repos.recurse_rock_manifest_entry(rock_manifest.lib, function(pathname, modname) | 169 | repos.recurse_rock_manifest_entry(rock_manifest.lib, function(pathname) |
166 | table.insert(ret, { name = modname, file = dir.path(lib_dir, pathname) }) | 170 | table.insert(ret, { |
171 | name = path.path_to_module(pathname), | ||
172 | file = adjust_path(name, version, lib_dir, pathname), | ||
173 | }) | ||
174 | end) | ||
175 | table.sort(ret, function(a, b) | ||
176 | if a.name == b.name then | ||
177 | return a.file < b.file | ||
178 | end | ||
179 | return a.name < b.name | ||
180 | end) | ||
181 | return ret | ||
182 | end | ||
183 | |||
184 | local function commands_to_list(name, version, repo) | ||
185 | local ret = {} | ||
186 | local rock_manifest = manif.load_rock_manifest(name, version, repo) | ||
187 | |||
188 | local bin_dir = path.deploy_bin_dir(repo) | ||
189 | repos.recurse_rock_manifest_entry(rock_manifest.bin, function(pathname) | ||
190 | pathname = adjust_path(name, version, bin_dir, pathname) | ||
191 | table.insert(ret, { | ||
192 | name = pathname, | ||
193 | file = adjust_path(name, version, bin_dir, pathname, cfg.wrapper_suffix), | ||
194 | }) | ||
167 | end) | 195 | end) |
168 | table.sort(ret, function(a, b) | 196 | table.sort(ret, function(a, b) |
169 | if a.name == b.name then | 197 | if a.name == b.name then |
@@ -209,7 +237,7 @@ local function show_rock(template, namespace, name, version, rockspec, repo, min | |||
209 | issues = desc.issues_url, | 237 | issues = desc.issues_url, |
210 | labels = desc.labels and table.concat(desc.labels, ", "), | 238 | labels = desc.labels and table.concat(desc.labels, ", "), |
211 | location = path.rocks_tree_to_string(repo), | 239 | location = path.rocks_tree_to_string(repo), |
212 | commands = files_to_list(name, version, minfo.commands, "command", repo), | 240 | commands = commands_to_list(name, version, repo), |
213 | modules = modules_to_list(name, version, repo), | 241 | modules = modules_to_list(name, version, repo), |
214 | bdeps = deps_to_list(rockspec.build_dependencies, tree), | 242 | bdeps = deps_to_list(rockspec.build_dependencies, tree), |
215 | tdeps = deps_to_list(rockspec.test_dependencies, tree), | 243 | tdeps = deps_to_list(rockspec.test_dependencies, tree), |
@@ -278,5 +306,4 @@ function show.command(flags, name, version) | |||
278 | return true | 306 | return true |
279 | end | 307 | end |
280 | 308 | ||
281 | |||
282 | return show | 309 | return show |
diff --git a/src/luarocks/repos.lua b/src/luarocks/repos.lua index 37a81c20..eaec87b8 100644 --- a/src/luarocks/repos.lua +++ b/src/luarocks/repos.lua | |||
@@ -9,6 +9,21 @@ local util = require("luarocks.util") | |||
9 | local dir = require("luarocks.dir") | 9 | local dir = require("luarocks.dir") |
10 | local manif = require("luarocks.manif") | 10 | local manif = require("luarocks.manif") |
11 | local vers = require("luarocks.core.vers") | 11 | local vers = require("luarocks.core.vers") |
12 | local E = {} | ||
13 | |||
14 | local unpack = unpack or table.unpack | ||
15 | |||
16 | --- Get type and name of an item (a module or a command) provided by a file. | ||
17 | -- @param deploy_type string: rock manifest subtree the file comes from ("bin", "lua", or "lib"). | ||
18 | -- @param file_path string: path to the file relatively to deploy_type subdirectory. | ||
19 | -- @return (string, string): item type ("module" or "command") and name. | ||
20 | local function get_provided_item(deploy_type, file_path) | ||
21 | assert(type(deploy_type) == "string") | ||
22 | assert(type(file_path) == "string") | ||
23 | local item_type = deploy_type == "bin" and "command" or "module" | ||
24 | local item_name = item_type == "command" and file_path or path.path_to_module(file_path) | ||
25 | return item_type, item_name | ||
26 | end | ||
12 | 27 | ||
13 | -- Tree of files installed by a package are stored | 28 | -- Tree of files installed by a package are stored |
14 | -- in its rock manifest. Some of these files have to | 29 | -- in its rock manifest. Some of these files have to |
@@ -52,37 +67,35 @@ function repos.is_installed(name, version) | |||
52 | end | 67 | end |
53 | 68 | ||
54 | function repos.recurse_rock_manifest_entry(entry, action) | 69 | function repos.recurse_rock_manifest_entry(entry, action) |
55 | assert(entry == nil or type(entry) == "table") | ||
56 | assert(type(action) == "function") | 70 | assert(type(action) == "function") |
57 | 71 | ||
58 | if entry == nil then | 72 | if entry == nil then |
59 | return true | 73 | return true |
60 | end | 74 | end |
61 | 75 | ||
62 | local function do_recurse_rock_manifest_tree(tree, parent_path, parent_mod) | 76 | local function do_recurse_rock_manifest_entry(tree, parent_path) |
77 | |||
63 | for file, sub in pairs(tree) do | 78 | for file, sub in pairs(tree) do |
64 | local sub_path = (parent_path and (parent_path .. "/") or "") .. file | 79 | local sub_path = (parent_path and (parent_path .. "/") or "") .. file |
65 | local sub_mod = (parent_mod and (parent_mod .. ".") or "") .. file | ||
66 | local ok, err | 80 | local ok, err |
67 | 81 | ||
68 | if type(sub) == "table" then | 82 | if type(sub) == "table" then |
69 | ok, err = do_recurse_rock_manifest_tree(sub, sub_path, sub_mod) | 83 | ok, err = do_recurse_rock_manifest_entry(sub, sub_path) |
70 | else | 84 | else |
71 | local mod_no_ext = sub_mod:gsub("%.[^.]*$", "") | 85 | ok, err = action(sub_path) |
72 | ok, err = action(sub_path, mod_no_ext) | ||
73 | end | 86 | end |
74 | 87 | ||
75 | if err then return nil, err end | 88 | if err then return nil, err end |
76 | end | 89 | end |
77 | return true | 90 | return true |
78 | end | 91 | end |
79 | return do_recurse_rock_manifest_tree(entry) | 92 | return do_recurse_rock_manifest_entry(entry) |
80 | end | 93 | end |
81 | 94 | ||
82 | local function store_package_data(result, rock_manifest, deploy_type) | 95 | local function store_package_data(result, rock_manifest, deploy_type) |
83 | if rock_manifest[deploy_type] then | 96 | if rock_manifest[deploy_type] then |
84 | repos.recurse_rock_manifest_entry(rock_manifest[deploy_type], function(file_path) | 97 | repos.recurse_rock_manifest_entry(rock_manifest[deploy_type], function(file_path) |
85 | local _, item_name = manif.get_provided_item(deploy_type, file_path) | 98 | local _, item_name = get_provided_item(deploy_type, file_path) |
86 | result[item_name] = file_path | 99 | result[item_name] = file_path |
87 | return true | 100 | return true |
88 | end) | 101 | end) |
@@ -206,29 +219,12 @@ local function find_suffixed(file, suffix) | |||
206 | return nil, table.concat(filenames, ", ") .. " not found" | 219 | return nil, table.concat(filenames, ", ") .. " not found" |
207 | end | 220 | end |
208 | 221 | ||
209 | local function move_suffixed(from_file, to_file, suffix) | 222 | local function check_suffix(filename, suffix) |
210 | local suffixed_from_file, err = find_suffixed(from_file, suffix) | 223 | local suffixed_filename, err = find_suffixed(filename, suffix) |
211 | if not suffixed_from_file then | 224 | if not suffixed_filename then |
212 | return nil, "Could not move " .. from_file .. " to " .. to_file .. ": " .. err | 225 | return "" |
213 | end | 226 | end |
214 | 227 | return suffixed_filename:sub(#filename + 1) | |
215 | suffix = suffixed_from_file:sub(#from_file + 1) | ||
216 | local suffixed_to_file = to_file .. suffix | ||
217 | return fs.move(suffixed_from_file, suffixed_to_file) | ||
218 | end | ||
219 | |||
220 | local function delete_suffixed(file, suffix) | ||
221 | local suffixed_file, err = find_suffixed(file, suffix) | ||
222 | if not suffixed_file then | ||
223 | return nil, "Could not remove " .. file .. ": " .. err, "not found" | ||
224 | end | ||
225 | |||
226 | fs.delete(suffixed_file) | ||
227 | if fs.exists(suffixed_file) then | ||
228 | return nil, "Failed deleting " .. suffixed_file .. ": file still exists", "fail" | ||
229 | end | ||
230 | |||
231 | return true | ||
232 | end | 228 | end |
233 | 229 | ||
234 | -- Files can be deployed using versioned and non-versioned names. | 230 | -- Files can be deployed using versioned and non-versioned names. |
@@ -238,38 +234,92 @@ end | |||
238 | -- is deployed using non-versioned name and others use versioned names. | 234 | -- is deployed using non-versioned name and others use versioned names. |
239 | 235 | ||
240 | local function get_deploy_paths(name, version, deploy_type, file_path, repo) | 236 | local function get_deploy_paths(name, version, deploy_type, file_path, repo) |
237 | assert(type(name) == "string") | ||
238 | assert(type(version) == "string") | ||
239 | assert(type(deploy_type) == "string") | ||
240 | assert(type(file_path) == "string") | ||
241 | |||
241 | repo = repo or cfg.root_dir | 242 | repo = repo or cfg.root_dir |
242 | local deploy_dir = path["deploy_" .. deploy_type .. "_dir"](repo) | 243 | local deploy_dir = path["deploy_" .. deploy_type .. "_dir"](repo) |
243 | local non_versioned = dir.path(deploy_dir, file_path) | 244 | local non_versioned = dir.path(deploy_dir, file_path) |
244 | local versioned = path.versioned_name(non_versioned, deploy_dir, name, version) | 245 | local versioned = path.versioned_name(non_versioned, deploy_dir, name, version) |
245 | return non_versioned, versioned | 246 | return { nv = non_versioned, v = versioned } |
246 | end | 247 | end |
247 | 248 | ||
248 | local function prepare_target(name, version, deploy_type, file_path, suffix) | 249 | local function check_spot_if_available(name, version, deploy_type, file_path) |
249 | local non_versioned, versioned = get_deploy_paths(name, version, deploy_type, file_path) | 250 | local item_type, item_name = get_provided_item(deploy_type, file_path) |
250 | local item_type, item_name = manif.get_provided_item(deploy_type, file_path) | ||
251 | local cur_name, cur_version = manif.get_current_provider(item_type, item_name) | 251 | local cur_name, cur_version = manif.get_current_provider(item_type, item_name) |
252 | if (not cur_name) | ||
253 | or (name < cur_name) | ||
254 | or (name == cur_name and (version == cur_version | ||
255 | or vers.compare_versions(version, cur_version))) then | ||
256 | return "nv", cur_name, cur_version, item_name | ||
257 | else | ||
258 | -- Existing version has priority, deploy new version using versioned name. | ||
259 | return "v", cur_name, cur_version, item_name | ||
260 | end | ||
261 | end | ||
262 | |||
263 | local function backup_existing(should_backup, target) | ||
264 | if not should_backup then | ||
265 | return | ||
266 | end | ||
267 | if fs.exists(target) then | ||
268 | local backup = target | ||
269 | repeat | ||
270 | backup = backup.."~" | ||
271 | until not fs.exists(backup) -- Slight race condition here, but shouldn't be a problem. | ||
272 | |||
273 | util.warning(target.." is not tracked by this installation of LuaRocks. Moving it to "..backup) | ||
274 | local move_ok, move_err = fs.move(target, backup) | ||
275 | if not move_ok then | ||
276 | return nil, move_err | ||
277 | end | ||
278 | end | ||
279 | end | ||
280 | |||
281 | local function op_install(op) | ||
282 | local ok, err = fs.make_dir(dir.dir_name(op.dst)) | ||
283 | if not ok then | ||
284 | return nil, err | ||
285 | end | ||
252 | 286 | ||
253 | if not cur_name then | 287 | ok, err = op.fn(op.src, op.dst, op.backup) |
254 | return non_versioned | 288 | if not ok then |
255 | elseif name < cur_name or (name == cur_name and vers.compare_versions(version, cur_version)) then | 289 | return nil, err |
256 | -- New version has priority. Move currently provided version back using versioned name. | 290 | end |
257 | local cur_deploy_type, cur_file_path = manif.get_providing_file(cur_name, cur_version, item_type, item_name) | ||
258 | local cur_non_versioned, cur_versioned = get_deploy_paths(cur_name, cur_version, cur_deploy_type, cur_file_path) | ||
259 | 291 | ||
260 | local dir_ok, dir_err = fs.make_dir(dir.dir_name(cur_versioned)) | 292 | fs.remove_dir_tree_if_empty(dir.dir_name(op.src)) |
261 | if not dir_ok then return nil, dir_err end | 293 | end |
262 | 294 | ||
263 | local move_ok, move_err = move_suffixed(cur_non_versioned, cur_versioned, suffix) | 295 | local function op_rename(op) |
264 | if not move_ok then return nil, move_err end | 296 | if op.suffix then |
297 | local suffix = check_suffix(op.src, op.suffix) | ||
298 | op.src = op.src .. suffix | ||
299 | op.dst = op.dst .. suffix | ||
300 | end | ||
265 | 301 | ||
266 | return non_versioned | 302 | if fs.exists(op.src) then |
303 | fs.make_dir(dir.dir_name(op.dst)) | ||
304 | local ok, err = fs.move(op.src, op.dst) | ||
305 | fs.remove_dir_tree_if_empty(dir.dir_name(op.src)) | ||
306 | return ok, err | ||
267 | else | 307 | else |
268 | -- Current version has priority, deploy new version using versioned name. | 308 | return true |
269 | return versioned | ||
270 | end | 309 | end |
271 | end | 310 | end |
272 | 311 | ||
312 | local function op_delete(op) | ||
313 | if op.suffix then | ||
314 | local suffix = check_suffix(op.name, op.suffix) | ||
315 | op.name = op.name .. suffix | ||
316 | end | ||
317 | |||
318 | local ok, err = fs.delete(op.name) | ||
319 | fs.remove_dir_tree_if_empty(dir.dir_name(op.name)) | ||
320 | return ok, err | ||
321 | end | ||
322 | |||
273 | --- Deploy a package from the rocks subdirectory. | 323 | --- Deploy a package from the rocks subdirectory. |
274 | -- @param name string: name of package | 324 | -- @param name string: name of package |
275 | -- @param version string: exact package version in string format | 325 | -- @param version string: exact package version in string format |
@@ -284,63 +334,89 @@ function repos.deploy_files(name, version, wrap_bin_scripts, deps_mode) | |||
284 | 334 | ||
285 | local rock_manifest, load_err = manif.load_rock_manifest(name, version) | 335 | local rock_manifest, load_err = manif.load_rock_manifest(name, version) |
286 | if not rock_manifest then return nil, load_err end | 336 | if not rock_manifest then return nil, load_err end |
337 | |||
338 | local repo = cfg.root_dir | ||
339 | local renames = {} | ||
340 | local installs = {} | ||
287 | 341 | ||
288 | local function deploy_file_tree(deploy_type, source_dir, move_fn, suffix) | 342 | local function install_binary(source, target, should_backup) |
289 | return repos.recurse_rock_manifest_entry(rock_manifest[deploy_type], function(file_path) | 343 | if wrap_bin_scripts and fs.is_lua(source) then |
290 | local source = dir.path(source_dir, file_path) | 344 | backup_existing(should_backup, target .. (cfg.wrapper_suffix or "")) |
345 | return fs.wrap_script(source, target, deps_mode, name, version) | ||
346 | else | ||
347 | backup_existing(should_backup, target) | ||
348 | return fs.copy_binary(source, target) | ||
349 | end | ||
350 | end | ||
291 | 351 | ||
292 | local target, prepare_err = prepare_target(name, version, deploy_type, file_path, suffix) | 352 | local function move_lua(source, target, should_backup) |
293 | if not target then return nil, prepare_err end | 353 | backup_existing(should_backup, target) |
354 | return fs.move(source, target, "read") | ||
355 | end | ||
294 | 356 | ||
295 | local dir_ok, dir_err = fs.make_dir(dir.dir_name(target)) | 357 | local function move_lib(source, target, should_backup) |
296 | if not dir_ok then return nil, dir_err end | 358 | backup_existing(should_backup, target) |
359 | return fs.move(source, target, "exec") | ||
360 | end | ||
297 | 361 | ||
298 | local suffixed_target, mover = move_fn(source, target) | 362 | if rock_manifest.bin then |
299 | if fs.exists(suffixed_target) then | 363 | local source_dir = path.bin_dir(name, version) |
300 | local backup = suffixed_target | 364 | repos.recurse_rock_manifest_entry(rock_manifest.bin, function(file_path) |
301 | repeat | 365 | local source = dir.path(source_dir, file_path) |
302 | backup = backup.."~" | 366 | local paths = get_deploy_paths(name, version, "bin", file_path, repo) |
303 | until not fs.exists(backup) -- Slight race condition here, but shouldn't be a problem. | 367 | local mode, cur_name, cur_version = check_spot_if_available(name, version, "bin", file_path) |
304 | 368 | ||
305 | util.warning(suffixed_target.." is not tracked by this installation of LuaRocks. Moving it to "..backup) | 369 | if mode == "nv" and cur_name then |
306 | local move_ok, move_err = fs.move(suffixed_target, backup) | 370 | local cur_paths = get_deploy_paths(cur_name, cur_version, "bin", file_path, repo) |
307 | if not move_ok then return nil, move_err end | 371 | table.insert(renames, { src = cur_paths.nv, dst = cur_paths.v, suffix = cfg.wrapper_suffix }) |
308 | end | 372 | end |
309 | 373 | local backup = name ~= cur_name or version ~= cur_version | |
310 | local move_ok, move_err = mover() | 374 | table.insert(installs, { fn = install_binary, src = source, dst = mode == "nv" and paths.nv or paths.v, backup = backup }) |
311 | if not move_ok then return nil, move_err end | ||
312 | |||
313 | fs.remove_dir_tree_if_empty(dir.dir_name(source)) | ||
314 | return true | ||
315 | end) | 375 | end) |
316 | end | 376 | end |
317 | 377 | ||
318 | local function install_binary(source, target) | 378 | if rock_manifest.lua then |
319 | if wrap_bin_scripts and fs.is_lua(source) then | 379 | local source_dir = path.lua_dir(name, version) |
320 | return target .. (cfg.wrapper_suffix or ""), function() | 380 | repos.recurse_rock_manifest_entry(rock_manifest.lua, function(file_path) |
321 | return fs.wrap_script(source, target, deps_mode, name, version) | 381 | local source = dir.path(source_dir, file_path) |
322 | end | 382 | local paths = get_deploy_paths(name, version, "lua", file_path, repo) |
323 | else | 383 | local mode, cur_name, cur_version = check_spot_if_available(name, version, "lua", file_path) |
324 | return target, function() | 384 | |
325 | return fs.copy_binary(source, target) | 385 | if mode == "nv" and cur_name then |
386 | local cur_paths = get_deploy_paths(cur_name, cur_version, "lua", file_path, repo) | ||
387 | table.insert(renames, { src = cur_paths.nv, dst = cur_paths.v }) | ||
388 | cur_paths = get_deploy_paths(cur_name, cur_version, "lib", file_path:gsub("%.lua$", "." .. cfg.lib_extension), repo) | ||
389 | table.insert(renames, { src = cur_paths.nv, dst = cur_paths.v }) | ||
326 | end | 390 | end |
327 | end | 391 | local backup = name ~= cur_name or version ~= cur_version |
392 | table.insert(installs, { fn = move_lua, src = source, dst = mode == "nv" and paths.nv or paths.v, backup = backup }) | ||
393 | end) | ||
328 | end | 394 | end |
329 | 395 | ||
330 | local function make_mover(perms) | 396 | if rock_manifest.lib then |
331 | return function(source, target) | 397 | local source_dir = path.lib_dir(name, version) |
332 | return target, function() return fs.move(source, target, perms) end | 398 | repos.recurse_rock_manifest_entry(rock_manifest.lib, function(file_path) |
333 | end | 399 | local source = dir.path(source_dir, file_path) |
400 | local paths = get_deploy_paths(name, version, "lib", file_path, repo) | ||
401 | local mode, cur_name, cur_version = check_spot_if_available(name, version, "lib", file_path) | ||
402 | |||
403 | if mode == "nv" and cur_name then | ||
404 | local cur_paths = get_deploy_paths(cur_name, cur_version, "lua", file_path:gsub("%.[^.]+$", ".lua"), repo) | ||
405 | table.insert(renames, { src = cur_paths.nv, dst = cur_paths.v }) | ||
406 | cur_paths = get_deploy_paths(cur_name, cur_version, "lib", file_path, repo) | ||
407 | table.insert(renames, { src = cur_paths.nv, dst = cur_paths.v }) | ||
408 | end | ||
409 | local backup = name ~= cur_name or version ~= cur_version | ||
410 | table.insert(installs, { fn = move_lib, src = source, dst = mode == "nv" and paths.nv or paths.v, backup = backup }) | ||
411 | end) | ||
334 | end | 412 | end |
335 | 413 | ||
336 | local ok, err = deploy_file_tree("bin", path.bin_dir(name, version), install_binary, cfg.wrapper_suffix) | 414 | for _, op in ipairs(renames) do |
337 | if not ok then return nil, err end | 415 | op_rename(op) |
338 | 416 | end | |
339 | ok, err = deploy_file_tree("lua", path.lua_dir(name, version), make_mover("read")) | 417 | for _, op in ipairs(installs) do |
340 | if not ok then return nil, err end | 418 | op_install(op) |
341 | 419 | end | |
342 | ok, err = deploy_file_tree("lib", path.lib_dir(name, version), make_mover("exec")) | ||
343 | if not ok then return nil, err end | ||
344 | 420 | ||
345 | local writer = require("luarocks.manif.writer") | 421 | local writer = require("luarocks.manif.writer") |
346 | return writer.add_to_manifest(name, version, nil, deps_mode) | 422 | return writer.add_to_manifest(name, version, nil, deps_mode) |
@@ -364,60 +440,76 @@ function repos.delete_version(name, version, deps_mode, quick) | |||
364 | local rock_manifest, load_err = manif.load_rock_manifest(name, version) | 440 | local rock_manifest, load_err = manif.load_rock_manifest(name, version) |
365 | if not rock_manifest then return nil, load_err end | 441 | if not rock_manifest then return nil, load_err end |
366 | 442 | ||
367 | local function delete_deployed_file_tree(deploy_type, suffix) | 443 | local repo = cfg.root_dir |
368 | return repos.recurse_rock_manifest_entry(rock_manifest[deploy_type], function(file_path) | 444 | local renames = {} |
369 | local non_versioned, versioned = get_deploy_paths(name, version, deploy_type, file_path) | 445 | local deletes = {} |
370 | |||
371 | -- Figure out if the file is deployed using versioned or non-versioned name. | ||
372 | local target | ||
373 | local item_type, item_name = manif.get_provided_item(deploy_type, file_path) | ||
374 | local cur_name, cur_version = manif.get_current_provider(item_type, item_name) | ||
375 | 446 | ||
376 | if cur_name == name and cur_version == version then | 447 | if rock_manifest.bin then |
377 | -- This package has highest priority, should be in non-versioned location. | 448 | repos.recurse_rock_manifest_entry(rock_manifest.bin, function(file_path) |
378 | target = non_versioned | 449 | local paths = get_deploy_paths(name, version, "bin", file_path, repo) |
450 | local mode, cur_name, cur_version, item_name = check_spot_if_available(name, version, "bin", file_path) | ||
451 | if mode == "v" then | ||
452 | table.insert(deletes, { name = paths.v, suffix = cfg.wrapper_suffix }) | ||
379 | else | 453 | else |
380 | target = versioned | 454 | table.insert(deletes, { name = paths.nv, suffix = cfg.wrapper_suffix }) |
381 | end | ||
382 | 455 | ||
383 | local ok, err, err_type = delete_suffixed(target, suffix) | 456 | local next_name, next_version = manif.get_next_provider("command", item_name) |
384 | if not ok then | 457 | if next_name then |
385 | if err_type == "not found" then | 458 | local next_paths = get_deploy_paths(next_name, next_version, "lua", file_path, repo) |
386 | util.warning(err) | 459 | table.insert(renames, { src = next_paths.v, dst = next_paths.nv, suffix = cfg.wrapper_suffix }) |
387 | else | ||
388 | return nil, err | ||
389 | end | 460 | end |
390 | end | 461 | end |
462 | end) | ||
463 | end | ||
391 | 464 | ||
392 | if not quick and target == non_versioned then | 465 | if rock_manifest.lua then |
393 | -- If another package provides this file, move its version | 466 | repos.recurse_rock_manifest_entry(rock_manifest.lua, function(file_path) |
394 | -- into non-versioned location instead. | 467 | local paths = get_deploy_paths(name, version, "lua", file_path, repo) |
395 | local next_name, next_version = manif.get_next_provider(item_type, item_name) | 468 | local mode, cur_name, cur_version, item_name = check_spot_if_available(name, version, "lua", file_path) |
469 | if mode == "v" then | ||
470 | table.insert(deletes, { name = paths.v }) | ||
471 | else | ||
472 | table.insert(deletes, { name = paths.nv }) | ||
396 | 473 | ||
474 | local next_name, next_version = manif.get_next_provider("module", item_name) | ||
397 | if next_name then | 475 | if next_name then |
398 | local next_deploy_type, next_file_path = manif.get_providing_file(next_name, next_version, item_type, item_name) | 476 | local next_lua_paths = get_deploy_paths(next_name, next_version, "lua", file_path, repo) |
399 | local next_non_versioned, next_versioned = get_deploy_paths(next_name, next_version, next_deploy_type, next_file_path) | 477 | table.insert(renames, { src = next_lua_paths.v, dst = next_lua_paths.nv }) |
400 | 478 | local next_lib_paths = get_deploy_paths(next_name, next_version, "lib", file_path:gsub("%.[^.]+$", ".lua"), repo) | |
401 | local move_ok, move_err = move_suffixed(next_versioned, next_non_versioned, suffix) | 479 | table.insert(renames, { src = next_lib_paths.v, dst = next_lib_paths.nv }) |
402 | if not move_ok then return nil, move_err end | ||
403 | |||
404 | fs.remove_dir_tree_if_empty(dir.dir_name(next_versioned)) | ||
405 | end | 480 | end |
406 | end | 481 | end |
407 | |||
408 | fs.remove_dir_tree_if_empty(dir.dir_name(target)) | ||
409 | return true | ||
410 | end) | 482 | end) |
411 | end | 483 | end |
412 | 484 | ||
413 | local ok, err = delete_deployed_file_tree("bin", cfg.wrapper_suffix) | 485 | if rock_manifest.lib then |
414 | if not ok then return nil, err end | 486 | repos.recurse_rock_manifest_entry(rock_manifest.lib, function(file_path) |
487 | local paths = get_deploy_paths(name, version, "lib", file_path, repo) | ||
488 | local mode, cur_name, cur_version, item_name = check_spot_if_available(name, version, "lib", file_path) | ||
489 | if mode == "v" then | ||
490 | table.insert(deletes, { name = paths.v }) | ||
491 | else | ||
492 | table.insert(deletes, { name = paths.nv }) | ||
415 | 493 | ||
416 | ok, err = delete_deployed_file_tree("lua") | 494 | local next_name, next_version = manif.get_next_provider("module", item_name) |
417 | if not ok then return nil, err end | 495 | if next_name then |
496 | local next_lua_paths = get_deploy_paths(next_name, next_version, "lua", file_path:gsub("%.[^.]+$", ".lua"), repo) | ||
497 | table.insert(renames, { src = next_lua_paths.v, dst = next_lua_paths.nv }) | ||
498 | local next_lib_paths = get_deploy_paths(next_name, next_version, "lib", file_path, repo) | ||
499 | table.insert(renames, { src = next_lib_paths.v, dst = next_lib_paths.nv }) | ||
500 | end | ||
501 | end | ||
502 | end) | ||
503 | end | ||
418 | 504 | ||
419 | ok, err = delete_deployed_file_tree("lib") | 505 | for _, op in ipairs(deletes) do |
420 | if not ok then return nil, err end | 506 | op_delete(op) |
507 | end | ||
508 | if not quick then | ||
509 | for _, op in ipairs(renames) do | ||
510 | op_rename(op) | ||
511 | end | ||
512 | end | ||
421 | 513 | ||
422 | fs.delete(path.install_dir(name, version)) | 514 | fs.delete(path.install_dir(name, version)) |
423 | if not get_installed_versions(name) then | 515 | if not get_installed_versions(name) then |
@@ -432,48 +524,4 @@ function repos.delete_version(name, version, deps_mode, quick) | |||
432 | return writer.remove_from_manifest(name, version, nil, deps_mode) | 524 | return writer.remove_from_manifest(name, version, nil, deps_mode) |
433 | end | 525 | end |
434 | 526 | ||
435 | --- Find full path to a file providing a module or a command | ||
436 | -- in a package. | ||
437 | -- @param name string: name of package. | ||
438 | -- @param version string: exact package version in string format. | ||
439 | -- @param item_type string: "module" or "command". | ||
440 | -- @param item_name string: module or command name. | ||
441 | -- @param root string or nil: A local root dir for a rocks tree. If not given, the default is used. | ||
442 | -- @return string: absolute path to the file providing given module | ||
443 | -- or command. | ||
444 | function repos.which(name, version, item_type, item_name, repo) | ||
445 | local deploy_type, file_path = manif.get_providing_file(name, version, item_type, item_name, repo) | ||
446 | local non_versioned, versioned = get_deploy_paths(name, version, deploy_type, file_path, repo) | ||
447 | local cur_name, cur_version = manif.get_current_provider(item_type, item_name) | ||
448 | local deploy_path = (name == cur_name and version == cur_version) and non_versioned or versioned | ||
449 | |||
450 | if deploy_type == "bin" and cfg.wrapper_suffix and cfg.wrapper_suffix ~= "" then | ||
451 | deploy_path = find_suffixed(deploy_path, cfg.wrapper_suffix) or deploy_path | ||
452 | end | ||
453 | |||
454 | return deploy_path | ||
455 | end | ||
456 | |||
457 | --- Find full path to a file providing a module or a command | ||
458 | -- in a package. | ||
459 | -- @param name string: name of package. | ||
460 | -- @param version string: exact package version in string format. | ||
461 | -- @param item_type string: "module" or "command". | ||
462 | -- @param item_name string: module or command name. | ||
463 | -- @param root string or nil: A local root dir for a rocks tree. If not given, the default is used. | ||
464 | -- @return string: absolute path to the file providing given module | ||
465 | -- or command. | ||
466 | function repos.which(name, version, item_type, item_name, repo) | ||
467 | local deploy_type, file_path = manif.get_providing_file(name, version, item_type, item_name, repo) | ||
468 | local non_versioned, versioned = get_deploy_paths(name, version, deploy_type, file_path, repo) | ||
469 | local cur_name, cur_version = manif.get_current_provider(item_type, item_name) | ||
470 | local deploy_path = (name == cur_name and version == cur_version) and non_versioned or versioned | ||
471 | |||
472 | if deploy_type == "bin" and cfg.wrapper_suffix and cfg.wrapper_suffix ~= "" then | ||
473 | deploy_path = find_suffixed(deploy_path, cfg.wrapper_suffix) or deploy_path | ||
474 | end | ||
475 | |||
476 | return deploy_path | ||
477 | end | ||
478 | |||
479 | return repos | 527 | return repos |