diff options
author | hisham <hisham@9ca3f7c1-7366-0410-b1a3-b5c78f85698c> | 2009-04-23 15:00:35 +0000 |
---|---|---|
committer | hisham <hisham@9ca3f7c1-7366-0410-b1a3-b5c78f85698c> | 2009-04-23 15:00:35 +0000 |
commit | 940d5b91d3372c46b690027e14af85f41c0cffd8 (patch) | |
tree | 2162f6b9e7b2b73bb8c54df1bd50df6c2c844216 /src | |
parent | 40b346c145cb7ff175e6955652a0a32debea9b6c (diff) | |
download | luarocks-940d5b91d3372c46b690027e14af85f41c0cffd8.tar.gz luarocks-940d5b91d3372c46b690027e14af85f41c0cffd8.tar.bz2 luarocks-940d5b91d3372c46b690027e14af85f41c0cffd8.zip |
Add LuaRocks package loader
git-svn-id: http://luarocks.org/svn/luarocks/trunk@12 9ca3f7c1-7366-0410-b1a3-b5c78f85698c
Diffstat (limited to 'src')
-rw-r--r-- | src/luarocks.lua | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/src/luarocks.lua b/src/luarocks.lua new file mode 100644 index 00000000..fad62e07 --- /dev/null +++ b/src/luarocks.lua | |||
@@ -0,0 +1,240 @@ | |||
1 | |||
2 | local global_env = _G | ||
3 | local plain_package_path = package.path | ||
4 | local plain_package_cpath = package.cpath | ||
5 | local package, require, assert, ipairs, pairs, os, print, table, type, next, unpack = | ||
6 | package, require, assert, ipairs, pairs, os, print, table, type, next, unpack | ||
7 | |||
8 | module("luarocks") | ||
9 | |||
10 | local path = require("luarocks.path") | ||
11 | local manif_core = require("luarocks.manif_core") | ||
12 | local deps = require("luarocks.deps") | ||
13 | local cfg = require("luarocks.cfg") | ||
14 | |||
15 | context = {} | ||
16 | |||
17 | -- Contains a table when rocks trees are loaded, | ||
18 | -- or 'false' to indicate rocks trees failed to load. | ||
19 | -- 'nil' indicates rocks trees were not attempted to be loaded yet. | ||
20 | rocks_trees = nil | ||
21 | |||
22 | local function load_rocks_trees() | ||
23 | local any_ok = false | ||
24 | local trees = {} | ||
25 | for _, tree in pairs(cfg.rocks_trees) do | ||
26 | local rocks_dir = tree .. "/rocks/" | ||
27 | local manifest, err = manif_core.load_local_manifest(rocks_dir) | ||
28 | if manifest then | ||
29 | any_ok = true | ||
30 | table.insert(trees, {rocks_dir=rocks_dir, manifest=manifest}) | ||
31 | end | ||
32 | end | ||
33 | if not any_ok then | ||
34 | rocks_trees = false | ||
35 | return false | ||
36 | end | ||
37 | rocks_trees = trees | ||
38 | return true | ||
39 | end | ||
40 | |||
41 | --- Process the dependencies of a package to determine its dependency | ||
42 | -- chain for loading modules. | ||
43 | -- @parse name string: The name of an installed rock. | ||
44 | -- @parse version string: The version of the rock, in string format | ||
45 | -- @parse manifest table: The local manifest table where this rock | ||
46 | -- is installed. | ||
47 | local function add_context(name, version, manifest) | ||
48 | -- assert(type(name) == "string") | ||
49 | -- assert(type(version) == "string") | ||
50 | -- assert(type(manifest) == "table") | ||
51 | |||
52 | if context[name] then | ||
53 | return | ||
54 | end | ||
55 | context[name] = version | ||
56 | |||
57 | local pkgdeps = manifest.dependencies and manifest.dependencies[name][version] | ||
58 | if not pkgdeps then | ||
59 | return | ||
60 | end | ||
61 | for _, dep in ipairs(pkgdeps) do | ||
62 | local package, constraints = dep.name, dep.constraints | ||
63 | |||
64 | for _, tree in pairs(rocks_trees) do do | ||
65 | local entries = tree.manifest.repository[package] | ||
66 | if entries then | ||
67 | break -- continue for | ||
68 | end | ||
69 | for version, packages in pairs(entries) do | ||
70 | if (not constraints) or deps.match_constraints(deps.parse_version(version), constraints) then | ||
71 | add_context(package, version, tree.manifest) | ||
72 | end | ||
73 | end | ||
74 | end end | ||
75 | end | ||
76 | end | ||
77 | |||
78 | --- Internal sorting function. | ||
79 | -- @param a table: A provider table. | ||
80 | -- @param b table: Another provider table. | ||
81 | -- @return boolean: True if the version of a is greater than that of b. | ||
82 | local function sort_versions(a,b) | ||
83 | return a.version > b.version | ||
84 | end | ||
85 | |||
86 | --- Specify a dependency chain for LuaRocks. | ||
87 | -- In the presence of multiple versions of packages, it is necessary to, | ||
88 | -- at some point, indicate which dependency chain we're following. | ||
89 | -- set_context does this by allowing one to pick a package to be the | ||
90 | -- root of this dependency chain. Once a dependency chain is picked it's | ||
91 | -- easy to know which modules to load ("I want to use *this* version of | ||
92 | -- A, which requires *that* version of B, which requires etc etc etc"). | ||
93 | -- @param name string: The package name of an installed rock. | ||
94 | -- @param version string or nil: Optionally, a version number | ||
95 | -- When a version is not given, it picks the highest version installed. | ||
96 | -- @return boolean: true if succeeded, false otherwise. | ||
97 | function set_context(name, version) | ||
98 | --assert(type(name) == "string") | ||
99 | --assert(type(version) == "string" or not version) | ||
100 | |||
101 | if rocks_trees == false or (not rocks_trees and not load_rocks_trees()) then | ||
102 | return false | ||
103 | end | ||
104 | |||
105 | local manifest | ||
106 | local vtables = {} | ||
107 | for _, tree in ipairs(rocks_trees) do | ||
108 | if version then | ||
109 | local manif_repo = tree.manifest.repository | ||
110 | if manif_repo[name] and manif_repo[name][version] then | ||
111 | manifest = tree.manifest | ||
112 | break | ||
113 | end | ||
114 | else | ||
115 | local versions = manif_core.get_versions(name, tree.manifest) | ||
116 | for _, version in ipairs(versions) do | ||
117 | table.insert(vtables, {version = deps.parse_version(version), manifest = tree.manifest}) | ||
118 | end | ||
119 | end | ||
120 | end | ||
121 | if not version then | ||
122 | if not next(vtables) then | ||
123 | table.sort(vtables, sort_versions) | ||
124 | local highest = vtables[#vtables] | ||
125 | version = highest.version.string | ||
126 | manifest = highest.manifest | ||
127 | end | ||
128 | end | ||
129 | if not manifest then | ||
130 | return false | ||
131 | end | ||
132 | |||
133 | add_context(name, version, manifest) | ||
134 | -- TODO: platform independence | ||
135 | local lpath, cpath = "", "" | ||
136 | for name, version in pairs(context) do | ||
137 | lpath = lpath .. path.lua_dir(name, version) .. "/?.lua;" | ||
138 | lpath = lpath .. path.lua_dir(name, version) .. "/?/init.lua;" | ||
139 | cpath = cpath .. path.lib_dir(name, version) .."/?."..cfg.lib_extension..";" | ||
140 | end | ||
141 | global_env.package.path = lpath .. plain_package_path | ||
142 | global_env.package.cpath = cpath .. plain_package_cpath | ||
143 | end | ||
144 | |||
145 | local function call_other_loaders(module, name, version, rocks_dir) | ||
146 | local save_path = package.path | ||
147 | local save_cpath = package.cpath | ||
148 | package.path = path.lua_dir(name, version, rocks_dir) .. "/?.lua;" | ||
149 | .. path.lua_dir(name, version, rocks_dir) .. "/?/init.lua;" .. save_path | ||
150 | package.cpath = path.lib_dir(name, version, rocks_dir) .. "/?."..cfg.lib_extension..";" .. save_cpath | ||
151 | for i, loader in pairs(package.loaders) do | ||
152 | if loader ~= luarocks_loader then | ||
153 | local results = { loader(module) } | ||
154 | if type(results[1]) == "function" then | ||
155 | package.path = save_path | ||
156 | package.cpath = save_cpath | ||
157 | return unpack(results) | ||
158 | end | ||
159 | end | ||
160 | end | ||
161 | package.path = save_path | ||
162 | package.cpath = save_cpath | ||
163 | return nil, "Failed loading module "..module.." in LuaRocks rock "..name.." "..version | ||
164 | end | ||
165 | |||
166 | local function pick_module(module, constraints) | ||
167 | --assert(type(module) == "string") | ||
168 | --assert(not constraints or type(constraints) == "string") | ||
169 | |||
170 | if not rocks_trees and not load_rocks_trees() then | ||
171 | return nil | ||
172 | end | ||
173 | |||
174 | if constraints then | ||
175 | if type(constraints) == "string" then | ||
176 | constraints = deps.parse_constraints(constraints) | ||
177 | else | ||
178 | constraints = nil | ||
179 | end | ||
180 | end | ||
181 | |||
182 | local providers = {} | ||
183 | for _, tree in pairs(rocks_trees) do | ||
184 | local entries = tree.manifest.modules[module] | ||
185 | if entries then | ||
186 | for _, entry in pairs(entries) do | ||
187 | local name, version = entry:match("^([^/]*)/(.*)$") | ||
188 | if context[name] == version then | ||
189 | return name, version, tree | ||
190 | end | ||
191 | version = deps.parse_version(version) | ||
192 | if (not constraints) or deps.match_constraints(version, constraints) then | ||
193 | table.insert(providers, {name = name, version = version, repo = tree}) | ||
194 | end | ||
195 | end | ||
196 | end | ||
197 | end | ||
198 | |||
199 | if next(providers) then | ||
200 | table.sort(providers, sort_versions) | ||
201 | local first = providers[1] | ||
202 | return first.name, first.version.string, first.repo | ||
203 | end | ||
204 | end | ||
205 | |||
206 | --- Inform which rock LuaRocks would use if require() is called | ||
207 | -- with the given arguments. | ||
208 | -- @param module string: The module name, like in plain require(). | ||
209 | -- @param constraints string or nil: An optional comma-separated | ||
210 | -- list of version constraints. | ||
211 | -- @return (string, string) or nil: Rock name and version if the | ||
212 | -- requested module can be supplied by LuaRocks, or nil if it can't. | ||
213 | function get_rock_from_module(module, constraints) | ||
214 | --assert(type(module) == "string") | ||
215 | --assert(not constraints or type(constraints) == "string") | ||
216 | local name, version = pick_module(module, constraints) | ||
217 | return name, version | ||
218 | end | ||
219 | |||
220 | --- Package loader for LuaRocks support. | ||
221 | -- A module is searched in installed rocks that match the | ||
222 | -- current LuaRocks context. If module is not part of the | ||
223 | -- context, or if a context has not yet been set, the module | ||
224 | -- in the package with the highest version is used. | ||
225 | -- @param module string: The module name, like in plain require(). | ||
226 | -- @return table: The module table (typically), like in plain | ||
227 | -- require(). See <a href="http://www.lua.org/manual/5.1/manual.html#pdf-require">require()</a> | ||
228 | -- in the Lua reference manual for details. | ||
229 | |||
230 | function luarocks_loader(module) | ||
231 | local name, version, repo = pick_module(module) | ||
232 | if not name then | ||
233 | return nil, "No LuaRocks module found for "..module | ||
234 | else | ||
235 | add_context(name, version, repo.manifest) | ||
236 | return call_other_loaders(module, name, version, repo.rocks_dir) | ||
237 | end | ||
238 | end | ||
239 | |||
240 | table.insert(global_env.package.loaders, luarocks_loader) | ||