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 |
