Mercurial > repo
view share/lua/5.2/luarocks/loader.lua @ 12518:2d8fe55c6e65 draft default tip
<int-e> learn The password of the month is release incident pilot.
author | HackEso <hackeso@esolangs.org> |
---|---|
date | Sun, 03 Nov 2024 00:31:02 +0000 |
parents | d137f631bad5 |
children |
line wrap: on
line source
--- 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. local global_env = _G local package, require, ipairs, pairs, table, type, next, unpack = package, require, ipairs, pairs, table, type, next, unpack module("luarocks.loader") local path = require("luarocks.path") local manif_core = require("luarocks.manif_core") local deps = require("luarocks.deps") local cfg = require("luarocks.cfg") context = {} -- Contains a table when rocks trees are loaded, -- or 'false' to indicate rocks trees failed to load. -- 'nil' indicates rocks trees were not attempted to be loaded yet. rocks_trees = nil local function load_rocks_trees() local any_ok = false local trees = {} for _, tree in ipairs(cfg.rocks_trees) do local manifest, err = manif_core.load_local_manifest(path.rocks_dir(tree)) if manifest then any_ok = true table.insert(trees, {tree=tree, manifest=manifest}) end end if not any_ok then rocks_trees = false return false end rocks_trees = trees return true end --- 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 add_context(name, version) -- assert(type(name) == "string") -- assert(type(version) == "string") if context[name] then return end context[name] = version if not rocks_trees and not load_rocks_trees() then return nil end local providers = {} for _, tree in ipairs(rocks_trees) do local manifest = tree.manifest local pkgdeps if manifest.dependencies and manifest.dependencies[name] then pkgdeps = manifest.dependencies[name][version] end if not pkgdeps then return nil end for _, dep in ipairs(pkgdeps) do local pkg, constraints = dep.name, dep.constraints for _, tree in ipairs(rocks_trees) do local entries = tree.manifest.repository[pkg] if entries then for version, pkgs in pairs(entries) do if (not constraints) or deps.match_constraints(deps.parse_version(version), constraints) then add_context(pkg, version) end end end end end end 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 i, loader in pairs(package.loaders) do if loader ~= luarocks_loader then local results = { 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 --- Search for a module in the rocks trees -- @param module string: module name (eg. "socket.core") -- @param filter_module_name function(string, string, string, string, number): -- a function that takes the module name (eg "socket.core"), 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: 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). local function select_module(module, filter_module_name) --assert(type(module) == "string") --assert(type(filter_module_name) == "function") if not rocks_trees and not load_rocks_trees() then return nil end local providers = {} for _, tree in ipairs(rocks_trees) do local entries = tree.manifest.modules[module] if entries then for i, entry in ipairs(entries) do local name, version = entry:match("^([^/]*)/(.*)$") local module_name = tree.manifest.repository[name][version][1].modules[module] if type(module_name) ~= "string" then error("Invalid format in manifest file (invalid data for "..tostring(name).." "..tostring(version)..")") end module_name = filter_module_name(module_name, name, version, tree.tree, i) if context[name] == version then return name, version, module_name end version = deps.parse_version(version) table.insert(providers, {name = name, version = version, module_name = module_name}) 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 end end --- Search for a module -- @param module string: module name (eg. "socket.core") -- @return string, string, string: 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). local function pick_module(module) return select_module(module, function(module_name, name, version, tree, i) if i > 1 then module_name = path.versioned_name(module_name, "", name, version) end module_name = path.path_to_module(module_name) return module_name end) end --- Return the pathname of the file that would be loaded for a module. -- @param module string: module name (eg. "socket.core") -- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so") function which(module) local name, version, module_name = select_module(module, path.which_i) return module_name 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 <a href="http://www.lua.org/manual/5.1/manual.html#pdf-require">require()</a> -- in the Lua reference manual for details. function luarocks_loader(module) local name, version, module_name = pick_module(module) if not name then return "No LuaRocks module found for "..module else add_context(name, version) return call_other_loaders(module, name, version, module_name) end end table.insert(global_env.package.loaders, 1, luarocks_loader)