diff options
author | Hisham Muhammad <hisham@gobolinux.org> | 2024-08-22 17:48:58 -0300 |
---|---|---|
committer | Hisham Muhammad <hisham@gobolinux.org> | 2024-10-21 13:30:51 -0300 |
commit | ce5ed124744644d414121c88c94cc67f3437362c (patch) | |
tree | a408e5b1da5c7a2204e1839cf757ebd7a829d9d9 /src | |
parent | d99f13f80e2b53a41d6d07d185fcef636f414c61 (diff) | |
download | luarocks-ce5ed124744644d414121c88c94cc67f3437362c.tar.gz luarocks-ce5ed124744644d414121c88c94cc67f3437362c.tar.bz2 luarocks-ce5ed124744644d414121c88c94cc67f3437362c.zip |
Teal: convert luarocks.loader
Diffstat (limited to 'src')
-rw-r--r-- | src/luarocks/loader.tl | 248 |
1 files changed, 156 insertions, 92 deletions
diff --git a/src/luarocks/loader.tl b/src/luarocks/loader.tl index 772fdfcb..527f1255 100644 --- a/src/luarocks/loader.tl +++ b/src/luarocks/loader.tl | |||
@@ -5,20 +5,20 @@ | |||
5 | -- used to load previous modules, so that the loader chooses versions | 5 | -- used to load previous modules, so that the loader chooses versions |
6 | -- that are declared to be compatible with the ones loaded earlier. | 6 | -- that are declared to be compatible with the ones loaded earlier. |
7 | 7 | ||
8 | -- luacheck: globals luarocks | ||
9 | |||
10 | local loaders = package.loaders or package.searchers | 8 | local loaders = package.loaders or package.searchers |
11 | local require, ipairs, table, type, next, tostring, error = | 9 | local require, ipairs, table, type, next, tostring, error = |
12 | require, ipairs, table, type, next, tostring, error | 10 | require, ipairs, table, type, next, tostring, error |
13 | local unpack = unpack or table.unpack | ||
14 | 11 | ||
15 | local loader = {} | 12 | local record loader |
13 | context: {string: string} | ||
14 | luarocks_loader: function(string): LoaderFn | string, any | ||
15 | end | ||
16 | 16 | ||
17 | local is_clean = not package.loaded["luarocks.core.cfg"] | 17 | local is_clean = not package.loaded["luarocks.core.cfg"] |
18 | 18 | ||
19 | -- This loader module depends only on core modules. | 19 | -- This loader module depends only on core modules. |
20 | local cfg = require("luarocks.core.cfg") | 20 | local cfg = require("luarocks.core.cfg") |
21 | local cfg_ok, err = cfg.init() | 21 | local cfg_ok, _err = cfg.init() |
22 | if cfg_ok then | 22 | if cfg_ok then |
23 | cfg.init_package_paths() | 23 | cfg.init_package_paths() |
24 | end | 24 | end |
@@ -26,12 +26,35 @@ end | |||
26 | local path = require("luarocks.core.path") | 26 | local path = require("luarocks.core.path") |
27 | local manif = require("luarocks.core.manif") | 27 | local manif = require("luarocks.core.manif") |
28 | local vers = require("luarocks.core.vers") | 28 | local vers = require("luarocks.core.vers") |
29 | local require = nil -- luacheck: ignore 411 | 29 | |
30 | local type Version = require("luarocks.core.types.version").Version | ||
31 | local type TreeManifest = require("luarocks.core.types.manifest").Tree_manifest | ||
32 | local type Tree = require("luarocks.core.types.tree").Tree | ||
33 | local type FilterFn = function(string, string, string, Tree, integer): string | ||
34 | local type LoaderFn = function() | ||
35 | |||
36 | local record Provider | ||
37 | name: string | ||
38 | version: Version | ||
39 | module_name: string | ||
40 | tree: TreeManifest | ||
41 | end | ||
42 | |||
30 | -------------------------------------------------------------------------------- | 43 | -------------------------------------------------------------------------------- |
44 | -- Backwards compatibility | ||
45 | -------------------------------------------------------------------------------- | ||
46 | |||
47 | local record LuaRocksGlobal | ||
48 | loader: loader | ||
49 | end | ||
50 | |||
51 | global luarocks: LuaRocksGlobal | ||
31 | 52 | ||
32 | -- Workaround for wrappers produced by older versions of LuaRocks | 53 | -- Workaround for wrappers produced by older versions of LuaRocks |
33 | local temporary_global = false | 54 | local temporary_global = false |
34 | local status, luarocks_value = pcall(function() return luarocks end) | 55 | local status, luarocks_value = pcall(function(): LuaRocksGlobal |
56 | return luarocks | ||
57 | end) | ||
35 | if status and luarocks_value then | 58 | if status and luarocks_value then |
36 | -- The site_config.lua file generated by old versions uses module(), | 59 | -- The site_config.lua file generated by old versions uses module(), |
37 | -- so it produces a global `luarocks` table. Since we have the table, | 60 | -- so it produces a global `luarocks` table. Since we have the table, |
@@ -52,16 +75,18 @@ else | |||
52 | end | 75 | end |
53 | end | 76 | end |
54 | 77 | ||
78 | -------------------------------------------------------------------------------- | ||
79 | -- Context management | ||
80 | -------------------------------------------------------------------------------- | ||
81 | |||
55 | loader.context = {} | 82 | loader.context = {} |
56 | 83 | ||
57 | --- Process the dependencies of a package to determine its dependency | 84 | --- Process the dependencies of a package to determine its dependency |
58 | -- chain for loading modules. | 85 | -- chain for loading modules. |
59 | -- @param name string: The name of an installed rock. | 86 | -- |
60 | -- @param version string: The version of the rock, in string format | 87 | -- @param name The name of an installed rock. |
61 | function loader.add_context(name, version) | 88 | -- @param version The version of the rock, in string format |
62 | -- assert(type(name) == "string") | 89 | function loader.add_context(name: string, version: string) |
63 | -- assert(type(version) == "string") | ||
64 | |||
65 | if temporary_global then | 90 | if temporary_global then |
66 | -- The first thing a wrapper does is to call add_context. | 91 | -- The first thing a wrapper does is to call add_context. |
67 | -- From here on, it's safe to clean the global environment. | 92 | -- From here on, it's safe to clean the global environment. |
@@ -71,17 +96,19 @@ function loader.add_context(name, version) | |||
71 | 96 | ||
72 | local tree_manifests = manif.load_rocks_tree_manifests() | 97 | local tree_manifests = manif.load_rocks_tree_manifests() |
73 | if not tree_manifests then | 98 | if not tree_manifests then |
74 | return nil | 99 | return |
75 | end | 100 | end |
76 | 101 | ||
77 | return manif.scan_dependencies(name, version, tree_manifests, loader.context) | 102 | manif.scan_dependencies(name, version, tree_manifests, loader.context) |
78 | end | 103 | end |
79 | 104 | ||
80 | --- Internal sorting function. | 105 | --- Internal sorting function. |
81 | -- @param a table: A provider table. | 106 | -- |
82 | -- @param b table: Another provider table. | 107 | -- @param a A provider table. |
83 | -- @return boolean: True if the version of a is greater than that of b. | 108 | -- @param b Another provider table. |
84 | local function sort_versions(a,b) | 109 | -- |
110 | -- @return true if the version of a is greater than that of b. | ||
111 | local function sort_versions(a: Provider, b: Provider): boolean | ||
85 | return a.version > b.version | 112 | return a.version > b.version |
86 | end | 113 | end |
87 | 114 | ||
@@ -92,67 +119,94 @@ end | |||
92 | -- the version 2.0.2 needs to be loaded and it is not the current | 119 | -- the version 2.0.2 needs to be loaded and it is not the current |
93 | -- version, the module requested for the other loaders will be | 120 | -- version, the module requested for the other loaders will be |
94 | -- "socket.core_2_0_2". | 121 | -- "socket.core_2_0_2". |
95 | -- @param module The module name requested by the user, such as "socket.core" | 122 | -- |
96 | -- @param name The rock name, such as "luasocket" | 123 | -- @param module The module name requested by the user, e.g. "socket.core" |
97 | -- @param version The rock version, such as "2.0.2-1" | 124 | -- @param name The rock name, such as "luasocket" |
98 | -- @param module_name The actual module name, such as "socket.core" or "socket.core_2_0_2". | 125 | -- @param version The rock version, such as "2.0.2-1" |
99 | -- @return table or (nil, string): The module table as returned by some other loader, | 126 | -- @param module_name Actual module name, such as "socket.core_2_0_2" |
100 | -- or nil followed by an error message if no other loader managed to load the module. | 127 | -- |
101 | local function call_other_loaders(module, name, version, module_name) | 128 | -- @return The loader function returned or an error message. |
129 | -- @return Additional loader data, if returned by the loader. | ||
130 | local function call_other_loaders(module: string, name: string, version: string, module_name: string): LoaderFn | string, any | ||
102 | for _, a_loader in ipairs(loaders) do | 131 | for _, a_loader in ipairs(loaders) do |
103 | if a_loader ~= loader.luarocks_loader then | 132 | if a_loader ~= loader.luarocks_loader then |
104 | local results = { a_loader(module_name) } | 133 | local results: {any} = { a_loader(module_name) } |
105 | if type(results[1]) == "function" then | 134 | local f = results[1] |
106 | return unpack(results) | 135 | if f is LoaderFn then |
136 | if #results == 2 then | ||
137 | return f, results[2] | ||
138 | else | ||
139 | return f | ||
140 | end | ||
107 | end | 141 | end |
108 | end | 142 | end |
109 | end | 143 | end |
110 | return "Failed loading module "..module.." in LuaRocks rock "..name.." "..version | 144 | return "Failed loading module " .. module .. " in LuaRocks rock " .. name .. " " .. version |
111 | end | 145 | end |
112 | 146 | ||
113 | local function add_providers(providers, entries, tree, module, filter_file_name) | 147 | --- Find entries which provide the wanted module in the tree, |
148 | -- and store them in the array of providers for later sorting. | ||
149 | -- | ||
150 | -- @param providers The array of providers being accumulated into | ||
151 | -- @param entries The packages which provide the module | ||
152 | -- @param tree TreeManifest where filenames can be found. | ||
153 | -- @param module The module name being looked up | ||
154 | -- @param filter_name A filtering function to adjust the filename. | ||
155 | -- | ||
156 | -- @return If the current LuaRocks loader context already resolved this | ||
157 | -- dependency based on other dependencies, return the name of the module | ||
158 | -- for immediate use. | ||
159 | -- @return Version of the module for immediate use, if matched. | ||
160 | -- @return File name of the module for immediate use, if matched. | ||
161 | local function add_providers(providers: {Provider}, entries: {string}, tree: TreeManifest, module: string, filter_name: FilterFn): string, string, string | ||
114 | for i, entry in ipairs(entries) do | 162 | for i, entry in ipairs(entries) do |
115 | local name, version = entry:match("^([^/]*)/(.*)$") | 163 | local name, version = entry:match("^([^/]*)/(.*)$") |
164 | |||
116 | local file_name = tree.manifest.repository[name][version][1].modules[module] | 165 | local file_name = tree.manifest.repository[name][version][1].modules[module] |
117 | if type(file_name) ~= "string" then | 166 | if type(file_name) ~= "string" then |
118 | error("Invalid data in manifest file for module "..tostring(module).." (invalid data for "..tostring(name).." "..tostring(version)..")") | 167 | error("Invalid data in manifest file for module " .. tostring(module) .. " (invalid data for " .. tostring(name) .. " " .. tostring(version) .. ")") |
119 | end | 168 | end |
120 | file_name = filter_file_name(file_name, name, version, tree.tree, i) | 169 | |
170 | file_name = filter_name(file_name, name, version, tree.tree, i) | ||
171 | |||
121 | if loader.context[name] == version then | 172 | if loader.context[name] == version then |
122 | return name, version, file_name | 173 | return name, version, file_name |
123 | end | 174 | end |
124 | version = vers.parse_version(version) | 175 | |
125 | table.insert(providers, {name = name, version = version, module_name = file_name, tree = tree}) | 176 | table.insert(providers, { |
177 | name = name, | ||
178 | version = vers.parse_version(version), | ||
179 | module_name = file_name, | ||
180 | tree = tree | ||
181 | }) | ||
126 | end | 182 | end |
127 | end | 183 | end |
128 | 184 | ||
129 | --- Search for a module in the rocks trees | 185 | --- Search for a module in the rocks trees. |
130 | -- @param module string: module name (eg. "socket.core") | 186 | -- |
131 | -- @param filter_file_name function(string, string, string, string, number): | 187 | -- @param module module name (eg. "socket.core") |
132 | -- a function that takes the module file name (eg "socket/core.so"), the rock name | 188 | -- @param filter_name a function that takes the module file name |
133 | -- (eg "luasocket"), the version (eg "2.0.2-1"), the path of the rocks tree | 189 | -- (eg "socket/core.so"), the rock name (eg "luasocket"), |
190 | -- the version (eg "2.0.2-1"), the path of the rocks tree | ||
134 | -- (eg "/usr/local"), and the numeric index of the matching entry, so the | 191 | -- (eg "/usr/local"), and the numeric index of the matching entry, so the |
135 | -- filter function can know if the matching module was the first entry or not. | 192 | -- filter function can know if the matching module was the first entry or not. |
136 | -- @return string, string, string, (string or table): | 193 | -- |
137 | -- * name of the rock containing the module (eg. "luasocket") | 194 | -- @return name of the rock containing the module (eg. "luasocket") |
138 | -- * version of the rock (eg. "2.0.2-1") | 195 | -- @return version of the rock (eg. "2.0.2-1") |
139 | -- * return value of filter_file_name | 196 | -- @return return value of filter_name |
140 | -- * tree of the module (string or table in `tree_manifests` format) | 197 | local function select_module(module: string, filter_name: FilterFn): string, string, string |
141 | local function select_module(module, filter_file_name) | ||
142 | --assert(type(module) == "string") | ||
143 | --assert(type(filter_module_name) == "function") | ||
144 | 198 | ||
145 | local tree_manifests = manif.load_rocks_tree_manifests() | 199 | local tree_manifests = manif.load_rocks_tree_manifests() |
146 | if not tree_manifests then | 200 | if not tree_manifests then |
147 | return nil | 201 | return nil |
148 | end | 202 | end |
149 | 203 | ||
150 | local providers = {} | 204 | local providers: {Provider} = {} |
151 | local initmodule | 205 | local initmodule: string |
152 | for _, tree in ipairs(tree_manifests) do | 206 | for _, tree in ipairs(tree_manifests) do |
153 | local entries = tree.manifest.modules[module] | 207 | local entries = tree.manifest.modules[module] |
154 | if entries then | 208 | if entries then |
155 | local n, v, f = add_providers(providers, entries, tree, module, filter_file_name) | 209 | local n, v, f = add_providers(providers, entries, tree, module, filter_name) |
156 | if n then | 210 | if n then |
157 | return n, v, f | 211 | return n, v, f |
158 | end | 212 | end |
@@ -160,7 +214,7 @@ local function select_module(module, filter_file_name) | |||
160 | initmodule = initmodule or module .. ".init" | 214 | initmodule = initmodule or module .. ".init" |
161 | entries = tree.manifest.modules[initmodule] | 215 | entries = tree.manifest.modules[initmodule] |
162 | if entries then | 216 | if entries then |
163 | local n, v, f = add_providers(providers, entries, tree, initmodule, filter_file_name) | 217 | local n, v, f = add_providers(providers, entries, tree, initmodule, filter_name) |
164 | if n then | 218 | if n then |
165 | return n, v, f | 219 | return n, v, f |
166 | end | 220 | end |
@@ -171,46 +225,53 @@ local function select_module(module, filter_file_name) | |||
171 | if next(providers) then | 225 | if next(providers) then |
172 | table.sort(providers, sort_versions) | 226 | table.sort(providers, sort_versions) |
173 | local first = providers[1] | 227 | local first = providers[1] |
174 | return first.name, first.version.string, first.module_name, first.tree | 228 | return first.name, first.version.string, first.module_name |
175 | end | 229 | end |
176 | end | 230 | end |
177 | 231 | ||
178 | --- Search for a module | 232 | --- Filter operation for adjusting the versioned names when multiple packages provide |
179 | -- @param module string: module name (eg. "socket.core") | 233 | -- the same file. |
180 | -- @return string, string, string, (string or table): | 234 | -- |
181 | -- * name of the rock containing the module (eg. "luasocket") | 235 | -- @param file_name The original filename |
182 | -- * version of the rock (eg. "2.0.2-1") | 236 | -- @param name The rock name |
183 | -- * name of the module (eg. "socket.core", or "socket.core_2_0_2" if file is stored versioned). | 237 | -- @param version The rock version |
184 | -- * tree of the module (string or table in `tree_manifests` format) | 238 | -- @param _tree (unused) |
185 | local function pick_module(module) | 239 | -- @param i The priority index, to determine whether to version the name. |
186 | return | 240 | -- |
187 | select_module(module, function(file_name, name, version, tree, i) | 241 | -- @return A filename, which may be plain or versioned. |
188 | if i > 1 then | 242 | -- (eg. "socket.core", or "socket.core_2_0_2" if file is stored versioned). |
189 | file_name = path.versioned_name(file_name, "", name, version) | 243 | local function filter_module_name(file_name: string, name: string, version: string, _tree: Tree, i: integer): string |
190 | end | 244 | if i > 1 then |
191 | return path.path_to_module(file_name) | 245 | file_name = path.versioned_name(file_name, "", name, version) |
192 | end) | 246 | end |
247 | return path.path_to_module(file_name) | ||
248 | end | ||
249 | |||
250 | --- Search for a module. | ||
251 | -- | ||
252 | -- @param module name of the module (eg. "socket.core") | ||
253 | -- | ||
254 | -- @return name of the rock containing the module (eg. "luasocket") | ||
255 | -- @return version of the rock (eg. "2.0.2-1") | ||
256 | -- @return name of the module (eg. "socket.core", or "socket.core_2_0_2" if file is stored versioned). | ||
257 | -- @return tree of the module (string or table in `tree_manifests` format) | ||
258 | local function pick_module(module: string): string, string, string, string | TreeManifest | ||
259 | return select_module(module, filter_module_name) | ||
193 | end | 260 | end |
194 | 261 | ||
195 | --- Return the pathname of the file that would be loaded for a module. | 262 | --- Return the pathname of the file that would be loaded for a module. |
196 | -- @param module string: module name (eg. "socket.core") | 263 | -- |
197 | -- @param where string: places to look for the module. If `where` contains | 264 | -- @param module module name (eg. "socket.core") |
265 | -- @param where places to look for the module. If `where` contains | ||
198 | -- "l", it will search using the LuaRocks loader; if it contains "p", | 266 | -- "l", it will search using the LuaRocks loader; if it contains "p", |
199 | -- it will look in the filesystem using package.path and package.cpath. | 267 | -- it will look in the filesystem using package.path and package.cpath. |
200 | -- You can use both at the same time. | 268 | -- You can use both at the same time. |
201 | -- @return If successful, it will return four values. | 269 | -- |
202 | -- * If found using the LuaRocks loader, it will return: | 270 | -- @return If found, filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so"), |
203 | -- * filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so"), | 271 | -- @return If found via the loader, the rock name; otherwise, "path" or "cpath" |
204 | -- * rock name | 272 | -- @return If found via the loader, the rock version; otherwise, nil |
205 | -- * rock version | 273 | -- @return If found via the loader, "l"; if found via package.path or package.cpath, "p". |
206 | -- * "l" to indicate the match comes from the loader. | 274 | function loader.which(module: string, where?: string): string, string, string, string |
207 | -- * If found scanning package.path and package.cpath, it will return: | ||
208 | -- * filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so"), | ||
209 | -- * "path" or "cpath" | ||
210 | -- * nil | ||
211 | -- * "p" to indicate the match comes from scanning package.path and cpath. | ||
212 | -- If unsuccessful, nothing is returned. | ||
213 | function loader.which(module, where) | ||
214 | where = where or "l" | 275 | where = where or "l" |
215 | if where:match("l") then | 276 | if where:match("l") then |
216 | local rock_name, rock_version, file_name = select_module(module, path.which_i) | 277 | local rock_name, rock_version, file_name = select_module(module, path.which_i) |
@@ -224,8 +285,8 @@ function loader.which(module, where) | |||
224 | end | 285 | end |
225 | if where:match("p") then | 286 | if where:match("p") then |
226 | local modpath = module:gsub("%.", "/") | 287 | local modpath = module:gsub("%.", "/") |
227 | for _, v in ipairs({"path", "cpath"}) do | 288 | for _, v in ipairs({package.path, package.cpath}) do |
228 | for p in package[v]:gmatch("([^;]+)") do | 289 | for p in v:gmatch("([^;]+)") do |
229 | local file_name = p:gsub("%?", modpath) -- luacheck: ignore 421 | 290 | local file_name = p:gsub("%?", modpath) -- luacheck: ignore 421 |
230 | local fd = io.open(file_name) | 291 | local fd = io.open(file_name) |
231 | if fd then | 292 | if fd then |
@@ -238,18 +299,21 @@ function loader.which(module, where) | |||
238 | end | 299 | end |
239 | 300 | ||
240 | --- Package loader for LuaRocks support. | 301 | --- Package loader for LuaRocks support. |
241 | -- A module is searched in installed rocks that match the | 302 | -- See <a href="http://www.lua.org/manual/5.4/manual.html#pdf-require">require()</a> |
303 | -- in the Lua reference manual for details on the require() mechanism. | ||
304 | -- The LuaRocks loader works by searching in installed rocks that match the | ||
242 | -- current LuaRocks context. If module is not part of the | 305 | -- current LuaRocks context. If module is not part of the |
243 | -- context, or if a context has not yet been set, the module | 306 | -- context, or if a context has not yet been set, the module |
244 | -- in the package with the highest version is used. | 307 | -- in the package with the highest version is used. |
245 | -- @param module string: The module name, like in plain require(). | 308 | -- |
246 | -- @return table: The module table (typically), like in plain | 309 | -- @param module The module name, like in plain require(). |
247 | -- require(). See <a href="http://www.lua.org/manual/5.1/manual.html#pdf-require">require()</a> | 310 | -- |
248 | -- in the Lua reference manual for details. | 311 | -- @return A function which can load the module found, |
249 | function loader.luarocks_loader(module) | 312 | -- or a string with an error message. |
313 | function loader.luarocks_loader(module: string): LoaderFn | string, any | ||
250 | local name, version, module_name = pick_module(module) | 314 | local name, version, module_name = pick_module(module) |
251 | if not name then | 315 | if not name then |
252 | return "No LuaRocks module found for "..module | 316 | return "No LuaRocks module found for " .. module |
253 | else | 317 | else |
254 | loader.add_context(name, version) | 318 | loader.add_context(name, version) |
255 | return call_other_loaders(module, name, version, module_name) | 319 | return call_other_loaders(module, name, version, module_name) |