diff options
author | Hisham Muhammad <hisham@gobolinux.org> | 2024-08-20 20:05:50 -0300 |
---|---|---|
committer | Hisham Muhammad <hisham@gobolinux.org> | 2024-08-20 20:06:33 -0300 |
commit | 703372dcff31de2dd1edcaedbf2aba68f5d572bf (patch) | |
tree | bc4f5b9f89be570ff1e95fa900130039aea3120a | |
parent | c400ccaec13d9004a970e41d248c1ccee050aa33 (diff) | |
download | luarocks-lua-to-teal-migration-loader.tar.gz luarocks-lua-to-teal-migration-loader.tar.bz2 luarocks-lua-to-teal-migration-loader.zip |
convert luarocks.loaderlua-to-teal-migration-loader
-rw-r--r-- | src/luarocks/core/cfg.d.tl | 1 | ||||
-rw-r--r-- | src/luarocks/core/path.tl | 4 | ||||
-rw-r--r-- | src/luarocks/loader-original.lua | 269 | ||||
-rw-r--r-- | src/luarocks/loader.lua | 316 | ||||
-rw-r--r-- | src/luarocks/loader.tl | 333 |
5 files changed, 795 insertions, 128 deletions
diff --git a/src/luarocks/core/cfg.d.tl b/src/luarocks/core/cfg.d.tl index 8437a043..03338d9b 100644 --- a/src/luarocks/core/cfg.d.tl +++ b/src/luarocks/core/cfg.d.tl | |||
@@ -59,6 +59,7 @@ local record cfg | |||
59 | end | 59 | end |
60 | -- loader | 60 | -- loader |
61 | init: function(?{string : string}, ?function(string)): boolean, string, string | 61 | init: function(?{string : string}, ?function(string)): boolean, string, string |
62 | init_package_paths: function() | ||
62 | -- rockspecs | 63 | -- rockspecs |
63 | each_platform: function(?string): (function():string) | 64 | each_platform: function(?string): (function():string) |
64 | -- fetch | 65 | -- fetch |
diff --git a/src/luarocks/core/path.tl b/src/luarocks/core/path.tl index eff15a51..680c3296 100644 --- a/src/luarocks/core/path.tl +++ b/src/luarocks/core/path.tl | |||
@@ -73,7 +73,7 @@ function path.deploy_lua_dir(tree: string | Tree): string | |||
73 | if tree is string then | 73 | if tree is string then |
74 | return dir.path(tree, cfg.lua_modules_path) | 74 | return dir.path(tree, cfg.lua_modules_path) |
75 | else | 75 | else |
76 | return tree.lua_dir or dir.path(tree.root, cfg.lua_modules_path) | 76 | return tree.lua_dir or dir.path(tree.root, cfg.lua_modules_path) |
77 | end | 77 | end |
78 | end | 78 | end |
79 | 79 | ||
@@ -95,7 +95,7 @@ local is_src_extension: {string: boolean} = { [".lua"] = true, [".tl"] = true, [ | |||
95 | -- @param i number: the index, 1 if version is the current default, > 1 otherwise. | 95 | -- @param i number: the index, 1 if version is the current default, > 1 otherwise. |
96 | -- This is done this way for use by select_module in luarocks.loader. | 96 | -- This is done this way for use by select_module in luarocks.loader. |
97 | -- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so") | 97 | -- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so") |
98 | function path.which_i(file_name: string, name: string, version: string, tree: string, i: number): string | 98 | function path.which_i(file_name: string, name: string, version: string, tree: string | Tree, i: number): string |
99 | local deploy_dir: string | 99 | local deploy_dir: string |
100 | local extension = file_name:match("%.[a-z]+$") | 100 | local extension = file_name:match("%.[a-z]+$") |
101 | if is_src_extension[extension] then | 101 | if is_src_extension[extension] then |
diff --git a/src/luarocks/loader-original.lua b/src/luarocks/loader-original.lua new file mode 100644 index 00000000..772fdfcb --- /dev/null +++ b/src/luarocks/loader-original.lua | |||
@@ -0,0 +1,269 @@ | |||
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 | |||
10 | local loaders = package.loaders or package.searchers | ||
11 | local require, ipairs, table, type, next, tostring, error = | ||
12 | require, ipairs, table, type, next, tostring, error | ||
13 | local unpack = unpack or table.unpack | ||
14 | |||
15 | local loader = {} | ||
16 | |||
17 | local is_clean = not package.loaded["luarocks.core.cfg"] | ||
18 | |||
19 | -- This loader module depends only on core modules. | ||
20 | local cfg = require("luarocks.core.cfg") | ||
21 | local cfg_ok, err = cfg.init() | ||
22 | if cfg_ok then | ||
23 | cfg.init_package_paths() | ||
24 | end | ||
25 | |||
26 | local path = require("luarocks.core.path") | ||
27 | local manif = require("luarocks.core.manif") | ||
28 | local vers = require("luarocks.core.vers") | ||
29 | local require = nil -- luacheck: ignore 411 | ||
30 | -------------------------------------------------------------------------------- | ||
31 | |||
32 | -- Workaround for wrappers produced by older versions of LuaRocks | ||
33 | local temporary_global = false | ||
34 | local status, luarocks_value = pcall(function() return luarocks end) | ||
35 | if status and luarocks_value then | ||
36 | -- The site_config.lua file generated by old versions uses module(), | ||
37 | -- so it produces a global `luarocks` table. Since we have the table, | ||
38 | -- add the `loader` field to make the old wrappers happy. | ||
39 | luarocks.loader = loader | ||
40 | else | ||
41 | -- When a new version is installed on top of an old version, | ||
42 | -- site_config.lua may be replaced, and then it no longer creates | ||
43 | -- a global. | ||
44 | -- Detect when being called via -lluarocks.loader; this is | ||
45 | -- most likely a wrapper. | ||
46 | local info = debug and debug.getinfo(2, "nS") | ||
47 | if info and info.what == "C" and not info.name then | ||
48 | luarocks = { loader = loader } | ||
49 | temporary_global = true | ||
50 | -- For the other half of this hack, | ||
51 | -- see the next use of `temporary_global` below. | ||
52 | end | ||
53 | end | ||
54 | |||
55 | loader.context = {} | ||
56 | |||
57 | --- Process the dependencies of a package to determine its dependency | ||
58 | -- chain for loading modules. | ||
59 | -- @param name string: The name of an installed rock. | ||
60 | -- @param version string: The version of the rock, in string format | ||
61 | function loader.add_context(name, version) | ||
62 | -- assert(type(name) == "string") | ||
63 | -- assert(type(version) == "string") | ||
64 | |||
65 | if temporary_global then | ||
66 | -- The first thing a wrapper does is to call add_context. | ||
67 | -- From here on, it's safe to clean the global environment. | ||
68 | luarocks = nil | ||
69 | temporary_global = false | ||
70 | end | ||
71 | |||
72 | local tree_manifests = manif.load_rocks_tree_manifests() | ||
73 | if not tree_manifests then | ||
74 | return nil | ||
75 | end | ||
76 | |||
77 | return manif.scan_dependencies(name, version, tree_manifests, loader.context) | ||
78 | end | ||
79 | |||
80 | --- Internal sorting function. | ||
81 | -- @param a table: A provider table. | ||
82 | -- @param b table: Another provider table. | ||
83 | -- @return boolean: True if the version of a is greater than that of b. | ||
84 | local function sort_versions(a,b) | ||
85 | return a.version > b.version | ||
86 | end | ||
87 | |||
88 | --- Request module to be loaded through other loaders, | ||
89 | -- once the proper name of the module has been determined. | ||
90 | -- For example, in case the module "socket.core" has been requested | ||
91 | -- to the LuaRocks loader and it determined based on context that | ||
92 | -- 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 | ||
94 | -- "socket.core_2_0_2". | ||
95 | -- @param module The module name requested by the user, such as "socket.core" | ||
96 | -- @param name The rock name, such as "luasocket" | ||
97 | -- @param version The rock version, such as "2.0.2-1" | ||
98 | -- @param module_name The actual module name, such as "socket.core" or "socket.core_2_0_2". | ||
99 | -- @return table or (nil, string): The module table as returned by some other loader, | ||
100 | -- or nil followed by an error message if no other loader managed to load the module. | ||
101 | local function call_other_loaders(module, name, version, module_name) | ||
102 | for _, a_loader in ipairs(loaders) do | ||
103 | if a_loader ~= loader.luarocks_loader then | ||
104 | local results = { a_loader(module_name) } | ||
105 | if type(results[1]) == "function" then | ||
106 | return unpack(results) | ||
107 | end | ||
108 | end | ||
109 | end | ||
110 | return "Failed loading module "..module.." in LuaRocks rock "..name.." "..version | ||
111 | end | ||
112 | |||
113 | local function add_providers(providers, entries, tree, module, filter_file_name) | ||
114 | for i, entry in ipairs(entries) do | ||
115 | local name, version = entry:match("^([^/]*)/(.*)$") | ||
116 | local file_name = tree.manifest.repository[name][version][1].modules[module] | ||
117 | if type(file_name) ~= "string" then | ||
118 | error("Invalid data in manifest file for module "..tostring(module).." (invalid data for "..tostring(name).." "..tostring(version)..")") | ||
119 | end | ||
120 | file_name = filter_file_name(file_name, name, version, tree.tree, i) | ||
121 | if loader.context[name] == version then | ||
122 | return name, version, file_name | ||
123 | end | ||
124 | version = vers.parse_version(version) | ||
125 | table.insert(providers, {name = name, version = version, module_name = file_name, tree = tree}) | ||
126 | end | ||
127 | end | ||
128 | |||
129 | --- Search for a module in the rocks trees | ||
130 | -- @param module string: module name (eg. "socket.core") | ||
131 | -- @param filter_file_name function(string, string, string, string, number): | ||
132 | -- a function that takes the module file name (eg "socket/core.so"), the rock name | ||
133 | -- (eg "luasocket"), 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 | ||
135 | -- filter function can know if the matching module was the first entry or not. | ||
136 | -- @return string, string, string, (string or table): | ||
137 | -- * name of the rock containing the module (eg. "luasocket") | ||
138 | -- * version of the rock (eg. "2.0.2-1") | ||
139 | -- * return value of filter_file_name | ||
140 | -- * tree of the module (string or table in `tree_manifests` format) | ||
141 | local function select_module(module, filter_file_name) | ||
142 | --assert(type(module) == "string") | ||
143 | --assert(type(filter_module_name) == "function") | ||
144 | |||
145 | local tree_manifests = manif.load_rocks_tree_manifests() | ||
146 | if not tree_manifests then | ||
147 | return nil | ||
148 | end | ||
149 | |||
150 | local providers = {} | ||
151 | local initmodule | ||
152 | for _, tree in ipairs(tree_manifests) do | ||
153 | local entries = tree.manifest.modules[module] | ||
154 | if entries then | ||
155 | local n, v, f = add_providers(providers, entries, tree, module, filter_file_name) | ||
156 | if n then | ||
157 | return n, v, f | ||
158 | end | ||
159 | else | ||
160 | initmodule = initmodule or module .. ".init" | ||
161 | entries = tree.manifest.modules[initmodule] | ||
162 | if entries then | ||
163 | local n, v, f = add_providers(providers, entries, tree, initmodule, filter_file_name) | ||
164 | if n then | ||
165 | return n, v, f | ||
166 | end | ||
167 | end | ||
168 | end | ||
169 | end | ||
170 | |||
171 | if next(providers) then | ||
172 | table.sort(providers, sort_versions) | ||
173 | local first = providers[1] | ||
174 | return first.name, first.version.string, first.module_name, first.tree | ||
175 | end | ||
176 | end | ||
177 | |||
178 | --- Search for a module | ||
179 | -- @param module string: module name (eg. "socket.core") | ||
180 | -- @return string, string, string, (string or table): | ||
181 | -- * name of the rock containing the module (eg. "luasocket") | ||
182 | -- * version of the rock (eg. "2.0.2-1") | ||
183 | -- * name of the module (eg. "socket.core", or "socket.core_2_0_2" if file is stored versioned). | ||
184 | -- * tree of the module (string or table in `tree_manifests` format) | ||
185 | local function pick_module(module) | ||
186 | return | ||
187 | select_module(module, function(file_name, name, version, tree, i) | ||
188 | if i > 1 then | ||
189 | file_name = path.versioned_name(file_name, "", name, version) | ||
190 | end | ||
191 | return path.path_to_module(file_name) | ||
192 | end) | ||
193 | end | ||
194 | |||
195 | --- Return the pathname of the file that would be loaded for a module. | ||
196 | -- @param module string: module name (eg. "socket.core") | ||
197 | -- @param where string: places to look for the module. If `where` contains | ||
198 | -- "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. | ||
200 | -- You can use both at the same time. | ||
201 | -- @return If successful, it will return four values. | ||
202 | -- * If found using the LuaRocks loader, it will return: | ||
203 | -- * filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so"), | ||
204 | -- * rock name | ||
205 | -- * rock version | ||
206 | -- * "l" to indicate the match comes from the loader. | ||
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" | ||
215 | if where:match("l") then | ||
216 | local rock_name, rock_version, file_name = select_module(module, path.which_i) | ||
217 | if rock_name then | ||
218 | local fd = io.open(file_name) | ||
219 | if fd then | ||
220 | fd:close() | ||
221 | return file_name, rock_name, rock_version, "l" | ||
222 | end | ||
223 | end | ||
224 | end | ||
225 | if where:match("p") then | ||
226 | local modpath = module:gsub("%.", "/") | ||
227 | for _, v in ipairs({"path", "cpath"}) do | ||
228 | for p in package[v]:gmatch("([^;]+)") do | ||
229 | local file_name = p:gsub("%?", modpath) -- luacheck: ignore 421 | ||
230 | local fd = io.open(file_name) | ||
231 | if fd then | ||
232 | fd:close() | ||
233 | return file_name, v, nil, "p" | ||
234 | end | ||
235 | end | ||
236 | end | ||
237 | end | ||
238 | end | ||
239 | |||
240 | --- Package loader for LuaRocks support. | ||
241 | -- A module is searched in installed rocks that match the | ||
242 | -- current LuaRocks context. If module is not part of the | ||
243 | -- context, or if a context has not yet been set, the module | ||
244 | -- in the package with the highest version is used. | ||
245 | -- @param module string: The module name, like in plain require(). | ||
246 | -- @return table: The module table (typically), like in plain | ||
247 | -- require(). See <a href="http://www.lua.org/manual/5.1/manual.html#pdf-require">require()</a> | ||
248 | -- in the Lua reference manual for details. | ||
249 | function loader.luarocks_loader(module) | ||
250 | local name, version, module_name = pick_module(module) | ||
251 | if not name then | ||
252 | return "No LuaRocks module found for "..module | ||
253 | else | ||
254 | loader.add_context(name, version) | ||
255 | return call_other_loaders(module, name, version, module_name) | ||
256 | end | ||
257 | end | ||
258 | |||
259 | table.insert(loaders, 1, loader.luarocks_loader) | ||
260 | |||
261 | if is_clean then | ||
262 | for modname, _ in pairs(package.loaded) do | ||
263 | if modname:match("^luarocks%.") then | ||
264 | package.loaded[modname] = nil | ||
265 | end | ||
266 | end | ||
267 | end | ||
268 | |||
269 | return loader | ||
diff --git a/src/luarocks/loader.lua b/src/luarocks/loader.lua index 772fdfcb..37f196f0 100644 --- a/src/luarocks/loader.lua +++ b/src/luarocks/loader.lua | |||
@@ -1,24 +1,24 @@ | |||
1 | --- A module which installs a Lua package loader that is LuaRocks-aware. | 1 | local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local debug = _tl_compat and _tl_compat.debug or debug; local io = _tl_compat and _tl_compat.io or io; local ipairs = _tl_compat and _tl_compat.ipairs or ipairs; local package = _tl_compat and _tl_compat.package or package; local pairs = _tl_compat and _tl_compat.pairs or pairs; local pcall = _tl_compat and _tl_compat.pcall or pcall; local string = _tl_compat and _tl_compat.string or string; local table = _tl_compat and _tl_compat.table or table |
2 | -- This loader uses dependency information from the LuaRocks tree to load | 2 | |
3 | -- correct versions of modules. It does this by constructing a "context" | 3 | |
4 | -- table in the environment, which records which versions of packages were | 4 | |
5 | -- used to load previous modules, so that the loader chooses versions | 5 | |
6 | -- that are declared to be compatible with the ones loaded earlier. | ||
7 | 6 | ||
8 | -- luacheck: globals luarocks | ||
9 | 7 | ||
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 loader = {} |
16 | 13 | ||
14 | |||
15 | |||
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 | |
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,121 +26,175 @@ 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 | ||
30 | -------------------------------------------------------------------------------- | ||
31 | 29 | ||
32 | -- Workaround for wrappers produced by older versions of LuaRocks | 30 | |
31 | |||
32 | |||
33 | |||
34 | |||
35 | |||
36 | |||
37 | |||
38 | |||
39 | |||
40 | |||
41 | |||
42 | |||
43 | |||
44 | |||
45 | |||
46 | |||
47 | |||
48 | |||
49 | |||
50 | |||
51 | |||
52 | |||
53 | |||
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() |
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 | |
37 | -- so it produces a global `luarocks` table. Since we have the table, | 60 | |
38 | -- add the `loader` field to make the old wrappers happy. | 61 | |
39 | luarocks.loader = loader | 62 | luarocks.loader = loader |
40 | else | 63 | else |
41 | -- When a new version is installed on top of an old version, | 64 | |
42 | -- site_config.lua may be replaced, and then it no longer creates | 65 | |
43 | -- a global. | 66 | |
44 | -- Detect when being called via -lluarocks.loader; this is | 67 | |
45 | -- most likely a wrapper. | 68 | |
46 | local info = debug and debug.getinfo(2, "nS") | 69 | local info = debug and debug.getinfo(2, "nS") |
47 | if info and info.what == "C" and not info.name then | 70 | if info and info.what == "C" and not info.name then |
48 | luarocks = { loader = loader } | 71 | luarocks = { loader = loader } |
49 | temporary_global = true | 72 | temporary_global = true |
50 | -- For the other half of this hack, | 73 | |
51 | -- see the next use of `temporary_global` below. | 74 | |
52 | end | 75 | end |
53 | end | 76 | end |
54 | 77 | ||
78 | |||
79 | |||
80 | |||
81 | |||
55 | loader.context = {} | 82 | loader.context = {} |
56 | 83 | ||
57 | --- Process the dependencies of a package to determine its dependency | ||
58 | -- chain for loading modules. | ||
59 | -- @param name string: The name of an installed rock. | ||
60 | -- @param version string: The version of the rock, in string format | ||
61 | function loader.add_context(name, version) | ||
62 | -- assert(type(name) == "string") | ||
63 | -- assert(type(version) == "string") | ||
64 | 84 | ||
85 | |||
86 | |||
87 | |||
88 | |||
89 | function loader.add_context(name, version) | ||
65 | if temporary_global then | 90 | if temporary_global then |
66 | -- The first thing a wrapper does is to call add_context. | 91 | |
67 | -- From here on, it's safe to clean the global environment. | 92 | |
68 | luarocks = nil | 93 | luarocks = nil |
69 | temporary_global = false | 94 | temporary_global = false |
70 | end | 95 | end |
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 | |
81 | -- @param a table: A provider table. | 106 | |
82 | -- @param b table: Another provider table. | 107 | |
83 | -- @return boolean: True if the version of a is greater than that of b. | 108 | |
84 | local function sort_versions(a,b) | 109 | |
110 | |||
111 | local function sort_versions(a, b) | ||
85 | return a.version > b.version | 112 | return a.version > b.version |
86 | end | 113 | end |
87 | 114 | ||
88 | --- Request module to be loaded through other loaders, | 115 | |
89 | -- once the proper name of the module has been determined. | 116 | |
90 | -- For example, in case the module "socket.core" has been requested | 117 | |
91 | -- to the LuaRocks loader and it determined based on context that | 118 | |
92 | -- the version 2.0.2 needs to be loaded and it is not the current | 119 | |
93 | -- version, the module requested for the other loaders will be | 120 | |
94 | -- "socket.core_2_0_2". | 121 | |
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 | |
97 | -- @param version The rock version, such as "2.0.2-1" | 124 | |
98 | -- @param module_name The actual module name, such as "socket.core" or "socket.core_2_0_2". | 125 | |
99 | -- @return table or (nil, string): The module table as returned by some other loader, | 126 | |
100 | -- or nil followed by an error message if no other loader managed to load the module. | 127 | |
128 | |||
129 | |||
101 | local function call_other_loaders(module, name, version, module_name) | 130 | local function call_other_loaders(module, name, version, module_name) |
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 = { a_loader(module_name) } |
105 | if type(results[1]) == "function" then | 134 | local f = results[1] |
106 | return unpack(results) | 135 | if type(f) == "function" 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 | |
148 | |||
149 | |||
150 | |||
151 | |||
152 | |||
153 | |||
154 | |||
155 | |||
156 | |||
157 | |||
158 | |||
159 | |||
160 | |||
161 | local function add_providers(providers, entries, tree, module, filter_name) | ||
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 | |
130 | -- @param module string: module name (eg. "socket.core") | 186 | |
131 | -- @param filter_file_name function(string, string, string, string, number): | 187 | |
132 | -- a function that takes the module file name (eg "socket/core.so"), the rock name | 188 | |
133 | -- (eg "luasocket"), the version (eg "2.0.2-1"), the path of the rocks tree | 189 | |
134 | -- (eg "/usr/local"), and the numeric index of the matching entry, so the | 190 | |
135 | -- filter function can know if the matching module was the first entry or not. | 191 | |
136 | -- @return string, string, string, (string or table): | 192 | |
137 | -- * name of the rock containing the module (eg. "luasocket") | 193 | |
138 | -- * version of the rock (eg. "2.0.2-1") | 194 | |
139 | -- * return value of filter_file_name | 195 | |
140 | -- * tree of the module (string or table in `tree_manifests` format) | 196 | |
141 | local function select_module(module, filter_file_name) | 197 | local function select_module(module, filter_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 |
@@ -152,7 +206,7 @@ local function select_module(module, filter_file_name) | |||
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 |
@@ -168,48 +222,55 @@ local function select_module(module, filter_file_name) | |||
168 | end | 222 | end |
169 | end | 223 | end |
170 | 224 | ||
171 | if next(providers) then | 225 | if next(providers) ~= nil 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 | |
179 | -- @param module string: module name (eg. "socket.core") | 233 | |
180 | -- @return string, string, string, (string or table): | 234 | |
181 | -- * name of the rock containing the module (eg. "luasocket") | 235 | |
182 | -- * version of the rock (eg. "2.0.2-1") | 236 | |
183 | -- * name of the module (eg. "socket.core", or "socket.core_2_0_2" if file is stored versioned). | 237 | |
184 | -- * tree of the module (string or table in `tree_manifests` format) | 238 | |
239 | |||
240 | |||
241 | |||
242 | |||
243 | local function filter_module_name(file_name, name, version, _tree, i) | ||
244 | if i > 1 then | ||
245 | file_name = path.versioned_name(file_name, "", name, version) | ||
246 | end | ||
247 | return path.path_to_module(file_name) | ||
248 | end | ||
249 | |||
250 | |||
251 | |||
252 | |||
253 | |||
254 | |||
255 | |||
256 | |||
257 | |||
185 | local function pick_module(module) | 258 | local function pick_module(module) |
186 | return | 259 | return select_module(module, filter_module_name) |
187 | select_module(module, function(file_name, name, version, tree, i) | ||
188 | if i > 1 then | ||
189 | file_name = path.versioned_name(file_name, "", name, version) | ||
190 | end | ||
191 | return path.path_to_module(file_name) | ||
192 | end) | ||
193 | end | 260 | end |
194 | 261 | ||
195 | --- Return the pathname of the file that would be loaded for a module. | 262 | |
196 | -- @param module string: module name (eg. "socket.core") | 263 | |
197 | -- @param where string: places to look for the module. If `where` contains | 264 | |
198 | -- "l", it will search using the LuaRocks loader; if it contains "p", | 265 | |
199 | -- it will look in the filesystem using package.path and package.cpath. | 266 | |
200 | -- You can use both at the same time. | 267 | |
201 | -- @return If successful, it will return four values. | 268 | |
202 | -- * If found using the LuaRocks loader, it will return: | 269 | |
203 | -- * filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so"), | 270 | |
204 | -- * rock name | 271 | |
205 | -- * rock version | 272 | |
206 | -- * "l" to indicate the match comes from the loader. | 273 | |
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) | 274 | 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 |
@@ -224,9 +285,9 @@ 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) |
230 | local fd = io.open(file_name) | 291 | local fd = io.open(file_name) |
231 | if fd then | 292 | if fd then |
232 | fd:close() | 293 | fd:close() |
@@ -237,19 +298,22 @@ function loader.which(module, where) | |||
237 | end | 298 | end |
238 | end | 299 | end |
239 | 300 | ||
240 | --- Package loader for LuaRocks support. | 301 | |
241 | -- A module is searched in installed rocks that match the | 302 | |
242 | -- current LuaRocks context. If module is not part of the | 303 | |
243 | -- context, or if a context has not yet been set, the module | 304 | |
244 | -- in the package with the highest version is used. | 305 | |
245 | -- @param module string: The module name, like in plain require(). | 306 | |
246 | -- @return table: The module table (typically), like in plain | 307 | |
247 | -- require(). See <a href="http://www.lua.org/manual/5.1/manual.html#pdf-require">require()</a> | 308 | |
248 | -- in the Lua reference manual for details. | 309 | |
310 | |||
311 | |||
312 | |||
249 | function loader.luarocks_loader(module) | 313 | function loader.luarocks_loader(module) |
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) |
diff --git a/src/luarocks/loader.tl b/src/luarocks/loader.tl new file mode 100644 index 00000000..0a5e3c30 --- /dev/null +++ b/src/luarocks/loader.tl | |||
@@ -0,0 +1,333 @@ | |||
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 | local loaders = package.loaders or package.searchers | ||
9 | local require, ipairs, table, type, next, tostring, error = | ||
10 | require, ipairs, table, type, next, tostring, error | ||
11 | |||
12 | local record loader | ||
13 | context: {string: string} | ||
14 | luarocks_loader: function(string): LoaderFn | string, any | ||
15 | end | ||
16 | |||
17 | local is_clean = not package.loaded["luarocks.core.cfg"] | ||
18 | |||
19 | -- This loader module depends only on core modules. | ||
20 | local cfg = require("luarocks.core.cfg") | ||
21 | local cfg_ok, _err = cfg.init() | ||
22 | if cfg_ok then | ||
23 | cfg.init_package_paths() | ||
24 | end | ||
25 | |||
26 | local path = require("luarocks.core.path") | ||
27 | local manif = require("luarocks.core.manif") | ||
28 | local vers = require("luarocks.core.vers") | ||
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 | |||
43 | -------------------------------------------------------------------------------- | ||
44 | -- Backwards compatibility | ||
45 | -------------------------------------------------------------------------------- | ||
46 | |||
47 | local record LuaRocksGlobal | ||
48 | loader: loader | ||
49 | end | ||
50 | |||
51 | global luarocks: LuaRocksGlobal | ||
52 | |||
53 | -- Workaround for wrappers produced by older versions of LuaRocks | ||
54 | local temporary_global = false | ||
55 | local status, luarocks_value = pcall(function(): LuaRocksGlobal | ||
56 | return luarocks | ||
57 | end) | ||
58 | if status and luarocks_value then | ||
59 | -- The site_config.lua file generated by old versions uses module(), | ||
60 | -- so it produces a global `luarocks` table. Since we have the table, | ||
61 | -- add the `loader` field to make the old wrappers happy. | ||
62 | luarocks.loader = loader | ||
63 | else | ||
64 | -- When a new version is installed on top of an old version, | ||
65 | -- site_config.lua may be replaced, and then it no longer creates | ||
66 | -- a global. | ||
67 | -- Detect when being called via -lluarocks.loader; this is | ||
68 | -- most likely a wrapper. | ||
69 | local info = debug and debug.getinfo(2, "nS") | ||
70 | if info and info.what == "C" and not info.name then | ||
71 | luarocks = { loader = loader } | ||
72 | temporary_global = true | ||
73 | -- For the other half of this hack, | ||
74 | -- see the next use of `temporary_global` below. | ||
75 | end | ||
76 | end | ||
77 | |||
78 | -------------------------------------------------------------------------------- | ||
79 | -- Context management | ||
80 | -------------------------------------------------------------------------------- | ||
81 | |||
82 | loader.context = {} | ||
83 | |||
84 | --- Process the dependencies of a package to determine its dependency | ||
85 | -- chain for loading modules. | ||
86 | -- | ||
87 | -- @param name The name of an installed rock. | ||
88 | -- @param version The version of the rock, in string format | ||
89 | function loader.add_context(name: string, version: string) | ||
90 | if temporary_global then | ||
91 | -- The first thing a wrapper does is to call add_context. | ||
92 | -- From here on, it's safe to clean the global environment. | ||
93 | luarocks = nil | ||
94 | temporary_global = false | ||
95 | end | ||
96 | |||
97 | local tree_manifests = manif.load_rocks_tree_manifests() | ||
98 | if not tree_manifests then | ||
99 | return | ||
100 | end | ||
101 | |||
102 | manif.scan_dependencies(name, version, tree_manifests, loader.context) | ||
103 | end | ||
104 | |||
105 | --- Internal sorting function. | ||
106 | -- | ||
107 | -- @param a A provider table. | ||
108 | -- @param b Another provider table. | ||
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 | ||
112 | return a.version > b.version | ||
113 | end | ||
114 | |||
115 | --- Request module to be loaded through other loaders, | ||
116 | -- once the proper name of the module has been determined. | ||
117 | -- For example, in case the module "socket.core" has been requested | ||
118 | -- to the LuaRocks loader and it determined based on context that | ||
119 | -- the version 2.0.2 needs to be loaded and it is not the current | ||
120 | -- version, the module requested for the other loaders will be | ||
121 | -- "socket.core_2_0_2". | ||
122 | -- | ||
123 | -- @param module The module name requested by the user, e.g. "socket.core" | ||
124 | -- @param name The rock name, such as "luasocket" | ||
125 | -- @param version The rock version, such as "2.0.2-1" | ||
126 | -- @param module_name Actual module name, such as "socket.core_2_0_2" | ||
127 | -- | ||
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 | ||
131 | for _, a_loader in ipairs(loaders) do | ||
132 | if a_loader ~= loader.luarocks_loader then | ||
133 | local results: {any} = { a_loader(module_name) } | ||
134 | local f = results[1] | ||
135 | if f is LoaderFn then | ||
136 | if #results == 2 then | ||
137 | return f, results[2] | ||
138 | else | ||
139 | return f | ||
140 | end | ||
141 | end | ||
142 | end | ||
143 | end | ||
144 | return "Failed loading module " .. module .. " in LuaRocks rock " .. name .. " " .. version | ||
145 | end | ||
146 | |||
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 | ||
162 | for i, entry in ipairs(entries) do | ||
163 | local name, version = entry:match("^([^/]*)/(.*)$") | ||
164 | |||
165 | local file_name = tree.manifest.repository[name][version][1].modules[module] | ||
166 | if type(file_name) ~= "string" then | ||
167 | error("Invalid data in manifest file for module " .. tostring(module) .. " (invalid data for " .. tostring(name) .. " " .. tostring(version) .. ")") | ||
168 | end | ||
169 | |||
170 | file_name = filter_name(file_name, name, version, tree.tree, i) | ||
171 | |||
172 | if loader.context[name] == version then | ||
173 | return name, version, file_name | ||
174 | end | ||
175 | |||
176 | table.insert(providers, { | ||
177 | name = name, | ||
178 | version = vers.parse_version(version), | ||
179 | module_name = file_name, | ||
180 | tree = tree | ||
181 | }) | ||
182 | end | ||
183 | end | ||
184 | |||
185 | --- Search for a module in the rocks trees. | ||
186 | -- | ||
187 | -- @param module module name (eg. "socket.core") | ||
188 | -- @param filter_name a function that takes the module file name | ||
189 | -- (eg "socket/core.so"), the rock name (eg "luasocket"), | ||
190 | -- the version (eg "2.0.2-1"), the path of the rocks tree | ||
191 | -- (eg "/usr/local"), and the numeric index of the matching entry, so the | ||
192 | -- filter function can know if the matching module was the first entry or not. | ||
193 | -- | ||
194 | -- @return name of the rock containing the module (eg. "luasocket") | ||
195 | -- @return version of the rock (eg. "2.0.2-1") | ||
196 | -- @return return value of filter_name | ||
197 | local function select_module(module: string, filter_name: FilterFn): string, string, string | ||
198 | |||
199 | local tree_manifests = manif.load_rocks_tree_manifests() | ||
200 | if not tree_manifests then | ||
201 | return nil | ||
202 | end | ||
203 | |||
204 | local providers: {Provider} = {} | ||
205 | local initmodule: string | ||
206 | for _, tree in ipairs(tree_manifests) do | ||
207 | local entries = tree.manifest.modules[module] | ||
208 | if entries then | ||
209 | local n, v, f = add_providers(providers, entries, tree, module, filter_name) | ||
210 | if n then | ||
211 | return n, v, f | ||
212 | end | ||
213 | else | ||
214 | initmodule = initmodule or module .. ".init" | ||
215 | entries = tree.manifest.modules[initmodule] | ||
216 | if entries then | ||
217 | local n, v, f = add_providers(providers, entries, tree, initmodule, filter_name) | ||
218 | if n then | ||
219 | return n, v, f | ||
220 | end | ||
221 | end | ||
222 | end | ||
223 | end | ||
224 | |||
225 | if next(providers) ~= nil then | ||
226 | table.sort(providers, sort_versions) | ||
227 | local first = providers[1] | ||
228 | return first.name, first.version.string, first.module_name | ||
229 | end | ||
230 | end | ||
231 | |||
232 | --- Filter operation for adjusting the versioned names when multiple packages provide | ||
233 | -- the same file. | ||
234 | -- | ||
235 | -- @param file_name The original filename | ||
236 | -- @param name The rock name | ||
237 | -- @param version The rock version | ||
238 | -- @param _tree (unused) | ||
239 | -- @param i The priority index, to determine whether to version the name. | ||
240 | -- | ||
241 | -- @return A filename, which may be plain or versioned. | ||
242 | -- (eg. "socket.core", or "socket.core_2_0_2" if file is stored versioned). | ||
243 | local function filter_module_name(file_name: string, name: string, version: string, _tree: Tree, i: integer): string | ||
244 | if i > 1 then | ||
245 | file_name = path.versioned_name(file_name, "", name, version) | ||
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) | ||
260 | end | ||
261 | |||
262 | --- Return the pathname of the file that would be loaded for a module. | ||
263 | -- | ||
264 | -- @param module module name (eg. "socket.core") | ||
265 | -- @param where places to look for the module. If `where` contains | ||
266 | -- "l", it will search using the LuaRocks loader; if it contains "p", | ||
267 | -- it will look in the filesystem using package.path and package.cpath. | ||
268 | -- You can use both at the same time. | ||
269 | -- | ||
270 | -- @return If found, 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" | ||
272 | -- @return If found via the loader, the rock version; otherwise, nil | ||
273 | -- @return If found via the loader, "l"; if found via package.path or package.cpath, "p". | ||
274 | function loader.which(module: string, where?: string): string, string, string, string | ||
275 | where = where or "l" | ||
276 | if where:match("l") then | ||
277 | local rock_name, rock_version, file_name = select_module(module, path.which_i) | ||
278 | if rock_name then | ||
279 | local fd = io.open(file_name) | ||
280 | if fd then | ||
281 | fd:close() | ||
282 | return file_name, rock_name, rock_version, "l" | ||
283 | end | ||
284 | end | ||
285 | end | ||
286 | if where:match("p") then | ||
287 | local modpath = module:gsub("%.", "/") | ||
288 | for _, v in ipairs({package.path, package.cpath}) do | ||
289 | for p in v:gmatch("([^;]+)") do | ||
290 | local file_name = p:gsub("%?", modpath) -- luacheck: ignore 421 | ||
291 | local fd = io.open(file_name) | ||
292 | if fd then | ||
293 | fd:close() | ||
294 | return file_name, v, nil, "p" | ||
295 | end | ||
296 | end | ||
297 | end | ||
298 | end | ||
299 | end | ||
300 | |||
301 | --- Package loader for LuaRocks support. | ||
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 | ||
305 | -- current LuaRocks context. If module is not part of the | ||
306 | -- context, or if a context has not yet been set, the module | ||
307 | -- in the package with the highest version is used. | ||
308 | -- | ||
309 | -- @param module The module name, like in plain require(). | ||
310 | -- | ||
311 | -- @return A function which can load the module found, | ||
312 | -- or a string with an error message. | ||
313 | function loader.luarocks_loader(module: string): LoaderFn | string, any | ||
314 | local name, version, module_name = pick_module(module) | ||
315 | if not name then | ||
316 | return "No LuaRocks module found for " .. module | ||
317 | else | ||
318 | loader.add_context(name, version) | ||
319 | return call_other_loaders(module, name, version, module_name) | ||
320 | end | ||
321 | end | ||
322 | |||
323 | table.insert(loaders, 1, loader.luarocks_loader) | ||
324 | |||
325 | if is_clean then | ||
326 | for modname, _ in pairs(package.loaded) do | ||
327 | if modname:match("^luarocks%.") then | ||
328 | package.loaded[modname] = nil | ||
329 | end | ||
330 | end | ||
331 | end | ||
332 | |||
333 | return loader | ||