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 | ||
