diff options
author | V1K1NGbg <victor@ilchev.com> | 2024-08-13 20:00:47 +0300 |
---|---|---|
committer | V1K1NGbg <victor@ilchev.com> | 2024-08-13 20:00:47 +0300 |
commit | 2ab89328bd35d20e4ef990934abf8382adc95b82 (patch) | |
tree | 7ec0bf331cfc092f38dc32a8b8608c870dd429d0 | |
parent | 9d4bebd145cbdf3185ed68ba1eb4140303eb093f (diff) | |
download | luarocks-2ab89328bd35d20e4ef990934abf8382adc95b82.tar.gz luarocks-2ab89328bd35d20e4ef990934abf8382adc95b82.tar.bz2 luarocks-2ab89328bd35d20e4ef990934abf8382adc95b82.zip |
repos
-rw-r--r-- | src/luarocks/manif.tl | 2 | ||||
-rw-r--r-- | src/luarocks/repos-original.lua | 681 | ||||
-rw-r--r-- | src/luarocks/repos.lua | 266 | ||||
-rw-r--r-- | src/luarocks/repos.tl | 24 |
4 files changed, 833 insertions, 140 deletions
diff --git a/src/luarocks/manif.tl b/src/luarocks/manif.tl index 0a329fff..6fbf3fb2 100644 --- a/src/luarocks/manif.tl +++ b/src/luarocks/manif.tl | |||
@@ -184,7 +184,7 @@ function manif.get_current_provider(item_type: string, item_name: string, repo?: | |||
184 | end | 184 | end |
185 | end | 185 | end |
186 | 186 | ||
187 | function manif.get_next_provider(item_type: string, item_name: string, repo: string | Tree): string, string | 187 | function manif.get_next_provider(item_type: string, item_name: string, repo?: string | Tree): string, string |
188 | local providers = get_providers(item_type, item_name, repo) | 188 | local providers = get_providers(item_type, item_name, repo) |
189 | if providers and providers[2] then | 189 | if providers and providers[2] then |
190 | return providers[2]:match("([^/]*)/([^/]*)") | 190 | return providers[2]:match("([^/]*)/([^/]*)") |
diff --git a/src/luarocks/repos-original.lua b/src/luarocks/repos-original.lua new file mode 100644 index 00000000..2e71b3f7 --- /dev/null +++ b/src/luarocks/repos-original.lua | |||
@@ -0,0 +1,681 @@ | |||
1 | |||
2 | --- Functions for managing the repository on disk. | ||
3 | local repos = {} | ||
4 | |||
5 | local fs = require("luarocks.fs") | ||
6 | local path = require("luarocks.path") | ||
7 | local cfg = require("luarocks.core.cfg") | ||
8 | local util = require("luarocks.util") | ||
9 | local dir = require("luarocks.dir") | ||
10 | local manif = require("luarocks.manif") | ||
11 | local vers = require("luarocks.core.vers") | ||
12 | |||
13 | local unpack = unpack or table.unpack -- luacheck: ignore 211 | ||
14 | |||
15 | -- Tree of files installed by a package are stored | ||
16 | -- in its rock manifest. Some of these files have to | ||
17 | -- be deployed to locations where Lua can load them as | ||
18 | -- modules or where they can be used as commands. | ||
19 | -- These files are characterised by pair | ||
20 | -- (deploy_type, file_path), where deploy_type is the first | ||
21 | -- component of the file path and file_path is the rest of the | ||
22 | -- path. Only files with deploy_type in {"lua", "lib", "bin"} | ||
23 | -- are deployed somewhere. | ||
24 | -- Each deployed file provides an "item". An item is | ||
25 | -- characterised by pair (item_type, item_name). | ||
26 | -- item_type is "command" for files with deploy_type | ||
27 | -- "bin" and "module" for deploy_type in {"lua", "lib"}. | ||
28 | -- item_name is same as file_path for commands | ||
29 | -- and is produced using path.path_to_module(file_path) | ||
30 | -- for modules. | ||
31 | |||
32 | --- Get all installed versions of a package. | ||
33 | -- @param name string: a package name. | ||
34 | -- @return table or nil: An array of strings listing installed | ||
35 | -- versions of a package, or nil if none is available. | ||
36 | local function get_installed_versions(name) | ||
37 | assert(type(name) == "string" and not name:match("/")) | ||
38 | |||
39 | local dirs = fs.list_dir(path.versions_dir(name)) | ||
40 | return (dirs and #dirs > 0) and dirs or nil | ||
41 | end | ||
42 | |||
43 | --- Check if a package exists in a local repository. | ||
44 | -- Version numbers are compared as exact string comparison. | ||
45 | -- @param name string: name of package | ||
46 | -- @param version string: package version in string format | ||
47 | -- @return boolean: true if a package is installed, | ||
48 | -- false otherwise. | ||
49 | function repos.is_installed(name, version) | ||
50 | assert(type(name) == "string" and not name:match("/")) | ||
51 | assert(type(version) == "string") | ||
52 | |||
53 | return fs.is_dir(path.install_dir(name, version)) | ||
54 | end | ||
55 | |||
56 | function repos.recurse_rock_manifest_entry(entry, action) | ||
57 | assert(type(action) == "function") | ||
58 | |||
59 | if entry == nil then | ||
60 | return true | ||
61 | end | ||
62 | |||
63 | local function do_recurse_rock_manifest_entry(tree, parent_path) | ||
64 | |||
65 | for file, sub in pairs(tree) do | ||
66 | local sub_path = (parent_path and (parent_path .. "/") or "") .. file | ||
67 | local ok, err -- luacheck: ignore 231 | ||
68 | |||
69 | if type(sub) == "table" then | ||
70 | ok, err = do_recurse_rock_manifest_entry(sub, sub_path) | ||
71 | else | ||
72 | ok, err = action(sub_path) | ||
73 | end | ||
74 | |||
75 | if err then return nil, err end | ||
76 | end | ||
77 | return true | ||
78 | end | ||
79 | return do_recurse_rock_manifest_entry(entry) | ||
80 | end | ||
81 | |||
82 | local function store_package_data(result, rock_manifest, deploy_type) | ||
83 | if rock_manifest[deploy_type] then | ||
84 | repos.recurse_rock_manifest_entry(rock_manifest[deploy_type], function(file_path) | ||
85 | local _, item_name = manif.get_provided_item(deploy_type, file_path) | ||
86 | result[item_name] = file_path | ||
87 | return true | ||
88 | end) | ||
89 | end | ||
90 | end | ||
91 | |||
92 | --- Obtain a table of modules within an installed package. | ||
93 | -- @param name string: The package name; for example "luasocket" | ||
94 | -- @param version string: The exact version number including revision; | ||
95 | -- for example "2.0.1-1". | ||
96 | -- @return table: A table of modules where keys are module names | ||
97 | -- and values are file paths of files providing modules | ||
98 | -- relative to "lib" or "lua" rock manifest subtree. | ||
99 | -- If no modules are found or if package name or version | ||
100 | -- are invalid, an empty table is returned. | ||
101 | function repos.package_modules(name, version) | ||
102 | assert(type(name) == "string" and not name:match("/")) | ||
103 | assert(type(version) == "string") | ||
104 | |||
105 | local result = {} | ||
106 | local rock_manifest = manif.load_rock_manifest(name, version) | ||
107 | if not rock_manifest then return result end | ||
108 | store_package_data(result, rock_manifest, "lib") | ||
109 | store_package_data(result, rock_manifest, "lua") | ||
110 | return result | ||
111 | end | ||
112 | |||
113 | --- Obtain a table of command-line scripts within an installed package. | ||
114 | -- @param name string: The package name; for example "luasocket" | ||
115 | -- @param version string: The exact version number including revision; | ||
116 | -- for example "2.0.1-1". | ||
117 | -- @return table: A table of commands where keys and values are command names | ||
118 | -- as strings - file paths of files providing commands | ||
119 | -- relative to "bin" rock manifest subtree. | ||
120 | -- If no commands are found or if package name or version | ||
121 | -- are invalid, an empty table is returned. | ||
122 | function repos.package_commands(name, version) | ||
123 | assert(type(name) == "string" and not name:match("/")) | ||
124 | assert(type(version) == "string") | ||
125 | |||
126 | local result = {} | ||
127 | local rock_manifest = manif.load_rock_manifest(name, version) | ||
128 | if not rock_manifest then return result end | ||
129 | store_package_data(result, rock_manifest, "bin") | ||
130 | return result | ||
131 | end | ||
132 | |||
133 | |||
134 | --- Check if a rock contains binary executables. | ||
135 | -- @param name string: name of an installed rock | ||
136 | -- @param version string: version of an installed rock | ||
137 | -- @return boolean: returns true if rock contains platform-specific | ||
138 | -- binary executables, or false if it is a pure-Lua rock. | ||
139 | function repos.has_binaries(name, version) | ||
140 | assert(type(name) == "string" and not name:match("/")) | ||
141 | assert(type(version) == "string") | ||
142 | |||
143 | local rock_manifest = manif.load_rock_manifest(name, version) | ||
144 | if rock_manifest and rock_manifest.bin then | ||
145 | for bin_name, md5 in pairs(rock_manifest.bin) do | ||
146 | -- TODO verify that it is the same file. If it isn't, find the actual command. | ||
147 | if fs.is_actual_binary(dir.path(cfg.deploy_bin_dir, bin_name)) then | ||
148 | return true | ||
149 | end | ||
150 | end | ||
151 | end | ||
152 | return false | ||
153 | end | ||
154 | |||
155 | function repos.run_hook(rockspec, hook_name) | ||
156 | assert(rockspec:type() == "rockspec") | ||
157 | assert(type(hook_name) == "string") | ||
158 | |||
159 | local hooks = rockspec.hooks | ||
160 | if not hooks then | ||
161 | return true | ||
162 | end | ||
163 | |||
164 | if cfg.hooks_enabled == false then | ||
165 | return nil, "This rockspec contains hooks, which are blocked by the 'hooks_enabled' setting in your LuaRocks configuration." | ||
166 | end | ||
167 | |||
168 | if not hooks.substituted_variables then | ||
169 | util.variable_substitutions(hooks, rockspec.variables) | ||
170 | hooks.substituted_variables = true | ||
171 | end | ||
172 | local hook = hooks[hook_name] | ||
173 | if hook then | ||
174 | util.printout(hook) | ||
175 | if not fs.execute(hook) then | ||
176 | return nil, "Failed running "..hook_name.." hook." | ||
177 | end | ||
178 | end | ||
179 | return true | ||
180 | end | ||
181 | |||
182 | function repos.should_wrap_bin_scripts(rockspec) | ||
183 | assert(rockspec:type() == "rockspec") | ||
184 | |||
185 | if cfg.wrap_bin_scripts ~= nil then | ||
186 | return cfg.wrap_bin_scripts | ||
187 | end | ||
188 | if rockspec.deploy and rockspec.deploy.wrap_bin_scripts == false then | ||
189 | return false | ||
190 | end | ||
191 | return true | ||
192 | end | ||
193 | |||
194 | local function find_suffixed(file, suffix) | ||
195 | local filenames = {file} | ||
196 | if suffix and suffix ~= "" then | ||
197 | table.insert(filenames, 1, file .. suffix) | ||
198 | end | ||
199 | |||
200 | for _, filename in ipairs(filenames) do | ||
201 | if fs.exists(filename) then | ||
202 | return filename | ||
203 | end | ||
204 | end | ||
205 | |||
206 | return nil, table.concat(filenames, ", ") .. " not found" | ||
207 | end | ||
208 | |||
209 | local function check_suffix(filename, suffix) | ||
210 | local suffixed_filename, err = find_suffixed(filename, suffix) | ||
211 | if not suffixed_filename then | ||
212 | return "" | ||
213 | end | ||
214 | return suffixed_filename:sub(#filename + 1) | ||
215 | end | ||
216 | |||
217 | -- Files can be deployed using versioned and non-versioned names. | ||
218 | -- Several items with same type and name can exist if they are | ||
219 | -- provided by different packages or versions. In any case | ||
220 | -- item from the newest version of lexicographically smallest package | ||
221 | -- is deployed using non-versioned name and others use versioned names. | ||
222 | |||
223 | local function get_deploy_paths(name, version, deploy_type, file_path, repo) | ||
224 | assert(type(name) == "string") | ||
225 | assert(type(version) == "string") | ||
226 | assert(type(deploy_type) == "string") | ||
227 | assert(type(file_path) == "string") | ||
228 | |||
229 | repo = repo or cfg.root_dir | ||
230 | local deploy_dir = path["deploy_" .. deploy_type .. "_dir"](repo) | ||
231 | local non_versioned = dir.path(deploy_dir, file_path) | ||
232 | local versioned = path.versioned_name(non_versioned, deploy_dir, name, version) | ||
233 | return { nv = non_versioned, v = versioned } | ||
234 | end | ||
235 | |||
236 | local function check_spot_if_available(name, version, deploy_type, file_path) | ||
237 | local item_type, item_name = manif.get_provided_item(deploy_type, file_path) | ||
238 | local cur_name, cur_version = manif.get_current_provider(item_type, item_name) | ||
239 | |||
240 | -- older versions of LuaRocks (< 3) registered "foo.init" files as "foo" | ||
241 | -- (which caused problems, so that behavior was changed). But look for that | ||
242 | -- in the manifest anyway for backward compatibility. | ||
243 | if not cur_name and deploy_type == "lua" and item_name:match("%.init$") then | ||
244 | cur_name, cur_version = manif.get_current_provider(item_type, (item_name:gsub("%.init$", ""))) | ||
245 | end | ||
246 | |||
247 | if (not cur_name) | ||
248 | or (name < cur_name) | ||
249 | or (name == cur_name and (version == cur_version | ||
250 | or vers.compare_versions(version, cur_version))) then | ||
251 | return "nv", cur_name, cur_version, item_name | ||
252 | else | ||
253 | -- Existing version has priority, deploy new version using versioned name. | ||
254 | return "v", cur_name, cur_version, item_name | ||
255 | end | ||
256 | end | ||
257 | |||
258 | local function backup_existing(should_backup, target) | ||
259 | if not should_backup then | ||
260 | fs.delete(target) | ||
261 | return | ||
262 | end | ||
263 | if fs.exists(target) then | ||
264 | local backup = target | ||
265 | repeat | ||
266 | backup = backup.."~" | ||
267 | until not fs.exists(backup) -- Slight race condition here, but shouldn't be a problem. | ||
268 | |||
269 | util.warning(target.." is not tracked by this installation of LuaRocks. Moving it to "..backup) | ||
270 | local move_ok, move_err = os.rename(target, backup) | ||
271 | if not move_ok then | ||
272 | return nil, move_err | ||
273 | end | ||
274 | return backup | ||
275 | end | ||
276 | end | ||
277 | |||
278 | local function prepare_op_install() | ||
279 | local mkdirs = {} | ||
280 | local rmdirs = {} | ||
281 | |||
282 | local function memoize_mkdir(d) | ||
283 | if mkdirs[d] then | ||
284 | return true | ||
285 | end | ||
286 | local ok, err = fs.make_dir(d) | ||
287 | if not ok then | ||
288 | return nil, err | ||
289 | end | ||
290 | mkdirs[d] = true | ||
291 | return true | ||
292 | end | ||
293 | |||
294 | local function op_install(op) | ||
295 | local ok, err = memoize_mkdir(dir.dir_name(op.dst)) | ||
296 | if not ok then | ||
297 | return nil, err | ||
298 | end | ||
299 | |||
300 | local backup, err = backup_existing(op.backup, op.dst) | ||
301 | if err then | ||
302 | return nil, err | ||
303 | end | ||
304 | if backup then | ||
305 | op.backup_file = backup | ||
306 | end | ||
307 | |||
308 | ok, err = op.fn(op.src, op.dst, op.backup) | ||
309 | if not ok then | ||
310 | return nil, err | ||
311 | end | ||
312 | |||
313 | rmdirs[dir.dir_name(op.src)] = true | ||
314 | return true | ||
315 | end | ||
316 | |||
317 | local function done_op_install() | ||
318 | for d, _ in pairs(rmdirs) do | ||
319 | fs.remove_dir_tree_if_empty(d) | ||
320 | end | ||
321 | end | ||
322 | |||
323 | return op_install, done_op_install | ||
324 | end | ||
325 | |||
326 | local function rollback_install(op) | ||
327 | fs.delete(op.dst) | ||
328 | if op.backup_file then | ||
329 | os.rename(op.backup_file, op.dst) | ||
330 | end | ||
331 | fs.remove_dir_tree_if_empty(dir.dir_name(op.dst)) | ||
332 | return true | ||
333 | end | ||
334 | |||
335 | local function op_rename(op) | ||
336 | if op.suffix then | ||
337 | local suffix = check_suffix(op.src, op.suffix) | ||
338 | op.src = op.src .. suffix | ||
339 | op.dst = op.dst .. suffix | ||
340 | end | ||
341 | |||
342 | if fs.exists(op.src) then | ||
343 | fs.make_dir(dir.dir_name(op.dst)) | ||
344 | fs.delete(op.dst) | ||
345 | local ok, err = os.rename(op.src, op.dst) | ||
346 | fs.remove_dir_tree_if_empty(dir.dir_name(op.src)) | ||
347 | return ok, err | ||
348 | else | ||
349 | return true | ||
350 | end | ||
351 | end | ||
352 | |||
353 | local function rollback_rename(op) | ||
354 | return op_rename({ src = op.dst, dst = op.src }) | ||
355 | end | ||
356 | |||
357 | local function prepare_op_delete() | ||
358 | local deletes = {} | ||
359 | local rmdirs = {} | ||
360 | |||
361 | local function done_op_delete() | ||
362 | for _, f in ipairs(deletes) do | ||
363 | os.remove(f) | ||
364 | end | ||
365 | |||
366 | for d, _ in pairs(rmdirs) do | ||
367 | fs.remove_dir_tree_if_empty(d) | ||
368 | end | ||
369 | end | ||
370 | |||
371 | local function op_delete(op) | ||
372 | if op.suffix then | ||
373 | local suffix = check_suffix(op.name, op.suffix) | ||
374 | op.name = op.name .. suffix | ||
375 | end | ||
376 | |||
377 | table.insert(deletes, op.name) | ||
378 | |||
379 | rmdirs[dir.dir_name(op.name)] = true | ||
380 | end | ||
381 | |||
382 | return op_delete, done_op_delete | ||
383 | end | ||
384 | |||
385 | local function rollback_ops(ops, op_fn, n) | ||
386 | for i = 1, n do | ||
387 | op_fn(ops[i]) | ||
388 | end | ||
389 | end | ||
390 | |||
391 | --- Double check that all files referenced in `rock_manifest` are installed in `repo`. | ||
392 | function repos.check_everything_is_installed(name, version, rock_manifest, repo, accept_versioned) | ||
393 | local missing = {} | ||
394 | local suffix = cfg.wrapper_suffix or "" | ||
395 | for _, category in ipairs({"bin", "lua", "lib"}) do | ||
396 | if rock_manifest[category] then | ||
397 | repos.recurse_rock_manifest_entry(rock_manifest[category], function(file_path) | ||
398 | local paths = get_deploy_paths(name, version, category, file_path, repo) | ||
399 | if category == "bin" then | ||
400 | if (fs.exists(paths.nv) or fs.exists(paths.nv .. suffix)) | ||
401 | or (accept_versioned and (fs.exists(paths.v) or fs.exists(paths.v .. suffix))) then | ||
402 | return | ||
403 | end | ||
404 | else | ||
405 | if fs.exists(paths.nv) or (accept_versioned and fs.exists(paths.v)) then | ||
406 | return | ||
407 | end | ||
408 | end | ||
409 | table.insert(missing, paths.nv) | ||
410 | end) | ||
411 | end | ||
412 | end | ||
413 | if #missing > 0 then | ||
414 | return nil, "failed deploying files. " .. | ||
415 | "The following files were not installed:\n" .. | ||
416 | table.concat(missing, "\n") | ||
417 | end | ||
418 | return true | ||
419 | end | ||
420 | |||
421 | --- Deploy a package from the rocks subdirectory. | ||
422 | -- @param name string: name of package | ||
423 | -- @param version string: exact package version in string format | ||
424 | -- @param wrap_bin_scripts bool: whether commands written in Lua should be wrapped. | ||
425 | -- @param deps_mode: string: Which trees to check dependencies for: | ||
426 | -- "one" for the current default tree, "all" for all trees, | ||
427 | -- "order" for all trees with priority >= the current default, "none" for no trees. | ||
428 | function repos.deploy_local_files(name, version, wrap_bin_scripts, deps_mode) | ||
429 | assert(type(name) == "string" and not name:match("/")) | ||
430 | assert(type(version) == "string") | ||
431 | assert(type(wrap_bin_scripts) == "boolean") | ||
432 | |||
433 | local rock_manifest, load_err = manif.load_rock_manifest(name, version) | ||
434 | if not rock_manifest then return nil, load_err end | ||
435 | |||
436 | local repo = cfg.root_dir | ||
437 | local renames = {} | ||
438 | local installs = {} | ||
439 | |||
440 | local function install_binary(source, target) | ||
441 | if wrap_bin_scripts and fs.is_lua(source) then | ||
442 | return fs.wrap_script(source, target, deps_mode, name, version) | ||
443 | else | ||
444 | return fs.copy_binary(source, target) | ||
445 | end | ||
446 | end | ||
447 | |||
448 | local function move_lua(source, target) | ||
449 | return fs.move(source, target, "read") | ||
450 | end | ||
451 | |||
452 | local function move_lib(source, target) | ||
453 | return fs.move(source, target, "exec") | ||
454 | end | ||
455 | |||
456 | if rock_manifest.bin then | ||
457 | local source_dir = path.bin_dir(name, version) | ||
458 | repos.recurse_rock_manifest_entry(rock_manifest.bin, function(file_path) | ||
459 | local source = dir.path(source_dir, file_path) | ||
460 | local paths = get_deploy_paths(name, version, "bin", file_path, repo) | ||
461 | local mode, cur_name, cur_version = check_spot_if_available(name, version, "bin", file_path) | ||
462 | |||
463 | if mode == "nv" and cur_name then | ||
464 | local cur_paths = get_deploy_paths(cur_name, cur_version, "bin", file_path, repo) | ||
465 | table.insert(renames, { src = cur_paths.nv, dst = cur_paths.v, suffix = cfg.wrapper_suffix }) | ||
466 | end | ||
467 | local target = mode == "nv" and paths.nv or paths.v | ||
468 | local backup = name ~= cur_name or version ~= cur_version | ||
469 | if wrap_bin_scripts and fs.is_lua(source) then | ||
470 | target = target .. (cfg.wrapper_suffix or "") | ||
471 | end | ||
472 | table.insert(installs, { fn = install_binary, src = source, dst = target, backup = backup }) | ||
473 | end) | ||
474 | end | ||
475 | |||
476 | if rock_manifest.lua then | ||
477 | local source_dir = path.lua_dir(name, version) | ||
478 | repos.recurse_rock_manifest_entry(rock_manifest.lua, function(file_path) | ||
479 | local source = dir.path(source_dir, file_path) | ||
480 | local paths = get_deploy_paths(name, version, "lua", file_path, repo) | ||
481 | local mode, cur_name, cur_version = check_spot_if_available(name, version, "lua", file_path) | ||
482 | |||
483 | if mode == "nv" and cur_name then | ||
484 | local cur_paths = get_deploy_paths(cur_name, cur_version, "lua", file_path, repo) | ||
485 | table.insert(renames, { src = cur_paths.nv, dst = cur_paths.v }) | ||
486 | cur_paths = get_deploy_paths(cur_name, cur_version, "lib", file_path:gsub("%.lua$", "." .. cfg.lib_extension), repo) | ||
487 | table.insert(renames, { src = cur_paths.nv, dst = cur_paths.v }) | ||
488 | end | ||
489 | local target = mode == "nv" and paths.nv or paths.v | ||
490 | local backup = name ~= cur_name or version ~= cur_version | ||
491 | table.insert(installs, { fn = move_lua, src = source, dst = target, backup = backup }) | ||
492 | end) | ||
493 | end | ||
494 | |||
495 | if rock_manifest.lib then | ||
496 | local source_dir = path.lib_dir(name, version) | ||
497 | repos.recurse_rock_manifest_entry(rock_manifest.lib, function(file_path) | ||
498 | local source = dir.path(source_dir, file_path) | ||
499 | local paths = get_deploy_paths(name, version, "lib", file_path, repo) | ||
500 | local mode, cur_name, cur_version = check_spot_if_available(name, version, "lib", file_path) | ||
501 | |||
502 | if mode == "nv" and cur_name then | ||
503 | local cur_paths = get_deploy_paths(cur_name, cur_version, "lua", file_path:gsub("%.[^.]+$", ".lua"), repo) | ||
504 | table.insert(renames, { src = cur_paths.nv, dst = cur_paths.v }) | ||
505 | cur_paths = get_deploy_paths(cur_name, cur_version, "lib", file_path, repo) | ||
506 | table.insert(renames, { src = cur_paths.nv, dst = cur_paths.v }) | ||
507 | end | ||
508 | local target = mode == "nv" and paths.nv or paths.v | ||
509 | local backup = name ~= cur_name or version ~= cur_version | ||
510 | table.insert(installs, { fn = move_lib, src = source, dst = target, backup = backup }) | ||
511 | end) | ||
512 | end | ||
513 | |||
514 | for i, op in ipairs(renames) do | ||
515 | local ok, err = op_rename(op) | ||
516 | if not ok then | ||
517 | rollback_ops(renames, rollback_rename, i - 1) | ||
518 | return nil, err | ||
519 | end | ||
520 | end | ||
521 | local op_install, done_op_install = prepare_op_install() | ||
522 | for i, op in ipairs(installs) do | ||
523 | local ok, err = op_install(op) | ||
524 | if not ok then | ||
525 | rollback_ops(installs, rollback_install, i - 1) | ||
526 | rollback_ops(renames, rollback_rename, #renames) | ||
527 | return nil, err | ||
528 | end | ||
529 | end | ||
530 | done_op_install() | ||
531 | |||
532 | local ok, err = repos.check_everything_is_installed(name, version, rock_manifest, repo, true) | ||
533 | if not ok then | ||
534 | return nil, err | ||
535 | end | ||
536 | |||
537 | return true | ||
538 | end | ||
539 | |||
540 | local function add_to_double_checks(double_checks, name, version) | ||
541 | double_checks[name] = double_checks[name] or {} | ||
542 | double_checks[name][version] = true | ||
543 | end | ||
544 | |||
545 | local function double_check_all(double_checks, repo) | ||
546 | local errs = {} | ||
547 | for next_name, versions in pairs(double_checks) do | ||
548 | for next_version in pairs(versions) do | ||
549 | local rock_manifest, load_err = manif.load_rock_manifest(next_name, next_version) | ||
550 | local ok, err = repos.check_everything_is_installed(next_name, next_version, rock_manifest, repo, true) | ||
551 | if not ok then | ||
552 | table.insert(errs, err) | ||
553 | end | ||
554 | end | ||
555 | end | ||
556 | if next(errs) then | ||
557 | return nil, table.concat(errs, "\n") | ||
558 | end | ||
559 | return true | ||
560 | end | ||
561 | |||
562 | --- Delete a package from the local repository. | ||
563 | -- @param name string: name of package | ||
564 | -- @param version string: exact package version in string format | ||
565 | -- @param deps_mode: string: Which trees to check dependencies for: | ||
566 | -- "one" for the current default tree, "all" for all trees, | ||
567 | -- "order" for all trees with priority >= the current default, "none" for no trees. | ||
568 | -- @param quick boolean: do not try to fix the versioned name | ||
569 | -- of another version that provides the same module that | ||
570 | -- was deleted. This is used during 'purge', as every module | ||
571 | -- will be eventually deleted. | ||
572 | function repos.delete_local_version(name, version, deps_mode, quick) | ||
573 | assert(type(name) == "string" and not name:match("/")) | ||
574 | assert(type(version) == "string") | ||
575 | assert(type(deps_mode) == "string") | ||
576 | |||
577 | local rock_manifest, load_err = manif.load_rock_manifest(name, version) | ||
578 | if not rock_manifest then | ||
579 | if not quick then | ||
580 | return nil, "rock_manifest file not found for "..name.." "..version.." - removed entry from the manifest", "remove" | ||
581 | end | ||
582 | return nil, load_err, "fail" | ||
583 | end | ||
584 | |||
585 | local repo = cfg.root_dir | ||
586 | local renames = {} | ||
587 | local deletes = {} | ||
588 | |||
589 | local double_checks = {} | ||
590 | |||
591 | if rock_manifest.bin then | ||
592 | repos.recurse_rock_manifest_entry(rock_manifest.bin, function(file_path) | ||
593 | local paths = get_deploy_paths(name, version, "bin", file_path, repo) | ||
594 | local mode, cur_name, cur_version, item_name = check_spot_if_available(name, version, "bin", file_path) | ||
595 | if mode == "v" then | ||
596 | table.insert(deletes, { name = paths.v, suffix = cfg.wrapper_suffix }) | ||
597 | else | ||
598 | table.insert(deletes, { name = paths.nv, suffix = cfg.wrapper_suffix }) | ||
599 | |||
600 | local next_name, next_version = manif.get_next_provider("command", item_name) | ||
601 | if next_name then | ||
602 | add_to_double_checks(double_checks, next_name, next_version) | ||
603 | local next_paths = get_deploy_paths(next_name, next_version, "bin", file_path, repo) | ||
604 | table.insert(renames, { src = next_paths.v, dst = next_paths.nv, suffix = cfg.wrapper_suffix }) | ||
605 | end | ||
606 | end | ||
607 | end) | ||
608 | end | ||
609 | |||
610 | if rock_manifest.lua then | ||
611 | repos.recurse_rock_manifest_entry(rock_manifest.lua, function(file_path) | ||
612 | local paths = get_deploy_paths(name, version, "lua", file_path, repo) | ||
613 | local mode, cur_name, cur_version, item_name = check_spot_if_available(name, version, "lua", file_path) | ||
614 | if mode == "v" then | ||
615 | table.insert(deletes, { name = paths.v }) | ||
616 | else | ||
617 | table.insert(deletes, { name = paths.nv }) | ||
618 | |||
619 | local next_name, next_version = manif.get_next_provider("module", item_name) | ||
620 | if next_name then | ||
621 | add_to_double_checks(double_checks, next_name, next_version) | ||
622 | local next_lua_paths = get_deploy_paths(next_name, next_version, "lua", file_path, repo) | ||
623 | table.insert(renames, { src = next_lua_paths.v, dst = next_lua_paths.nv }) | ||
624 | local next_lib_paths = get_deploy_paths(next_name, next_version, "lib", file_path:gsub("%.[^.]+$", ".lua"), repo) | ||
625 | table.insert(renames, { src = next_lib_paths.v, dst = next_lib_paths.nv }) | ||
626 | end | ||
627 | end | ||
628 | end) | ||
629 | end | ||
630 | |||
631 | if rock_manifest.lib then | ||
632 | repos.recurse_rock_manifest_entry(rock_manifest.lib, function(file_path) | ||
633 | local paths = get_deploy_paths(name, version, "lib", file_path, repo) | ||
634 | local mode, cur_name, cur_version, item_name = check_spot_if_available(name, version, "lib", file_path) | ||
635 | if mode == "v" then | ||
636 | table.insert(deletes, { name = paths.v }) | ||
637 | else | ||
638 | table.insert(deletes, { name = paths.nv }) | ||
639 | |||
640 | local next_name, next_version = manif.get_next_provider("module", item_name) | ||
641 | if next_name then | ||
642 | add_to_double_checks(double_checks, next_name, next_version) | ||
643 | local next_lua_paths = get_deploy_paths(next_name, next_version, "lua", file_path:gsub("%.[^.]+$", ".lua"), repo) | ||
644 | table.insert(renames, { src = next_lua_paths.v, dst = next_lua_paths.nv }) | ||
645 | local next_lib_paths = get_deploy_paths(next_name, next_version, "lib", file_path, repo) | ||
646 | table.insert(renames, { src = next_lib_paths.v, dst = next_lib_paths.nv }) | ||
647 | end | ||
648 | end | ||
649 | end) | ||
650 | end | ||
651 | |||
652 | local op_delete, done_op_delete = prepare_op_delete() | ||
653 | for _, op in ipairs(deletes) do | ||
654 | op_delete(op) | ||
655 | end | ||
656 | done_op_delete() | ||
657 | |||
658 | if not quick then | ||
659 | for _, op in ipairs(renames) do | ||
660 | op_rename(op) | ||
661 | end | ||
662 | |||
663 | local ok, err = double_check_all(double_checks, repo) | ||
664 | if not ok then | ||
665 | return nil, err, "fail" | ||
666 | end | ||
667 | end | ||
668 | |||
669 | fs.delete(path.install_dir(name, version)) | ||
670 | if not get_installed_versions(name) then | ||
671 | fs.delete(dir.path(cfg.rocks_dir, name)) | ||
672 | end | ||
673 | |||
674 | if quick then | ||
675 | return true, nil, "ok" | ||
676 | end | ||
677 | |||
678 | return true, nil, "remove" | ||
679 | end | ||
680 | |||
681 | return repos | ||
diff --git a/src/luarocks/repos.lua b/src/luarocks/repos.lua index 2e71b3f7..186bc1c1 100644 --- a/src/luarocks/repos.lua +++ b/src/luarocks/repos.lua | |||
@@ -1,6 +1,20 @@ | |||
1 | local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local assert = _tl_compat and _tl_compat.assert or assert; local ipairs = _tl_compat and _tl_compat.ipairs or ipairs; local os = _tl_compat and _tl_compat.os or os; local pairs = _tl_compat and _tl_compat.pairs or pairs; local string = _tl_compat and _tl_compat.string or string; local table = _tl_compat and _tl_compat.table or table | ||
2 | |||
3 | local repos = {Op = {}, Paths = {}, } | ||
4 | |||
5 | |||
6 | |||
7 | |||
8 | |||
9 | |||
10 | |||
11 | |||
12 | |||
13 | |||
14 | |||
15 | |||
16 | |||
1 | 17 | ||
2 | --- Functions for managing the repository on disk. | ||
3 | local repos = {} | ||
4 | 18 | ||
5 | local fs = require("luarocks.fs") | 19 | local fs = require("luarocks.fs") |
6 | local path = require("luarocks.path") | 20 | local path = require("luarocks.path") |
@@ -10,45 +24,55 @@ local dir = require("luarocks.dir") | |||
10 | local manif = require("luarocks.manif") | 24 | local manif = require("luarocks.manif") |
11 | local vers = require("luarocks.core.vers") | 25 | local vers = require("luarocks.core.vers") |
12 | 26 | ||
13 | local unpack = unpack or table.unpack -- luacheck: ignore 211 | 27 | |
14 | 28 | ||
15 | -- Tree of files installed by a package are stored | 29 | |
16 | -- in its rock manifest. Some of these files have to | 30 | |
17 | -- be deployed to locations where Lua can load them as | 31 | |
18 | -- modules or where they can be used as commands. | 32 | |
19 | -- These files are characterised by pair | 33 | |
20 | -- (deploy_type, file_path), where deploy_type is the first | 34 | |
21 | -- component of the file path and file_path is the rest of the | 35 | |
22 | -- path. Only files with deploy_type in {"lua", "lib", "bin"} | 36 | |
23 | -- are deployed somewhere. | 37 | |
24 | -- Each deployed file provides an "item". An item is | 38 | |
25 | -- characterised by pair (item_type, item_name). | 39 | |
26 | -- item_type is "command" for files with deploy_type | 40 | |
27 | -- "bin" and "module" for deploy_type in {"lua", "lib"}. | 41 | |
28 | -- item_name is same as file_path for commands | 42 | |
29 | -- and is produced using path.path_to_module(file_path) | 43 | |
30 | -- for modules. | 44 | |
31 | 45 | ||
32 | --- Get all installed versions of a package. | 46 | |
33 | -- @param name string: a package name. | 47 | |
34 | -- @return table or nil: An array of strings listing installed | 48 | |
35 | -- versions of a package, or nil if none is available. | 49 | |
50 | |||
51 | |||
52 | |||
53 | |||
54 | |||
55 | |||
56 | |||
57 | |||
58 | |||
59 | |||
60 | |||
36 | local function get_installed_versions(name) | 61 | local function get_installed_versions(name) |
37 | assert(type(name) == "string" and not name:match("/")) | 62 | assert(not name:match("/")) |
38 | 63 | ||
39 | local dirs = fs.list_dir(path.versions_dir(name)) | 64 | local dirs = fs.list_dir(path.versions_dir(name)) |
40 | return (dirs and #dirs > 0) and dirs or nil | 65 | return (dirs and #dirs > 0) and dirs or nil |
41 | end | 66 | end |
42 | 67 | ||
43 | --- Check if a package exists in a local repository. | 68 | |
44 | -- Version numbers are compared as exact string comparison. | 69 | |
45 | -- @param name string: name of package | 70 | |
46 | -- @param version string: package version in string format | 71 | |
47 | -- @return boolean: true if a package is installed, | 72 | |
48 | -- false otherwise. | 73 | |
49 | function repos.is_installed(name, version) | 74 | function repos.is_installed(name, version) |
50 | assert(type(name) == "string" and not name:match("/")) | 75 | assert(not name:match("/")) |
51 | assert(type(version) == "string") | ||
52 | 76 | ||
53 | return fs.is_dir(path.install_dir(name, version)) | 77 | return fs.is_dir(path.install_dir(name, version)) |
54 | end | 78 | end |
@@ -64,7 +88,7 @@ function repos.recurse_rock_manifest_entry(entry, action) | |||
64 | 88 | ||
65 | for file, sub in pairs(tree) do | 89 | for file, sub in pairs(tree) do |
66 | local sub_path = (parent_path and (parent_path .. "/") or "") .. file | 90 | local sub_path = (parent_path and (parent_path .. "/") or "") .. file |
67 | local ok, err -- luacheck: ignore 231 | 91 | local ok, err |
68 | 92 | ||
69 | if type(sub) == "table" then | 93 | if type(sub) == "table" then |
70 | ok, err = do_recurse_rock_manifest_entry(sub, sub_path) | 94 | ok, err = do_recurse_rock_manifest_entry(sub, sub_path) |
@@ -89,18 +113,17 @@ local function store_package_data(result, rock_manifest, deploy_type) | |||
89 | end | 113 | end |
90 | end | 114 | end |
91 | 115 | ||
92 | --- Obtain a table of modules within an installed package. | 116 | |
93 | -- @param name string: The package name; for example "luasocket" | 117 | |
94 | -- @param version string: The exact version number including revision; | 118 | |
95 | -- for example "2.0.1-1". | 119 | |
96 | -- @return table: A table of modules where keys are module names | 120 | |
97 | -- and values are file paths of files providing modules | 121 | |
98 | -- relative to "lib" or "lua" rock manifest subtree. | 122 | |
99 | -- If no modules are found or if package name or version | 123 | |
100 | -- are invalid, an empty table is returned. | 124 | |
101 | function repos.package_modules(name, version) | 125 | function repos.package_modules(name, version) |
102 | assert(type(name) == "string" and not name:match("/")) | 126 | assert(not name:match("/")) |
103 | assert(type(version) == "string") | ||
104 | 127 | ||
105 | local result = {} | 128 | local result = {} |
106 | local rock_manifest = manif.load_rock_manifest(name, version) | 129 | local rock_manifest = manif.load_rock_manifest(name, version) |
@@ -110,18 +133,17 @@ function repos.package_modules(name, version) | |||
110 | return result | 133 | return result |
111 | end | 134 | end |
112 | 135 | ||
113 | --- Obtain a table of command-line scripts within an installed package. | 136 | |
114 | -- @param name string: The package name; for example "luasocket" | 137 | |
115 | -- @param version string: The exact version number including revision; | 138 | |
116 | -- for example "2.0.1-1". | 139 | |
117 | -- @return table: A table of commands where keys and values are command names | 140 | |
118 | -- as strings - file paths of files providing commands | 141 | |
119 | -- relative to "bin" rock manifest subtree. | 142 | |
120 | -- If no commands are found or if package name or version | 143 | |
121 | -- are invalid, an empty table is returned. | 144 | |
122 | function repos.package_commands(name, version) | 145 | function repos.package_commands(name, version) |
123 | assert(type(name) == "string" and not name:match("/")) | 146 | assert(not name:match("/")) |
124 | assert(type(version) == "string") | ||
125 | 147 | ||
126 | local result = {} | 148 | local result = {} |
127 | local rock_manifest = manif.load_rock_manifest(name, version) | 149 | local rock_manifest = manif.load_rock_manifest(name, version) |
@@ -131,19 +153,22 @@ function repos.package_commands(name, version) | |||
131 | end | 153 | end |
132 | 154 | ||
133 | 155 | ||
134 | --- Check if a rock contains binary executables. | 156 | |
135 | -- @param name string: name of an installed rock | 157 | |
136 | -- @param version string: version of an installed rock | 158 | |
137 | -- @return boolean: returns true if rock contains platform-specific | 159 | |
138 | -- binary executables, or false if it is a pure-Lua rock. | 160 | |
139 | function repos.has_binaries(name, version) | 161 | function repos.has_binaries(name, version) |
140 | assert(type(name) == "string" and not name:match("/")) | 162 | assert(not name:match("/")) |
141 | assert(type(version) == "string") | 163 | |
164 | local entries = manif.load_rock_manifest(name, version) | ||
165 | if not entries then | ||
166 | return false | ||
167 | end | ||
168 | local bin = entries["bin"] | ||
169 | if type(bin) == "table" then | ||
170 | for bin_name, md5 in pairs(bin) do | ||
142 | 171 | ||
143 | local rock_manifest = manif.load_rock_manifest(name, version) | ||
144 | if rock_manifest and rock_manifest.bin then | ||
145 | for bin_name, md5 in pairs(rock_manifest.bin) do | ||
146 | -- TODO verify that it is the same file. If it isn't, find the actual command. | ||
147 | if fs.is_actual_binary(dir.path(cfg.deploy_bin_dir, bin_name)) then | 172 | if fs.is_actual_binary(dir.path(cfg.deploy_bin_dir, bin_name)) then |
148 | return true | 173 | return true |
149 | end | 174 | end |
@@ -153,8 +178,6 @@ function repos.has_binaries(name, version) | |||
153 | end | 178 | end |
154 | 179 | ||
155 | function repos.run_hook(rockspec, hook_name) | 180 | function repos.run_hook(rockspec, hook_name) |
156 | assert(rockspec:type() == "rockspec") | ||
157 | assert(type(hook_name) == "string") | ||
158 | 181 | ||
159 | local hooks = rockspec.hooks | 182 | local hooks = rockspec.hooks |
160 | if not hooks then | 183 | if not hooks then |
@@ -169,18 +192,17 @@ function repos.run_hook(rockspec, hook_name) | |||
169 | util.variable_substitutions(hooks, rockspec.variables) | 192 | util.variable_substitutions(hooks, rockspec.variables) |
170 | hooks.substituted_variables = true | 193 | hooks.substituted_variables = true |
171 | end | 194 | end |
172 | local hook = hooks[hook_name] | 195 | local hook = (hooks)[hook_name] |
173 | if hook then | 196 | if hook then |
174 | util.printout(hook) | 197 | util.printout(hook) |
175 | if not fs.execute(hook) then | 198 | if not fs.execute(hook) then |
176 | return nil, "Failed running "..hook_name.." hook." | 199 | return nil, "Failed running " .. hook_name .. " hook." |
177 | end | 200 | end |
178 | end | 201 | end |
179 | return true | 202 | return true |
180 | end | 203 | end |
181 | 204 | ||
182 | function repos.should_wrap_bin_scripts(rockspec) | 205 | function repos.should_wrap_bin_scripts(rockspec) |
183 | assert(rockspec:type() == "rockspec") | ||
184 | 206 | ||
185 | if cfg.wrap_bin_scripts ~= nil then | 207 | if cfg.wrap_bin_scripts ~= nil then |
186 | return cfg.wrap_bin_scripts | 208 | return cfg.wrap_bin_scripts |
@@ -192,7 +214,7 @@ function repos.should_wrap_bin_scripts(rockspec) | |||
192 | end | 214 | end |
193 | 215 | ||
194 | local function find_suffixed(file, suffix) | 216 | local function find_suffixed(file, suffix) |
195 | local filenames = {file} | 217 | local filenames = { file } |
196 | if suffix and suffix ~= "" then | 218 | if suffix and suffix ~= "" then |
197 | table.insert(filenames, 1, file .. suffix) | 219 | table.insert(filenames, 1, file .. suffix) |
198 | end | 220 | end |
@@ -214,20 +236,16 @@ local function check_suffix(filename, suffix) | |||
214 | return suffixed_filename:sub(#filename + 1) | 236 | return suffixed_filename:sub(#filename + 1) |
215 | end | 237 | end |
216 | 238 | ||
217 | -- Files can be deployed using versioned and non-versioned names. | 239 | |
218 | -- Several items with same type and name can exist if they are | 240 | |
219 | -- provided by different packages or versions. In any case | 241 | |
220 | -- item from the newest version of lexicographically smallest package | 242 | |
221 | -- is deployed using non-versioned name and others use versioned names. | 243 | |
222 | 244 | ||
223 | local function get_deploy_paths(name, version, deploy_type, file_path, repo) | 245 | local function get_deploy_paths(name, version, deploy_type, file_path, repo) |
224 | assert(type(name) == "string") | ||
225 | assert(type(version) == "string") | ||
226 | assert(type(deploy_type) == "string") | ||
227 | assert(type(file_path) == "string") | ||
228 | 246 | ||
229 | repo = repo or cfg.root_dir | 247 | repo = repo or cfg.root_dir |
230 | local deploy_dir = path["deploy_" .. deploy_type .. "_dir"](repo) | 248 | local deploy_dir = (path)["deploy_" .. deploy_type .. "_dir"](repo) |
231 | local non_versioned = dir.path(deploy_dir, file_path) | 249 | local non_versioned = dir.path(deploy_dir, file_path) |
232 | local versioned = path.versioned_name(non_versioned, deploy_dir, name, version) | 250 | local versioned = path.versioned_name(non_versioned, deploy_dir, name, version) |
233 | return { nv = non_versioned, v = versioned } | 251 | return { nv = non_versioned, v = versioned } |
@@ -237,20 +255,20 @@ local function check_spot_if_available(name, version, deploy_type, file_path) | |||
237 | local item_type, item_name = manif.get_provided_item(deploy_type, file_path) | 255 | local item_type, item_name = manif.get_provided_item(deploy_type, file_path) |
238 | local cur_name, cur_version = manif.get_current_provider(item_type, item_name) | 256 | local cur_name, cur_version = manif.get_current_provider(item_type, item_name) |
239 | 257 | ||
240 | -- older versions of LuaRocks (< 3) registered "foo.init" files as "foo" | 258 | |
241 | -- (which caused problems, so that behavior was changed). But look for that | 259 | |
242 | -- in the manifest anyway for backward compatibility. | 260 | |
243 | if not cur_name and deploy_type == "lua" and item_name:match("%.init$") then | 261 | if not cur_name and deploy_type == "lua" and item_name:match("%.init$") then |
244 | cur_name, cur_version = manif.get_current_provider(item_type, (item_name:gsub("%.init$", ""))) | 262 | cur_name, cur_version = manif.get_current_provider(item_type, (item_name:gsub("%.init$", ""))) |
245 | end | 263 | end |
246 | 264 | ||
247 | if (not cur_name) | 265 | if (not cur_name) or |
248 | or (name < cur_name) | 266 | (name < cur_name) or |
249 | or (name == cur_name and (version == cur_version | 267 | (name == cur_name and (version == cur_version or |
250 | or vers.compare_versions(version, cur_version))) then | 268 | vers.compare_versions(version, cur_version))) then |
251 | return "nv", cur_name, cur_version, item_name | 269 | return "nv", cur_name, cur_version, item_name |
252 | else | 270 | else |
253 | -- Existing version has priority, deploy new version using versioned name. | 271 | |
254 | return "v", cur_name, cur_version, item_name | 272 | return "v", cur_name, cur_version, item_name |
255 | end | 273 | end |
256 | end | 274 | end |
@@ -263,10 +281,10 @@ local function backup_existing(should_backup, target) | |||
263 | if fs.exists(target) then | 281 | if fs.exists(target) then |
264 | local backup = target | 282 | local backup = target |
265 | repeat | 283 | repeat |
266 | backup = backup.."~" | 284 | backup = backup .. "~" |
267 | until not fs.exists(backup) -- Slight race condition here, but shouldn't be a problem. | 285 | until not fs.exists(backup) |
268 | 286 | ||
269 | util.warning(target.." is not tracked by this installation of LuaRocks. Moving it to "..backup) | 287 | util.warning(target .. " is not tracked by this installation of LuaRocks. Moving it to " .. backup) |
270 | local move_ok, move_err = os.rename(target, backup) | 288 | local move_ok, move_err = os.rename(target, backup) |
271 | if not move_ok then | 289 | if not move_ok then |
272 | return nil, move_err | 290 | return nil, move_err |
@@ -388,17 +406,17 @@ local function rollback_ops(ops, op_fn, n) | |||
388 | end | 406 | end |
389 | end | 407 | end |
390 | 408 | ||
391 | --- Double check that all files referenced in `rock_manifest` are installed in `repo`. | 409 | |
392 | function repos.check_everything_is_installed(name, version, rock_manifest, repo, accept_versioned) | 410 | function repos.check_everything_is_installed(name, version, rock_manifest, repo, accept_versioned) |
393 | local missing = {} | 411 | local missing = {} |
394 | local suffix = cfg.wrapper_suffix or "" | 412 | local suffix = cfg.wrapper_suffix or "" |
395 | for _, category in ipairs({"bin", "lua", "lib"}) do | 413 | for _, category in ipairs({ "bin", "lua", "lib" }) do |
396 | if rock_manifest[category] then | 414 | if rock_manifest[category] then |
397 | repos.recurse_rock_manifest_entry(rock_manifest[category], function(file_path) | 415 | repos.recurse_rock_manifest_entry(rock_manifest[category], function(file_path) |
398 | local paths = get_deploy_paths(name, version, category, file_path, repo) | 416 | local paths = get_deploy_paths(name, version, category, file_path, repo) |
399 | if category == "bin" then | 417 | if category == "bin" then |
400 | if (fs.exists(paths.nv) or fs.exists(paths.nv .. suffix)) | 418 | if (fs.exists(paths.nv) or fs.exists(paths.nv .. suffix)) or |
401 | or (accept_versioned and (fs.exists(paths.v) or fs.exists(paths.v .. suffix))) then | 419 | (accept_versioned and (fs.exists(paths.v) or fs.exists(paths.v .. suffix))) then |
402 | return | 420 | return |
403 | end | 421 | end |
404 | else | 422 | else |
@@ -412,23 +430,21 @@ function repos.check_everything_is_installed(name, version, rock_manifest, repo, | |||
412 | end | 430 | end |
413 | if #missing > 0 then | 431 | if #missing > 0 then |
414 | return nil, "failed deploying files. " .. | 432 | return nil, "failed deploying files. " .. |
415 | "The following files were not installed:\n" .. | 433 | "The following files were not installed:\n" .. |
416 | table.concat(missing, "\n") | 434 | table.concat(missing, "\n") |
417 | end | 435 | end |
418 | return true | 436 | return true |
419 | end | 437 | end |
420 | 438 | ||
421 | --- Deploy a package from the rocks subdirectory. | 439 | |
422 | -- @param name string: name of package | 440 | |
423 | -- @param version string: exact package version in string format | 441 | |
424 | -- @param wrap_bin_scripts bool: whether commands written in Lua should be wrapped. | 442 | |
425 | -- @param deps_mode: string: Which trees to check dependencies for: | 443 | |
426 | -- "one" for the current default tree, "all" for all trees, | 444 | |
427 | -- "order" for all trees with priority >= the current default, "none" for no trees. | 445 | |
428 | function repos.deploy_local_files(name, version, wrap_bin_scripts, deps_mode) | 446 | function repos.deploy_local_files(name, version, wrap_bin_scripts, deps_mode) |
429 | assert(type(name) == "string" and not name:match("/")) | 447 | assert(not name:match("/")) |
430 | assert(type(version) == "string") | ||
431 | assert(type(wrap_bin_scripts) == "boolean") | ||
432 | 448 | ||
433 | local rock_manifest, load_err = manif.load_rock_manifest(name, version) | 449 | local rock_manifest, load_err = manif.load_rock_manifest(name, version) |
434 | if not rock_manifest then return nil, load_err end | 450 | if not rock_manifest then return nil, load_err end |
@@ -553,31 +569,29 @@ local function double_check_all(double_checks, repo) | |||
553 | end | 569 | end |
554 | end | 570 | end |
555 | end | 571 | end |
556 | if next(errs) then | 572 | if next(errs) ~= nil then |
557 | return nil, table.concat(errs, "\n") | 573 | return nil, table.concat(errs, "\n") |
558 | end | 574 | end |
559 | return true | 575 | return true |
560 | end | 576 | end |
561 | 577 | ||
562 | --- Delete a package from the local repository. | 578 | |
563 | -- @param name string: name of package | 579 | |
564 | -- @param version string: exact package version in string format | 580 | |
565 | -- @param deps_mode: string: Which trees to check dependencies for: | 581 | |
566 | -- "one" for the current default tree, "all" for all trees, | 582 | |
567 | -- "order" for all trees with priority >= the current default, "none" for no trees. | 583 | |
568 | -- @param quick boolean: do not try to fix the versioned name | 584 | |
569 | -- of another version that provides the same module that | 585 | |
570 | -- was deleted. This is used during 'purge', as every module | 586 | |
571 | -- will be eventually deleted. | 587 | |
572 | function repos.delete_local_version(name, version, deps_mode, quick) | 588 | function repos.delete_local_version(name, version, deps_mode, quick) |
573 | assert(type(name) == "string" and not name:match("/")) | 589 | assert(not name:match("/")) |
574 | assert(type(version) == "string") | ||
575 | assert(type(deps_mode) == "string") | ||
576 | 590 | ||
577 | local rock_manifest, load_err = manif.load_rock_manifest(name, version) | 591 | local rock_manifest, load_err = manif.load_rock_manifest(name, version) |
578 | if not rock_manifest then | 592 | if not rock_manifest then |
579 | if not quick then | 593 | if not quick then |
580 | return nil, "rock_manifest file not found for "..name.." "..version.." - removed entry from the manifest", "remove" | 594 | return nil, "rock_manifest file not found for " .. name .. " " .. version .. " - removed entry from the manifest", "remove" |
581 | end | 595 | end |
582 | return nil, load_err, "fail" | 596 | return nil, load_err, "fail" |
583 | end | 597 | end |
diff --git a/src/luarocks/repos.tl b/src/luarocks/repos.tl index b5e1efe8..e98ffedb 100644 --- a/src/luarocks/repos.tl +++ b/src/luarocks/repos.tl | |||
@@ -341,7 +341,7 @@ local function prepare_op_install(): function(Op): (boolean, string), function() | |||
341 | return op_install, done_op_install | 341 | return op_install, done_op_install |
342 | end | 342 | end |
343 | 343 | ||
344 | local function rollback_install(op: Op): boolean | 344 | local function rollback_install(op: Op): boolean, string |
345 | fs.delete(op.dst) | 345 | fs.delete(op.dst) |
346 | if op.backup_file then | 346 | if op.backup_file then |
347 | os.rename(op.backup_file, op.dst) | 347 | os.rename(op.backup_file, op.dst) |
@@ -553,13 +553,13 @@ function repos.deploy_local_files(name: string, version: string, wrap_bin_script | |||
553 | return true | 553 | return true |
554 | end | 554 | end |
555 | 555 | ||
556 | local function add_to_double_checks(double_checks, name, version) | 556 | local function add_to_double_checks(double_checks: {string: {string: boolean}}, name: string, version: string) |
557 | double_checks[name] = double_checks[name] or {} | 557 | double_checks[name] = double_checks[name] or {} |
558 | double_checks[name][version] = true | 558 | double_checks[name][version] = true |
559 | end | 559 | end |
560 | 560 | ||
561 | local function double_check_all(double_checks, repo) | 561 | local function double_check_all(double_checks: {string: {string: boolean}}, repo: string | Tree): boolean, string |
562 | local errs = {} | 562 | local errs: {string} = {} |
563 | for next_name, versions in pairs(double_checks) do | 563 | for next_name, versions in pairs(double_checks) do |
564 | for next_version in pairs(versions) do | 564 | for next_version in pairs(versions) do |
565 | local rock_manifest, load_err = manif.load_rock_manifest(next_name, next_version) | 565 | local rock_manifest, load_err = manif.load_rock_manifest(next_name, next_version) |
@@ -569,7 +569,7 @@ local function double_check_all(double_checks, repo) | |||
569 | end | 569 | end |
570 | end | 570 | end |
571 | end | 571 | end |
572 | if next(errs) then | 572 | if next(errs) ~= nil then |
573 | return nil, table.concat(errs, "\n") | 573 | return nil, table.concat(errs, "\n") |
574 | end | 574 | end |
575 | return true | 575 | return true |
@@ -585,10 +585,8 @@ end | |||
585 | -- of another version that provides the same module that | 585 | -- of another version that provides the same module that |
586 | -- was deleted. This is used during 'purge', as every module | 586 | -- was deleted. This is used during 'purge', as every module |
587 | -- will be eventually deleted. | 587 | -- will be eventually deleted. |
588 | function repos.delete_local_version(name, version, deps_mode, quick) | 588 | function repos.delete_local_version(name: string, version: string, deps_mode: string, quick: boolean): boolean, string, string |
589 | assert(type(name) == "string" and not name:match("/")) | 589 | assert(not name:match("/")) |
590 | assert(type(version) == "string") | ||
591 | assert(type(deps_mode) == "string") | ||
592 | 590 | ||
593 | local rock_manifest, load_err = manif.load_rock_manifest(name, version) | 591 | local rock_manifest, load_err = manif.load_rock_manifest(name, version) |
594 | if not rock_manifest then | 592 | if not rock_manifest then |
@@ -605,7 +603,7 @@ function repos.delete_local_version(name, version, deps_mode, quick) | |||
605 | local double_checks = {} | 603 | local double_checks = {} |
606 | 604 | ||
607 | if rock_manifest.bin then | 605 | if rock_manifest.bin then |
608 | repos.recurse_rock_manifest_entry(rock_manifest.bin, function(file_path) | 606 | repos.recurse_rock_manifest_entry(rock_manifest.bin, function(file_path: string): boolean, string |
609 | local paths = get_deploy_paths(name, version, "bin", file_path, repo) | 607 | local paths = get_deploy_paths(name, version, "bin", file_path, repo) |
610 | local mode, cur_name, cur_version, item_name = check_spot_if_available(name, version, "bin", file_path) | 608 | local mode, cur_name, cur_version, item_name = check_spot_if_available(name, version, "bin", file_path) |
611 | if mode == "v" then | 609 | if mode == "v" then |
@@ -624,7 +622,7 @@ function repos.delete_local_version(name, version, deps_mode, quick) | |||
624 | end | 622 | end |
625 | 623 | ||
626 | if rock_manifest.lua then | 624 | if rock_manifest.lua then |
627 | repos.recurse_rock_manifest_entry(rock_manifest.lua, function(file_path) | 625 | repos.recurse_rock_manifest_entry(rock_manifest.lua, function(file_path: string): boolean, string |
628 | local paths = get_deploy_paths(name, version, "lua", file_path, repo) | 626 | local paths = get_deploy_paths(name, version, "lua", file_path, repo) |
629 | local mode, cur_name, cur_version, item_name = check_spot_if_available(name, version, "lua", file_path) | 627 | local mode, cur_name, cur_version, item_name = check_spot_if_available(name, version, "lua", file_path) |
630 | if mode == "v" then | 628 | if mode == "v" then |
@@ -645,7 +643,7 @@ function repos.delete_local_version(name, version, deps_mode, quick) | |||
645 | end | 643 | end |
646 | 644 | ||
647 | if rock_manifest.lib then | 645 | if rock_manifest.lib then |
648 | repos.recurse_rock_manifest_entry(rock_manifest.lib, function(file_path) | 646 | repos.recurse_rock_manifest_entry(rock_manifest.lib, function(file_path: string): boolean, string |
649 | local paths = get_deploy_paths(name, version, "lib", file_path, repo) | 647 | local paths = get_deploy_paths(name, version, "lib", file_path, repo) |
650 | local mode, cur_name, cur_version, item_name = check_spot_if_available(name, version, "lib", file_path) | 648 | local mode, cur_name, cur_version, item_name = check_spot_if_available(name, version, "lib", file_path) |
651 | if mode == "v" then | 649 | if mode == "v" then |
@@ -694,4 +692,4 @@ function repos.delete_local_version(name, version, deps_mode, quick) | |||
694 | return true, nil, "remove" | 692 | return true, nil, "remove" |
695 | end | 693 | end |
696 | 694 | ||
697 | return rep \ No newline at end of file | 695 | return repos \ No newline at end of file |