view share/lua/5.2/luarocks/loader.lua @ 7910:7d5f1c5e44b1

<moon__> mkx bin/hfs//erro You have discovered an eerie caven. The air above the dark stone floor is alive with vorices of purple light and dark, boiling clouds. Seemingly bottomless glowing pit mark the surface.
author HackBot
date Sat, 07 May 2016 00:41:47 +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)