aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorV1K1NGbg <victor@ilchev.com>2024-08-06 15:13:11 +0300
committerV1K1NGbg <victor@ilchev.com>2024-08-06 15:13:11 +0300
commita7c441464aa0ff24900a1cedd455a4cc1c678b50 (patch)
tree840443fb8ff67311e0c4043026f7b5b816d05a1a
parent4e40d895c233a90ca5cf7676375f17cb827f250a (diff)
downloadluarocks-a7c441464aa0ff24900a1cedd455a4cc1c678b50.tar.gz
luarocks-a7c441464aa0ff24900a1cedd455a4cc1c678b50.tar.bz2
luarocks-a7c441464aa0ff24900a1cedd455a4cc1c678b50.zip
deps fetch and search
-rw-r--r--src/luarocks/config.tl3
-rw-r--r--src/luarocks/core/cfg.d.tl4
-rw-r--r--src/luarocks/core/types/ordering.d.tl2
-rw-r--r--src/luarocks/core/types/persist.d.tl4
-rw-r--r--src/luarocks/core/types/result.d.tl16
-rw-r--r--src/luarocks/deplocks.tl3
-rw-r--r--src/luarocks/deps.lua2
-rw-r--r--src/luarocks/deps.tl43
-rw-r--r--src/luarocks/fetch.tl8
-rw-r--r--src/luarocks/persist.tl22
-rw-r--r--src/luarocks/remove.lua2
-rw-r--r--src/luarocks/results.tl22
-rw-r--r--src/luarocks/search-original.lua393
-rw-r--r--src/luarocks/search.lua233
-rw-r--r--src/luarocks/search.tl399
-rw-r--r--src/luarocks/util.tl8
16 files changed, 985 insertions, 179 deletions
diff --git a/src/luarocks/config.tl b/src/luarocks/config.tl
index 93347453..7e589fce 100644
--- a/src/luarocks/config.tl
+++ b/src/luarocks/config.tl
@@ -10,7 +10,8 @@ local cfg_skip: {string: boolean} = {
10 upload_servers = true, 10 upload_servers = true,
11} 11}
12 12
13local type PersistableTable = persist.PersistableTable 13local type p = require("luarocks.core.types.persist")
14local type PersistableTable = p.PersistableTable
14 15
15function config.should_skip(k: string, v: any): boolean 16function config.should_skip(k: string, v: any): boolean
16 return v is function or cfg_skip[k] 17 return v is function or cfg_skip[k]
diff --git a/src/luarocks/core/cfg.d.tl b/src/luarocks/core/cfg.d.tl
index b8501924..6d993a52 100644
--- a/src/luarocks/core/cfg.d.tl
+++ b/src/luarocks/core/cfg.d.tl
@@ -60,7 +60,9 @@ local record cfg
60 -- rockspecs 60 -- rockspecs
61 each_platform: function(?string): (function():string) 61 each_platform: function(?string): (function():string)
62 -- fetch 62 -- fetch
63 rocks_servers: {{string}} 63 rocks_servers: {{string} | string}
64 -- search
65 disabled_servers: {string: boolean}
64end 66end
65 67
66return cfg \ No newline at end of file 68return cfg \ No newline at end of file
diff --git a/src/luarocks/core/types/ordering.d.tl b/src/luarocks/core/types/ordering.d.tl
index c16140f8..653e267f 100644
--- a/src/luarocks/core/types/ordering.d.tl
+++ b/src/luarocks/core/types/ordering.d.tl
@@ -1,6 +1,6 @@
1local record ordering 1local record ordering
2 record Ordering<K> 2 record Ordering<K>
3 is {K} 3 {K}
4 sub_orders: {K: Ordering<K>} 4 sub_orders: {K: Ordering<K>}
5 end 5 end
6 6
diff --git a/src/luarocks/core/types/persist.d.tl b/src/luarocks/core/types/persist.d.tl
new file mode 100644
index 00000000..259461de
--- /dev/null
+++ b/src/luarocks/core/types/persist.d.tl
@@ -0,0 +1,4 @@
1local record persist
2 type PersistableTable = { string | number : string | number | boolean | PersistableTable }
3end
4return persist \ No newline at end of file
diff --git a/src/luarocks/core/types/result.d.tl b/src/luarocks/core/types/result.d.tl
new file mode 100644
index 00000000..a23339d4
--- /dev/null
+++ b/src/luarocks/core/types/result.d.tl
@@ -0,0 +1,16 @@
1local type q = require("luarocks.core.types.query")
2local type Query = q.Query
3
4local record result
5 record Result
6 name: string
7 version: string
8 namespace: string
9 arch: string
10 repo: string
11 type: function(): string
12 satisfies: function(Result, Query): boolean
13 end
14end
15
16return result \ No newline at end of file
diff --git a/src/luarocks/deplocks.tl b/src/luarocks/deplocks.tl
index 693dd04b..d9d176f1 100644
--- a/src/luarocks/deplocks.tl
+++ b/src/luarocks/deplocks.tl
@@ -5,7 +5,8 @@ local dir = require("luarocks.dir")
5local util = require("luarocks.util") 5local util = require("luarocks.util")
6local persist = require("luarocks.persist") 6local persist = require("luarocks.persist")
7 7
8local type PersistableTable = persist.PersistableTable 8local type p = require("luarocks.core.types.persist")
9local type PersistableTable = p.PersistableTable
9 10
10local deptable: PersistableTable = {} 11local deptable: PersistableTable = {}
11local deptable_mode = "start" 12local deptable_mode = "start"
diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua
index 344991f6..1a9eefde 100644
--- a/src/luarocks/deps.lua
+++ b/src/luarocks/deps.lua
@@ -142,7 +142,7 @@ end
142-- parsed as tables; and a table of "no-upgrade" missing dependencies 142-- parsed as tables; and a table of "no-upgrade" missing dependencies
143-- (to be used in plugin modules so that a plugin does not force upgrade of 143-- (to be used in plugin modules so that a plugin does not force upgrade of
144-- its parent application). 144-- its parent application).
145function deps.match_deps(dependencies, rocks_provided, skip_set, deps_mode) 145function deps.match_deps(dependencies, rocks_provided, deps_mode, skip_set)
146 assert(type(dependencies) == "table") 146 assert(type(dependencies) == "table")
147 assert(type(rocks_provided) == "table") 147 assert(type(rocks_provided) == "table")
148 assert(type(skip_set) == "table" or skip_set == nil) 148 assert(type(skip_set) == "table" or skip_set == nil)
diff --git a/src/luarocks/deps.tl b/src/luarocks/deps.tl
index 104be1b9..53b2d088 100644
--- a/src/luarocks/deps.tl
+++ b/src/luarocks/deps.tl
@@ -25,6 +25,12 @@ local type Query = q.Query
25local type v = require("luarocks.core.types.version") 25local type v = require("luarocks.core.types.version")
26local type Version = v.Version 26local type Version = v.Version
27 27
28local type p = require("luarocks.core.types.persist")
29local type PersistableTable = p.PersistableTable
30
31local type r = require("luarocks.core.types.result")
32local type Result = r.Result
33
28--- Generate a function that matches dep queries against the manifest, 34--- Generate a function that matches dep queries against the manifest,
29-- taking into account rocks_provided, the list of versions to skip, 35-- taking into account rocks_provided, the list of versions to skip,
30-- and the lockfile. 36-- and the lockfile.
@@ -42,9 +48,9 @@ local type Version = v.Version
42-- * map of versions to locations 48-- * map of versions to locations
43-- * version matched via lockfile if any 49-- * version matched via lockfile if any
44-- * true if rock matched via rocks_provided 50-- * true if rock matched via rocks_provided
45local function prepare_get_versions(deps_mode: string, rocks_provided: {string : string}, depskey: string, skip_set?): function(Query): {string}, {string: string | Tree}, string, boolean 51local function prepare_get_versions(deps_mode: string, rocks_provided: {string : string}, depskey: string, skip_set?: {string: {string: boolean}}): function(Query): {string}, {string: string | Tree}, string | number | boolean | PersistableTable, boolean
46 52
47 return function(dep: Query): {string}, {string: string | Tree}, string, boolean 53 return function(dep: Query): {string}, {string: string | Tree}, string | number | boolean | PersistableTable, boolean
48 local versions, locations: {string}, {string: string | Tree} 54 local versions, locations: {string}, {string: string | Tree}
49 local provided = rocks_provided[dep.name] 55 local provided = rocks_provided[dep.name]
50 if provided then 56 if provided then
@@ -114,7 +120,7 @@ local function match_dep(dep: Query,
114end 120end
115 121
116local function match_all_deps(dependencies: {Query}, 122local function match_all_deps(dependencies: {Query},
117 get_versions: function(Query): {string}, {string: string | Tree}, string, boolean): {Query: any}, {string}, {string} 123 get_versions: function(Query): {string}, {string: string | Tree}, string, boolean): {Query: Result}, {string: Query}, {string: Query}
118 124
119 local matched, missing, no_upgrade = {}, {}, {} 125 local matched, missing, no_upgrade = {}, {}, {}
120 126
@@ -123,7 +129,7 @@ local function match_all_deps(dependencies: {Query},
123 found, _, dep, provided = match_dep(dep, get_versions) 129 found, _, dep, provided = match_dep(dep, get_versions)
124 if found then 130 if found then
125 if not provided then 131 if not provided then
126 matched[dep] = {name = dep.name, version = found} 132 matched[dep] = {name = dep.name, version = found} as Result
127 end 133 end
128 else 134 else
129 if dep.constraints[1] and dep.constraints[1].no_upgrade then 135 if dep.constraints[1] and dep.constraints[1].no_upgrade then
@@ -149,20 +155,13 @@ end
149-- parsed as tables; and a table of "no-upgrade" missing dependencies 155-- parsed as tables; and a table of "no-upgrade" missing dependencies
150-- (to be used in plugin modules so that a plugin does not force upgrade of 156-- (to be used in plugin modules so that a plugin does not force upgrade of
151-- its parent application). 157-- its parent application).
152function deps.match_deps(dependencies, rocks_provided, skip_set, deps_mode) 158function deps.match_deps(dependencies: {Query}, rocks_provided: {string: string}, deps_mode: string, skip_set?: {string: {string: boolean}}): {Query : Result}, {string : Query}, {string : Query}
153 assert(type(dependencies) == "table")
154 assert(type(rocks_provided) == "table")
155 assert(type(skip_set) == "table" or skip_set == nil)
156 assert(type(deps_mode) == "string")
157 159
158 local get_versions = prepare_get_versions(deps_mode, rocks_provided, "dependencies", skip_set) 160 local get_versions = prepare_get_versions(deps_mode, rocks_provided, "dependencies", skip_set)
159 return match_all_deps(dependencies, get_versions) 161 return match_all_deps(dependencies, get_versions)
160end 162end
161 163
162local function rock_status(dep, get_versions) 164local function rock_status(dep: Query, get_versions: function(Query): {string}, {string : string | Tree}, string, boolean): string, string
163 assert(dep:type() == "query")
164 assert(type(get_versions) == "function")
165
166 local installed, _, _, provided = match_dep(dep, get_versions) 165 local installed, _, _, provided = match_dep(dep, get_versions)
167 local installation_type = provided and "provided by VM" or "installed" 166 local installation_type = provided and "provided by VM" or "installed"
168 return installed and installed.." "..installation_type..": success" or "not installed" 167 return installed and installed.." "..installation_type..": success" or "not installed"
@@ -177,12 +176,7 @@ end
177-- by this Lua implementation for the given dependency. 176-- by this Lua implementation for the given dependency.
178-- "one" for the current default tree, "all" for all trees, 177-- "one" for the current default tree, "all" for all trees,
179-- "order" for all trees with priority >= the current default, "none" for no trees. 178-- "order" for all trees with priority >= the current default, "none" for no trees.
180function deps.report_missing_dependencies(name, version, dependencies, deps_mode, rocks_provided) 179function deps.report_missing_dependencies(name: string, version: string, dependencies: {Query}, deps_mode: string, rocks_provided: {string: string})
181 assert(type(name) == "string")
182 assert(type(version) == "string")
183 assert(type(dependencies) == "table")
184 assert(type(deps_mode) == "string")
185 assert(type(rocks_provided) == "table")
186 180
187 if deps_mode == "none" then 181 if deps_mode == "none" then
188 return 182 return
@@ -193,7 +187,7 @@ function deps.report_missing_dependencies(name, version, dependencies, deps_mode
193 local first_missing_dep = true 187 local first_missing_dep = true
194 188
195 for _, dep in ipairs(dependencies) do 189 for _, dep in ipairs(dependencies) do
196 local found, _ 190 local found, _: string, string | Tree
197 found, _, dep = match_dep(dep, get_versions) 191 found, _, dep = match_dep(dep, get_versions)
198 if not found then 192 if not found then
199 if first_missing_dep then 193 if first_missing_dep then
@@ -206,19 +200,14 @@ function deps.report_missing_dependencies(name, version, dependencies, deps_mode
206 end 200 end
207end 201end
208 202
209function deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey) 203function deps.fulfill_dependency(dep: Query, deps_mode: string, rocks_provided: {string: string}, verify: boolean, depskey?: string): boolean, string, string | Tree
210 assert(dep:type() == "query")
211 assert(type(deps_mode) == "string" or deps_mode == nil)
212 assert(type(rocks_provided) == "table" or rocks_provided == nil)
213 assert(type(verify) == "boolean" or verify == nil)
214 assert(type(depskey) == "string")
215 204
216 deps_mode = deps_mode or "all" 205 deps_mode = deps_mode or "all"
217 rocks_provided = rocks_provided or {} 206 rocks_provided = rocks_provided or {}
218 207
219 local get_versions = prepare_get_versions(deps_mode, rocks_provided, depskey) 208 local get_versions = prepare_get_versions(deps_mode, rocks_provided, depskey)
220 209
221 local found, where 210 local found, where: string, string | Tree
222 found, where, dep = match_dep(dep, get_versions) 211 found, where, dep = match_dep(dep, get_versions)
223 if found then 212 if found then
224 local tree_manifests = manif.load_rocks_tree_manifests(deps_mode) 213 local tree_manifests = manif.load_rocks_tree_manifests(deps_mode)
diff --git a/src/luarocks/fetch.tl b/src/luarocks/fetch.tl
index 6612b253..bb1fd725 100644
--- a/src/luarocks/fetch.tl
+++ b/src/luarocks/fetch.tl
@@ -24,9 +24,9 @@ local function ensure_trailing_slash(url: string): string
24 return (url:gsub("/*$", "/")) 24 return (url:gsub("/*$", "/"))
25end 25end
26 26
27local function is_url_relative_to_rocks_servers(url: string, servers: {{string}}): integer, string, {string} 27local function is_url_relative_to_rocks_servers(url: string, servers: {{string} | string}): integer, string, {string}
28 for _, item in ipairs(servers) do 28 for _, item in ipairs(servers) do
29 if type(item) == "table" then 29 if item is {string} then
30 for i, s in ipairs(item) do 30 for i, s in ipairs(item) do
31 local base = ensure_trailing_slash(s) 31 local base = ensure_trailing_slash(s)
32 if string.find(url, base, 1, true) == 1 then 32 if string.find(url, base, 1, true) == 1 then
@@ -37,7 +37,7 @@ local function is_url_relative_to_rocks_servers(url: string, servers: {{string}}
37 end 37 end
38end 38end
39 39
40local function download_with_mirrors(url: string, filename: string, cache: boolean, servers: {{string}}): string, string, string, boolean 40local function download_with_mirrors(url: string, filename: string, cache: boolean, servers: {{string} | string}): string, string, string, boolean
41 local idx, rest, mirrors = is_url_relative_to_rocks_servers(url, servers) 41 local idx, rest, mirrors = is_url_relative_to_rocks_servers(url, servers)
42 42
43 if not idx then 43 if not idx then
@@ -581,7 +581,7 @@ function fetch.fetch_sources(rockspec: Rockspec, extract: boolean, dest_dir?: st
581 if dir.is_basic_protocol(protocol) then 581 if dir.is_basic_protocol(protocol) then
582 proto = fetch as Fetch 582 proto = fetch as Fetch
583 else 583 else
584 ok, proto = pcall(require, ("luarocks.fetch."..protocol:gsub("[+-]", "_")) as string) as (boolean, Fetch) 584 ok, proto = pcall(require, "luarocks.fetch."..protocol:gsub("[+-]", "_")) as (boolean, Fetch)
585 if not ok then 585 if not ok then
586 return nil, "Unknown protocol "..protocol 586 return nil, "Unknown protocol "..protocol
587 end 587 end
diff --git a/src/luarocks/persist.tl b/src/luarocks/persist.tl
index 5c6b47c3..cc07d295 100644
--- a/src/luarocks/persist.tl
+++ b/src/luarocks/persist.tl
@@ -4,9 +4,6 @@
4local record persist 4local record persist
5 run_file: function(string, {string:any}): boolean, any | string, string 5 run_file: function(string, {string:any}): boolean, any | string, string
6 load_into_table: function(string, ?{string:any}) : {any: any}, {any: any} | string, string 6 load_into_table: function(string, ?{string:any}) : {any: any}, {any: any} | string, string
7
8 type PersistableTable = { string | number : string | number | boolean | PersistableTable }
9
10end 7end
11 8
12local core = require("luarocks.core.persist") 9local core = require("luarocks.core.persist")
@@ -16,7 +13,12 @@ local fs = require("luarocks.fs")
16local cfg = require("luarocks.core.cfg") 13local cfg = require("luarocks.core.cfg")
17 14
18local type Config = cfg 15local type Config = cfg
19local type PersistableTable = persist.PersistableTable 16
17local type o = require("luarocks.core.types.ordering")
18local type SortBy = o.SortBy
19
20local type p = require("luarocks.core.types.persist")
21local type PersistableTable = p.PersistableTable
20 22
21persist.run_file = core.run_file 23persist.run_file = core.run_file
22persist.load_into_table = core.load_into_table 24persist.load_into_table = core.load_into_table
@@ -26,7 +28,7 @@ local interface Writer
26 buffer: {number | string} 28 buffer: {number | string}
27end 29end
28 30
29local write_table: function(out: Writer, tbl: PersistableTable, level: integer, sort_by: util.SortBy<number | string>) 31local write_table: function(out: Writer, tbl: PersistableTable, level: integer, sort_by: SortBy<number | string>)
30 32
31--- Write a value as Lua code. 33--- Write a value as Lua code.
32-- This function handles only numbers and strings, invoking write_table 34-- This function handles only numbers and strings, invoking write_table
@@ -36,7 +38,7 @@ local write_table: function(out: Writer, tbl: PersistableTable, level: integer,
36-- @param level number: the indentation level 38-- @param level number: the indentation level
37-- @param sub_order table: optional prioritization table 39-- @param sub_order table: optional prioritization table
38-- @see write_table 40-- @see write_table
39function persist.write_value(out: Writer, v: any, level: integer, sub_order?: util.SortBy<number | string>) 41function persist.write_value(out: Writer, v: any, level: integer, sub_order?: SortBy<number | string>)
40 if v is PersistableTable then 42 if v is PersistableTable then
41 level = level or 0 43 level = level or 0
42 write_table(out, v, level + 1, sub_order) 44 write_table(out, v, level + 1, sub_order)
@@ -110,7 +112,7 @@ end
110-- @param tbl table: the table to be written. 112-- @param tbl table: the table to be written.
111-- @param level number: the indentation level 113-- @param level number: the indentation level
112-- @param sort_by table: optional prioritization table 114-- @param sort_by table: optional prioritization table
113write_table = function(out: Writer, tbl: PersistableTable, level: integer, sort_by: util.SortBy<number | string>) 115write_table = function(out: Writer, tbl: PersistableTable, level: integer, sort_by: SortBy<number | string>)
114 out:write("{") 116 out:write("{")
115 local sep = "\n" 117 local sep = "\n"
116 local indentation = " " 118 local indentation = " "
@@ -149,7 +151,7 @@ end
149-- @param tbl table: the table to be written. 151-- @param tbl table: the table to be written.
150-- @param sort_by table: optional prioritization table 152-- @param sort_by table: optional prioritization table
151-- @return true if successful; nil and error message if failed. 153-- @return true if successful; nil and error message if failed.
152local function write_table_as_assignments(out: Writer, tbl: PersistableTable, sort_by: util.SortBy<number | string>): boolean, string 154local function write_table_as_assignments(out: Writer, tbl: PersistableTable, sort_by: SortBy<number | string>): boolean, string
153 for k, v, sub_order in util.sortedpairs(tbl, sort_by) do 155 for k, v, sub_order in util.sortedpairs(tbl, sort_by) do
154 if not (k is string and is_valid_plain_key(k)) then 156 if not (k is string and is_valid_plain_key(k)) then
155 return nil, "cannot store '"..tostring(k).."' as a plain key." 157 return nil, "cannot store '"..tostring(k).."' as a plain key."
@@ -182,7 +184,7 @@ end
182-- @param tbl table: the table containing the data to be written 184-- @param tbl table: the table containing the data to be written
183-- @param sort_by table: an optional array indicating the order of top-level fields. 185-- @param sort_by table: an optional array indicating the order of top-level fields.
184-- @return persisted data as string; or nil and an error message 186-- @return persisted data as string; or nil and an error message
185function persist.save_from_table_to_string(tbl: PersistableTable, sort_by?: util.SortBy<number | string>): string, string 187function persist.save_from_table_to_string(tbl: PersistableTable, sort_by?: SortBy<number | string>): string, string
186 local out: Writer = {buffer = {}} 188 local out: Writer = {buffer = {}}
187 function out:write(data: string) table.insert(self.buffer, data) end 189 function out:write(data: string) table.insert(self.buffer, data) end
188 local ok, err = write_table_as_assignments(out, tbl, sort_by) 190 local ok, err = write_table_as_assignments(out, tbl, sort_by)
@@ -201,7 +203,7 @@ end
201-- @param sort_by table: an optional array indicating the order of top-level fields. 203-- @param sort_by table: an optional array indicating the order of top-level fields.
202-- @return boolean or (nil, string): true if successful, or nil and a 204-- @return boolean or (nil, string): true if successful, or nil and a
203-- message in case of errors. 205-- message in case of errors.
204function persist.save_from_table(filename: string, tbl: PersistableTable, sort_by?: util.SortBy<number | string>): boolean, string 206function persist.save_from_table(filename: string, tbl: PersistableTable, sort_by?: SortBy<number | string>): boolean, string
205 local prefix = dir.dir_name(filename) 207 local prefix = dir.dir_name(filename)
206 fs.make_dir(prefix) 208 fs.make_dir(prefix)
207 local out = io.open(filename, "w") 209 local out = io.open(filename, "w")
diff --git a/src/luarocks/remove.lua b/src/luarocks/remove.lua
index a24b54ba..55390cd0 100644
--- a/src/luarocks/remove.lua
+++ b/src/luarocks/remove.lua
@@ -33,7 +33,7 @@ local function check_dependents(name, versions, deps_mode)
33 for rock_version, _ in pairs(rock_versions) do 33 for rock_version, _ in pairs(rock_versions) do
34 local rockspec, err = fetch.load_rockspec(path.rockspec_file(rock_name, rock_version)) 34 local rockspec, err = fetch.load_rockspec(path.rockspec_file(rock_name, rock_version))
35 if rockspec then 35 if rockspec then
36 local _, missing = deps.match_deps(rockspec.dependencies, rockspec.rocks_provided, skip_set, deps_mode) 36 local _, missing = deps.match_deps(rockspec.dependencies, rockspec.rocks_provided, deps_mode, skip_set)
37 if missing[name] then 37 if missing[name] then
38 table.insert(dependents, { name = rock_name, version = rock_version }) 38 table.insert(dependents, { name = rock_name, version = rock_version })
39 end 39 end
diff --git a/src/luarocks/results.tl b/src/luarocks/results.tl
index cbe6704d..cefc5ea2 100644
--- a/src/luarocks/results.tl
+++ b/src/luarocks/results.tl
@@ -1,11 +1,4 @@
1local record results 1local record results
2 record Results --? name
3 name: string
4 version: string
5 namespace: string
6 arch: string
7 repo: string
8 end
9end 2end
10 3
11local vers = require("luarocks.core.vers") 4local vers = require("luarocks.core.vers")
@@ -13,17 +6,18 @@ local util = require("luarocks.util")
13local type q = require("luarocks.core.types.query") 6local type q = require("luarocks.core.types.query")
14local type Query = q.Query 7local type Query = q.Query
15 8
16local type Results = results.Results 9local type r = require("luarocks.core.types.result")
10local type Result = r.Result
17 11
18local result_mt: metatable<Results> = {} 12local result_mt: metatable<Result> = {}
19 13
20result_mt.__index = results.Results 14result_mt.__index = r.Result
21 15
22function results.Results.type(): string --? remove later 16function r.Result.type(): string --? remove later
23 return "result" 17 return "result"
24end 18end
25 19
26function results.new(name: string, version: string, repo: string, arch?: string, namespace?: string): Results, boolean 20function results.new(name: string, version: string, repo: string, arch?: string, namespace?: string): Result, boolean
27 21
28 assert(not name:match("/")) 22 assert(not name:match("/"))
29 -- assert(type(arch) == "string" or not arch) --! arch?: string 23 -- assert(type(arch) == "string" or not arch) --! arch?: string
@@ -34,7 +28,7 @@ function results.new(name: string, version: string, repo: string, arch?: string,
34 name, namespace = util.split_namespace(name) 28 name, namespace = util.split_namespace(name)
35 end 29 end
36 30
37 local self: Results = { 31 local self: Result = {
38 name = name, 32 name = name,
39 version = version, 33 version = version,
40 namespace = namespace, 34 namespace = namespace,
@@ -63,7 +57,7 @@ end
63--- Returns true if the result satisfies a given query. 57--- Returns true if the result satisfies a given query.
64-- @param query: a query. 58-- @param query: a query.
65-- @return boolean. 59-- @return boolean.
66function results.Results:satisfies(query: Query): boolean 60function r.Result:satisfies(query: Query): boolean
67 return match_name(query, self.name) 61 return match_name(query, self.name)
68 and (query.arch[self.arch] or query.arch["any"]) 62 and (query.arch[self.arch] or query.arch["any"])
69 and ((not query.namespace) or (query.namespace == self.namespace)) 63 and ((not query.namespace) or (query.namespace == self.namespace))
diff --git a/src/luarocks/search-original.lua b/src/luarocks/search-original.lua
new file mode 100644
index 00000000..180f8f45
--- /dev/null
+++ b/src/luarocks/search-original.lua
@@ -0,0 +1,393 @@
1local search = {}
2
3local dir = require("luarocks.dir")
4local path = require("luarocks.path")
5local manif = require("luarocks.manif")
6local vers = require("luarocks.core.vers")
7local cfg = require("luarocks.core.cfg")
8local util = require("luarocks.util")
9local queries = require("luarocks.queries")
10local results = require("luarocks.results")
11
12--- Store a search result (a rock or rockspec) in the result tree.
13-- @param result_tree table: The result tree, where keys are package names and
14-- values are tables matching version strings to arrays of
15-- tables with fields "arch" and "repo".
16-- @param result table: A result.
17function search.store_result(result_tree, result)
18 assert(type(result_tree) == "table")
19 assert(result:type() == "result")
20
21 local name = result.name
22 local version = result.version
23
24 if not result_tree[name] then result_tree[name] = {} end
25 if not result_tree[name][version] then result_tree[name][version] = {} end
26 table.insert(result_tree[name][version], {
27 arch = result.arch,
28 repo = result.repo,
29 namespace = result.namespace,
30 })
31end
32
33--- Store a match in a result tree if version matches query.
34-- Name, version, arch and repository path are stored in a given
35-- table, optionally checking if version and arch (if given) match
36-- a query.
37-- @param result_tree table: The result tree, where keys are package names and
38-- values are tables matching version strings to arrays of
39-- tables with fields "arch" and "repo".
40-- @param result table: a result object.
41-- @param query table: a query object.
42local function store_if_match(result_tree, result, query)
43 assert(result:type() == "result")
44 assert(query:type() == "query")
45
46 if result:satisfies(query) then
47 search.store_result(result_tree, result)
48 end
49end
50
51--- Perform search on a local repository.
52-- @param repo string: The pathname of the local repository.
53-- @param query table: a query object.
54-- @param result_tree table or nil: If given, this table will store the
55-- result tree; if not given, a new table will be created.
56-- @return table: The result tree, where keys are package names and
57-- values are tables matching version strings to arrays of
58-- tables with fields "arch" and "repo".
59-- If a table was given in the "result_tree" parameter, that is the result value.
60function search.disk_search(repo, query, result_tree)
61 assert(type(repo) == "string")
62 assert(query:type() == "query")
63 assert(type(result_tree) == "table" or not result_tree)
64
65 local fs = require("luarocks.fs")
66
67 if not result_tree then
68 result_tree = {}
69 end
70
71 for name in fs.dir(repo) do
72 local pathname = dir.path(repo, name)
73 local rname, rversion, rarch = path.parse_name(name)
74
75 if rname and (pathname:match(".rockspec$") or pathname:match(".rock$")) then
76 local result = results.new(rname, rversion, repo, rarch)
77 store_if_match(result_tree, result, query)
78 elseif fs.is_dir(pathname) then
79 for version in fs.dir(pathname) do
80 if version:match("-%d+$") then
81 local namespace = path.read_namespace(name, version, repo)
82 local result = results.new(name, version, repo, "installed", namespace)
83 store_if_match(result_tree, result, query)
84 end
85 end
86 end
87 end
88 return result_tree
89end
90
91--- Perform search on a rocks server or tree.
92-- @param result_tree table: The result tree, where keys are package names and
93-- values are tables matching version strings to arrays of
94-- tables with fields "arch" and "repo".
95-- @param repo string: The URL of a rocks server or
96-- the pathname of a rocks tree (as returned by path.rocks_dir()).
97-- @param query table: a query object.
98-- @param lua_version string: Lua version in "5.x" format, defaults to installed version.
99-- @param is_local boolean
100-- @return true or, in case of errors, nil, an error message and an optional error code.
101local function manifest_search(result_tree, repo, query, lua_version, is_local)
102 assert(type(result_tree) == "table")
103 assert(type(repo) == "string")
104 assert(query:type() == "query")
105
106 -- FIXME do not add this in local repos
107 if (not is_local) and query.namespace then
108 repo = repo .. "/manifests/" .. query.namespace
109 end
110
111 local manifest, err, errcode = manif.load_manifest(repo, lua_version, not is_local)
112 if not manifest then
113 return nil, err, errcode
114 end
115 for name, versions in pairs(manifest.repository) do
116 for version, items in pairs(versions) do
117 local namespace = is_local and path.read_namespace(name, version, repo) or query.namespace
118 for _, item in ipairs(items) do
119 local result = results.new(name, version, repo, item.arch, namespace)
120 store_if_match(result_tree, result, query)
121 end
122 end
123 end
124 return true
125end
126
127local function remote_manifest_search(result_tree, repo, query, lua_version)
128 return manifest_search(result_tree, repo, query, lua_version, false)
129end
130
131function search.local_manifest_search(result_tree, repo, query, lua_version)
132 return manifest_search(result_tree, repo, query, lua_version, true)
133end
134
135--- Search on all configured rocks servers.
136-- @param query table: a query object.
137-- @param lua_version string: Lua version in "5.x" format, defaults to installed version.
138-- @return table: A table where keys are package names
139-- and values are tables matching version strings to arrays of
140-- tables with fields "arch" and "repo".
141function search.search_repos(query, lua_version)
142 assert(query:type() == "query")
143
144 local result_tree = {}
145 for _, repo in ipairs(cfg.rocks_servers) do
146 if type(repo) == "string" then
147 repo = { repo }
148 end
149 for _, mirror in ipairs(repo) do
150 if not cfg.disabled_servers[mirror] then
151 local protocol, pathname = dir.split_url(mirror)
152 if protocol == "file" then
153 mirror = pathname
154 end
155 local ok, err, errcode = remote_manifest_search(result_tree, mirror, query, lua_version)
156 if errcode == "network" then
157 cfg.disabled_servers[mirror] = true
158 end
159 if ok then
160 break
161 else
162 util.warning("Failed searching manifest: "..err)
163 if errcode == "downloader" then
164 break
165 end
166 end
167 end
168 end
169 end
170 -- search through rocks in rocks_provided
171 local provided_repo = "provided by VM or rocks_provided"
172 for name, version in pairs(util.get_rocks_provided()) do
173 local result = results.new(name, version, provided_repo, "installed")
174 store_if_match(result_tree, result, query)
175 end
176 return result_tree
177end
178
179--- Get the URL for the latest in a set of versions.
180-- @param name string: The package name to be used in the URL.
181-- @param versions table: An array of version informations, as stored
182-- in search result trees.
183-- @return string or nil: the URL for the latest version if one could
184-- be picked, or nil.
185local function pick_latest_version(name, versions)
186 assert(type(name) == "string" and not name:match("/"))
187 assert(type(versions) == "table")
188
189 local vtables = {}
190 for v, _ in pairs(versions) do
191 table.insert(vtables, vers.parse_version(v))
192 end
193 table.sort(vtables)
194 local version = vtables[#vtables].string
195 local items = versions[version]
196 if items then
197 local pick = 1
198 for i, item in ipairs(items) do
199 if (item.arch == 'src' and items[pick].arch == 'rockspec')
200 or (item.arch ~= 'src' and item.arch ~= 'rockspec') then
201 pick = i
202 end
203 end
204 return path.make_url(items[pick].repo, name, version, items[pick].arch)
205 end
206 return nil
207end
208
209-- Find out which other Lua versions provide rock versions matching a query,
210-- @param query table: a query object.
211-- @return table: array of Lua versions supported, in "5.x" format.
212local function supported_lua_versions(query)
213 assert(query:type() == "query")
214 local result_tree = {}
215
216 for lua_version in util.lua_versions() do
217 if lua_version ~= cfg.lua_version then
218 util.printout("Checking for Lua " .. lua_version .. "...")
219 if search.search_repos(query, lua_version)[query.name] then
220 table.insert(result_tree, lua_version)
221 end
222 end
223 end
224
225 return result_tree
226end
227
228--- Attempt to get a single URL for a given search for a rock.
229-- @param query table: a query object.
230-- @return string or (nil, string, string): URL for latest matching version
231-- of the rock if it was found, or nil followed by an error message
232-- and an error code.
233function search.find_suitable_rock(query)
234 assert(query:type() == "query")
235
236 local rocks_provided = util.get_rocks_provided()
237
238 if rocks_provided[query.name] ~= nil then
239 -- Do not install versions listed in rocks_provided.
240 return nil, "Rock "..query.name.." "..rocks_provided[query.name]..
241 " is already provided by VM or via 'rocks_provided' in the config file.", "provided"
242 end
243
244 local result_tree = search.search_repos(query)
245 local first_rock = next(result_tree)
246 if not first_rock then
247 return nil, "No results matching query were found for Lua " .. cfg.lua_version .. ".", "notfound"
248 elseif next(result_tree, first_rock) then
249 -- Shouldn't happen as query must match only one package.
250 return nil, "Several rocks matched query.", "manyfound"
251 else
252 return pick_latest_version(query.name, result_tree[first_rock])
253 end
254end
255
256function search.find_src_or_rockspec(name, namespace, version, check_lua_versions)
257 local query = queries.new(name, namespace, version, false, "src|rockspec")
258 local url, err = search.find_rock_checking_lua_versions(query, check_lua_versions)
259 if not url then
260 return nil, "Could not find a result named "..tostring(query)..": "..err
261 end
262 return url
263end
264
265function search.find_rock_checking_lua_versions(query, check_lua_versions)
266 local url, err, errcode = search.find_suitable_rock(query)
267 if url then
268 return url
269 end
270
271 if errcode == "notfound" then
272 local add
273 if check_lua_versions then
274 util.printout(query.name .. " not found for Lua " .. cfg.lua_version .. ".")
275 util.printout("Checking if available for other Lua versions...")
276
277 -- Check if constraints are satisfiable with other Lua versions.
278 local lua_versions = supported_lua_versions(query)
279
280 if #lua_versions ~= 0 then
281 -- Build a nice message in "only Lua 5.x and 5.y but not 5.z." format
282 for i, lua_version in ipairs(lua_versions) do
283 lua_versions[i] = "Lua "..lua_version
284 end
285
286 local versions_message = "only "..table.concat(lua_versions, " and ")..
287 " but not Lua "..cfg.lua_version.."."
288
289 if #query.constraints == 0 then
290 add = query.name.." supports "..versions_message
291 elseif #query.constraints == 1 and query.constraints[1].op == "==" then
292 add = query.name.." "..query.constraints[1].version.string.." supports "..versions_message
293 else
294 add = "Matching "..query.name.." versions support "..versions_message
295 end
296 else
297 add = query.name.." is not available for any Lua versions."
298 end
299 else
300 add = "To check if it is available for other Lua versions, use --check-lua-versions."
301 end
302 err = err .. "\n" .. add
303 end
304
305 return nil, err
306end
307
308--- Print a list of rocks/rockspecs on standard output.
309-- @param result_tree table: A result tree.
310-- @param porcelain boolean or nil: A flag to force machine-friendly output.
311function search.print_result_tree(result_tree, porcelain)
312 assert(type(result_tree) == "table")
313 assert(type(porcelain) == "boolean" or not porcelain)
314
315 if porcelain then
316 for package, versions in util.sortedpairs(result_tree) do
317 for version, repos in util.sortedpairs(versions, vers.compare_versions) do
318 for _, repo in ipairs(repos) do
319 local nrepo = dir.normalize(repo.repo)
320 util.printout(package, version, repo.arch, nrepo, repo.namespace)
321 end
322 end
323 end
324 return
325 end
326
327 for package, versions in util.sortedpairs(result_tree) do
328 local namespaces = {}
329 for version, repos in util.sortedpairs(versions, vers.compare_versions) do
330 for _, repo in ipairs(repos) do
331 local key = repo.namespace or ""
332 local list = namespaces[key] or {}
333 namespaces[key] = list
334
335 repo.repo = dir.normalize(repo.repo)
336 table.insert(list, " "..version.." ("..repo.arch..") - "..path.root_dir(repo.repo))
337 end
338 end
339 for key, list in util.sortedpairs(namespaces) do
340 util.printout(key == "" and package or key .. "/" .. package)
341 for _, line in ipairs(list) do
342 util.printout(line)
343 end
344 util.printout()
345 end
346 end
347end
348
349function search.pick_installed_rock(query, given_tree)
350 assert(query:type() == "query")
351
352 local result_tree = {}
353 local tree_map = {}
354 local trees = cfg.rocks_trees
355 if given_tree then
356 trees = { given_tree }
357 end
358 for _, tree in ipairs(trees) do
359 local rocks_dir = path.rocks_dir(tree)
360 tree_map[rocks_dir] = tree
361 search.local_manifest_search(result_tree, rocks_dir, query)
362 end
363 if not next(result_tree) then
364 return nil, "cannot find package "..tostring(query).."\nUse 'list' to find installed rocks."
365 end
366
367 if not result_tree[query.name] and next(result_tree, next(result_tree)) then
368 local out = { "multiple installed packages match the name '"..tostring(query).."':\n\n" }
369 for name, _ in util.sortedpairs(result_tree) do
370 table.insert(out, " " .. name .. "\n")
371 end
372 table.insert(out, "\nPlease specify a single rock.\n")
373 return nil, table.concat(out)
374 end
375
376 local repo_url
377
378 local name, versions
379 if result_tree[query.name] then
380 name, versions = query.name, result_tree[query.name]
381 else
382 name, versions = util.sortedpairs(result_tree)()
383 end
384
385 local version, repositories = util.sortedpairs(versions, vers.compare_versions)()
386 for _, rp in ipairs(repositories) do repo_url = rp.repo end
387
388 local repo = tree_map[repo_url]
389 return name, version, repo, repo_url
390end
391
392return search
393
diff --git a/src/luarocks/search.lua b/src/luarocks/search.lua
index 180f8f45..1404e303 100644
--- a/src/luarocks/search.lua
+++ b/src/luarocks/search.lua
@@ -1,4 +1,4 @@
1local search = {} 1local _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 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; local search = {}
2 2
3local dir = require("luarocks.dir") 3local dir = require("luarocks.dir")
4local path = require("luarocks.path") 4local path = require("luarocks.path")
@@ -9,14 +9,25 @@ local util = require("luarocks.util")
9local queries = require("luarocks.queries") 9local queries = require("luarocks.queries")
10local results = require("luarocks.results") 10local results = require("luarocks.results")
11 11
12--- Store a search result (a rock or rockspec) in the result tree. 12
13-- @param result_tree table: The result tree, where keys are package names and 13
14-- values are tables matching version strings to arrays of 14
15-- tables with fields "arch" and "repo". 15
16-- @param result table: A result. 16
17
18
19
20
21
22
23
24
25
26
27
28
17function search.store_result(result_tree, result) 29function search.store_result(result_tree, result)
18 assert(type(result_tree) == "table") 30 assert(type(result_tree) == "table")
19 assert(result:type() == "result")
20 31
21 local name = result.name 32 local name = result.name
22 local version = result.version 33 local version = result.version
@@ -30,37 +41,32 @@ function search.store_result(result_tree, result)
30 }) 41 })
31end 42end
32 43
33--- Store a match in a result tree if version matches query. 44
34-- Name, version, arch and repository path are stored in a given 45
35-- table, optionally checking if version and arch (if given) match 46
36-- a query. 47
37-- @param result_tree table: The result tree, where keys are package names and 48
38-- values are tables matching version strings to arrays of 49
39-- tables with fields "arch" and "repo". 50
40-- @param result table: a result object. 51
41-- @param query table: a query object. 52
42local function store_if_match(result_tree, result, query) 53local function store_if_match(result_tree, result, query)
43 assert(result:type() == "result")
44 assert(query:type() == "query")
45 54
46 if result:satisfies(query) then 55 if result:satisfies(query) then
47 search.store_result(result_tree, result) 56 search.store_result(result_tree, result)
48 end 57 end
49end 58end
50 59
51--- Perform search on a local repository. 60
52-- @param repo string: The pathname of the local repository. 61
53-- @param query table: a query object. 62
54-- @param result_tree table or nil: If given, this table will store the 63
55-- result tree; if not given, a new table will be created. 64
56-- @return table: The result tree, where keys are package names and 65
57-- values are tables matching version strings to arrays of 66
58-- tables with fields "arch" and "repo". 67
59-- If a table was given in the "result_tree" parameter, that is the result value. 68
60function search.disk_search(repo, query, result_tree) 69function search.disk_search(repo, query, result_tree)
61 assert(type(repo) == "string")
62 assert(query:type() == "query")
63 assert(type(result_tree) == "table" or not result_tree)
64 70
65 local fs = require("luarocks.fs") 71 local fs = require("luarocks.fs")
66 72
@@ -88,22 +94,19 @@ function search.disk_search(repo, query, result_tree)
88 return result_tree 94 return result_tree
89end 95end
90 96
91--- Perform search on a rocks server or tree. 97
92-- @param result_tree table: The result tree, where keys are package names and 98
93-- values are tables matching version strings to arrays of 99
94-- tables with fields "arch" and "repo". 100
95-- @param repo string: The URL of a rocks server or 101
96-- the pathname of a rocks tree (as returned by path.rocks_dir()). 102
97-- @param query table: a query object. 103
98-- @param lua_version string: Lua version in "5.x" format, defaults to installed version. 104
99-- @param is_local boolean 105
100-- @return true or, in case of errors, nil, an error message and an optional error code. 106
101local function manifest_search(result_tree, repo, query, lua_version, is_local) 107local function manifest_search(result_tree, repo, query, lua_version, is_local)
102 assert(type(result_tree) == "table")
103 assert(type(repo) == "string")
104 assert(query:type() == "query")
105 108
106 -- FIXME do not add this in local repos 109
107 if (not is_local) and query.namespace then 110 if (not is_local) and query.namespace then
108 repo = repo .. "/manifests/" .. query.namespace 111 repo = repo .. "/manifests/" .. query.namespace
109 end 112 end
@@ -132,19 +135,21 @@ function search.local_manifest_search(result_tree, repo, query, lua_version)
132 return manifest_search(result_tree, repo, query, lua_version, true) 135 return manifest_search(result_tree, repo, query, lua_version, true)
133end 136end
134 137
135--- Search on all configured rocks servers. 138
136-- @param query table: a query object. 139
137-- @param lua_version string: Lua version in "5.x" format, defaults to installed version. 140
138-- @return table: A table where keys are package names 141
139-- and values are tables matching version strings to arrays of 142
140-- tables with fields "arch" and "repo". 143
141function search.search_repos(query, lua_version) 144function search.search_repos(query, lua_version)
142 assert(query:type() == "query")
143 145
144 local result_tree = {} 146 local result_tree = {}
145 for _, repo in ipairs(cfg.rocks_servers) do 147 local repo = {}
146 if type(repo) == "string" then 148 for _, repostr in ipairs(cfg.rocks_servers) do
147 repo = { repo } 149 if type(repostr) == "string" then
150 repo = { repostr }
151 else
152 repo = repostr
148 end 153 end
149 for _, mirror in ipairs(repo) do 154 for _, mirror in ipairs(repo) do
150 if not cfg.disabled_servers[mirror] then 155 if not cfg.disabled_servers[mirror] then
@@ -159,7 +164,7 @@ function search.search_repos(query, lua_version)
159 if ok then 164 if ok then
160 break 165 break
161 else 166 else
162 util.warning("Failed searching manifest: "..err) 167 util.warning("Failed searching manifest: " .. err)
163 if errcode == "downloader" then 168 if errcode == "downloader" then
164 break 169 break
165 end 170 end
@@ -167,7 +172,7 @@ function search.search_repos(query, lua_version)
167 end 172 end
168 end 173 end
169 end 174 end
170 -- search through rocks in rocks_provided 175
171 local provided_repo = "provided by VM or rocks_provided" 176 local provided_repo = "provided by VM or rocks_provided"
172 for name, version in pairs(util.get_rocks_provided()) do 177 for name, version in pairs(util.get_rocks_provided()) do
173 local result = results.new(name, version, provided_repo, "installed") 178 local result = results.new(name, version, provided_repo, "installed")
@@ -176,15 +181,14 @@ function search.search_repos(query, lua_version)
176 return result_tree 181 return result_tree
177end 182end
178 183
179--- Get the URL for the latest in a set of versions. 184
180-- @param name string: The package name to be used in the URL. 185
181-- @param versions table: An array of version informations, as stored 186
182-- in search result trees. 187
183-- @return string or nil: the URL for the latest version if one could 188
184-- be picked, or nil. 189
185local function pick_latest_version(name, versions) 190local function pick_latest_version(name, versions)
186 assert(type(name) == "string" and not name:match("/")) 191 assert(not name:match("/"))
187 assert(type(versions) == "table")
188 192
189 local vtables = {} 193 local vtables = {}
190 for v, _ in pairs(versions) do 194 for v, _ in pairs(versions) do
@@ -196,8 +200,8 @@ local function pick_latest_version(name, versions)
196 if items then 200 if items then
197 local pick = 1 201 local pick = 1
198 for i, item in ipairs(items) do 202 for i, item in ipairs(items) do
199 if (item.arch == 'src' and items[pick].arch == 'rockspec') 203 if (item.arch == 'src' and items[pick].arch == 'rockspec') or
200 or (item.arch ~= 'src' and item.arch ~= 'rockspec') then 204 (item.arch ~= 'src' and item.arch ~= 'rockspec') then
201 pick = i 205 pick = i
202 end 206 end
203 end 207 end
@@ -206,11 +210,10 @@ local function pick_latest_version(name, versions)
206 return nil 210 return nil
207end 211end
208 212
209-- Find out which other Lua versions provide rock versions matching a query, 213
210-- @param query table: a query object. 214
211-- @return table: array of Lua versions supported, in "5.x" format. 215
212local function supported_lua_versions(query) 216local function supported_lua_versions(query)
213 assert(query:type() == "query")
214 local result_tree = {} 217 local result_tree = {}
215 218
216 for lua_version in util.lua_versions() do 219 for lua_version in util.lua_versions() do
@@ -225,43 +228,33 @@ local function supported_lua_versions(query)
225 return result_tree 228 return result_tree
226end 229end
227 230
228--- Attempt to get a single URL for a given search for a rock. 231
229-- @param query table: a query object. 232
230-- @return string or (nil, string, string): URL for latest matching version 233
231-- of the rock if it was found, or nil followed by an error message 234
232-- and an error code. 235
233function search.find_suitable_rock(query) 236function search.find_suitable_rock(query)
234 assert(query:type() == "query")
235 237
236 local rocks_provided = util.get_rocks_provided() 238 local rocks_provided = util.get_rocks_provided()
237 239
238 if rocks_provided[query.name] ~= nil then 240 if rocks_provided[query.name] ~= nil then
239 -- Do not install versions listed in rocks_provided. 241
240 return nil, "Rock "..query.name.." "..rocks_provided[query.name].. 242 return nil, "Rock " .. query.name .. " " .. rocks_provided[query.name] ..
241 " is already provided by VM or via 'rocks_provided' in the config file.", "provided" 243 " is already provided by VM or via 'rocks_provided' in the config file.", "provided"
242 end 244 end
243 245
244 local result_tree = search.search_repos(query) 246 local result_tree = search.search_repos(query)
245 local first_rock = next(result_tree) 247 local first_rock = next(result_tree)
246 if not first_rock then 248 if not first_rock then
247 return nil, "No results matching query were found for Lua " .. cfg.lua_version .. ".", "notfound" 249 return nil, "No results matching query were found for Lua " .. cfg.lua_version .. ".", "notfound"
248 elseif next(result_tree, first_rock) then 250 elseif next(result_tree, first_rock) ~= nil then
249 -- Shouldn't happen as query must match only one package. 251
250 return nil, "Several rocks matched query.", "manyfound" 252 return nil, "Several rocks matched query.", "manyfound"
251 else 253 else
252 return pick_latest_version(query.name, result_tree[first_rock]) 254 return pick_latest_version(query.name, result_tree[first_rock])
253 end 255 end
254end 256end
255 257
256function search.find_src_or_rockspec(name, namespace, version, check_lua_versions)
257 local query = queries.new(name, namespace, version, false, "src|rockspec")
258 local url, err = search.find_rock_checking_lua_versions(query, check_lua_versions)
259 if not url then
260 return nil, "Could not find a result named "..tostring(query)..": "..err
261 end
262 return url
263end
264
265function search.find_rock_checking_lua_versions(query, check_lua_versions) 258function search.find_rock_checking_lua_versions(query, check_lua_versions)
266 local url, err, errcode = search.find_suitable_rock(query) 259 local url, err, errcode = search.find_suitable_rock(query)
267 if url then 260 if url then
@@ -274,27 +267,34 @@ function search.find_rock_checking_lua_versions(query, check_lua_versions)
274 util.printout(query.name .. " not found for Lua " .. cfg.lua_version .. ".") 267 util.printout(query.name .. " not found for Lua " .. cfg.lua_version .. ".")
275 util.printout("Checking if available for other Lua versions...") 268 util.printout("Checking if available for other Lua versions...")
276 269
277 -- Check if constraints are satisfiable with other Lua versions. 270
278 local lua_versions = supported_lua_versions(query) 271 local lua_versions = supported_lua_versions(query)
279 272
280 if #lua_versions ~= 0 then 273 if #lua_versions ~= 0 then
281 -- Build a nice message in "only Lua 5.x and 5.y but not 5.z." format 274
282 for i, lua_version in ipairs(lua_versions) do 275 for i, lua_version in ipairs(lua_versions) do
283 lua_versions[i] = "Lua "..lua_version 276 lua_versions[i] = "Lua " .. lua_version
284 end 277 end
285 278
286 local versions_message = "only "..table.concat(lua_versions, " and ").. 279 local versions_message = "only " .. table.concat(lua_versions, " and ") ..
287 " but not Lua "..cfg.lua_version.."." 280 " but not Lua " .. cfg.lua_version .. "."
288 281
289 if #query.constraints == 0 then 282 if #query.constraints == 0 then
290 add = query.name.." supports "..versions_message 283 add = query.name .. " supports " .. versions_message
291 elseif #query.constraints == 1 and query.constraints[1].op == "==" then 284 elseif #query.constraints == 1 and query.constraints[1].op == "==" then
292 add = query.name.." "..query.constraints[1].version.string.." supports "..versions_message 285 local queryversionstr
286 local queryversion = query.constraints[1].version
287 if type(queryversion) == "table" then
288 queryversionstr = queryversion.string
289 else
290 queryversionstr = queryversion
291 end
292 add = query.name .. " " .. queryversionstr .. " supports " .. versions_message
293 else 293 else
294 add = "Matching "..query.name.." versions support "..versions_message 294 add = "Matching " .. query.name .. " versions support " .. versions_message
295 end 295 end
296 else 296 else
297 add = query.name.." is not available for any Lua versions." 297 add = query.name .. " is not available for any Lua versions."
298 end 298 end
299 else 299 else
300 add = "To check if it is available for other Lua versions, use --check-lua-versions." 300 add = "To check if it is available for other Lua versions, use --check-lua-versions."
@@ -305,26 +305,33 @@ function search.find_rock_checking_lua_versions(query, check_lua_versions)
305 return nil, err 305 return nil, err
306end 306end
307 307
308--- Print a list of rocks/rockspecs on standard output. 308function search.find_src_or_rockspec(name, namespace, version, check_lua_versions)
309-- @param result_tree table: A result tree. 309 local query = queries.new(name, namespace, version, false, "src|rockspec")
310-- @param porcelain boolean or nil: A flag to force machine-friendly output. 310 local url, err = search.find_rock_checking_lua_versions(query, check_lua_versions)
311 if not url then
312 return nil, "Could not find a result named " .. tostring(query) .. ": " .. err
313 end
314 return url
315end
316
317
318
319
311function search.print_result_tree(result_tree, porcelain) 320function search.print_result_tree(result_tree, porcelain)
312 assert(type(result_tree) == "table")
313 assert(type(porcelain) == "boolean" or not porcelain)
314 321
315 if porcelain then 322 if porcelain then
316 for package, versions in util.sortedpairs(result_tree) do 323 for packagestr, versions in util.sortedpairs(result_tree) do
317 for version, repos in util.sortedpairs(versions, vers.compare_versions) do 324 for version, repos in util.sortedpairs(versions, vers.compare_versions) do
318 for _, repo in ipairs(repos) do 325 for _, repo in ipairs(repos) do
319 local nrepo = dir.normalize(repo.repo) 326 local nrepo = dir.normalize(repo.repo)
320 util.printout(package, version, repo.arch, nrepo, repo.namespace) 327 util.printout(packagestr, version, repo.arch, nrepo, repo.namespace)
321 end 328 end
322 end 329 end
323 end 330 end
324 return 331 return
325 end 332 end
326 333
327 for package, versions in util.sortedpairs(result_tree) do 334 for packagestr, versions in util.sortedpairs(result_tree) do
328 local namespaces = {} 335 local namespaces = {}
329 for version, repos in util.sortedpairs(versions, vers.compare_versions) do 336 for version, repos in util.sortedpairs(versions, vers.compare_versions) do
330 for _, repo in ipairs(repos) do 337 for _, repo in ipairs(repos) do
@@ -333,11 +340,11 @@ function search.print_result_tree(result_tree, porcelain)
333 namespaces[key] = list 340 namespaces[key] = list
334 341
335 repo.repo = dir.normalize(repo.repo) 342 repo.repo = dir.normalize(repo.repo)
336 table.insert(list, " "..version.." ("..repo.arch..") - "..path.root_dir(repo.repo)) 343 table.insert(list, " " .. version .. " (" .. repo.arch .. ") - " .. path.root_dir(repo.repo))
337 end 344 end
338 end 345 end
339 for key, list in util.sortedpairs(namespaces) do 346 for key, list in util.sortedpairs(namespaces) do
340 util.printout(key == "" and package or key .. "/" .. package) 347 util.printout(key == "" and packagestr or key .. "/" .. packagestr)
341 for _, line in ipairs(list) do 348 for _, line in ipairs(list) do
342 util.printout(line) 349 util.printout(line)
343 end 350 end
@@ -347,7 +354,6 @@ function search.print_result_tree(result_tree, porcelain)
347end 354end
348 355
349function search.pick_installed_rock(query, given_tree) 356function search.pick_installed_rock(query, given_tree)
350 assert(query:type() == "query")
351 357
352 local result_tree = {} 358 local result_tree = {}
353 local tree_map = {} 359 local tree_map = {}
@@ -361,11 +367,11 @@ function search.pick_installed_rock(query, given_tree)
361 search.local_manifest_search(result_tree, rocks_dir, query) 367 search.local_manifest_search(result_tree, rocks_dir, query)
362 end 368 end
363 if not next(result_tree) then 369 if not next(result_tree) then
364 return nil, "cannot find package "..tostring(query).."\nUse 'list' to find installed rocks." 370 return nil, "cannot find package " .. tostring(query) .. "\nUse 'list' to find installed rocks."
365 end 371 end
366 372
367 if not result_tree[query.name] and next(result_tree, next(result_tree)) then 373 if not result_tree[query.name] and next(result_tree, next(result_tree)) ~= nil then
368 local out = { "multiple installed packages match the name '"..tostring(query).."':\n\n" } 374 local out = { "multiple installed packages match the name '" .. tostring(query) .. "':\n\n" }
369 for name, _ in util.sortedpairs(result_tree) do 375 for name, _ in util.sortedpairs(result_tree) do
370 table.insert(out, " " .. name .. "\n") 376 table.insert(out, " " .. name .. "\n")
371 end 377 end
@@ -390,4 +396,3 @@ function search.pick_installed_rock(query, given_tree)
390end 396end
391 397
392return search 398return search
393
diff --git a/src/luarocks/search.tl b/src/luarocks/search.tl
new file mode 100644
index 00000000..7d8a9055
--- /dev/null
+++ b/src/luarocks/search.tl
@@ -0,0 +1,399 @@
1local search = {}
2
3local dir = require("luarocks.dir")
4local path = require("luarocks.path")
5local manif = require("luarocks.manif")
6local vers = require("luarocks.core.vers")
7local cfg = require("luarocks.core.cfg")
8local util = require("luarocks.util")
9local queries = require("luarocks.queries")
10local results = require("luarocks.results")
11
12local type r = require("luarocks.core.types.result")
13local type Result = r.Result
14
15local type q = require("luarocks.core.types.query")
16local type Query = q.Query
17
18local type v = require("luarocks.core.types.version")
19local type Version = v.Version
20
21local type t = require("luarocks.core.types.tree")
22local type Tree = t.Tree
23
24--- Store a search result (a rock or rockspec) in the result tree.
25-- @param result_tree table: The result tree, where keys are package names and
26-- values are tables matching version strings to arrays of
27-- tables with fields "arch" and "repo".
28-- @param result table: A result.
29function search.store_result(result_tree: {string: {string: {Result}}}, result: Result)
30 assert(type(result_tree) == "table")
31
32 local name = result.name
33 local version = result.version
34
35 if not result_tree[name] then result_tree[name] = {} end
36 if not result_tree[name][version] then result_tree[name][version] = {} end
37 table.insert(result_tree[name][version], {
38 arch = result.arch,
39 repo = result.repo,
40 namespace = result.namespace,
41 } as Result)
42end
43
44--- Store a match in a result tree if version matches query.
45-- Name, version, arch and repository path are stored in a given
46-- table, optionally checking if version and arch (if given) match
47-- a query.
48-- @param result_tree table: The result tree, where keys are package names and
49-- values are tables matching version strings to arrays of
50-- tables with fields "arch" and "repo".
51-- @param result table: a result object.
52-- @param query table: a query object.
53local function store_if_match(result_tree: {string: {string: {Result}}}, result: Result, query: Query)
54
55 if result:satisfies(query) then
56 search.store_result(result_tree, result)
57 end
58end
59
60--- Perform search on a local repository.
61-- @param repo string: The pathname of the local repository.
62-- @param query table: a query object.
63-- @param result_tree table or nil: If given, this table will store the
64-- result tree; if not given, a new table will be created.
65-- @return table: The result tree, where keys are package names and
66-- values are tables matching version strings to arrays of
67-- tables with fields "arch" and "repo".
68-- If a table was given in the "result_tree" parameter, that is the result value.
69function search.disk_search(repo: string, query: Query, result_tree: {string: {string: {Result}}}): {string: {string: {Result}}}
70
71 local fs = require("luarocks.fs")
72
73 if not result_tree then
74 result_tree = {}
75 end
76
77 for name in fs.dir(repo) do
78 local pathname = dir.path(repo, name)
79 local rname, rversion, rarch = path.parse_name(name)
80
81 if rname and (pathname:match(".rockspec$") or pathname:match(".rock$")) then
82 local result = results.new(rname, rversion, repo, rarch)
83 store_if_match(result_tree, result, query)
84 elseif fs.is_dir(pathname) then
85 for version in fs.dir(pathname) do
86 if version:match("-%d+$") then
87 local namespace = path.read_namespace(name, version, repo)
88 local result = results.new(name, version, repo, "installed", namespace)
89 store_if_match(result_tree, result, query)
90 end
91 end
92 end
93 end
94 return result_tree
95end
96
97--- Perform search on a rocks server or tree.
98-- @param result_tree table: The result tree, where keys are package names and
99-- values are tables matching version strings to arrays of
100-- tables with fields "arch" and "repo".
101-- @param repo string: The URL of a rocks server or
102-- the pathname of a rocks tree (as returned by path.rocks_dir()).
103-- @param query table: a query object.
104-- @param lua_version string: Lua version in "5.x" format, defaults to installed version.
105-- @param is_local boolean
106-- @return true or, in case of errors, nil, an error message and an optional error code.
107local function manifest_search(result_tree: {string: {string: {Result}}}, repo: string, query: Query, lua_version: string, is_local: boolean): boolean, string, string
108
109 -- FIXME do not add this in local repos
110 if (not is_local) and query.namespace then
111 repo = repo .. "/manifests/" .. query.namespace
112 end
113
114 local manifest, err, errcode = manif.load_manifest(repo, lua_version, not is_local)
115 if not manifest then
116 return nil, err, errcode
117 end
118 for name, versions in pairs(manifest.repository) do
119 for version, items in pairs(versions) do
120 local namespace = is_local and path.read_namespace(name, version, repo) or query.namespace
121 for _, item in ipairs(items) do
122 local result = results.new(name, version, repo, item.arch, namespace)
123 store_if_match(result_tree, result, query)
124 end
125 end
126 end
127 return true
128end
129
130local function remote_manifest_search(result_tree: {string: {string: {Result}}}, repo: string, query: Query, lua_version?: string): boolean, string, string
131 return manifest_search(result_tree, repo, query, lua_version, false)
132end
133
134function search.local_manifest_search(result_tree: {string: {string: {Result}}}, repo: string, query: Query, lua_version?: string): boolean, string, string
135 return manifest_search(result_tree, repo, query, lua_version, true)
136end
137
138--- Search on all configured rocks servers.
139-- @param query table: a query object.
140-- @param lua_version string: Lua version in "5.x" format, defaults to installed version.
141-- @return table: A table where keys are package names
142-- and values are tables matching version strings to arrays of
143-- tables with fields "arch" and "repo".
144function search.search_repos(query: Query, lua_version?: string): {string : {string : {Result}}}
145
146 local result_tree = {}
147 local repo = {}
148 for _, repostr in ipairs(cfg.rocks_servers) do
149 if repostr is string then
150 repo = { repostr }
151 else
152 repo = repostr
153 end
154 for _, mirror in ipairs(repo) do
155 if not cfg.disabled_servers[mirror] then
156 local protocol, pathname = dir.split_url(mirror)
157 if protocol == "file" then
158 mirror = pathname
159 end
160 local ok, err, errcode = remote_manifest_search(result_tree, mirror, query, lua_version)
161 if errcode == "network" then
162 cfg.disabled_servers[mirror] = true
163 end
164 if ok then
165 break
166 else
167 util.warning("Failed searching manifest: "..err)
168 if errcode == "downloader" then
169 break
170 end
171 end
172 end
173 end
174 end
175 -- search through rocks in rocks_provided
176 local provided_repo = "provided by VM or rocks_provided"
177 for name, version in pairs(util.get_rocks_provided()) do
178 local result = results.new(name, version, provided_repo, "installed")
179 store_if_match(result_tree, result, query)
180 end
181 return result_tree
182end
183
184--- Get the URL for the latest in a set of versions.
185-- @param name string: The package name to be used in the URL.
186-- @param versions table: An array of version informations, as stored
187-- in search result trees.
188-- @return string or nil: the URL for the latest version if one could
189-- be picked, or nil.
190local function pick_latest_version(name: string, versions: {string: {Result}}): string
191 assert(not name:match("/"))
192
193 local vtables = {}
194 for v, _ in pairs(versions) do
195 table.insert(vtables, vers.parse_version(v))
196 end
197 table.sort(vtables)
198 local version = vtables[#vtables].string
199 local items = versions[version]
200 if items then
201 local pick = 1
202 for i, item in ipairs(items) do
203 if (item.arch == 'src' and items[pick].arch == 'rockspec')
204 or (item.arch ~= 'src' and item.arch ~= 'rockspec') then
205 pick = i
206 end
207 end
208 return path.make_url(items[pick].repo, name, version, items[pick].arch)
209 end
210 return nil
211end
212
213-- Find out which other Lua versions provide rock versions matching a query,
214-- @param query table: a query object.
215-- @return table: array of Lua versions supported, in "5.x" format.
216local function supported_lua_versions(query: Query): {string}
217 local result_tree = {}
218
219 for lua_version in util.lua_versions() do
220 if lua_version ~= cfg.lua_version then
221 util.printout("Checking for Lua " .. lua_version .. "...")
222 if search.search_repos(query, lua_version)[query.name] then
223 table.insert(result_tree, lua_version)
224 end
225 end
226 end
227
228 return result_tree
229end
230
231--- Attempt to get a single URL for a given search for a rock.
232-- @param query table: a query object.
233-- @return string or (nil, string, string): URL for latest matching version
234-- of the rock if it was found, or nil followed by an error message
235-- and an error code.
236function search.find_suitable_rock(query: Query): string, string, string
237
238 local rocks_provided = util.get_rocks_provided()
239
240 if rocks_provided[query.name] ~= nil then
241 -- Do not install versions listed in rocks_provided.
242 return nil, "Rock "..query.name.." "..rocks_provided[query.name]..
243 " is already provided by VM or via 'rocks_provided' in the config file.", "provided"
244 end
245
246 local result_tree = search.search_repos(query)
247 local first_rock = next(result_tree)
248 if not first_rock then
249 return nil, "No results matching query were found for Lua " .. cfg.lua_version .. ".", "notfound"
250 elseif next(result_tree, first_rock) ~= nil then
251 -- Shouldn't happen as query must match only one package.
252 return nil, "Several rocks matched query.", "manyfound"
253 else
254 return pick_latest_version(query.name, result_tree[first_rock])
255 end
256end
257
258function search.find_rock_checking_lua_versions(query: Query, check_lua_versions): string, string
259 local url, err, errcode = search.find_suitable_rock(query)
260 if url then
261 return url
262 end
263
264 if errcode == "notfound" then
265 local add: string
266 if check_lua_versions then
267 util.printout(query.name .. " not found for Lua " .. cfg.lua_version .. ".")
268 util.printout("Checking if available for other Lua versions...")
269
270 -- Check if constraints are satisfiable with other Lua versions.
271 local lua_versions = supported_lua_versions(query)
272
273 if #lua_versions ~= 0 then
274 -- Build a nice message in "only Lua 5.x and 5.y but not 5.z." format
275 for i, lua_version in ipairs(lua_versions) do
276 lua_versions[i] = "Lua "..lua_version
277 end
278
279 local versions_message = "only "..table.concat(lua_versions, " and ")..
280 " but not Lua "..cfg.lua_version.."."
281
282 if #query.constraints == 0 then
283 add = query.name.." supports "..versions_message
284 elseif #query.constraints == 1 and query.constraints[1].op == "==" then
285 local queryversionstr: string
286 local queryversion = query.constraints[1].version
287 if queryversion is Version then
288 queryversionstr = queryversion.string
289 else
290 queryversionstr = queryversion
291 end
292 add = query.name.." "..queryversionstr.." supports "..versions_message
293 else
294 add = "Matching "..query.name.." versions support "..versions_message
295 end
296 else
297 add = query.name.." is not available for any Lua versions."
298 end
299 else
300 add = "To check if it is available for other Lua versions, use --check-lua-versions."
301 end
302 err = err .. "\n" .. add
303 end
304
305 return nil, err
306end
307
308function search.find_src_or_rockspec(name: string, namespace: string, version: string, check_lua_versions): string, string
309 local query = queries.new(name, namespace, version, false, "src|rockspec")
310 local url, err = search.find_rock_checking_lua_versions(query, check_lua_versions)
311 if not url then
312 return nil, "Could not find a result named "..tostring(query)..": "..err
313 end
314 return url
315end
316
317--- Print a list of rocks/rockspecs on standard output.
318-- @param result_tree table: A result tree.
319-- @param porcelain boolean or nil: A flag to force machine-friendly output.
320function search.print_result_tree(result_tree: {string: {string: {Result}}}, porcelain?: boolean)
321
322 if porcelain then
323 for packagestr, versions in util.sortedpairs(result_tree) do
324 for version, repos in util.sortedpairs(versions, vers.compare_versions) do
325 for _, repo in ipairs(repos) do
326 local nrepo = dir.normalize(repo.repo)
327 util.printout(packagestr, version, repo.arch, nrepo, repo.namespace)
328 end
329 end
330 end
331 return
332 end
333
334 for packagestr, versions in util.sortedpairs(result_tree) do
335 local namespaces: {string: {string}} = {}
336 for version, repos in util.sortedpairs(versions, vers.compare_versions) do
337 for _, repo in ipairs(repos) do
338 local key = repo.namespace or ""
339 local list = namespaces[key] or {}
340 namespaces[key] = list
341
342 repo.repo = dir.normalize(repo.repo)
343 table.insert(list, " "..version.." ("..repo.arch..") - "..path.root_dir(repo.repo))
344 end
345 end
346 for key, list in util.sortedpairs(namespaces) do
347 util.printout(key == "" and packagestr or key .. "/" .. packagestr)
348 for _, line in ipairs(list) do
349 util.printout(line)
350 end
351 util.printout()
352 end
353 end
354end
355
356function search.pick_installed_rock(query: Query, given_tree: string | Tree): string, string, string | Tree, string
357
358 local result_tree = {}
359 local tree_map = {}
360 local trees = cfg.rocks_trees
361 if given_tree then
362 trees = { given_tree }
363 end
364 for _, tree in ipairs(trees) do
365 local rocks_dir = path.rocks_dir(tree)
366 tree_map[rocks_dir] = tree
367 search.local_manifest_search(result_tree, rocks_dir, query)
368 end
369 if not next(result_tree) then
370 return nil, "cannot find package "..tostring(query).."\nUse 'list' to find installed rocks."
371 end
372
373 if not result_tree[query.name] and next(result_tree, next(result_tree) as string) ~= nil then
374 local out = { "multiple installed packages match the name '"..tostring(query).."':\n\n" }
375 for name, _ in util.sortedpairs(result_tree) do
376 table.insert(out, " " .. name .. "\n")
377 end
378 table.insert(out, "\nPlease specify a single rock.\n")
379 return nil, table.concat(out)
380 end
381
382 local repo_url: string
383
384 local name, versions: string, {string : {Result}}
385 if result_tree[query.name] then
386 name, versions = query.name, result_tree[query.name]
387 else
388 name, versions = util.sortedpairs(result_tree)()
389 end
390
391 local version, repositories = util.sortedpairs(versions, vers.compare_versions)()
392 for _, rp in ipairs(repositories) do repo_url = rp.repo end
393
394 local repo = tree_map[repo_url]
395 return name, version, repo, repo_url
396end
397
398return search
399
diff --git a/src/luarocks/util.tl b/src/luarocks/util.tl
index 9e940f8c..d57de5e8 100644
--- a/src/luarocks/util.tl
+++ b/src/luarocks/util.tl
@@ -8,13 +8,13 @@ local core = require("luarocks.core.util")
8local cfg = require("luarocks.core.cfg") 8local cfg = require("luarocks.core.cfg")
9 9
10local type o = require("luarocks.core.types.ordering") 10local type o = require("luarocks.core.types.ordering")
11local type Ordering = o.Ordering 11local type Ordering= o.Ordering
12local type SortBy = o.SortBy 12local type SortBy = o.SortBy
13 13
14local record util 14local record util
15 cleanup_path: function(string, string, string, boolean): string 15 cleanup_path: function(string, string, string, boolean): string
16 split_string: function(string, string, number): {string} 16 split_string: function(string, string, number): {string}
17 sortedpairs: function<K, V>(tbl: {K: V}, sort_by?: SortBy): function(): K, V, Ordering 17 sortedpairs: function<K, V>(tbl: {K: V}, sort_by?: SortBy): function(): K, V, Ordering<K>
18 deep_merge: function({any : any}, {any : any}) 18 deep_merge: function({any : any}, {any : any})
19 deep_merge_under: function({any : any}, {any : any}) 19 deep_merge_under: function({any : any}, {any : any})
20 popen_read: function(string, ?string): string 20 popen_read: function(string, ?string): string
@@ -164,7 +164,7 @@ function util.variable_substitutions<K>(tbl: {K: string}, vars: {string: string}
164 end 164 end
165end 165end
166 166
167function util.lua_versions(sort: string): function(): string 167function util.lua_versions(sort?: string): function(): string
168 local versions = { "5.1", "5.2", "5.3", "5.4" } 168 local versions = { "5.1", "5.2", "5.3", "5.4" }
169 local i = 0 169 local i = 0
170 if sort == "descending" then 170 if sort == "descending" then
@@ -560,7 +560,7 @@ end
560-- @return a table with rock names as keys and versions and values, 560-- @return a table with rock names as keys and versions and values,
561-- specifying modules that are already provided by the VM (including 561-- specifying modules that are already provided by the VM (including
562-- "lua" for the Lua version and, for format 3.0+, "luajit" if detected). 562-- "lua" for the Lua version and, for format 3.0+, "luajit" if detected).
563function util.get_rocks_provided(rockspec: Rockspec): {string: string} 563function util.get_rocks_provided(rockspec?: Rockspec): {string: string}
564 564
565 if not rockspec and cfg.cache.rocks_provided then 565 if not rockspec and cfg.cache.rocks_provided then
566 return cfg.cache.rocks_provided 566 return cfg.cache.rocks_provided