comparison share/lua/5.2/luarocks/loader.lua @ 1132:d137f631bad5

<GreyKnight> (cd luabuild/luarocks-2.0.12; make install)
author HackBot
date Fri, 14 Dec 2012 22:24:27 +0000
parents
children
comparison
equal deleted inserted replaced
1131:ff65dfb63263 1132:d137f631bad5
1
2 --- A module which installs a Lua package loader that is LuaRocks-aware.
3 -- This loader uses dependency information from the LuaRocks tree to load
4 -- correct versions of modules. It does this by constructing a "context"
5 -- table in the environment, which records which versions of packages were
6 -- used to load previous modules, so that the loader chooses versions
7 -- that are declared to be compatible with the ones loaded earlier.
8 local global_env = _G
9 local package, require, ipairs, pairs, table, type, next, unpack =
10 package, require, ipairs, pairs, table, type, next, unpack
11
12 module("luarocks.loader")
13
14 local path = require("luarocks.path")
15 local manif_core = require("luarocks.manif_core")
16 local deps = require("luarocks.deps")
17 local cfg = require("luarocks.cfg")
18
19 context = {}
20
21 -- Contains a table when rocks trees are loaded,
22 -- or 'false' to indicate rocks trees failed to load.
23 -- 'nil' indicates rocks trees were not attempted to be loaded yet.
24 rocks_trees = nil
25
26 local function load_rocks_trees()
27 local any_ok = false
28 local trees = {}
29 for _, tree in ipairs(cfg.rocks_trees) do
30 local manifest, err = manif_core.load_local_manifest(path.rocks_dir(tree))
31 if manifest then
32 any_ok = true
33 table.insert(trees, {tree=tree, manifest=manifest})
34 end
35 end
36 if not any_ok then
37 rocks_trees = false
38 return false
39 end
40 rocks_trees = trees
41 return true
42 end
43
44 --- Process the dependencies of a package to determine its dependency
45 -- chain for loading modules.
46 -- @param name string: The name of an installed rock.
47 -- @param version string: The version of the rock, in string format
48 function add_context(name, version)
49 -- assert(type(name) == "string")
50 -- assert(type(version) == "string")
51
52 if context[name] then
53 return
54 end
55 context[name] = version
56
57 if not rocks_trees and not load_rocks_trees() then
58 return nil
59 end
60
61 local providers = {}
62 for _, tree in ipairs(rocks_trees) do
63 local manifest = tree.manifest
64
65 local pkgdeps
66 if manifest.dependencies and manifest.dependencies[name] then
67 pkgdeps = manifest.dependencies[name][version]
68 end
69 if not pkgdeps then
70 return nil
71 end
72 for _, dep in ipairs(pkgdeps) do
73 local pkg, constraints = dep.name, dep.constraints
74
75 for _, tree in ipairs(rocks_trees) do
76 local entries = tree.manifest.repository[pkg]
77 if entries then
78 for version, pkgs in pairs(entries) do
79 if (not constraints) or deps.match_constraints(deps.parse_version(version), constraints) then
80 add_context(pkg, version)
81 end
82 end
83 end
84 end
85 end
86 end
87 end
88
89 --- Internal sorting function.
90 -- @param a table: A provider table.
91 -- @param b table: Another provider table.
92 -- @return boolean: True if the version of a is greater than that of b.
93 local function sort_versions(a,b)
94 return a.version > b.version
95 end
96
97 --- Request module to be loaded through other loaders,
98 -- once the proper name of the module has been determined.
99 -- For example, in case the module "socket.core" has been requested
100 -- to the LuaRocks loader and it determined based on context that
101 -- the version 2.0.2 needs to be loaded and it is not the current
102 -- version, the module requested for the other loaders will be
103 -- "socket.core_2_0_2".
104 -- @param module The module name requested by the user, such as "socket.core"
105 -- @param name The rock name, such as "luasocket"
106 -- @param version The rock version, such as "2.0.2-1"
107 -- @param module_name The actual module name, such as "socket.core" or "socket.core_2_0_2".
108 -- @return table or (nil, string): The module table as returned by some other loader,
109 -- or nil followed by an error message if no other loader managed to load the module.
110 local function call_other_loaders(module, name, version, module_name)
111 for i, loader in pairs(package.loaders) do
112 if loader ~= luarocks_loader then
113 local results = { loader(module_name) }
114 if type(results[1]) == "function" then
115 return unpack(results)
116 end
117 end
118 end
119 return "Failed loading module "..module.." in LuaRocks rock "..name.." "..version
120 end
121
122 --- Search for a module in the rocks trees
123 -- @param module string: module name (eg. "socket.core")
124 -- @param filter_module_name function(string, string, string, string, number):
125 -- a function that takes the module name (eg "socket.core"), the rock name
126 -- (eg "luasocket"), the version (eg "2.0.2-1"), the path of the rocks tree
127 -- (eg "/usr/local"), and the numeric index of the matching entry, so the
128 -- filter function can know if the matching module was the first entry or not.
129 -- @return string, string, string: name of the rock containing the module
130 -- (eg. "luasocket"), version of the rock (eg. "2.0.2-1"),
131 -- name of the module (eg. "socket.core", or "socket.core_2_0_2" if file is
132 -- stored versioned).
133 local function select_module(module, filter_module_name)
134 --assert(type(module) == "string")
135 --assert(type(filter_module_name) == "function")
136
137 if not rocks_trees and not load_rocks_trees() then
138 return nil
139 end
140
141 local providers = {}
142 for _, tree in ipairs(rocks_trees) do
143 local entries = tree.manifest.modules[module]
144 if entries then
145 for i, entry in ipairs(entries) do
146 local name, version = entry:match("^([^/]*)/(.*)$")
147 local module_name = tree.manifest.repository[name][version][1].modules[module]
148 if type(module_name) ~= "string" then
149 error("Invalid format in manifest file (invalid data for "..tostring(name).." "..tostring(version)..")")
150 end
151 module_name = filter_module_name(module_name, name, version, tree.tree, i)
152 if context[name] == version then
153 return name, version, module_name
154 end
155 version = deps.parse_version(version)
156 table.insert(providers, {name = name, version = version, module_name = module_name})
157 end
158 end
159 end
160
161 if next(providers) then
162 table.sort(providers, sort_versions)
163 local first = providers[1]
164 return first.name, first.version.string, first.module_name
165 end
166 end
167
168 --- Search for a module
169 -- @param module string: module name (eg. "socket.core")
170 -- @return string, string, string: name of the rock containing the module
171 -- (eg. "luasocket"), version of the rock (eg. "2.0.2-1"),
172 -- name of the module (eg. "socket.core", or "socket.core_2_0_2" if file is
173 -- stored versioned).
174 local function pick_module(module)
175 return
176 select_module(module, function(module_name, name, version, tree, i)
177 if i > 1 then
178 module_name = path.versioned_name(module_name, "", name, version)
179 end
180 module_name = path.path_to_module(module_name)
181 return module_name
182 end)
183 end
184
185 --- Return the pathname of the file that would be loaded for a module.
186 -- @param module string: module name (eg. "socket.core")
187 -- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so")
188 function which(module)
189 local name, version, module_name = select_module(module, path.which_i)
190 return module_name
191 end
192
193 --- Package loader for LuaRocks support.
194 -- A module is searched in installed rocks that match the
195 -- current LuaRocks context. If module is not part of the
196 -- context, or if a context has not yet been set, the module
197 -- in the package with the highest version is used.
198 -- @param module string: The module name, like in plain require().
199 -- @return table: The module table (typically), like in plain
200 -- require(). See <a href="http://www.lua.org/manual/5.1/manual.html#pdf-require">require()</a>
201 -- in the Lua reference manual for details.
202 function luarocks_loader(module)
203 local name, version, module_name = pick_module(module)
204 if not name then
205 return "No LuaRocks module found for "..module
206 else
207 add_context(name, version)
208 return call_other_loaders(module, name, version, module_name)
209 end
210 end
211
212 table.insert(global_env.package.loaders, 1, luarocks_loader)