aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorV1K1NGbg <victor@ilchev.com>2024-08-05 19:41:58 +0300
committerV1K1NGbg <victor@ilchev.com>2024-08-05 20:51:31 +0300
commite33a230018ef6a8df918d061180ccf8d79921447 (patch)
treebeaadb9ed7060dc26521b3f69d716b3698f16dd4
parent515bce044a68283f460b37a08f4c6ec24ec98d53 (diff)
downloadluarocks-e33a230018ef6a8df918d061180ccf8d79921447.tar.gz
luarocks-e33a230018ef6a8df918d061180ccf8d79921447.tar.bz2
luarocks-e33a230018ef6a8df918d061180ccf8d79921447.zip
core types definition
-rw-r--r--src/luarocks/core/cfg.d.tl135
-rw-r--r--src/luarocks/core/manif.tl35
-rw-r--r--src/luarocks/core/path.tl3
-rw-r--r--src/luarocks/core/types/manifest.d.tl22
-rw-r--r--src/luarocks/core/types/ordering.d.tl10
-rw-r--r--src/luarocks/core/types/query.d.tl15
-rw-r--r--src/luarocks/core/types/rockspec.d.tl124
-rw-r--r--src/luarocks/core/types/tree.d.tl10
-rw-r--r--src/luarocks/core/types/version.d.tl18
-rw-r--r--src/luarocks/core/util.tl17
-rw-r--r--src/luarocks/core/vers.tl20
-rw-r--r--src/luarocks/deps.tl836
-rw-r--r--src/luarocks/fetch.tl5
-rw-r--r--src/luarocks/fetch/cvs.tl4
-rw-r--r--src/luarocks/fetch/git.tl7
-rw-r--r--src/luarocks/fetch/git_file.tl4
-rw-r--r--src/luarocks/fetch/git_http.tl4
-rw-r--r--src/luarocks/fetch/git_ssh.tl4
-rw-r--r--src/luarocks/fetch/hg.tl4
-rw-r--r--src/luarocks/fetch/hg_http.tl4
-rw-r--r--src/luarocks/fetch/sscm.tl6
-rw-r--r--src/luarocks/fetch/svn.tl6
-rw-r--r--src/luarocks/loader.tl270
-rw-r--r--src/luarocks/manif.tl9
-rw-r--r--src/luarocks/path.tl3
-rw-r--r--src/luarocks/queries.tl32
-rw-r--r--src/luarocks/results.tl4
-rw-r--r--src/luarocks/rockspecs.tl12
-rw-r--r--src/luarocks/test.tl100
-rw-r--r--src/luarocks/type/manifest.tl2
-rw-r--r--src/luarocks/type/rockspec.tl5
-rw-r--r--src/luarocks/util.tl3
32 files changed, 1491 insertions, 242 deletions
diff --git a/src/luarocks/core/cfg.d.tl b/src/luarocks/core/cfg.d.tl
index 95d3aae7..bbb070f2 100644
--- a/src/luarocks/core/cfg.d.tl
+++ b/src/luarocks/core/cfg.d.tl
@@ -1,3 +1,9 @@
1local type rockspec = require("luarocks.core.types.rockspec")
2local type Rockspec = rockspec.Rockspec
3local type Variables = rockspec.Variables
4local type tree = require("luarocks.core.types.tree")
5local type Tree = tree.Tree
6
1local record cfg 7local record cfg
2 detect_sysconfdir: function(): string 8 detect_sysconfdir: function(): string
3 make_platforms: function(system: string): {any: boolean} 9 make_platforms: function(system: string): {any: boolean}
@@ -18,136 +24,7 @@ local record cfg
18 lib_extension: string 24 lib_extension: string
19 local_cache: string 25 local_cache: string
20 only_sources_from: string 26 only_sources_from: string
21 record Tree
22 root: string
23 rocks_dir: string
24 lua_dir: string
25 lib_dir: string
26 end
27 record Description
28 summary: string
29 detailed: string
30 homepage: string
31 issues_url: string
32 maintainer: string
33 license: string
34 labels: any --!
35 end
36
37 record Variables
38 HG: string
39 CVS: string
40 LUA: string
41 GPG: string
42 GIT: string
43 SVN: string
44 CURL: string
45 SSCM: string
46 PREFIX: string
47 LUADIR: string
48 LIBDIR: string
49 CONFDIR: string
50 BINDIR: string
51 DOCDIR: string
52 CURLNOCERTFLAG: string
53 end
54
55 record Source
56 url: string
57 module: string
58 pathname: string
59 tag: string
60 md5: string
61 file: string
62 dir: string
63 branch: string
64 cvs_tag: string
65 cvs_module: string
66 protocol: string --! not in the rockspec definition but used
67 dir_set: boolean
68 identifier: string
69 platforms: any --!
70 end
71
72 record Test
73 type: string
74 platforms: any --! {{string: any}}?
75 end
76
77 record Install
78 lua: any
79 lib: any
80 conf: any
81 bin: any
82 end
83
84 record Build
85 type: string
86 modules: string
87 copy_directories: string
88 platforms: any --!
89 install: Install
90 end
91
92 record Dependencie --!1 --? Query??
93
94 end
95 27
96 record Dependencies
97 {Dependencie} --!1
98 platforms: any --!
99 end
100
101 record BuildDependencies
102 {Dependencie} --!1
103 platforms: any --!
104 end
105
106 record SupportedPlatforms
107 end
108
109 record ExternalDependencies
110 {Dependencie} --!1
111 platforms: any --!
112 end
113
114 record TestDependencies
115 {Dependencie} --!1
116 platforms: any --!
117 end
118
119 record Hooks
120 post_install: string
121 platforms: any --!
122 end
123
124 record Deploy
125 wrap_bin_scripts: boolean
126 end
127
128 record Rockspec
129 rockspec_format: string
130 name: string --! not in the rockspec definition but used
131 package: string
132 version: string
133 local_abs_filename: string
134 rocks_provided: {string : string}
135 source: Source
136 description: Description
137 build: Build
138 dependencies: Dependencies
139 build_dependencies: BuildDependencies
140 test_dependencies: TestDependencies
141 supported_platforms: SupportedPlatforms
142 external_dependencies: ExternalDependencies
143 variables: Variables
144 hooks: Hooks
145 test: Test
146 deploy: Deploy
147 type: function(Rockspec): string
148 format_is_at_least: function(Rockspec, string): boolean
149 end
150
151 record cache 28 record cache
152 luajit_version_checked: boolean 29 luajit_version_checked: boolean
153 luajit_version: string 30 luajit_version: string
diff --git a/src/luarocks/core/manif.tl b/src/luarocks/core/manif.tl
index cfa53dd0..742e64b7 100644
--- a/src/luarocks/core/manif.tl
+++ b/src/luarocks/core/manif.tl
@@ -7,35 +7,20 @@ local util = require("luarocks.core.util")
7local vers = require("luarocks.core.vers") 7local vers = require("luarocks.core.vers")
8local path = require("luarocks.core.path") 8local path = require("luarocks.core.path")
9 9
10local type Constraint = vers.Constraint 10local type tree = require("luarocks.core.types.tree")
11local type Tree = tree.Tree
11 12
12--- Core functions for querying manifest files. 13--- Core functions for querying manifest files.
13local record manif 14local record manif
14
15 record DependencyVersion
16 constraints: {Constraint}
17 name: string
18 end
19
20 record Manifest
21 arch: string
22 commands: {string: {string}}
23 dependencies: {string: {string: {DependencyVersion}}}
24 modules: {string: {string}}
25 repository: {string: {string: Manifest}}
26 end
27
28 record Tree_manifest
29 tree: cfg.Tree
30 manifest: Manifest
31 end
32end 15end
33 16
34-------------------------------------------------------------------------------- 17--------------------------------------------------------------------------------
35 18local type query = require("luarocks.core.types.query")
36local type DependencyVersion = manif.DependencyVersion 19local type Query = query.Query
37local type Manifest = manif.Manifest 20
38local type Tree_manifest = manif.Tree_manifest 21local type manifest = require("luarocks.core.types.manifest")
22local type Manifest = manifest.Manifest
23local type Tree_manifest = manifest.Tree_manifest
39 24
40 25
41 26
@@ -98,7 +83,7 @@ end
98 83
99function manif.load_rocks_tree_manifests(deps_mode?: string): {Tree_manifest} 84function manif.load_rocks_tree_manifests(deps_mode?: string): {Tree_manifest}
100 local trees = {} 85 local trees = {}
101 path.map_trees(deps_mode, function(tree: cfg.Tree) 86 path.map_trees(deps_mode, function(tree: Tree)
102 local manifest= manif.fast_load_local_manifest(path.rocks_dir(tree)) 87 local manifest= manif.fast_load_local_manifest(path.rocks_dir(tree))
103 if manifest then 88 if manifest then
104 table.insert(trees, {tree=tree, manifest=manifest}) 89 table.insert(trees, {tree=tree, manifest=manifest})
@@ -116,7 +101,7 @@ function manif.scan_dependencies(name: string, version: string, tree_manifests:
116 for _, tree in ipairs(tree_manifests) do 101 for _, tree in ipairs(tree_manifests) do
117 local manifest = tree.manifest 102 local manifest = tree.manifest
118 103
119 local pkgdeps: {DependencyVersion} 104 local pkgdeps: {Query}
120 if manifest.dependencies and manifest.dependencies[name] then 105 if manifest.dependencies and manifest.dependencies[name] then
121 pkgdeps = manifest.dependencies[name][version] 106 pkgdeps = manifest.dependencies[name][version]
122 end 107 end
diff --git a/src/luarocks/core/path.tl b/src/luarocks/core/path.tl
index 213c0d69..563a36ef 100644
--- a/src/luarocks/core/path.tl
+++ b/src/luarocks/core/path.tl
@@ -5,7 +5,8 @@ end
5local cfg = require("luarocks.core.cfg") 5local cfg = require("luarocks.core.cfg")
6local dir = require("luarocks.core.dir") 6local dir = require("luarocks.core.dir")
7 7
8local type Tree = cfg.Tree 8local type tree = require("luarocks.core.types.tree")
9local type Tree = tree.Tree
9 10
10local dir_sep = package.config:sub(1, 1) 11local dir_sep = package.config:sub(1, 1)
11-------------------------------------------------------------------------------- 12--------------------------------------------------------------------------------
diff --git a/src/luarocks/core/types/manifest.d.tl b/src/luarocks/core/types/manifest.d.tl
new file mode 100644
index 00000000..f24869b9
--- /dev/null
+++ b/src/luarocks/core/types/manifest.d.tl
@@ -0,0 +1,22 @@
1local type query = require("luarocks.core.types.query")
2local type Query = query.Query
3
4local type tree = require("luarocks.core.types.tree")
5local type Tree = tree.Tree
6
7local record manifest
8 record Manifest
9 arch: string
10 commands: {string: {string}}
11 dependencies: {string: {string: {Query}}}
12 modules: {string: {string}}
13 repository: {string: {string: {Manifest}}}
14 end
15
16 record Tree_manifest
17 tree: Tree
18 manifest: Manifest
19 end
20 end
21
22 return manifest \ No newline at end of file
diff --git a/src/luarocks/core/types/ordering.d.tl b/src/luarocks/core/types/ordering.d.tl
new file mode 100644
index 00000000..c16140f8
--- /dev/null
+++ b/src/luarocks/core/types/ordering.d.tl
@@ -0,0 +1,10 @@
1local record ordering
2 record Ordering<K>
3 is {K}
4 sub_orders: {K: Ordering<K>}
5 end
6
7 type SortBy<K> = table.SortFunction<K> | Ordering<K>
8 end
9
10 return ordering \ No newline at end of file
diff --git a/src/luarocks/core/types/query.d.tl b/src/luarocks/core/types/query.d.tl
new file mode 100644
index 00000000..e1ef21b6
--- /dev/null
+++ b/src/luarocks/core/types/query.d.tl
@@ -0,0 +1,15 @@
1local type version = require("luarocks.core.types.version")
2local type Constraint = version.Constraint
3
4local record query
5 record Query
6 name: string
7 namespace: string
8 constraints: {Constraint}
9 substring: boolean
10 arch: {string: boolean}
11 type: function(): string
12 end
13end
14
15return query \ No newline at end of file
diff --git a/src/luarocks/core/types/rockspec.d.tl b/src/luarocks/core/types/rockspec.d.tl
new file mode 100644
index 00000000..438391fa
--- /dev/null
+++ b/src/luarocks/core/types/rockspec.d.tl
@@ -0,0 +1,124 @@
1local type query = require("luarocks.core.types.query")
2local type Query = query.Query
3
4local record rockspec
5 record Description
6 summary: string
7 detailed: string
8 homepage: string
9 issues_url: string
10 maintainer: string
11 license: string
12 labels: any --!
13 end
14
15 record Variables
16 HG: string
17 CVS: string
18 LUA: string
19 GPG: string
20 GIT: string
21 SVN: string
22 CURL: string
23 SSCM: string
24 PREFIX: string
25 LUADIR: string
26 LIBDIR: string
27 CONFDIR: string
28 BINDIR: string
29 DOCDIR: string
30 CURLNOCERTFLAG: string
31 end
32
33 record Source
34 url: string
35 module: string
36 pathname: string
37 tag: string
38 md5: string
39 file: string
40 dir: string
41 branch: string
42 cvs_tag: string
43 cvs_module: string
44 protocol: string --! not in the rockspec definition but used
45 dir_set: boolean
46 identifier: string
47 end
48
49 record Test
50 type: string
51 end
52
53 record Install
54 lua: any
55 lib: any
56 conf: any
57 bin: any
58 end
59
60 record Build
61 type: string
62 modules: string
63 copy_directories: string
64 install: Install
65 end
66
67 record Dependencies
68 {string}
69 -- when converted:
70 queries: {Query}
71 end
72
73 record BuildDependencies
74 {string}
75 queries: {Query}
76 end
77
78 record SupportedPlatforms
79 end
80
81 record ExternalDependencies
82 {string}
83 queries: {Query}
84 end
85
86 record TestDependencies
87 {string}
88 queries: {Query}
89 end
90
91 record Hooks
92 post_install: string
93
94 end
95
96 record Deploy
97 wrap_bin_scripts: boolean
98 end
99
100 record Rockspec
101 rockspec_format: string
102 name: string --! not in the rockspec definition but used
103 package: string
104 version: string
105 local_abs_filename: string
106 rocks_provided: {string : string}
107 source: Source
108 description: Description
109 build: Build
110 dependencies: Dependencies
111 build_dependencies: BuildDependencies
112 test_dependencies: TestDependencies
113 supported_platforms: SupportedPlatforms
114 external_dependencies: ExternalDependencies
115 variables: Variables
116 hooks: Hooks
117 test: Test
118 deploy: Deploy
119 type: function(): string
120 format_is_at_least: function(Rockspec, string): boolean
121 end
122end
123
124return rockspec \ No newline at end of file
diff --git a/src/luarocks/core/types/tree.d.tl b/src/luarocks/core/types/tree.d.tl
new file mode 100644
index 00000000..df54def9
--- /dev/null
+++ b/src/luarocks/core/types/tree.d.tl
@@ -0,0 +1,10 @@
1local record tree
2 record Tree
3 root: string
4 rocks_dir: string
5 lua_dir: string
6 lib_dir: string
7 end
8end
9
10return tree \ No newline at end of file
diff --git a/src/luarocks/core/types/version.d.tl b/src/luarocks/core/types/version.d.tl
new file mode 100644
index 00000000..92a80996
--- /dev/null
+++ b/src/luarocks/core/types/version.d.tl
@@ -0,0 +1,18 @@
1local record version
2 record Version
3 is {number}
4 string: string
5 revision: number
6 metamethod __eq: function(Version, Version): boolean
7 metamethod __lt: function(Version, Version): boolean
8 metamethod __le: function(Version, Version): boolean
9 end
10
11 record Constraint
12 op: string
13 version: Version | string
14 no_upgrade: boolean
15 end
16 end
17
18 return version \ No newline at end of file
diff --git a/src/luarocks/core/util.tl b/src/luarocks/core/util.tl
index 76d7b42e..ad6d8f9e 100644
--- a/src/luarocks/core/util.tl
+++ b/src/luarocks/core/util.tl
@@ -1,16 +1,13 @@
1 1
2local record util 2local record util
3 record Ordering<K>
4 {K}
5
6 sub_orders: {K: Ordering<K>}
7 end
8
9 type SortBy<K> = table.SortFunction<K> | util.Ordering<K>
10end 3end
11 4
12-------------------------------------------------------------------------------- 5--------------------------------------------------------------------------------
13 6
7local type ordering = require("luarocks.core.types.ordering")
8local type Ordering<K> = ordering.Ordering<K>
9local type SortBy<K> = ordering.SortBy<K>
10
14local dir_sep = package.config:sub(1, 1) 11local dir_sep = package.config:sub(1, 1)
15 12
16--- Run a process and read a its output. 13--- Run a process and read a its output.
@@ -292,9 +289,9 @@ end
292-- for that key, which is returned by the iterator as the third value after the key 289-- for that key, which is returned by the iterator as the third value after the key
293-- and the value. 290-- and the value.
294-- @return function: the iterator function. 291-- @return function: the iterator function.
295function util.sortedpairs<K, V>(tbl: {K: V}, sort_by?: util.SortBy<K>): function(): K, V, util.Ordering<K> 292function util.sortedpairs<K, V>(tbl: {K: V}, sort_by?: SortBy<K>): function(): K, V, Ordering<K>
296 local keys = util.keys(tbl) 293 local keys = util.keys(tbl)
297 local sub_orders: {K: util.Ordering<K>} = nil 294 local sub_orders: {K: Ordering<K>} = nil
298 295
299 if sort_by == nil then 296 if sort_by == nil then
300 table.sort(keys, default_sort) 297 table.sort(keys, default_sort)
@@ -328,7 +325,7 @@ function util.sortedpairs<K, V>(tbl: {K: V}, sort_by?: util.SortBy<K>): function
328 end 325 end
329 326
330 local i = 1 327 local i = 1
331 return function(): K, V, util.Ordering<K> 328 return function(): K, V, Ordering<K>
332 local key = keys[i] 329 local key = keys[i]
333 i = i + 1 330 i = i + 1
334 return key, tbl[key], sub_orders and sub_orders[key] 331 return key, tbl[key], sub_orders and sub_orders[key]
diff --git a/src/luarocks/core/vers.tl b/src/luarocks/core/vers.tl
index eae6d3d5..ab1c6c5b 100644
--- a/src/luarocks/core/vers.tl
+++ b/src/luarocks/core/vers.tl
@@ -1,21 +1,10 @@
1local record vers 1local record vers
2 record Version
3 {number} -- next version of Teal: "is {number}"
4 string: string
5 revision: number
6 metamethod __eq: function(Version, Version): boolean
7 metamethod __lt: function(Version, Version): boolean
8 metamethod __le: function(Version, Version): boolean
9 end
10
11 record Constraint
12 op: string
13 version: Version | string
14 no_upgrade: boolean
15 end
16end 2end
17 3
18local util = require("luarocks.core.util") 4local util = require("luarocks.core.util")
5local type version = require("luarocks.core.types.version")
6local type Version = version.Version
7local type Constraint = version.Constraint
19-------------------------------------------------------------------------------- 8--------------------------------------------------------------------------------
20 9
21local deltas: {string: integer} = { 10local deltas: {string: integer} = {
@@ -28,9 +17,6 @@ local deltas: {string: integer} = {
28 alpha = -1000000 17 alpha = -1000000
29} 18}
30 19
31local type Version = vers.Version
32local type Constraint = vers.Constraint
33
34local version_mt: metatable<Version> = { 20local version_mt: metatable<Version> = {
35 --- Equality comparison for versions. 21 --- Equality comparison for versions.
36 -- All version numbers must be equal. 22 -- All version numbers must be equal.
diff --git a/src/luarocks/deps.tl b/src/luarocks/deps.tl
new file mode 100644
index 00000000..8fe9feff
--- /dev/null
+++ b/src/luarocks/deps.tl
@@ -0,0 +1,836 @@
1
2--- High-level dependency related functions.
3local record deps
4end
5
6local cfg = require("luarocks.core.cfg")
7local manif = require("luarocks.manif")
8local path = require("luarocks.path")
9local dir = require("luarocks.dir")
10local fun = require("luarocks.fun")
11local util = require("luarocks.util")
12local vers = require("luarocks.core.vers")
13local queries = require("luarocks.queries")
14local deplocks = require("luarocks.deplocks")
15
16local type rockspec = require("luarocks.core.types.rockspec")
17local type Rockspec = rockspec.Rockspec
18
19local type tree = require("luarocks.core.types.tree")
20local type Tree = tree.Tree
21
22local core = require("luarocks.core.manif")
23local type DependencyVersion = core.DependencyVersion
24local type version = require("luarocks.core.types.version")
25local type Version = version.Version
26
27--- Generate a function that matches dep queries against the manifest,
28-- taking into account rocks_provided, the list of versions to skip,
29-- and the lockfile.
30-- @param deps_mode "one", "none", "all" or "order"
31-- @param rocks_provided a one-level table mapping names to versions,
32-- listing rocks to consider provided by the VM
33-- @param rocks_provided table: A table of auto-provided dependencies.
34-- by this Lua implementation for the given dependency.
35-- @param depskey key to use when matching the lockfile ("dependencies",
36-- "build_dependencies", etc.)
37-- @param skip_set a two-level table mapping names to versions to
38-- boolean, listing rocks that should not be matched
39-- @return function(dep): {string}, {string:string}, string, boolean
40-- * array of matching versions
41-- * map of versions to locations
42-- * version matched via lockfile if any
43-- * true if rock matched via rocks_provided
44local function prepare_get_versions(deps_mode: string, rocks_provided: {string : string}, depskey: string, skip_set?): function(DependencyVersion): {string}, {string: string | Tree}, string, boolean
45
46 return function(dep: DependencyVersion): {string}, {string: string | Tree}, string, boolean
47 local versions, locations: {string}, {string: string | Tree}
48 local provided = rocks_provided[dep.name]
49 if provided then
50 -- Provided rocks have higher priority than manifest's rocks.
51 versions, locations = { provided }, {}
52 else
53 if deps_mode == "none" then
54 deps_mode = "one"
55 end
56 versions, locations = manif.get_versions(dep, deps_mode)
57 end
58
59 if skip_set and skip_set[dep.name] then
60 for i = #versions, 1, -1 do
61 local v = versions[i]
62 if skip_set[dep.name][v] then
63 table.remove(versions, i)
64 end
65 end
66 end
67
68 local lockversion = deplocks.get(depskey, dep.name) --! cast?
69
70 return versions, locations, lockversion, provided ~= nil
71 end
72end
73
74--- Attempt to match a dependency to an installed rock.
75-- @param get_versions a getter function obtained via prepare_get_versions
76-- @return (string, string, table) or (nil, nil, table):
77-- 1. latest installed version of the rock matching the dependency
78-- 2. location where the installed version is installed
79-- 3. the 'dep' query table
80-- 4. true if provided via VM
81-- or
82-- 1. nil
83-- 2. nil
84-- 3. either 'dep' or an alternative query to be used
85-- 4. false
86local function match_dep(dep: DependencyVersion,
87 get_versions: function(DependencyVersion): {string}, {string: string | Tree}, string, boolean): string, string | Tree, DependencyVersion, boolean
88
89 local versions, locations, lockversion, provided = get_versions(dep)
90
91 local latest_version: Version
92 local latest_vstring: string
93 for _, vstring in ipairs(versions) do
94 local version = vers.parse_version(vstring)
95 if vers.match_constraints(version, dep.constraints) then
96 if not latest_version or version > latest_version then
97 latest_version = version
98 latest_vstring = vstring
99 end
100 end
101 end
102
103 if lockversion and not locations[lockversion] then
104 local latest_matching_msg = ""
105 if latest_vstring and latest_vstring ~= lockversion then
106 latest_matching_msg = " (latest matching is " .. latest_vstring .. ")"
107 end
108 util.printout("Forcing " .. dep.name .. " to pinned version " .. lockversion .. latest_matching_msg)
109 return nil, nil, queries.new(dep.name, dep.namespace, lockversion)
110 end
111
112 return latest_vstring, locations[latest_vstring], dep, provided
113end
114
115local function match_all_deps(dependencies: {DependencyVersion},
116 get_versions: function(DependencyVersion): {string}, {string: string | Tree}, string, boolean): {DependencyVersion: any}, {string}, {string}
117
118 local matched, missing, no_upgrade = {}, {}, {}
119
120 for _, dep in ipairs(dependencies) do
121 local found, _, provided: string, string | Tree, boolean
122 found, _, dep, provided = match_dep(dep, get_versions)
123 if found then
124 if not provided then
125 matched[dep] = {name = dep.name, version = found}
126 end
127 else
128 if dep.constraints[1] and dep.constraints[1].no_upgrade then
129 no_upgrade[dep.name] = dep
130 else
131 missing[dep.name] = dep
132 end
133 end
134 end
135 return matched, missing, no_upgrade
136end
137
138--- Attempt to match dependencies of a rockspec to installed rocks.
139-- @param dependencies table: The table of dependencies.
140-- @param rocks_provided table: The table of auto-provided dependencies.
141-- @param skip_set table or nil: Program versions to not use as valid matches.
142-- Table where keys are program names and values are tables where keys
143-- are program versions and values are 'true'.
144-- @param deps_mode string: Which trees to check dependencies for
145-- @return table, table, table: A table where keys are dependencies parsed
146-- in table format and values are tables containing fields 'name' and
147-- version' representing matches; a table of missing dependencies
148-- parsed as tables; and a table of "no-upgrade" missing dependencies
149-- (to be used in plugin modules so that a plugin does not force upgrade of
150-- its parent application).
151function deps.match_deps(dependencies, rocks_provided, skip_set, deps_mode)
152 assert(type(dependencies) == "table")
153 assert(type(rocks_provided) == "table")
154 assert(type(skip_set) == "table" or skip_set == nil)
155 assert(type(deps_mode) == "string")
156
157 local get_versions = prepare_get_versions(deps_mode, rocks_provided, "dependencies", skip_set)
158 return match_all_deps(dependencies, get_versions)
159end
160
161local function rock_status(dep, get_versions)
162 assert(dep:type() == "query")
163 assert(type(get_versions) == "function")
164
165 local installed, _, _, provided = match_dep(dep, get_versions)
166 local installation_type = provided and "provided by VM" or "installed"
167 return installed and installed.." "..installation_type..": success" or "not installed"
168end
169
170--- Check depenendencies of a package and report any missing ones.
171-- @param name string: package name.
172-- @param version string: package version.
173-- @param dependencies table: array of dependencies.
174-- @param deps_mode string: Which trees to check dependencies for
175-- @param rocks_provided table: A table of auto-dependencies provided
176-- by this Lua implementation for the given dependency.
177-- "one" for the current default tree, "all" for all trees,
178-- "order" for all trees with priority >= the current default, "none" for no trees.
179function deps.report_missing_dependencies(name, version, dependencies, deps_mode, rocks_provided)
180 assert(type(name) == "string")
181 assert(type(version) == "string")
182 assert(type(dependencies) == "table")
183 assert(type(deps_mode) == "string")
184 assert(type(rocks_provided) == "table")
185
186 if deps_mode == "none" then
187 return
188 end
189
190 local get_versions = prepare_get_versions(deps_mode, rocks_provided, "dependencies")
191
192 local first_missing_dep = true
193
194 for _, dep in ipairs(dependencies) do
195 local found, _
196 found, _, dep = match_dep(dep, get_versions)
197 if not found then
198 if first_missing_dep then
199 util.printout(("Missing dependencies for %s %s:"):format(name, version))
200 first_missing_dep = false
201 end
202
203 util.printout((" %s (%s)"):format(tostring(dep), rock_status(dep, get_versions)))
204 end
205 end
206end
207
208function deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey)
209 assert(dep:type() == "query")
210 assert(type(deps_mode) == "string" or deps_mode == nil)
211 assert(type(rocks_provided) == "table" or rocks_provided == nil)
212 assert(type(verify) == "boolean" or verify == nil)
213 assert(type(depskey) == "string")
214
215 deps_mode = deps_mode or "all"
216 rocks_provided = rocks_provided or {}
217
218 local get_versions = prepare_get_versions(deps_mode, rocks_provided, depskey)
219
220 local found, where
221 found, where, dep = match_dep(dep, get_versions)
222 if found then
223 local tree_manifests = manif.load_rocks_tree_manifests(deps_mode)
224 manif.scan_dependencies(dep.name, found, tree_manifests, deplocks.proxy(depskey))
225 return true, found, where
226 end
227
228 local search = require("luarocks.search")
229 local install = require("luarocks.cmd.install")
230
231 local url, search_err = search.find_suitable_rock(dep)
232 if not url then
233 return nil, "Could not satisfy dependency "..tostring(dep)..": "..search_err
234 end
235 util.printout("Installing "..url)
236 local install_args = {
237 rock = url,
238 deps_mode = deps_mode,
239 namespace = dep.namespace,
240 verify = verify,
241 }
242 local ok, install_err, errcode = install.command(install_args)
243 if not ok then
244 return nil, "Failed installing dependency: "..url.." - "..install_err, errcode
245 end
246
247 found, where = match_dep(dep, get_versions)
248 assert(found)
249 return true, found, where
250end
251
252local function check_supported_platforms(rockspec)
253 if rockspec.supported_platforms and next(rockspec.supported_platforms) then
254 local all_negative = true
255 local supported = false
256 for _, plat in pairs(rockspec.supported_platforms) do
257 local neg
258 neg, plat = plat:match("^(!?)(.*)")
259 if neg == "!" then
260 if cfg.is_platform(plat) then
261 return nil, "This rockspec for "..rockspec.package.." does not support "..plat.." platforms."
262 end
263 else
264 all_negative = false
265 if cfg.is_platform(plat) then
266 supported = true
267 break
268 end
269 end
270 end
271 if supported == false and not all_negative then
272 local plats = cfg.print_platforms()
273 return nil, "This rockspec for "..rockspec.package.." does not support "..plats.." platforms."
274 end
275 end
276
277 return true
278end
279
280--- Check dependencies of a rock and attempt to install any missing ones.
281-- Packages are installed using the LuaRocks "install" command.
282-- Aborts the program if a dependency could not be fulfilled.
283-- @param rockspec table: A rockspec in table format.
284-- @param depskey string: Rockspec key to fetch to get dependency table
285-- ("dependencies", "build_dependencies", etc.).
286-- @param deps_mode string
287-- @param verify boolean
288-- @param deplock_dir string: dirname of the deplock file
289-- @return boolean or (nil, string, [string]): True if no errors occurred, or
290-- nil and an error message if any test failed, followed by an optional
291-- error code.
292function deps.fulfill_dependencies(rockspec, depskey, deps_mode, verify, deplock_dir)
293 assert(type(rockspec) == "table")
294 assert(type(depskey) == "string")
295 assert(type(deps_mode) == "string")
296 assert(type(verify) == "boolean" or verify == nil)
297 assert(type(deplock_dir) == "string" or deplock_dir == nil)
298
299 local name = rockspec.name
300 local version = rockspec.version
301 local rocks_provided = rockspec.rocks_provided
302
303 local ok, filename, err = deplocks.load(name, deplock_dir or ".")
304 if filename then
305 util.printout("Using dependencies pinned in lockfile: " .. filename)
306
307 local get_versions = prepare_get_versions("none", rocks_provided, depskey)
308 for dnsname, dversion in deplocks.each(depskey) do
309 local dname, dnamespace = util.split_namespace(dnsname)
310 local dep = queries.new(dname, dnamespace, dversion)
311
312 util.printout(("%s %s is pinned to %s (%s)"):format(
313 name, version, tostring(dep), rock_status(dep, get_versions)))
314
315 local ok, err = deps.fulfill_dependency(dep, "none", rocks_provided, verify, depskey)
316 if not ok then
317 return nil, err
318 end
319 end
320 util.printout()
321 return true
322 elseif err then
323 util.warning(err)
324 end
325
326 ok, err = check_supported_platforms(rockspec)
327 if not ok then
328 return nil, err
329 end
330
331 deps.report_missing_dependencies(name, version, rockspec[depskey], deps_mode, rocks_provided)
332
333 util.printout()
334
335 local get_versions = prepare_get_versions(deps_mode, rocks_provided, depskey)
336 for _, dep in ipairs(rockspec[depskey]) do
337
338 util.printout(("%s %s depends on %s (%s)"):format(
339 name, version, tostring(dep), rock_status(dep, get_versions)))
340
341 local ok, found_or_err, _, no_upgrade = deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey)
342 if ok then
343 deplocks.add(depskey, dep.name, found_or_err)
344 else
345 if no_upgrade then
346 util.printerr("This version of "..name.." is designed for use with")
347 util.printerr(tostring(dep)..", but is configured to avoid upgrading it")
348 util.printerr("automatically. Please upgrade "..dep.name.." with")
349 util.printerr(" luarocks install "..dep.name)
350 util.printerr("or look for a suitable version of "..name.." with")
351 util.printerr(" luarocks search "..name)
352 end
353 return nil, found_or_err
354 end
355 end
356
357 return true
358end
359
360--- If filename matches a pattern, return the capture.
361-- For example, given "libfoo.so" and "lib?.so" is a pattern,
362-- returns "foo" (which can then be used to build names
363-- based on other patterns.
364-- @param file string: a filename
365-- @param pattern string: a pattern, where ? is to be matched by the filename.
366-- @return string The pattern, if found, or nil.
367local function deconstruct_pattern(file, pattern)
368 local depattern = "^"..(pattern:gsub("%.", "%%."):gsub("%*", ".*"):gsub("?", "(.*)")).."$"
369 return (file:match(depattern))
370end
371
372--- Construct all possible patterns for a name and add to the files array.
373-- Run through the patterns array replacing all occurrences of "?"
374-- with the given file name and store them in the files array.
375-- @param file string A raw name (e.g. "foo")
376-- @param array of string An array of patterns with "?" as the wildcard
377-- (e.g. {"?.so", "lib?.so"})
378-- @param files The array of constructed names
379local function add_all_patterns(file, patterns, files)
380 for _, pattern in ipairs(patterns) do
381 table.insert(files, {#files + 1, (pattern:gsub("?", file))})
382 end
383end
384
385local function get_external_deps_dirs(mode)
386 local patterns = cfg.external_deps_patterns
387 local subdirs = cfg.external_deps_subdirs
388 if mode == "install" then
389 patterns = cfg.runtime_external_deps_patterns
390 subdirs = cfg.runtime_external_deps_subdirs
391 end
392 local dirs = {
393 BINDIR = { subdir = subdirs.bin, testfile = "program", pattern = patterns.bin },
394 INCDIR = { subdir = subdirs.include, testfile = "header", pattern = patterns.include },
395 LIBDIR = { subdir = subdirs.lib, testfile = "library", pattern = patterns.lib }
396 }
397 if mode == "install" then
398 dirs.INCDIR = nil
399 end
400 return dirs
401end
402
403local function resolve_prefix(prefix, dirs)
404 if type(prefix) == "string" then
405 return prefix
406 elseif type(prefix) == "table" then
407 if prefix.bin then
408 dirs.BINDIR.subdir = prefix.bin
409 end
410 if prefix.include then
411 if dirs.INCDIR then
412 dirs.INCDIR.subdir = prefix.include
413 end
414 end
415 if prefix.lib then
416 dirs.LIBDIR.subdir = prefix.lib
417 end
418 return prefix.prefix
419 end
420end
421
422local function add_patterns_for_file(files, file, patterns)
423 -- If it doesn't look like it contains a filename extension
424 if not (file:match("%.[a-z]+$") or file:match("%.[a-z]+%.")) then
425 add_all_patterns(file, patterns, files)
426 else
427 for _, pattern in ipairs(patterns) do
428 local matched = deconstruct_pattern(file, pattern)
429 if matched then
430 add_all_patterns(matched, patterns, files)
431 end
432 end
433 table.insert(files, {#files + 1, file})
434 end
435end
436
437local function check_external_dependency_at(prefix, name, ext_files, vars, dirs, err_files, cache)
438 local fs = require("luarocks.fs")
439 cache = cache or {}
440
441 for dirname, dirdata in util.sortedpairs(dirs) do
442 local paths
443 local path_var_value = vars[name.."_"..dirname]
444 if path_var_value then
445 paths = { path_var_value }
446 elseif type(dirdata.subdir) == "table" then
447 paths = {}
448 for i,v in ipairs(dirdata.subdir) do
449 paths[i] = dir.path(prefix, v)
450 end
451 else
452 paths = { dir.path(prefix, dirdata.subdir) }
453 end
454 local file_or_files = ext_files[dirdata.testfile]
455 if file_or_files then
456 local files = {}
457 if type(file_or_files) == "string" then
458 add_patterns_for_file(files, file_or_files, dirdata.pattern)
459 elseif type(file_or_files) == "table" then
460 for _, f in ipairs(file_or_files) do
461 add_patterns_for_file(files, f, dirdata.pattern)
462 end
463 end
464
465 local found = false
466 table.sort(files, function(a, b)
467 if (not a[2]:match("%*")) and b[2]:match("%*") then
468 return true
469 elseif a[2]:match("%*") and (not b[2]:match("%*")) then
470 return false
471 else
472 return a[1] < b[1]
473 end
474 end)
475 for _, fa in ipairs(files) do
476
477 local f = fa[2]
478 -- small convenience hack
479 if f:match("%.so$") or f:match("%.dylib$") or f:match("%.dll$") then
480 f = f:gsub("%.[^.]+$", "."..cfg.external_lib_extension)
481 end
482
483 local pattern
484 if f:match("%*") then
485 pattern = "^" .. f:gsub("([-.+])", "%%%1"):gsub("%*", ".*") .. "$"
486 f = "matching "..f
487 end
488
489 for _, d in ipairs(paths) do
490 if pattern then
491 if not cache[d] then
492 cache[d] = fs.list_dir(d)
493 end
494 local match = string.match
495 for _, entry in ipairs(cache[d]) do
496 if match(entry, pattern) then
497 found = true
498 break
499 end
500 end
501 else
502 found = fs.is_file(dir.path(d, f))
503 end
504 if found then
505 dirdata.dir = d
506 dirdata.file = f
507 break
508 else
509 table.insert(err_files[dirdata.testfile], f.." in "..d)
510 end
511 end
512 if found then
513 break
514 end
515 end
516 if not found then
517 return nil, dirname, dirdata.testfile
518 end
519 else
520 -- When we have a set of subdir suffixes, look for one that exists.
521 -- For these reason, we now put "lib" ahead of "" on Windows in our
522 -- default set.
523 dirdata.dir = paths[1]
524 for _, p in ipairs(paths) do
525 if fs.exists(p) then
526 dirdata.dir = p
527 break
528 end
529 end
530 end
531 end
532
533 for dirname, dirdata in pairs(dirs) do
534 vars[name.."_"..dirname] = dirdata.dir
535 vars[name.."_"..dirname.."_FILE"] = dirdata.file
536 end
537 vars[name.."_DIR"] = prefix
538 return true
539end
540
541local function check_external_dependency(name, ext_files, vars, mode, cache)
542 local ok
543 local err_dirname
544 local err_testfile
545 local err_files = {program = {}, header = {}, library = {}}
546
547 local dirs = get_external_deps_dirs(mode)
548
549 local prefixes
550 if vars[name .. "_DIR"] then
551 prefixes = { vars[name .. "_DIR"] }
552 elseif vars.DEPS_DIR then
553 prefixes = { vars.DEPS_DIR }
554 else
555 prefixes = cfg.external_deps_dirs
556 end
557
558 for _, prefix in ipairs(prefixes) do
559 prefix = resolve_prefix(prefix, dirs)
560 if cfg.is_platform("mingw32") and name == "LUA" then
561 dirs.LIBDIR.pattern = fun.filter(util.deep_copy(dirs.LIBDIR.pattern), function(s)
562 return not s:match("%.a$")
563 end)
564 elseif cfg.is_platform("windows") and name == "LUA" then
565 dirs.LIBDIR.pattern = fun.filter(util.deep_copy(dirs.LIBDIR.pattern), function(s)
566 return not s:match("%.dll$")
567 end)
568 end
569 ok, err_dirname, err_testfile = check_external_dependency_at(prefix, name, ext_files, vars, dirs, err_files, cache)
570 if ok then
571 return true
572 end
573 end
574
575 return nil, err_dirname, err_testfile, err_files
576end
577
578function deps.autodetect_external_dependencies(build)
579 -- only applies to the 'builtin' build type
580 if not build or not build.modules then
581 return nil
582 end
583
584 local extdeps = {}
585 local any = false
586 for _, data in pairs(build.modules) do
587 if type(data) == "table" and data.libraries then
588 local libraries = data.libraries
589 if type(libraries) == "string" then
590 libraries = { libraries }
591 end
592 local incdirs = {}
593 local libdirs = {}
594 for _, lib in ipairs(libraries) do
595 local upper = lib:upper():gsub("%+", "P"):gsub("[^%w]", "_")
596 any = true
597 extdeps[upper] = { library = lib }
598 table.insert(incdirs, "$(" .. upper .. "_INCDIR)")
599 table.insert(libdirs, "$(" .. upper .. "_LIBDIR)")
600 end
601 if not data.incdirs then
602 data.incdirs = incdirs
603 end
604 if not data.libdirs then
605 data.libdirs = libdirs
606 end
607 end
608 end
609 return any and extdeps or nil
610end
611
612--- Set up path-related variables for external dependencies.
613-- For each key in the external_dependencies table in the
614-- rockspec file, four variables are created: <key>_DIR, <key>_BINDIR,
615-- <key>_INCDIR and <key>_LIBDIR. These are not overwritten
616-- if already set (e.g. by the LuaRocks config file or through the
617-- command-line). Values in the external_dependencies table
618-- are tables that may contain a "header" or a "library" field,
619-- with filenames to be tested for existence.
620-- @param rockspec table: The rockspec table.
621-- @param mode string: if "build" is given, checks all files;
622-- if "install" is given, do not scan for headers.
623-- @return boolean or (nil, string): True if no errors occurred, or
624-- nil and an error message if any test failed.
625function deps.check_external_deps(rockspec, mode)
626
627 if not rockspec.external_dependencies then
628 rockspec.external_dependencies = deps.autodetect_external_dependencies(rockspec.build)
629 end
630 if not rockspec.external_dependencies then
631 return true
632 end
633
634 for name, ext_files in util.sortedpairs(rockspec.external_dependencies) do
635 local ok, err_dirname, err_testfile, err_files = check_external_dependency(name, ext_files, rockspec.variables, mode)
636 if not ok then
637 local lines = {"Could not find "..err_testfile.." file for "..name}
638
639 local err_paths = {}
640 for _, err_file in ipairs(err_files[err_testfile]) do
641 if not err_paths[err_file] then
642 err_paths[err_file] = true
643 table.insert(lines, " No file "..err_file)
644 end
645 end
646
647 table.insert(lines, "You may have to install "..name.." in your system and/or pass "..name.."_DIR or "..name.."_"..err_dirname.." to the luarocks command.")
648 table.insert(lines, "Example: luarocks install "..rockspec.name.." "..name.."_DIR=/usr/local")
649
650 return nil, table.concat(lines, "\n"), "dependency"
651 end
652 end
653 return true
654end
655
656--- Recursively add satisfied dependencies of a package to a table,
657-- to build a transitive closure of all dependent packages.
658-- Additionally ensures that `dependencies` table of the manifest is up-to-date.
659-- @param results table: The results table being built, maps package names to versions.
660-- @param mdeps table: The manifest dependencies table.
661-- @param name string: Package name.
662-- @param version string: Package version.
663function deps.scan_deps(results, mdeps, name, version, deps_mode)
664 assert(type(results) == "table")
665 assert(type(mdeps) == "table")
666 assert(type(name) == "string" and not name:match("/"))
667 assert(type(version) == "string")
668
669 local fetch = require("luarocks.fetch")
670
671 if results[name] then
672 return
673 end
674 if not mdeps[name] then mdeps[name] = {} end
675 local mdn = mdeps[name]
676 local dependencies = mdn[version]
677 local rocks_provided
678 if not dependencies then
679 local rockspec, err = fetch.load_local_rockspec(path.rockspec_file(name, version), false)
680 if not rockspec then
681 return
682 end
683 dependencies = rockspec.dependencies
684 rocks_provided = rockspec.rocks_provided
685 mdn[version] = dependencies
686 else
687 rocks_provided = util.get_rocks_provided()
688 end
689
690 local get_versions = prepare_get_versions(deps_mode, rocks_provided, "dependencies")
691
692 local matched = match_all_deps(dependencies, get_versions)
693 results[name] = version
694 for _, match in pairs(matched) do
695 deps.scan_deps(results, mdeps, match.name, match.version, deps_mode)
696 end
697end
698
699local function lua_h_exists(d, luaver)
700 local major, minor = luaver:match("(%d+)%.(%d+)")
701 local luanum = ("%s%02d"):format(major, tonumber(minor))
702
703 local lua_h = dir.path(d, "lua.h")
704 local fd = io.open(lua_h)
705 if fd then
706 local data = fd:read("*a")
707 fd:close()
708 if data:match("LUA_VERSION_NUM%s*" .. tostring(luanum)) then
709 return d
710 end
711 return nil, "Lua header lua.h found at " .. d .. " does not match Lua version " .. luaver .. ". You can use `luarocks config variables.LUA_INCDIR <path>` to set the correct location.", "dependency", 2
712 end
713
714 return nil, "Failed finding Lua header lua.h (searched at " .. d .. "). You may need to install Lua development headers. You can use `luarocks config variables.LUA_INCDIR <path>` to set the correct location.", "dependency", 1
715end
716
717local function find_lua_incdir(prefix, luaver, luajitver)
718 luajitver = luajitver and luajitver:gsub("%-.*", "")
719 local shortv = luaver:gsub("%.", "")
720 local incdirs = {
721 prefix .. "/include/lua/" .. luaver,
722 prefix .. "/include/lua" .. luaver,
723 prefix .. "/include/lua-" .. luaver,
724 prefix .. "/include/lua" .. shortv,
725 prefix .. "/include",
726 prefix,
727 luajitver and (prefix .. "/include/luajit-" .. (luajitver:match("^(%d+%.%d+)") or "")),
728 }
729 local errprio = 0
730 local mainerr
731 for _, d in ipairs(incdirs) do
732 local ok, err, _, prio = lua_h_exists(d, luaver)
733 if ok then
734 return d
735 end
736 if prio > errprio then
737 mainerr = err
738 errprio = prio
739 end
740 end
741
742 -- not found, will fallback to a default
743 return nil, mainerr
744end
745
746function deps.check_lua_incdir(vars)
747 if vars.LUA_INCDIR_OK == true
748 then return true
749 end
750
751 local ljv = util.get_luajit_version()
752
753 if vars.LUA_INCDIR then
754 local ok, err = lua_h_exists(vars.LUA_INCDIR, cfg.lua_version)
755 if ok then
756 vars.LUA_INCDIR_OK = true
757 end
758 return ok, err
759 end
760
761 if vars.LUA_DIR then
762 local d, err = find_lua_incdir(vars.LUA_DIR, cfg.lua_version, ljv)
763 if d then
764 vars.LUA_INCDIR = d
765 vars.LUA_INCDIR_OK = true
766 return true
767 end
768 return nil, err
769 end
770
771 return nil, "Failed finding Lua headers; neither LUA_DIR or LUA_INCDIR are set. You may need to install them or configure LUA_INCDIR.", "dependency"
772end
773
774function deps.check_lua_libdir(vars)
775 if vars.LUA_LIBDIR_OK == true
776 then return true
777 end
778
779 local fs = require("luarocks.fs")
780 local ljv = util.get_luajit_version()
781
782 if vars.LUA_LIBDIR and vars.LUALIB and fs.exists(dir.path(vars.LUA_LIBDIR, vars.LUALIB)) then
783 vars.LUA_LIBDIR_OK = true
784 return true
785 end
786
787 local shortv = cfg.lua_version:gsub("%.", "")
788 local libnames = {
789 "lua" .. cfg.lua_version,
790 "lua" .. shortv,
791 "lua-" .. cfg.lua_version,
792 "lua-" .. shortv,
793 "lua",
794 }
795 if ljv then
796 table.insert(libnames, 1, "luajit-" .. cfg.lua_version)
797 table.insert(libnames, 2, "luajit")
798 end
799 local cache = {}
800 local save_LUA_INCDIR = vars.LUA_INCDIR
801 local ok, _, _, errfiles = check_external_dependency("LUA", { library = libnames }, vars, "build", cache)
802 vars.LUA_INCDIR = save_LUA_INCDIR
803 local err
804 if ok then
805 local filename = dir.path(vars.LUA_LIBDIR, vars.LUA_LIBDIR_FILE)
806 local fd = io.open(filename, "r")
807 if fd then
808 if not vars.LUA_LIBDIR_FILE:match((cfg.lua_version:gsub("%.", "%%.?"))) then
809 -- if filename isn't versioned, check file contents
810 local txt = fd:read("*a")
811 ok = txt:match("Lua " .. cfg.lua_version, 1, true)
812 or txt:match("lua" .. (cfg.lua_version:gsub("%.", "")), 1, true)
813 if not ok then
814 err = "Lua library at " .. filename .. " does not match Lua version " .. cfg.lua_version .. ". You can use `luarocks config variables.LUA_LIBDIR <path>` to set the correct location."
815 end
816 end
817
818 fd:close()
819 end
820 end
821
822 if ok then
823 vars.LUALIB = vars.LUA_LIBDIR_FILE
824 vars.LUA_LIBDIR_OK = true
825 return true
826 else
827 err = err or "Failed finding the Lua library. You can use `luarocks config variables.LUA_LIBDIR <path>` to set the correct location."
828 return nil, err, "dependency", errfiles
829 end
830end
831
832function deps.get_deps_mode(args)
833 return args.deps_mode or cfg.deps_mode
834end
835
836return deps
diff --git a/src/luarocks/fetch.tl b/src/luarocks/fetch.tl
index 6434edac..4c126575 100644
--- a/src/luarocks/fetch.tl
+++ b/src/luarocks/fetch.tl
@@ -13,7 +13,8 @@ local util = require("luarocks.util")
13local cfg = require("luarocks.core.cfg") 13local cfg = require("luarocks.core.cfg")
14 14
15local type Lock = fs.Lock --! 15local type Lock = fs.Lock --!
16local type Rockspec = cfg.Rockspec 16local type rockspec = require("luarocks.core.types.rockspec")
17local type Rockspec = rockspec.Rockspec
17 18
18 19
19local function ensure_trailing_slash(url: string): string 20local function ensure_trailing_slash(url: string): string
@@ -517,7 +518,6 @@ end
517-- the fetched source tarball and the temporary directory created to 518-- the fetched source tarball and the temporary directory created to
518-- store it; or nil and an error message and optional error code. 519-- store it; or nil and an error message and optional error code.
519function fetch.get_sources(rockspec: Rockspec, extract: boolean, dest_dir?: string): string, string, string 520function fetch.get_sources(rockspec: Rockspec, extract: boolean, dest_dir?: string): string, string, string
520 -- assert(rockspec:type() == "rockspec") --!
521 521
522 local url = rockspec.source.url 522 local url = rockspec.source.url
523 local name = rockspec.name.."-"..rockspec.version 523 local name = rockspec.name.."-"..rockspec.version
@@ -563,7 +563,6 @@ end
563-- the fetched source tarball and the temporary directory created to 563-- the fetched source tarball and the temporary directory created to
564-- store it; or nil and an error message. 564-- store it; or nil and an error message.
565function fetch.fetch_sources(rockspec: Rockspec, extract: string, dest_dir?: string): string, string, string, string, string 565function fetch.fetch_sources(rockspec: Rockspec, extract: string, dest_dir?: string): string, string, string, string, string
566 assert(rockspec:type() == "rockspec") --!
567 566
568 -- auto-convert git://github.com URLs to use git+https 567 -- auto-convert git://github.com URLs to use git+https
569 -- see https://github.blog/2021-09-01-improving-git-protocol-security-github/ 568 -- see https://github.blog/2021-09-01-improving-git-protocol-security-github/
diff --git a/src/luarocks/fetch/cvs.tl b/src/luarocks/fetch/cvs.tl
index 60f55957..f40d0991 100644
--- a/src/luarocks/fetch/cvs.tl
+++ b/src/luarocks/fetch/cvs.tl
@@ -6,9 +6,9 @@ end
6local fs = require("luarocks.fs") 6local fs = require("luarocks.fs")
7local dir = require("luarocks.dir") 7local dir = require("luarocks.dir")
8local util = require("luarocks.util") 8local util = require("luarocks.util")
9local cfg = require("luarocks.core.cfg") --! import for Rockspec
10 9
11local type Rockspec = cfg.Rockspec 10local type rockspec = require("luarocks.core.types.rockspec")
11local type Rockspec = rockspec.Rockspec
12 12
13--- Download sources for building a rock, using CVS. 13--- Download sources for building a rock, using CVS.
14-- @param rockspec table: The rockspec table 14-- @param rockspec table: The rockspec table
diff --git a/src/luarocks/fetch/git.tl b/src/luarocks/fetch/git.tl
index f9eed558..1a4438c9 100644
--- a/src/luarocks/fetch/git.tl
+++ b/src/luarocks/fetch/git.tl
@@ -8,10 +8,11 @@ local fs = require("luarocks.fs")
8local dir = require("luarocks.dir") 8local dir = require("luarocks.dir")
9local vers = require("luarocks.core.vers") 9local vers = require("luarocks.core.vers")
10local util = require("luarocks.util") 10local util = require("luarocks.util")
11local cfg = require("luarocks.core.cfg") --!
12 11
13local type Rockspec = cfg.Rockspec 12local type rockspec = require("luarocks.core.types.rockspec")
14local type Version = vers.Version 13local type Rockspec = rockspec.Rockspec
14local type version = require("luarocks.core.types.version")
15local type Version = version.Version
15 16
16local cached_git_version: Version 17local cached_git_version: Version
17 18
diff --git a/src/luarocks/fetch/git_file.tl b/src/luarocks/fetch/git_file.tl
index cd2f3405..858e67a3 100644
--- a/src/luarocks/fetch/git_file.tl
+++ b/src/luarocks/fetch/git_file.tl
@@ -4,9 +4,9 @@ local record git_file
4end 4end
5 5
6local git = require("luarocks.fetch.git") 6local git = require("luarocks.fetch.git")
7local cfg = require("luarocks.core.cfg") --!
8 7
9local type Rockspec = cfg.Rockspec 8local type rockspec = require("luarocks.core.types.rockspec")
9local type Rockspec = rockspec.Rockspec
10 10
11--- Fetch sources for building a rock from a local Git repository. 11--- Fetch sources for building a rock from a local Git repository.
12-- @param rockspec table: The rockspec table 12-- @param rockspec table: The rockspec table
diff --git a/src/luarocks/fetch/git_http.tl b/src/luarocks/fetch/git_http.tl
index b0164c1b..a7b3d692 100644
--- a/src/luarocks/fetch/git_http.tl
+++ b/src/luarocks/fetch/git_http.tl
@@ -11,9 +11,9 @@ local record git_http
11end 11end
12 12
13local git = require("luarocks.fetch.git") 13local git = require("luarocks.fetch.git")
14local cfg = require("luarocks.core.cfg") --!
15 14
16local type Rockspec = cfg.Rockspec 15local type rockspec = require("luarocks.core.types.rockspec")
16local type Rockspec = rockspec.Rockspec
17 17
18--- Fetch sources for building a rock from a local Git repository. 18--- Fetch sources for building a rock from a local Git repository.
19-- @param rockspec table: The rockspec table 19-- @param rockspec table: The rockspec table
diff --git a/src/luarocks/fetch/git_ssh.tl b/src/luarocks/fetch/git_ssh.tl
index 7cb68be3..65954353 100644
--- a/src/luarocks/fetch/git_ssh.tl
+++ b/src/luarocks/fetch/git_ssh.tl
@@ -11,9 +11,9 @@ local record git_ssh
11end 11end
12 12
13local git = require("luarocks.fetch.git") 13local git = require("luarocks.fetch.git")
14local cfg = require("luarocks.core.cfg") --!
15 14
16local type Rockspec = cfg.Rockspec 15local type rockspec = require("luarocks.core.types.rockspec")
16local type Rockspec = rockspec.Rockspec
17 17
18--- Fetch sources for building a rock from a local Git repository. 18--- Fetch sources for building a rock from a local Git repository.
19-- @param rockspec table: The rockspec table 19-- @param rockspec table: The rockspec table
diff --git a/src/luarocks/fetch/hg.tl b/src/luarocks/fetch/hg.tl
index 1acc2bea..0fbf5601 100644
--- a/src/luarocks/fetch/hg.tl
+++ b/src/luarocks/fetch/hg.tl
@@ -6,9 +6,9 @@ end
6local fs = require("luarocks.fs") 6local fs = require("luarocks.fs")
7local dir = require("luarocks.dir") 7local dir = require("luarocks.dir")
8local util = require("luarocks.util") 8local util = require("luarocks.util")
9local cfg = require("luarocks.core.cfg") --!
10 9
11local type Rockspec = cfg.Rockspec 10local type rockspec = require("luarocks.core.types.rockspec")
11local type Rockspec = rockspec.Rockspec
12 12
13--- Download sources for building a rock, using hg. 13--- Download sources for building a rock, using hg.
14-- @param rockspec table: The rockspec table 14-- @param rockspec table: The rockspec table
diff --git a/src/luarocks/fetch/hg_http.tl b/src/luarocks/fetch/hg_http.tl
index b51bc1e9..f526d2d5 100644
--- a/src/luarocks/fetch/hg_http.tl
+++ b/src/luarocks/fetch/hg_http.tl
@@ -9,9 +9,9 @@ local record hg_http
9end 9end
10 10
11local hg = require("luarocks.fetch.hg") 11local hg = require("luarocks.fetch.hg")
12local cfg = require("luarocks.core.cfg") --!
13 12
14local type Rockspec = cfg.Rockspec 13local type rockspec = require("luarocks.core.types.rockspec")
14local type Rockspec = rockspec.Rockspec
15 15
16--- Download sources for building a rock, using hg over http. 16--- Download sources for building a rock, using hg over http.
17-- @param rockspec table: The rockspec table 17-- @param rockspec table: The rockspec table
diff --git a/src/luarocks/fetch/sscm.tl b/src/luarocks/fetch/sscm.tl
index f708267c..ad5a615e 100644
--- a/src/luarocks/fetch/sscm.tl
+++ b/src/luarocks/fetch/sscm.tl
@@ -5,9 +5,9 @@ end
5 5
6local fs = require("luarocks.fs") 6local fs = require("luarocks.fs")
7local dir = require("luarocks.dir") 7local dir = require("luarocks.dir")
8local cfg = require("luarocks.core.cfg") --!
9 8
10local Rockspec = cfg.Rockspec 9local type rockspec = require("luarocks.core.types.rockspec")
10local type Rockspec = rockspec.Rockspec
11 11
12--- Download sources via Surround SCM Server for building a rock. 12--- Download sources via Surround SCM Server for building a rock.
13-- @param rockspec table: The rockspec table 13-- @param rockspec table: The rockspec table
@@ -17,8 +17,6 @@ local Rockspec = cfg.Rockspec
17-- the fetched source tarball and the temporary directory created to 17-- the fetched source tarball and the temporary directory created to
18-- store it; or nil and an error message. 18-- store it; or nil and an error message.
19function sscm.get_sources(rockspec: Rockspec, extract: boolean, dest_dir?: string): string, string 19function sscm.get_sources(rockspec: Rockspec, extract: boolean, dest_dir?: string): string, string
20 assert(rockspec:type() == "rockspec")
21 assert(type(dest_dir) == "string" or not dest_dir)
22 20
23 local sscm_cmd = rockspec.variables.SSCM 21 local sscm_cmd = rockspec.variables.SSCM
24 local module = rockspec.source.module or dir.base_name(rockspec.source.url) 22 local module = rockspec.source.module or dir.base_name(rockspec.source.url)
diff --git a/src/luarocks/fetch/svn.tl b/src/luarocks/fetch/svn.tl
index 43355e63..df3cdde9 100644
--- a/src/luarocks/fetch/svn.tl
+++ b/src/luarocks/fetch/svn.tl
@@ -6,9 +6,9 @@ end
6local fs = require("luarocks.fs") 6local fs = require("luarocks.fs")
7local dir = require("luarocks.dir") 7local dir = require("luarocks.dir")
8local util = require("luarocks.util") 8local util = require("luarocks.util")
9local cfg = require("luarocks.core.cfg") --!
10 9
11local Rockspec = cfg.Rockspec 10local type rockspec = require("luarocks.core.types.rockspec")
11local type Rockspec = rockspec.Rockspec
12 12
13--- Download sources for building a rock, using Subversion. 13--- Download sources for building a rock, using Subversion.
14-- @param rockspec table: The rockspec table 14-- @param rockspec table: The rockspec table
@@ -18,8 +18,6 @@ local Rockspec = cfg.Rockspec
18-- the fetched source tarball and the temporary directory created to 18-- the fetched source tarball and the temporary directory created to
19-- store it; or nil and an error message. 19-- store it; or nil and an error message.
20function svn.get_sources(rockspec: Rockspec, extract: boolean, dest_dir?: string): string, string 20function svn.get_sources(rockspec: Rockspec, extract: boolean, dest_dir?: string): string, string
21 assert(rockspec:type() == "rockspec")
22 assert(type(dest_dir) == "string" or not dest_dir)
23 21
24 local svn_cmd = rockspec.variables.SVN 22 local svn_cmd = rockspec.variables.SVN
25 local ok, err_msg = fs.is_tool_available(svn_cmd, "Subversion") 23 local ok, err_msg = fs.is_tool_available(svn_cmd, "Subversion")
diff --git a/src/luarocks/loader.tl b/src/luarocks/loader.tl
new file mode 100644
index 00000000..896b7ce1
--- /dev/null
+++ b/src/luarocks/loader.tl
@@ -0,0 +1,270 @@
1--- A module which installs a Lua package loader that is LuaRocks-aware.
2-- This loader uses dependency information from the LuaRocks tree to load
3-- correct versions of modules. It does this by constructing a "context"
4-- table in the environment, which records which versions of packages were
5-- used to load previous modules, so that the loader chooses versions
6-- that are declared to be compatible with the ones loaded earlier.
7
8-- luacheck: globals luarocks
9
10local loaders = package.loaders or package.searchers
11local require, ipairs, table, type, next, tostring, error =
12 require, ipairs, table, type, next, tostring, error
13local unpack = unpack or table.unpack
14
15local record loader
16end
17
18local is_clean = not package.loaded["luarocks.core.cfg"]
19
20-- This loader module depends only on core modules.
21local cfg = require("luarocks.core.cfg")
22local cfg_ok, err = cfg.init()
23if cfg_ok then
24 cfg.init_package_paths()
25end
26
27local path = require("luarocks.core.path")
28local manif = require("luarocks.core.manif")
29local vers = require("luarocks.core.vers")
30local require = nil -- luacheck: ignore 411
31--------------------------------------------------------------------------------
32
33-- Workaround for wrappers produced by older versions of LuaRocks
34local temporary_global = false
35local status, luarocks_value = pcall(function() return luarocks end)
36if status and luarocks_value then
37 -- The site_config.lua file generated by old versions uses module(),
38 -- so it produces a global `luarocks` table. Since we have the table,
39 -- add the `loader` field to make the old wrappers happy.
40 luarocks.loader = loader
41else
42 -- When a new version is installed on top of an old version,
43 -- site_config.lua may be replaced, and then it no longer creates
44 -- a global.
45 -- Detect when being called via -lluarocks.loader; this is
46 -- most likely a wrapper.
47 local info = debug and debug.getinfo(2, "nS")
48 if info and info.what == "C" and not info.name then
49 luarocks = { loader = loader }
50 temporary_global = true
51 -- For the other half of this hack,
52 -- see the next use of `temporary_global` below.
53 end
54end
55
56loader.context = {}
57
58--- Process the dependencies of a package to determine its dependency
59-- chain for loading modules.
60-- @param name string: The name of an installed rock.
61-- @param version string: The version of the rock, in string format
62function loader.add_context(name, version)
63 -- assert(type(name) == "string")
64 -- assert(type(version) == "string")
65
66 if temporary_global then
67 -- The first thing a wrapper does is to call add_context.
68 -- From here on, it's safe to clean the global environment.
69 luarocks = nil
70 temporary_global = false
71 end
72
73 local tree_manifests = manif.load_rocks_tree_manifests()
74 if not tree_manifests then
75 return nil
76 end
77
78 return manif.scan_dependencies(name, version, tree_manifests, loader.context)
79end
80
81--- Internal sorting function.
82-- @param a table: A provider table.
83-- @param b table: Another provider table.
84-- @return boolean: True if the version of a is greater than that of b.
85local function sort_versions(a,b)
86 return a.version > b.version
87end
88
89--- Request module to be loaded through other loaders,
90-- once the proper name of the module has been determined.
91-- For example, in case the module "socket.core" has been requested
92-- to the LuaRocks loader and it determined based on context that
93-- the version 2.0.2 needs to be loaded and it is not the current
94-- version, the module requested for the other loaders will be
95-- "socket.core_2_0_2".
96-- @param module The module name requested by the user, such as "socket.core"
97-- @param name The rock name, such as "luasocket"
98-- @param version The rock version, such as "2.0.2-1"
99-- @param module_name The actual module name, such as "socket.core" or "socket.core_2_0_2".
100-- @return table or (nil, string): The module table as returned by some other loader,
101-- or nil followed by an error message if no other loader managed to load the module.
102local function call_other_loaders(module, name, version, module_name)
103 for _, a_loader in ipairs(loaders) do
104 if a_loader ~= loader.luarocks_loader then
105 local results = { a_loader(module_name) }
106 if type(results[1]) == "function" then
107 return unpack(results)
108 end
109 end
110 end
111 return "Failed loading module "..module.." in LuaRocks rock "..name.." "..version
112end
113
114local function add_providers(providers, entries, tree, module, filter_file_name)
115 for i, entry in ipairs(entries) do
116 local name, version = entry:match("^([^/]*)/(.*)$")
117 local file_name = tree.manifest.repository[name][version][1].modules[module]
118 if type(file_name) ~= "string" then
119 error("Invalid data in manifest file for module "..tostring(module).." (invalid data for "..tostring(name).." "..tostring(version)..")")
120 end
121 file_name = filter_file_name(file_name, name, version, tree.tree, i)
122 if loader.context[name] == version then
123 return name, version, file_name
124 end
125 version = vers.parse_version(version)
126 table.insert(providers, {name = name, version = version, module_name = file_name, tree = tree})
127 end
128end
129
130--- Search for a module in the rocks trees
131-- @param module string: module name (eg. "socket.core")
132-- @param filter_file_name function(string, string, string, string, number):
133-- a function that takes the module file name (eg "socket/core.so"), the rock name
134-- (eg "luasocket"), the version (eg "2.0.2-1"), the path of the rocks tree
135-- (eg "/usr/local"), and the numeric index of the matching entry, so the
136-- filter function can know if the matching module was the first entry or not.
137-- @return string, string, string, (string or table):
138-- * name of the rock containing the module (eg. "luasocket")
139-- * version of the rock (eg. "2.0.2-1")
140-- * return value of filter_file_name
141-- * tree of the module (string or table in `tree_manifests` format)
142local function select_module(module, filter_file_name)
143 --assert(type(module) == "string")
144 --assert(type(filter_module_name) == "function")
145
146 local tree_manifests = manif.load_rocks_tree_manifests()
147 if not tree_manifests then
148 return nil
149 end
150
151 local providers = {}
152 local initmodule
153 for _, tree in ipairs(tree_manifests) do
154 local entries = tree.manifest.modules[module]
155 if entries then
156 local n, v, f = add_providers(providers, entries, tree, module, filter_file_name)
157 if n then
158 return n, v, f
159 end
160 else
161 initmodule = initmodule or module .. ".init"
162 entries = tree.manifest.modules[initmodule]
163 if entries then
164 local n, v, f = add_providers(providers, entries, tree, initmodule, filter_file_name)
165 if n then
166 return n, v, f
167 end
168 end
169 end
170 end
171
172 if next(providers) then
173 table.sort(providers, sort_versions)
174 local first = providers[1]
175 return first.name, first.version.string, first.module_name, first.tree
176 end
177end
178
179--- Search for a module
180-- @param module string: module name (eg. "socket.core")
181-- @return string, string, string, (string or table):
182-- * name of the rock containing the module (eg. "luasocket")
183-- * version of the rock (eg. "2.0.2-1")
184-- * name of the module (eg. "socket.core", or "socket.core_2_0_2" if file is stored versioned).
185-- * tree of the module (string or table in `tree_manifests` format)
186local function pick_module(module)
187 return
188 select_module(module, function(file_name, name, version, tree, i)
189 if i > 1 then
190 file_name = path.versioned_name(file_name, "", name, version)
191 end
192 return path.path_to_module(file_name)
193 end)
194end
195
196--- Return the pathname of the file that would be loaded for a module.
197-- @param module string: module name (eg. "socket.core")
198-- @param where string: places to look for the module. If `where` contains
199-- "l", it will search using the LuaRocks loader; if it contains "p",
200-- it will look in the filesystem using package.path and package.cpath.
201-- You can use both at the same time.
202-- @return If successful, it will return four values.
203-- * If found using the LuaRocks loader, it will return:
204-- * filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so"),
205-- * rock name
206-- * rock version
207-- * "l" to indicate the match comes from the loader.
208-- * If found scanning package.path and package.cpath, it will return:
209-- * filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so"),
210-- * "path" or "cpath"
211-- * nil
212-- * "p" to indicate the match comes from scanning package.path and cpath.
213-- If unsuccessful, nothing is returned.
214function loader.which(module, where)
215 where = where or "l"
216 if where:match("l") then
217 local rock_name, rock_version, file_name = select_module(module, path.which_i)
218 if rock_name then
219 local fd = io.open(file_name)
220 if fd then
221 fd:close()
222 return file_name, rock_name, rock_version, "l"
223 end
224 end
225 end
226 if where:match("p") then
227 local modpath = module:gsub("%.", "/")
228 for _, v in ipairs({"path", "cpath"}) do
229 for p in package[v]:gmatch("([^;]+)") do
230 local file_name = p:gsub("%?", modpath) -- luacheck: ignore 421
231 local fd = io.open(file_name)
232 if fd then
233 fd:close()
234 return file_name, v, nil, "p"
235 end
236 end
237 end
238 end
239end
240
241--- Package loader for LuaRocks support.
242-- A module is searched in installed rocks that match the
243-- current LuaRocks context. If module is not part of the
244-- context, or if a context has not yet been set, the module
245-- in the package with the highest version is used.
246-- @param module string: The module name, like in plain require().
247-- @return table: The module table (typically), like in plain
248-- require(). See <a href="http://www.lua.org/manual/5.1/manual.html#pdf-require">require()</a>
249-- in the Lua reference manual for details.
250function loader.luarocks_loader(module)
251 local name, version, module_name = pick_module(module)
252 if not name then
253 return "No LuaRocks module found for "..module
254 else
255 loader.add_context(name, version)
256 return call_other_loaders(module, name, version, module_name)
257 end
258end
259
260table.insert(loaders, 1, loader.luarocks_loader)
261
262if is_clean then
263 for modname, _ in pairs(package.loaded) do
264 if modname:match("^luarocks%.") then
265 package.loaded[modname] = nil
266 end
267 end
268end
269
270return loader
diff --git a/src/luarocks/manif.tl b/src/luarocks/manif.tl
index a7949932..f0f838b8 100644
--- a/src/luarocks/manif.tl
+++ b/src/luarocks/manif.tl
@@ -19,9 +19,11 @@ local util = require("luarocks.util")
19local queries = require("luarocks.queries") 19local queries = require("luarocks.queries")
20local type_manifest = require("luarocks.type.manifest") 20local type_manifest = require("luarocks.type.manifest")
21 21
22local type tree = require("luarocks.core.types.tree")
23local type Tree = tree.Tree
22local type Manifest = core.Manifest 24local type Manifest = core.Manifest
23local type Tree_manifest = core.Tree_manifest 25local type Tree_manifest = core.Tree_manifest
24local type Tree = cfg.Tree 26local type DependencyVersion = core.DependencyVersion --!
25 27
26manif.cache_manifest = core.cache_manifest 28manif.cache_manifest = core.cache_manifest
27manif.load_rocks_tree_manifests = core.load_rocks_tree_manifests 29manif.load_rocks_tree_manifests = core.load_rocks_tree_manifests
@@ -190,14 +192,13 @@ end
190-- or "all", to use all trees. 192-- or "all", to use all trees.
191-- @return table: An array of strings listing installed 193-- @return table: An array of strings listing installed
192-- versions of a package, and a table indicating where they are found. 194-- versions of a package, and a table indicating where they are found.
193function manif.get_versions(dep, deps_mode: string): {string}, {string: string | Tree} 195function manif.get_versions(dep: DependencyVersion, deps_mode: string): {string}, {string: string | Tree}
194 -- assert(type(dep) == "table") --!
195 196
196 local name: string = dep.name 197 local name: string = dep.name
197 local namespace: string = dep.namespace 198 local namespace: string = dep.namespace
198 199
199 local version_set = {} 200 local version_set = {}
200 path.map_trees(deps_mode, function(tree) 201 path.map_trees(deps_mode, function(tree: string | Tree)
201 local manifest = manif.load_manifest(path.rocks_dir(tree)) 202 local manifest = manif.load_manifest(path.rocks_dir(tree))
202 203
203 if manifest and manifest.repository[name] then 204 if manifest and manifest.repository[name] then
diff --git a/src/luarocks/path.tl b/src/luarocks/path.tl
index f350f80c..1dc77e86 100644
--- a/src/luarocks/path.tl
+++ b/src/luarocks/path.tl
@@ -8,7 +8,8 @@ local core = require("luarocks.core.path")
8local dir = require("luarocks.dir") 8local dir = require("luarocks.dir")
9local util = require("luarocks.core.util") 9local util = require("luarocks.core.util")
10 10
11local type Tree = cfg.Tree 11local type tree = require("luarocks.core.types.tree")
12local type Tree = tree.Tree
12 13
13local record path 14local record path
14 rocks_dir: function(string | Tree): string 15 rocks_dir: function(string | Tree): string
diff --git a/src/luarocks/queries.tl b/src/luarocks/queries.tl
index 749cafe9..dec57585 100644
--- a/src/luarocks/queries.tl
+++ b/src/luarocks/queries.tl
@@ -1,31 +1,27 @@
1 1
2local record queries 2local record queries
3 record Query
4 name: string
5 namespace: string
6 constraints: {vers.Constraint}
7 substring: boolean
8 arch: {string: boolean}
9 end
10end 3end
11 4
12local vers = require("luarocks.core.vers") 5local vers = require("luarocks.core.vers")
13local util = require("luarocks.util") 6local util = require("luarocks.util")
14local cfg = require("luarocks.core.cfg") 7local cfg = require("luarocks.core.cfg")
15 8
16local type Query = queries.Query 9local type query = require("luarocks.core.types.query")
17local type Constraint = vers.Constraint 10local type version = require("luarocks.core.types.version")
11local type Query = query.Query
12local type Version = version.Version
13local type Constraint = version.Constraint
18 14
19local query_mt: metatable<Query> = {} 15local query_mt: metatable<Query> = {}
20 16
21query_mt.__index = queries.Query 17query_mt.__index = query.Query
22 18
23function queries.Query.type(): string --? remove later 19function query.Query.type(): string --? remove later
24 return "query" 20 return "query"
25end 21end
26 22
27-- Fallback default value for the `arch` field, if not explicitly set. 23-- Fallback default value for the `arch` field, if not explicitly set.
28queries.Query.arch = { 24query.Query.arch = {
29 src = true, 25 src = true,
30 all = true, 26 all = true,
31 rockspec = true, 27 rockspec = true,
@@ -34,7 +30,7 @@ queries.Query.arch = {
34} 30}
35 31
36-- Fallback default value for the `substring` field, if not explicitly set. 32-- Fallback default value for the `substring` field, if not explicitly set.
37queries.Query.substring = false 33query.Query.substring = false
38 34
39--- Convert the arch field of a query table to table format. 35--- Convert the arch field of a query table to table format.
40-- @param input string, table or nil 36-- @param input string, table or nil
@@ -79,7 +75,7 @@ function queries.new(name: string, namespace?: string, version?: string, substri
79 table.insert(self.constraints, { op = operator, version = vers.parse_version(version)}) 75 table.insert(self.constraints, { op = operator, version = vers.parse_version(version)})
80 end 76 end
81 77
82 queries.Query.arch[cfg.arch] = true 78 query.Query.arch[cfg.arch] = true
83 return setmetatable(self, query_mt) 79 return setmetatable(self, query_mt)
84end 80end
85 81
@@ -183,13 +179,13 @@ do
183 constraints = constraints, 179 constraints = constraints,
184 } 180 }
185 181
186 queries.Query.arch[cfg.arch] = true 182 query.Query.arch[cfg.arch] = true
187 return setmetatable(self, query_mt) 183 return setmetatable(self, query_mt)
188 end 184 end
189end 185end
190 186
191function queries.from_persisted_table(tbl: Query): Query 187function queries.from_persisted_table(tbl: Query): Query
192 queries.Query.arch[cfg.arch] = true 188 query.Query.arch[cfg.arch] = true
193 return setmetatable(tbl, query_mt) 189 return setmetatable(tbl, query_mt)
194end 190end
195 191
@@ -209,9 +205,9 @@ function query_mt.__tostring(self: Query): string
209 local pretty = {} 205 local pretty = {}
210 for _, c in ipairs(self.constraints) do 206 for _, c in ipairs(self.constraints) do
211 local cv = c.version 207 local cv = c.version
212 -- local v = cv is vers.Version and cv.string or cv --TEAL BUG 208 -- local v = cv is Version and cv.string or cv --TEAL BUG
213 local v: string 209 local v: string
214 if cv is vers.Version then 210 if cv is Version then
215 v = cv.string 211 v = cv.string
216 else 212 else
217 v = cv 213 v = cv
diff --git a/src/luarocks/results.tl b/src/luarocks/results.tl
index cae6ead9..99f70ec4 100644
--- a/src/luarocks/results.tl
+++ b/src/luarocks/results.tl
@@ -10,10 +10,10 @@ end
10 10
11local vers = require("luarocks.core.vers") 11local vers = require("luarocks.core.vers")
12local util = require("luarocks.util") 12local util = require("luarocks.util")
13local queries = require("luarocks.queries") 13local type query = require("luarocks.core.types.query")
14 14
15local type Results = results.Results 15local type Results = results.Results
16local type Query = queries.Query 16local type Query = query.Query
17 17
18local result_mt: metatable<Results> = {} 18local result_mt: metatable<Results> = {}
19 19
diff --git a/src/luarocks/rockspecs.tl b/src/luarocks/rockspecs.tl
index 390b4d5d..cdd0dcff 100644
--- a/src/luarocks/rockspecs.tl
+++ b/src/luarocks/rockspecs.tl
@@ -9,9 +9,9 @@ local type_rockspec = require("luarocks.type.rockspec")
9local util = require("luarocks.util") 9local util = require("luarocks.util")
10local vers = require("luarocks.core.vers") 10local vers = require("luarocks.core.vers")
11 11
12local type Rockspec = cfg.Rockspec 12local type rockspec = require("luarocks.core.types.rockspec")
13local type Variables = cfg.Variables 13local type Rockspec = rockspec.Rockspec
14local type Dependencie = cfg.Dependencie 14local type Variables = rockspec.Variables
15 15
16local vendored_build_type_set: {string: boolean} = { 16local vendored_build_type_set: {string: boolean} = {
17 ["builtin"] = true, 17 ["builtin"] = true,
@@ -24,9 +24,9 @@ local vendored_build_type_set: {string: boolean} = {
24 24
25local rockspec_mt: metatable<Rockspec> = {} 25local rockspec_mt: metatable<Rockspec> = {}
26 26
27rockspec_mt.__index = cfg.Rockspec 27rockspec_mt.__index = rockspec.Rockspec
28 28
29function cfg.Rockspec:type(): string 29function rockspec.Rockspec.type(): string
30 return "rockspec" 30 return "rockspec"
31end 31end
32 32
@@ -103,7 +103,7 @@ function rockspecs.from_persisted_table(filename: string, rockspec: Rockspec, gl
103 end 103 end
104 104
105 if not quick then 105 if not quick then
106 local ok, err = type_rockspec.check(rockspec as {any: any}, globals or {}) 106 local ok, err = type_rockspec.check(rockspec, globals or {})
107 if not ok then 107 if not ok then
108 return nil, err 108 return nil, err
109 end 109 end
diff --git a/src/luarocks/test.tl b/src/luarocks/test.tl
new file mode 100644
index 00000000..58b055dd
--- /dev/null
+++ b/src/luarocks/test.tl
@@ -0,0 +1,100 @@
1local record test
2end
3
4local fetch = require("luarocks.fetch")
5local deps = require("luarocks.deps")
6local util = require("luarocks.util")
7
8local test_types = {
9 "busted",
10 "command",
11}
12
13local test_modules = {}
14
15for _, test_type in ipairs(test_types) do
16 local mod = require("luarocks.test." .. test_type)
17 table.insert(test_modules, mod)
18 test_modules[test_type] = mod
19 test_modules[mod] = test_type
20end
21
22local function get_test_type(rockspec)
23 if rockspec.test and rockspec.test.type then
24 return rockspec.test.type
25 end
26
27 for _, test_module in ipairs(test_modules) do
28 if test_module.detect_type() then
29 return test_modules[test_module]
30 end
31 end
32
33 return nil, "could not detect test type -- no test suite for " .. rockspec.package .. "?"
34end
35
36-- Run test suite as configured in rockspec in the current directory.
37function test.run_test_suite(rockspec_arg, test_type, args, prepare)
38 local rockspec
39 if type(rockspec_arg) == "string" then
40 local err, errcode
41 rockspec, err, errcode = fetch.load_rockspec(rockspec_arg)
42 if err then
43 return nil, err, errcode
44 end
45 else
46 assert(type(rockspec_arg) == "table")
47 rockspec = rockspec_arg
48 end
49
50 if not test_type then
51 local err
52 test_type, err = get_test_type(rockspec, test_type)
53 if not test_type then
54 return nil, err
55 end
56 end
57 assert(test_type)
58
59 local all_deps = {
60 "dependencies",
61 "build_dependencies",
62 "test_dependencies",
63 }
64 for _, dep_kind in ipairs(all_deps) do
65 if rockspec[dep_kind] and next(rockspec[dep_kind]) then
66 local ok, err, errcode = deps.fulfill_dependencies(rockspec, dep_kind, "all")
67 if err then
68 return nil, err, errcode
69 end
70 end
71 end
72
73 local mod_name = "luarocks.test." .. test_type
74 local pok, test_mod = pcall(require, mod_name)
75 if not pok then
76 return nil, "failed loading test execution module " .. mod_name
77 end
78
79 if prepare then
80 if test_type == "busted" then
81 return test_mod.run_tests(rockspec_arg, {"--version"})
82 else
83 return true
84 end
85 else
86 local flags = rockspec.test and rockspec.test.flags
87 if type(flags) == "table" then
88 util.variable_substitutions(flags, rockspec.variables)
89
90 -- insert any flags given in test.flags at the front of args
91 for i = 1, #flags do
92 table.insert(args, i, flags[i])
93 end
94 end
95
96 return test_mod.run_tests(rockspec.test, args)
97 end
98end
99
100return test
diff --git a/src/luarocks/type/manifest.tl b/src/luarocks/type/manifest.tl
index 0eca2f56..f379f1e0 100644
--- a/src/luarocks/type/manifest.tl
+++ b/src/luarocks/type/manifest.tl
@@ -80,7 +80,7 @@ local manifest_formats = type_check.declare_schemas({
80-- mismatches. 80-- mismatches.
81-- @return boolean or (nil, string): true if type checking 81-- @return boolean or (nil, string): true if type checking
82-- succeeded, or nil and an error message if it failed. 82-- succeeded, or nil and an error message if it failed.
83function type_manifest.check(manifest: {any: any}, globals: {string: any}): boolean, string 83function type_manifest.check(manifest: {any: any}, globals: {string: any}): boolean, string --!
84 local format = manifest_formats["3.0"] 84 local format = manifest_formats["3.0"]
85 local ok, err = type_check.check_undeclared_globals(globals, format) 85 local ok, err = type_check.check_undeclared_globals(globals, format)
86 if not ok then return nil, err end 86 if not ok then return nil, err end
diff --git a/src/luarocks/type/rockspec.tl b/src/luarocks/type/rockspec.tl
index 6f431bd9..1b03736d 100644
--- a/src/luarocks/type/rockspec.tl
+++ b/src/luarocks/type/rockspec.tl
@@ -1,8 +1,11 @@
1local record type_rockspec 1local record type_rockspec
2 order: util.Ordering<string> 2 order: Ordering<string>
3 rockspec_format: string 3 rockspec_format: string
4end 4end
5 5
6local type ordering = require("luarocks.core.types.ordering")
7local type Ordering = ordering.Ordering
8
6local type_check = require("luarocks.type_check") 9local type_check = require("luarocks.type_check")
7local util = require("luarocks.core.util") --! 10local util = require("luarocks.core.util") --!
8 11
diff --git a/src/luarocks/util.tl b/src/luarocks/util.tl
index 80742419..d39c2198 100644
--- a/src/luarocks/util.tl
+++ b/src/luarocks/util.tl
@@ -49,7 +49,8 @@ util.keys = core.keys
49util.matchquote = core.matchquote 49util.matchquote = core.matchquote
50 50
51local type Fn = util.Fn 51local type Fn = util.Fn
52local type Rockspec = cfg.Rockspec 52local type rockspec = require("luarocks.core.types.rockspec")
53local type Rockspec = rockspec.Rockspec
53local type Parser = util.Parser 54local type Parser = util.Parser
54 55
55 56