From d99f13f80e2b53a41d6d07d185fcef636f414c61 Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Thu, 22 Aug 2024 17:48:58 -0300 Subject: Teal: rename luarocks.loader --- src/luarocks/loader.lua | 269 ------------------------------------------------ src/luarocks/loader.tl | 269 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 269 insertions(+), 269 deletions(-) delete mode 100644 src/luarocks/loader.lua create mode 100644 src/luarocks/loader.tl (limited to 'src') diff --git a/src/luarocks/loader.lua b/src/luarocks/loader.lua deleted file mode 100644 index 772fdfcb..00000000 --- a/src/luarocks/loader.lua +++ /dev/null @@ -1,269 +0,0 @@ ---- A module which installs a Lua package loader that is LuaRocks-aware. --- This loader uses dependency information from the LuaRocks tree to load --- correct versions of modules. It does this by constructing a "context" --- table in the environment, which records which versions of packages were --- used to load previous modules, so that the loader chooses versions --- that are declared to be compatible with the ones loaded earlier. - --- luacheck: globals luarocks - -local loaders = package.loaders or package.searchers -local require, ipairs, table, type, next, tostring, error = - require, ipairs, table, type, next, tostring, error -local unpack = unpack or table.unpack - -local loader = {} - -local is_clean = not package.loaded["luarocks.core.cfg"] - --- This loader module depends only on core modules. -local cfg = require("luarocks.core.cfg") -local cfg_ok, err = cfg.init() -if cfg_ok then - cfg.init_package_paths() -end - -local path = require("luarocks.core.path") -local manif = require("luarocks.core.manif") -local vers = require("luarocks.core.vers") -local require = nil -- luacheck: ignore 411 --------------------------------------------------------------------------------- - --- Workaround for wrappers produced by older versions of LuaRocks -local temporary_global = false -local status, luarocks_value = pcall(function() return luarocks end) -if status and luarocks_value then - -- The site_config.lua file generated by old versions uses module(), - -- so it produces a global `luarocks` table. Since we have the table, - -- add the `loader` field to make the old wrappers happy. - luarocks.loader = loader -else - -- When a new version is installed on top of an old version, - -- site_config.lua may be replaced, and then it no longer creates - -- a global. - -- Detect when being called via -lluarocks.loader; this is - -- most likely a wrapper. - local info = debug and debug.getinfo(2, "nS") - if info and info.what == "C" and not info.name then - luarocks = { loader = loader } - temporary_global = true - -- For the other half of this hack, - -- see the next use of `temporary_global` below. - end -end - -loader.context = {} - ---- Process the dependencies of a package to determine its dependency --- chain for loading modules. --- @param name string: The name of an installed rock. --- @param version string: The version of the rock, in string format -function loader.add_context(name, version) - -- assert(type(name) == "string") - -- assert(type(version) == "string") - - if temporary_global then - -- The first thing a wrapper does is to call add_context. - -- From here on, it's safe to clean the global environment. - luarocks = nil - temporary_global = false - end - - local tree_manifests = manif.load_rocks_tree_manifests() - if not tree_manifests then - return nil - end - - return manif.scan_dependencies(name, version, tree_manifests, loader.context) -end - ---- Internal sorting function. --- @param a table: A provider table. --- @param b table: Another provider table. --- @return boolean: True if the version of a is greater than that of b. -local function sort_versions(a,b) - return a.version > b.version -end - ---- Request module to be loaded through other loaders, --- once the proper name of the module has been determined. --- For example, in case the module "socket.core" has been requested --- to the LuaRocks loader and it determined based on context that --- the version 2.0.2 needs to be loaded and it is not the current --- version, the module requested for the other loaders will be --- "socket.core_2_0_2". --- @param module The module name requested by the user, such as "socket.core" --- @param name The rock name, such as "luasocket" --- @param version The rock version, such as "2.0.2-1" --- @param module_name The actual module name, such as "socket.core" or "socket.core_2_0_2". --- @return table or (nil, string): The module table as returned by some other loader, --- or nil followed by an error message if no other loader managed to load the module. -local function call_other_loaders(module, name, version, module_name) - for _, a_loader in ipairs(loaders) do - if a_loader ~= loader.luarocks_loader then - local results = { a_loader(module_name) } - if type(results[1]) == "function" then - return unpack(results) - end - end - end - return "Failed loading module "..module.." in LuaRocks rock "..name.." "..version -end - -local function add_providers(providers, entries, tree, module, filter_file_name) - for i, entry in ipairs(entries) do - local name, version = entry:match("^([^/]*)/(.*)$") - local file_name = tree.manifest.repository[name][version][1].modules[module] - if type(file_name) ~= "string" then - error("Invalid data in manifest file for module "..tostring(module).." (invalid data for "..tostring(name).." "..tostring(version)..")") - end - file_name = filter_file_name(file_name, name, version, tree.tree, i) - if loader.context[name] == version then - return name, version, file_name - end - version = vers.parse_version(version) - table.insert(providers, {name = name, version = version, module_name = file_name, tree = tree}) - end -end - ---- Search for a module in the rocks trees --- @param module string: module name (eg. "socket.core") --- @param filter_file_name function(string, string, string, string, number): --- a function that takes the module file name (eg "socket/core.so"), the rock name --- (eg "luasocket"), the version (eg "2.0.2-1"), the path of the rocks tree --- (eg "/usr/local"), and the numeric index of the matching entry, so the --- filter function can know if the matching module was the first entry or not. --- @return string, string, string, (string or table): --- * name of the rock containing the module (eg. "luasocket") --- * version of the rock (eg. "2.0.2-1") --- * return value of filter_file_name --- * tree of the module (string or table in `tree_manifests` format) -local function select_module(module, filter_file_name) - --assert(type(module) == "string") - --assert(type(filter_module_name) == "function") - - local tree_manifests = manif.load_rocks_tree_manifests() - if not tree_manifests then - return nil - end - - local providers = {} - local initmodule - for _, tree in ipairs(tree_manifests) do - local entries = tree.manifest.modules[module] - if entries then - local n, v, f = add_providers(providers, entries, tree, module, filter_file_name) - if n then - return n, v, f - end - else - initmodule = initmodule or module .. ".init" - entries = tree.manifest.modules[initmodule] - if entries then - local n, v, f = add_providers(providers, entries, tree, initmodule, filter_file_name) - if n then - return n, v, f - end - end - end - end - - if next(providers) then - table.sort(providers, sort_versions) - local first = providers[1] - return first.name, first.version.string, first.module_name, first.tree - end -end - ---- Search for a module --- @param module string: module name (eg. "socket.core") --- @return string, string, string, (string or table): --- * name of the rock containing the module (eg. "luasocket") --- * version of the rock (eg. "2.0.2-1") --- * name of the module (eg. "socket.core", or "socket.core_2_0_2" if file is stored versioned). --- * tree of the module (string or table in `tree_manifests` format) -local function pick_module(module) - return - select_module(module, function(file_name, name, version, tree, i) - if i > 1 then - file_name = path.versioned_name(file_name, "", name, version) - end - return path.path_to_module(file_name) - end) -end - ---- Return the pathname of the file that would be loaded for a module. --- @param module string: module name (eg. "socket.core") --- @param where string: places to look for the module. If `where` contains --- "l", it will search using the LuaRocks loader; if it contains "p", --- it will look in the filesystem using package.path and package.cpath. --- You can use both at the same time. --- @return If successful, it will return four values. --- * If found using the LuaRocks loader, it will return: --- * filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so"), --- * rock name --- * rock version --- * "l" to indicate the match comes from the loader. --- * If found scanning package.path and package.cpath, it will return: --- * filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so"), --- * "path" or "cpath" --- * nil --- * "p" to indicate the match comes from scanning package.path and cpath. --- If unsuccessful, nothing is returned. -function loader.which(module, where) - where = where or "l" - if where:match("l") then - local rock_name, rock_version, file_name = select_module(module, path.which_i) - if rock_name then - local fd = io.open(file_name) - if fd then - fd:close() - return file_name, rock_name, rock_version, "l" - end - end - end - if where:match("p") then - local modpath = module:gsub("%.", "/") - for _, v in ipairs({"path", "cpath"}) do - for p in package[v]:gmatch("([^;]+)") do - local file_name = p:gsub("%?", modpath) -- luacheck: ignore 421 - local fd = io.open(file_name) - if fd then - fd:close() - return file_name, v, nil, "p" - end - end - end - end -end - ---- Package loader for LuaRocks support. --- A module is searched in installed rocks that match the --- current LuaRocks context. If module is not part of the --- context, or if a context has not yet been set, the module --- in the package with the highest version is used. --- @param module string: The module name, like in plain require(). --- @return table: The module table (typically), like in plain --- require(). See require() --- in the Lua reference manual for details. -function loader.luarocks_loader(module) - local name, version, module_name = pick_module(module) - if not name then - return "No LuaRocks module found for "..module - else - loader.add_context(name, version) - return call_other_loaders(module, name, version, module_name) - end -end - -table.insert(loaders, 1, loader.luarocks_loader) - -if is_clean then - for modname, _ in pairs(package.loaded) do - if modname:match("^luarocks%.") then - package.loaded[modname] = nil - end - end -end - -return loader diff --git a/src/luarocks/loader.tl b/src/luarocks/loader.tl new file mode 100644 index 00000000..772fdfcb --- /dev/null +++ b/src/luarocks/loader.tl @@ -0,0 +1,269 @@ +--- A module which installs a Lua package loader that is LuaRocks-aware. +-- This loader uses dependency information from the LuaRocks tree to load +-- correct versions of modules. It does this by constructing a "context" +-- table in the environment, which records which versions of packages were +-- used to load previous modules, so that the loader chooses versions +-- that are declared to be compatible with the ones loaded earlier. + +-- luacheck: globals luarocks + +local loaders = package.loaders or package.searchers +local require, ipairs, table, type, next, tostring, error = + require, ipairs, table, type, next, tostring, error +local unpack = unpack or table.unpack + +local loader = {} + +local is_clean = not package.loaded["luarocks.core.cfg"] + +-- This loader module depends only on core modules. +local cfg = require("luarocks.core.cfg") +local cfg_ok, err = cfg.init() +if cfg_ok then + cfg.init_package_paths() +end + +local path = require("luarocks.core.path") +local manif = require("luarocks.core.manif") +local vers = require("luarocks.core.vers") +local require = nil -- luacheck: ignore 411 +-------------------------------------------------------------------------------- + +-- Workaround for wrappers produced by older versions of LuaRocks +local temporary_global = false +local status, luarocks_value = pcall(function() return luarocks end) +if status and luarocks_value then + -- The site_config.lua file generated by old versions uses module(), + -- so it produces a global `luarocks` table. Since we have the table, + -- add the `loader` field to make the old wrappers happy. + luarocks.loader = loader +else + -- When a new version is installed on top of an old version, + -- site_config.lua may be replaced, and then it no longer creates + -- a global. + -- Detect when being called via -lluarocks.loader; this is + -- most likely a wrapper. + local info = debug and debug.getinfo(2, "nS") + if info and info.what == "C" and not info.name then + luarocks = { loader = loader } + temporary_global = true + -- For the other half of this hack, + -- see the next use of `temporary_global` below. + end +end + +loader.context = {} + +--- Process the dependencies of a package to determine its dependency +-- chain for loading modules. +-- @param name string: The name of an installed rock. +-- @param version string: The version of the rock, in string format +function loader.add_context(name, version) + -- assert(type(name) == "string") + -- assert(type(version) == "string") + + if temporary_global then + -- The first thing a wrapper does is to call add_context. + -- From here on, it's safe to clean the global environment. + luarocks = nil + temporary_global = false + end + + local tree_manifests = manif.load_rocks_tree_manifests() + if not tree_manifests then + return nil + end + + return manif.scan_dependencies(name, version, tree_manifests, loader.context) +end + +--- Internal sorting function. +-- @param a table: A provider table. +-- @param b table: Another provider table. +-- @return boolean: True if the version of a is greater than that of b. +local function sort_versions(a,b) + return a.version > b.version +end + +--- Request module to be loaded through other loaders, +-- once the proper name of the module has been determined. +-- For example, in case the module "socket.core" has been requested +-- to the LuaRocks loader and it determined based on context that +-- the version 2.0.2 needs to be loaded and it is not the current +-- version, the module requested for the other loaders will be +-- "socket.core_2_0_2". +-- @param module The module name requested by the user, such as "socket.core" +-- @param name The rock name, such as "luasocket" +-- @param version The rock version, such as "2.0.2-1" +-- @param module_name The actual module name, such as "socket.core" or "socket.core_2_0_2". +-- @return table or (nil, string): The module table as returned by some other loader, +-- or nil followed by an error message if no other loader managed to load the module. +local function call_other_loaders(module, name, version, module_name) + for _, a_loader in ipairs(loaders) do + if a_loader ~= loader.luarocks_loader then + local results = { a_loader(module_name) } + if type(results[1]) == "function" then + return unpack(results) + end + end + end + return "Failed loading module "..module.." in LuaRocks rock "..name.." "..version +end + +local function add_providers(providers, entries, tree, module, filter_file_name) + for i, entry in ipairs(entries) do + local name, version = entry:match("^([^/]*)/(.*)$") + local file_name = tree.manifest.repository[name][version][1].modules[module] + if type(file_name) ~= "string" then + error("Invalid data in manifest file for module "..tostring(module).." (invalid data for "..tostring(name).." "..tostring(version)..")") + end + file_name = filter_file_name(file_name, name, version, tree.tree, i) + if loader.context[name] == version then + return name, version, file_name + end + version = vers.parse_version(version) + table.insert(providers, {name = name, version = version, module_name = file_name, tree = tree}) + end +end + +--- Search for a module in the rocks trees +-- @param module string: module name (eg. "socket.core") +-- @param filter_file_name function(string, string, string, string, number): +-- a function that takes the module file name (eg "socket/core.so"), the rock name +-- (eg "luasocket"), the version (eg "2.0.2-1"), the path of the rocks tree +-- (eg "/usr/local"), and the numeric index of the matching entry, so the +-- filter function can know if the matching module was the first entry or not. +-- @return string, string, string, (string or table): +-- * name of the rock containing the module (eg. "luasocket") +-- * version of the rock (eg. "2.0.2-1") +-- * return value of filter_file_name +-- * tree of the module (string or table in `tree_manifests` format) +local function select_module(module, filter_file_name) + --assert(type(module) == "string") + --assert(type(filter_module_name) == "function") + + local tree_manifests = manif.load_rocks_tree_manifests() + if not tree_manifests then + return nil + end + + local providers = {} + local initmodule + for _, tree in ipairs(tree_manifests) do + local entries = tree.manifest.modules[module] + if entries then + local n, v, f = add_providers(providers, entries, tree, module, filter_file_name) + if n then + return n, v, f + end + else + initmodule = initmodule or module .. ".init" + entries = tree.manifest.modules[initmodule] + if entries then + local n, v, f = add_providers(providers, entries, tree, initmodule, filter_file_name) + if n then + return n, v, f + end + end + end + end + + if next(providers) then + table.sort(providers, sort_versions) + local first = providers[1] + return first.name, first.version.string, first.module_name, first.tree + end +end + +--- Search for a module +-- @param module string: module name (eg. "socket.core") +-- @return string, string, string, (string or table): +-- * name of the rock containing the module (eg. "luasocket") +-- * version of the rock (eg. "2.0.2-1") +-- * name of the module (eg. "socket.core", or "socket.core_2_0_2" if file is stored versioned). +-- * tree of the module (string or table in `tree_manifests` format) +local function pick_module(module) + return + select_module(module, function(file_name, name, version, tree, i) + if i > 1 then + file_name = path.versioned_name(file_name, "", name, version) + end + return path.path_to_module(file_name) + end) +end + +--- Return the pathname of the file that would be loaded for a module. +-- @param module string: module name (eg. "socket.core") +-- @param where string: places to look for the module. If `where` contains +-- "l", it will search using the LuaRocks loader; if it contains "p", +-- it will look in the filesystem using package.path and package.cpath. +-- You can use both at the same time. +-- @return If successful, it will return four values. +-- * If found using the LuaRocks loader, it will return: +-- * filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so"), +-- * rock name +-- * rock version +-- * "l" to indicate the match comes from the loader. +-- * If found scanning package.path and package.cpath, it will return: +-- * filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so"), +-- * "path" or "cpath" +-- * nil +-- * "p" to indicate the match comes from scanning package.path and cpath. +-- If unsuccessful, nothing is returned. +function loader.which(module, where) + where = where or "l" + if where:match("l") then + local rock_name, rock_version, file_name = select_module(module, path.which_i) + if rock_name then + local fd = io.open(file_name) + if fd then + fd:close() + return file_name, rock_name, rock_version, "l" + end + end + end + if where:match("p") then + local modpath = module:gsub("%.", "/") + for _, v in ipairs({"path", "cpath"}) do + for p in package[v]:gmatch("([^;]+)") do + local file_name = p:gsub("%?", modpath) -- luacheck: ignore 421 + local fd = io.open(file_name) + if fd then + fd:close() + return file_name, v, nil, "p" + end + end + end + end +end + +--- Package loader for LuaRocks support. +-- A module is searched in installed rocks that match the +-- current LuaRocks context. If module is not part of the +-- context, or if a context has not yet been set, the module +-- in the package with the highest version is used. +-- @param module string: The module name, like in plain require(). +-- @return table: The module table (typically), like in plain +-- require(). See require() +-- in the Lua reference manual for details. +function loader.luarocks_loader(module) + local name, version, module_name = pick_module(module) + if not name then + return "No LuaRocks module found for "..module + else + loader.add_context(name, version) + return call_other_loaders(module, name, version, module_name) + end +end + +table.insert(loaders, 1, loader.luarocks_loader) + +if is_clean then + for modname, _ in pairs(package.loaded) do + if modname:match("^luarocks%.") then + package.loaded[modname] = nil + end + end +end + +return loader -- cgit v1.2.3-55-g6feb