aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/luarocks/manif/writer.tl (renamed from src/luarocks/manif/writer.lua)157
1 files changed, 59 insertions, 98 deletions
diff --git a/src/luarocks/manif/writer.lua b/src/luarocks/manif/writer.tl
index 36f5f57f..b333c36f 100644
--- a/src/luarocks/manif/writer.lua
+++ b/src/luarocks/manif/writer.tl
@@ -1,5 +1,6 @@
1 1
2local writer = {} 2local record writer
3end
3 4
4local cfg = require("luarocks.core.cfg") 5local cfg = require("luarocks.core.cfg")
5local search = require("luarocks.search") 6local search = require("luarocks.search")
@@ -15,6 +16,17 @@ local persist = require("luarocks.persist")
15local manif = require("luarocks.manif") 16local manif = require("luarocks.manif")
16local queries = require("luarocks.queries") 17local queries = require("luarocks.queries")
17 18
19local type Manifest = require("luarocks.core.types.manifest").Manifest
20
21local type Rockspec = require("luarocks.core.types.rockspec").Rockspec
22
23local type Result = require("luarocks.core.types.result").Result
24
25local type PersistableTable = require("luarocks.core.types.persist").PersistableTable
26
27local type RockManifest = require("luarocks.core.types.rockmanifest").RockManifest
28local type Entry = require("luarocks.core.types.rockmanifest").RockManifest.Entry
29
18--- Update storage table to account for items provided by a package. 30--- Update storage table to account for items provided by a package.
19-- @param storage table: a table storing items in the following format: 31-- @param storage table: a table storing items in the following format:
20-- keys are item names and values are arrays of packages providing each item, 32-- keys are item names and values are arrays of packages providing each item,
@@ -22,15 +34,12 @@ local queries = require("luarocks.queries")
22-- @param items table: a table mapping item names to paths. 34-- @param items table: a table mapping item names to paths.
23-- @param name string: package name. 35-- @param name string: package name.
24-- @param version string: package version. 36-- @param version string: package version.
25local function store_package_items(storage, name, version, items) 37local function store_package_items(storage: {string: {string}}, name: string, version: string, items: {string: string})
26 assert(type(storage) == "table") 38 assert(not name:match("/"))
27 assert(type(items) == "table")
28 assert(type(name) == "string" and not name:match("/"))
29 assert(type(version) == "string")
30 39
31 local package_identifier = name.."/"..version 40 local package_identifier = name.."/"..version
32 41
33 for item_name, path in pairs(items) do -- luacheck: ignore 431 42 for item_name, _ in pairs(items) do -- luacheck: ignore 431
34 if not storage[item_name] then 43 if not storage[item_name] then
35 storage[item_name] = {} 44 storage[item_name] = {}
36 end 45 end
@@ -46,15 +55,12 @@ end
46-- @param items table: a table mapping item names to paths. 55-- @param items table: a table mapping item names to paths.
47-- @param name string: package name. 56-- @param name string: package name.
48-- @param version string: package version. 57-- @param version string: package version.
49local function remove_package_items(storage, name, version, items) 58local function remove_package_items(storage: {string: {string}}, name: string, version: string, items: {string: string})
50 assert(type(storage) == "table") 59 assert(not name:match("/"))
51 assert(type(items) == "table")
52 assert(type(name) == "string" and not name:match("/"))
53 assert(type(version) == "string")
54 60
55 local package_identifier = name.."/"..version 61 local package_identifier = name.."/"..version
56 62
57 for item_name, path in pairs(items) do -- luacheck: ignore 431 63 for item_name, _path in pairs(items) do
58 local key = item_name 64 local key = item_name
59 local all_identifiers = storage[key] 65 local all_identifiers = storage[key]
60 if not all_identifiers then 66 if not all_identifiers then
@@ -87,9 +93,7 @@ end
87-- @param deps_mode string: Dependency mode: "one" for the current default tree, 93-- @param deps_mode string: Dependency mode: "one" for the current default tree,
88-- "all" for all trees, "order" for all trees with priority >= the current default, 94-- "all" for all trees, "order" for all trees with priority >= the current default,
89-- "none" for no trees. 95-- "none" for no trees.
90local function update_dependencies(manifest, deps_mode) 96local function update_dependencies(manifest: Manifest, deps_mode: string)
91 assert(type(manifest) == "table")
92 assert(type(deps_mode) == "string")
93 97
94 if not manifest.dependencies then manifest.dependencies = {} end 98 if not manifest.dependencies then manifest.dependencies = {} end
95 local mdeps = manifest.dependencies 99 local mdeps = manifest.dependencies
@@ -117,10 +121,7 @@ end
117-- @param b string: Version to compare. 121-- @param b string: Version to compare.
118-- @return boolean: The comparison result, according to the 122-- @return boolean: The comparison result, according to the
119-- rule outlined above. 123-- rule outlined above.
120local function sort_pkgs(a, b) 124local function sort_pkgs(a: string, b: string): boolean
121 assert(type(a) == "string")
122 assert(type(b) == "string")
123
124 local na, va = a:match("(.*)/(.*)$") 125 local na, va = a:match("(.*)/(.*)$")
125 local nb, vb = b:match("(.*)/(.*)$") 126 local nb, vb = b:match("(.*)/(.*)$")
126 127
@@ -130,15 +131,14 @@ end
130--- Sort items of a package matching table by version number (higher versions first). 131--- Sort items of a package matching table by version number (higher versions first).
131-- @param tbl table: the package matching table: keys should be strings 132-- @param tbl table: the package matching table: keys should be strings
132-- and values arrays of strings with packages names in "name/version" format. 133-- and values arrays of strings with packages names in "name/version" format.
133local function sort_package_matching_table(tbl) 134local function sort_package_matching_table(tbl: {string: {string}})
134 assert(type(tbl) == "table")
135 135
136 if next(tbl) then 136 if next(tbl) then
137 for item, pkgs in pairs(tbl) do 137 for item, pkgs in pairs(tbl) do
138 if #pkgs > 1 then 138 if #pkgs > 1 then
139 table.sort(pkgs, sort_pkgs) 139 table.sort(pkgs, sort_pkgs)
140 -- Remove duplicates from the sorted array. 140 -- Remove duplicates from the sorted array.
141 local prev = nil 141 local prev: string = nil
142 local i = 1 142 local i = 1
143 while pkgs[i] do 143 while pkgs[i] do
144 local curr = pkgs[i] 144 local curr = pkgs[i]
@@ -160,26 +160,24 @@ end
160-- @param lua_version string or nil: filter by Lua version 160-- @param lua_version string or nil: filter by Lua version
161-- @param repodir string: directory of repository being scanned 161-- @param repodir string: directory of repository being scanned
162-- @param cache table: temporary rockspec cache table 162-- @param cache table: temporary rockspec cache table
163local function filter_by_lua_version(manifest, lua_version, repodir, cache) 163local function filter_by_lua_version(manifest: Manifest, lua_version_str: string, repodir: string, cache: {string: Rockspec})
164 assert(type(manifest) == "table")
165 assert(type(repodir) == "string")
166 assert((not cache) or type(cache) == "table")
167 164
168 cache = cache or {} 165 cache = cache or {}
169 lua_version = vers.parse_version(lua_version) 166 local lua_version = vers.parse_version(lua_version_str)
170 for pkg, versions in pairs(manifest.repository) do 167 for pkg, versions in pairs(manifest.repository) do
171 local to_remove = {} 168 local to_remove: {string} = {}
172 for version, repositories in pairs(versions) do 169 for version, repositories in pairs(versions) do
173 for _, repo in ipairs(repositories) do 170 for _, repo in ipairs(repositories) do
174 if repo.arch == "rockspec" then 171 if repo.arch == "rockspec" then
175 local pathname = dir.path(repodir, pkg.."-"..version..".rockspec") 172 local pathname = dir.path(repodir, pkg.."-"..version..".rockspec")
176 local rockspec, err = cache[pathname] 173 local rockspec = cache[pathname]
174 local err: string
177 if not rockspec then 175 if not rockspec then
178 rockspec, err = fetch.load_local_rockspec(pathname, true) 176 rockspec, err = fetch.load_local_rockspec(pathname, true)
179 end 177 end
180 if rockspec then 178 if rockspec then
181 cache[pathname] = rockspec 179 cache[pathname] = rockspec
182 for _, dep in ipairs(rockspec.dependencies) do 180 for _, dep in ipairs(rockspec.dependencies.queries) do
183 if dep.name == "lua" then 181 if dep.name == "lua" then
184 if not vers.match_constraints(lua_version, dep.constraints) then 182 if not vers.match_constraints(lua_version, dep.constraints) then
185 table.insert(to_remove, version) 183 table.insert(to_remove, version)
@@ -209,16 +207,14 @@ end
209-- @param manifest table: A manifest table (must contain repository, modules, commands tables). 207-- @param manifest table: A manifest table (must contain repository, modules, commands tables).
210-- It will be altered to include the search results. 208-- It will be altered to include the search results.
211-- @return boolean or (nil, string): true in case of success, or nil followed by an error message. 209-- @return boolean or (nil, string): true in case of success, or nil followed by an error message.
212local function store_results(results, manifest) 210local function store_results(results: {string: {string: {Result}}}, manifest: Manifest): boolean, string
213 assert(type(results) == "table")
214 assert(type(manifest) == "table")
215 211
216 for name, versions in pairs(results) do 212 for name, versions in pairs(results) do
217 local pkgtable = manifest.repository[name] or {} 213 local pkgtable = manifest.repository[name] or {}
218 for version, entries in pairs(versions) do 214 for version, entries in pairs(versions) do
219 local versiontable = {} 215 local versiontable = {}
220 for _, entry in ipairs(entries) do 216 for _, entry in ipairs(entries) do
221 local entrytable = {} 217 local entrytable: Manifest.Entry = {}
222 entrytable.arch = entry.arch 218 entrytable.arch = entry.arch
223 if entry.arch == "installed" then 219 if entry.arch == "installed" then
224 local rock_manifest, err = manif.load_rock_manifest(name, version) 220 local rock_manifest, err = manif.load_rock_manifest(name, version)
@@ -246,10 +242,8 @@ end
246-- @param tbl table: The table to be saved. 242-- @param tbl table: The table to be saved.
247-- @return boolean or (nil, string): true if successful, or nil and a 243-- @return boolean or (nil, string): true if successful, or nil and a
248-- message in case of errors. 244-- message in case of errors.
249local function save_table(where, name, tbl) 245local function save_table(where: string, name: string, tbl: PersistableTable): boolean, string
250 assert(type(where) == "string") 246 assert(not name:match("/"))
251 assert(type(name) == "string" and not name:match("/"))
252 assert(type(tbl) == "table")
253 247
254 local filename = dir.path(where, name) 248 local filename = dir.path(where, name)
255 local ok, err = persist.save_from_table(filename..".tmp", tbl) 249 local ok, err = persist.save_from_table(filename..".tmp", tbl)
@@ -259,25 +253,28 @@ local function save_table(where, name, tbl)
259 return ok, err 253 return ok, err
260end 254end
261 255
262function writer.make_rock_manifest(name, version) 256function writer.make_rock_manifest(name: string, version: string): boolean, string
263 local install_dir = path.install_dir(name, version) 257 local install_dir = path.install_dir(name, version)
264 local tree = {} 258 local tree: {string: Entry} = {}
265 for _, file in ipairs(fs.find(install_dir)) do 259 for _, file in ipairs(fs.find(install_dir)) do
266 local full_path = dir.path(install_dir, file) 260 local full_path = dir.path(install_dir, file)
267 local walk = tree 261 local walk = tree
268 local last 262 local last: {string : Entry}
269 local last_name 263 local last_name: string
264 local next: Entry
270 for filename in file:gmatch("[^\\/]+") do 265 for filename in file:gmatch("[^\\/]+") do
271 local next = walk[filename] 266 next = walk[filename]
272 if not next then 267 if not next then
273 next = {} 268 next = {}
274 walk[filename] = next 269 walk[filename] = next
275 end 270 end
276 last = walk 271 last = walk
277 last_name = filename 272 last_name = filename
273 assert(next is {string: Entry})
278 walk = next 274 walk = next
279 end 275 end
280 if fs.is_file(full_path) then 276 if fs.is_file(full_path) then
277
281 local sum, err = fs.get_md5(full_path) 278 local sum, err = fs.get_md5(full_path)
282 if not sum then 279 if not sum then
283 return nil, "Failed producing checksum: "..tostring(err) 280 return nil, "Failed producing checksum: "..tostring(err)
@@ -285,9 +282,9 @@ function writer.make_rock_manifest(name, version)
285 last[last_name] = sum 282 last[last_name] = sum
286 end 283 end
287 end 284 end
288 local rock_manifest = { rock_manifest=tree } 285 local rock_manifest: RockManifest = { rock_manifest=tree }
289 manif.rock_manifest_cache[name.."/"..version] = rock_manifest 286 manif.rock_manifest_cache[name.."/"..version] = rock_manifest
290 save_table(install_dir, "rock_manifest", rock_manifest ) 287 save_table(install_dir, "rock_manifest", rock_manifest as PersistableTable)
291 return true 288 return true
292end 289end
293 290
@@ -297,10 +294,8 @@ end
297-- @param namespace string?: the namespace 294-- @param namespace string?: the namespace
298-- @return true if successful (or unnecessary, if there is no namespace), 295-- @return true if successful (or unnecessary, if there is no namespace),
299-- or nil and an error message. 296-- or nil and an error message.
300function writer.make_namespace_file(name, version, namespace) 297function writer.make_namespace_file(name: string, version: string, namespace?: string): boolean, string
301 assert(type(name) == "string" and not name:match("/")) 298 assert(not name:match("/"))
302 assert(type(version) == "string")
303 assert(type(namespace) == "string" or not namespace)
304 if not namespace then 299 if not namespace then
305 return true 300 return true
306 end 301 end
@@ -326,9 +321,7 @@ end
326-- @param remote boolean: 'true' if making a manifest for a rocks server. 321-- @param remote boolean: 'true' if making a manifest for a rocks server.
327-- @return boolean or (nil, string): True if manifest was generated, 322-- @return boolean or (nil, string): True if manifest was generated,
328-- or nil and an error message. 323-- or nil and an error message.
329function writer.make_manifest(repo, deps_mode, remote) 324function writer.make_manifest(repo: string, deps_mode: string, remote?: boolean): boolean, string
330 assert(type(repo) == "string")
331 assert(type(deps_mode) == "string")
332 325
333 if deps_mode == "none" then deps_mode = cfg.deps_mode end 326 if deps_mode == "none" then deps_mode = cfg.deps_mode end
334 327
@@ -349,10 +342,10 @@ function writer.make_manifest(repo, deps_mode, remote)
349 local cache = {} 342 local cache = {}
350 for luaver in util.lua_versions() do 343 for luaver in util.lua_versions() do
351 local vmanifest = { repository = {}, modules = {}, commands = {} } 344 local vmanifest = { repository = {}, modules = {}, commands = {} }
352 local ok, err = store_results(results, vmanifest) 345 ok, err = store_results(results, vmanifest)
353 filter_by_lua_version(vmanifest, luaver, repo, cache) 346 filter_by_lua_version(vmanifest, luaver, repo, cache)
354 if not cfg.no_manifest then 347 if not cfg.no_manifest then
355 save_table(repo, "manifest-"..luaver, vmanifest) 348 save_table(repo, "manifest-"..luaver, vmanifest as PersistableTable)
356 end 349 end
357 end 350 end
358 else 351 else
@@ -363,7 +356,7 @@ function writer.make_manifest(repo, deps_mode, remote)
363 -- We want to have cache updated; but exit before save_table is called 356 -- We want to have cache updated; but exit before save_table is called
364 return true 357 return true
365 end 358 end
366 return save_table(repo, "manifest", manifest) 359 return save_table(repo, "manifest", manifest as PersistableTable)
367end 360end
368 361
369--- Update manifest file for a local repository 362--- Update manifest file for a local repository
@@ -377,11 +370,9 @@ end
377-- "none" for using the default dependency mode from the configuration. 370-- "none" for using the default dependency mode from the configuration.
378-- @return boolean or (nil, string): True if manifest was updated successfully, 371-- @return boolean or (nil, string): True if manifest was updated successfully,
379-- or nil and an error message. 372-- or nil and an error message.
380function writer.add_to_manifest(name, version, repo, deps_mode) 373function writer.add_to_manifest(name: string, version: string, repo: string, deps_mode: string): boolean, string
381 assert(type(name) == "string" and not name:match("/")) 374 assert(not name:match("/"))
382 assert(type(version) == "string")
383 local rocks_dir = path.rocks_dir(repo or cfg.root_dir) 375 local rocks_dir = path.rocks_dir(repo or cfg.root_dir)
384 assert(type(deps_mode) == "string")
385 376
386 if deps_mode == "none" then deps_mode = cfg.deps_mode end 377 if deps_mode == "none" then deps_mode = cfg.deps_mode end
387 378
@@ -394,9 +385,10 @@ function writer.add_to_manifest(name, version, repo, deps_mode)
394 return writer.make_manifest(rocks_dir, deps_mode) 385 return writer.make_manifest(rocks_dir, deps_mode)
395 end 386 end
396 387
397 local results = {[name] = {[version] = {{arch = "installed", repo = rocks_dir}}}} 388 local results: {string : {string : {Result}}} = {[name] = {[version] = {{arch = "installed", repo = rocks_dir}}}}
398 389
399 local ok, err = store_results(results, manifest) 390 local ok: boolean
391 ok, err = store_results(results, manifest) --!
400 if not ok then return nil, err end 392 if not ok then return nil, err end
401 393
402 update_dependencies(manifest, deps_mode) 394 update_dependencies(manifest, deps_mode)
@@ -404,7 +396,7 @@ function writer.add_to_manifest(name, version, repo, deps_mode)
404 if cfg.no_manifest then 396 if cfg.no_manifest then
405 return true 397 return true
406 end 398 end
407 return save_table(rocks_dir, "manifest", manifest) 399 return save_table(rocks_dir, "manifest", manifest as PersistableTable)
408end 400end
409 401
410--- Update manifest file for a local repository 402--- Update manifest file for a local repository
@@ -418,11 +410,9 @@ end
418-- "none" for using the default dependency mode from the configuration. 410-- "none" for using the default dependency mode from the configuration.
419-- @return boolean or (nil, string): True if manifest was updated successfully, 411-- @return boolean or (nil, string): True if manifest was updated successfully,
420-- or nil and an error message. 412-- or nil and an error message.
421function writer.remove_from_manifest(name, version, repo, deps_mode) 413function writer.remove_from_manifest(name: string, version: string, repo: string, deps_mode: string): boolean, string
422 assert(type(name) == "string" and not name:match("/")) 414 assert(not name:match("/"))
423 assert(type(version) == "string")
424 local rocks_dir = path.rocks_dir(repo or cfg.root_dir) 415 local rocks_dir = path.rocks_dir(repo or cfg.root_dir)
425 assert(type(deps_mode) == "string")
426 416
427 if deps_mode == "none" then deps_mode = cfg.deps_mode end 417 if deps_mode == "none" then deps_mode = cfg.deps_mode end
428 418
@@ -446,7 +436,7 @@ function writer.remove_from_manifest(name, version, repo, deps_mode)
446 return writer.make_manifest(rocks_dir, deps_mode) 436 return writer.make_manifest(rocks_dir, deps_mode)
447 end 437 end
448 438
449 remove_package_items(manifest.modules, name, version, version_entry.modules) 439 remove_package_items(manifest.modules, name, version, version_entry.modules) --!
450 remove_package_items(manifest.commands, name, version, version_entry.commands) 440 remove_package_items(manifest.commands, name, version, version_entry.commands)
451 441
452 package_entry[version] = nil 442 package_entry[version] = nil
@@ -463,36 +453,7 @@ function writer.remove_from_manifest(name, version, repo, deps_mode)
463 if cfg.no_manifest then 453 if cfg.no_manifest then
464 return true 454 return true
465 end 455 end
466 return save_table(rocks_dir, "manifest", manifest) 456 return save_table(rocks_dir, "manifest", manifest as PersistableTable)
467end
468
469--- Report missing dependencies for all rocks installed in a repository.
470-- @param repo string or nil: Pathname of a local repository. If not given,
471-- the default local repository is used.
472-- @param deps_mode string: Dependency mode: "one" for the current default tree,
473-- "all" for all trees, "order" for all trees with priority >= the current default,
474-- "none" for using the default dependency mode from the configuration.
475function writer.check_dependencies(repo, deps_mode)
476 local rocks_dir = path.rocks_dir(repo or cfg.root_dir)
477 assert(type(deps_mode) == "string")
478 if deps_mode == "none" then deps_mode = cfg.deps_mode end
479
480 local manifest = manif.load_manifest(rocks_dir)
481 if not manifest then
482 return
483 end
484
485 for name, versions in util.sortedpairs(manifest.repository) do
486 for version, version_entries in util.sortedpairs(versions, vers.compare_versions) do
487 for _, entry in ipairs(version_entries) do
488 if entry.arch == "installed" then
489 if manifest.dependencies[name] and manifest.dependencies[name][version] then
490 deps.report_missing_dependencies(name, version, manifest.dependencies[name][version], deps_mode, util.get_rocks_provided())
491 end
492 end
493 end
494 end
495 end
496end 457end
497 458
498return writer 459return writer