aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorV1K1NGbg <victor@ilchev.com>2024-08-06 21:21:35 +0300
committerV1K1NGbg <victor@ilchev.com>2024-08-06 21:21:35 +0300
commitbd2e8c62298d85816faed12604363c2240a49dee (patch)
tree1e7b1733ff317bd91ec044d6efed77629be36172
parent2b553013c302a84a8f76ca093fda89e6f4e54432 (diff)
downloadluarocks-bd2e8c62298d85816faed12604363c2240a49dee.tar.gz
luarocks-bd2e8c62298d85816faed12604363c2240a49dee.tar.bz2
luarocks-bd2e8c62298d85816faed12604363c2240a49dee.zip
rockspec
-rw-r--r--src/luarocks/core/types/rockspec.tl (renamed from src/luarocks/core/types/rockspec.d.tl)0
-rw-r--r--src/luarocks/deps-incomplete.lua (renamed from src/luarocks/deps-original.lua)427
-rw-r--r--src/luarocks/deps.lua427
-rw-r--r--src/luarocks/deps.tl2
-rw-r--r--src/luarocks/rockspecs-original.lua183
-rw-r--r--src/luarocks/rockspecs.lua131
-rw-r--r--src/luarocks/rockspecs.tl10
7 files changed, 691 insertions, 489 deletions
diff --git a/src/luarocks/core/types/rockspec.d.tl b/src/luarocks/core/types/rockspec.tl
index b9ed54de..b9ed54de 100644
--- a/src/luarocks/core/types/rockspec.d.tl
+++ b/src/luarocks/core/types/rockspec.tl
diff --git a/src/luarocks/deps-original.lua b/src/luarocks/deps-incomplete.lua
index 1a9eefde..df2fbbd5 100644
--- a/src/luarocks/deps-original.lua
+++ b/src/luarocks/deps-incomplete.lua
@@ -1,7 +1,8 @@
1local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local assert = _tl_compat and _tl_compat.assert or assert; local io = _tl_compat and _tl_compat.io or io; local ipairs = _tl_compat and _tl_compat.ipairs or ipairs; local pairs = _tl_compat and _tl_compat.pairs or pairs; local string = _tl_compat and _tl_compat.string or string; local table = _tl_compat and _tl_compat.table or table
1 2
2--- High-level dependency related functions.
3local deps = {} 3local deps = {}
4 4
5
5local cfg = require("luarocks.core.cfg") 6local cfg = require("luarocks.core.cfg")
6local manif = require("luarocks.manif") 7local manif = require("luarocks.manif")
7local path = require("luarocks.path") 8local path = require("luarocks.path")
@@ -12,34 +13,55 @@ local vers = require("luarocks.core.vers")
12local queries = require("luarocks.queries") 13local queries = require("luarocks.queries")
13local deplocks = require("luarocks.deplocks") 14local deplocks = require("luarocks.deplocks")
14 15
15--- Generate a function that matches dep queries against the manifest, 16
16-- taking into account rocks_provided, the list of versions to skip, 17
17-- and the lockfile. 18
18-- @param deps_mode "one", "none", "all" or "order" 19
19-- @param rocks_provided a one-level table mapping names to versions, 20
20-- listing rocks to consider provided by the VM 21
21-- @param rocks_provided table: A table of auto-provided dependencies. 22
22-- by this Lua implementation for the given dependency. 23
23-- @param depskey key to use when matching the lockfile ("dependencies", 24
24-- "build_dependencies", etc.) 25
25-- @param skip_set a two-level table mapping names to versions to 26
26-- boolean, listing rocks that should not be matched 27
27-- @return function(dep): {string}, {string:string}, string, boolean 28
28-- * array of matching versions 29
29-- * map of versions to locations 30
30-- * version matched via lockfile if any 31
31-- * true if rock matched via rocks_provided 32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
32local function prepare_get_versions(deps_mode, rocks_provided, depskey, skip_set) 58local function prepare_get_versions(deps_mode, rocks_provided, depskey, skip_set)
33 assert(type(deps_mode) == "string")
34 assert(type(rocks_provided) == "table")
35 assert(type(depskey) == "string")
36 assert(type(skip_set) == "table" or skip_set == nil)
37 59
38 return function(dep) 60 return function(dep)
39 local versions, locations 61 local versions, locations
40 local provided = rocks_provided[dep.name] 62 local provided = rocks_provided[dep.name]
41 if provided then 63 if provided then
42 -- Provided rocks have higher priority than manifest's rocks. 64
43 versions, locations = { provided }, {} 65 versions, locations = { provided }, {}
44 else 66 else
45 if deps_mode == "none" then 67 if deps_mode == "none" then
@@ -63,21 +85,20 @@ local function prepare_get_versions(deps_mode, rocks_provided, depskey, skip_set
63 end 85 end
64end 86end
65 87
66--- Attempt to match a dependency to an installed rock. 88
67-- @param get_versions a getter function obtained via prepare_get_versions 89
68-- @return (string, string, table) or (nil, nil, table): 90
69-- 1. latest installed version of the rock matching the dependency 91
70-- 2. location where the installed version is installed 92
71-- 3. the 'dep' query table 93
72-- 4. true if provided via VM 94
73-- or 95
74-- 1. nil 96
75-- 2. nil 97
76-- 3. either 'dep' or an alternative query to be used 98
77-- 4. false 99
78local function match_dep(dep, get_versions) 100local function match_dep(dep,
79 assert(type(dep) == "table") 101 get_versions)
80 assert(type(get_versions) == "function")
81 102
82 local versions, locations, lockversion, provided = get_versions(dep) 103 local versions, locations, lockversion, provided = get_versions(dep)
83 104
@@ -105,9 +126,8 @@ local function match_dep(dep, get_versions)
105 return latest_vstring, locations[latest_vstring], dep, provided 126 return latest_vstring, locations[latest_vstring], dep, provided
106end 127end
107 128
108local function match_all_deps(dependencies, get_versions) 129local function match_all_deps(dependencies,
109 assert(type(dependencies) == "table") 130 get_versions)
110 assert(type(get_versions) == "function")
111 131
112 local matched, missing, no_upgrade = {}, {}, {} 132 local matched, missing, no_upgrade = {}, {}, {}
113 133
@@ -116,7 +136,7 @@ local function match_all_deps(dependencies, get_versions)
116 found, _, dep, provided = match_dep(dep, get_versions) 136 found, _, dep, provided = match_dep(dep, get_versions)
117 if found then 137 if found then
118 if not provided then 138 if not provided then
119 matched[dep] = {name = dep.name, version = found} 139 matched[dep] = { name = dep.name, version = found }
120 end 140 end
121 else 141 else
122 if dep.constraints[1] and dep.constraints[1].no_upgrade then 142 if dep.constraints[1] and dep.constraints[1].no_upgrade then
@@ -129,53 +149,41 @@ local function match_all_deps(dependencies, get_versions)
129 return matched, missing, no_upgrade 149 return matched, missing, no_upgrade
130end 150end
131 151
132--- Attempt to match dependencies of a rockspec to installed rocks. 152
133-- @param dependencies table: The table of dependencies. 153
134-- @param rocks_provided table: The table of auto-provided dependencies. 154
135-- @param skip_set table or nil: Program versions to not use as valid matches. 155
136-- Table where keys are program names and values are tables where keys 156
137-- are program versions and values are 'true'. 157
138-- @param deps_mode string: Which trees to check dependencies for 158
139-- @return table, table, table: A table where keys are dependencies parsed 159
140-- in table format and values are tables containing fields 'name' and 160
141-- version' representing matches; a table of missing dependencies 161
142-- parsed as tables; and a table of "no-upgrade" missing dependencies 162
143-- (to be used in plugin modules so that a plugin does not force upgrade of 163
144-- its parent application). 164
145function deps.match_deps(dependencies, rocks_provided, deps_mode, skip_set) 165function deps.match_deps(dependencies, rocks_provided, deps_mode, skip_set)
146 assert(type(dependencies) == "table")
147 assert(type(rocks_provided) == "table")
148 assert(type(skip_set) == "table" or skip_set == nil)
149 assert(type(deps_mode) == "string")
150 166
151 local get_versions = prepare_get_versions(deps_mode, rocks_provided, "dependencies", skip_set) 167 local get_versions = prepare_get_versions(deps_mode, rocks_provided, "dependencies", skip_set)
152 return match_all_deps(dependencies, get_versions) 168 return match_all_deps(dependencies, get_versions)
153end 169end
154 170
155local function rock_status(dep, get_versions) 171local function rock_status(dep, get_versions)
156 assert(dep:type() == "query")
157 assert(type(get_versions) == "function")
158
159 local installed, _, _, provided = match_dep(dep, get_versions) 172 local installed, _, _, provided = match_dep(dep, get_versions)
160 local installation_type = provided and "provided by VM" or "installed" 173 local installation_type = provided and "provided by VM" or "installed"
161 return installed and installed.." "..installation_type..": success" or "not installed" 174 return installed and installed .. " " .. installation_type .. ": success" or "not installed"
162end 175end
163 176
164--- Check depenendencies of a package and report any missing ones. 177
165-- @param name string: package name. 178
166-- @param version string: package version. 179
167-- @param dependencies table: array of dependencies. 180
168-- @param deps_mode string: Which trees to check dependencies for 181
169-- @param rocks_provided table: A table of auto-dependencies provided 182
170-- by this Lua implementation for the given dependency. 183
171-- "one" for the current default tree, "all" for all trees, 184
172-- "order" for all trees with priority >= the current default, "none" for no trees. 185
173function deps.report_missing_dependencies(name, version, dependencies, deps_mode, rocks_provided) 186function deps.report_missing_dependencies(name, version, dependencies, deps_mode, rocks_provided)
174 assert(type(name) == "string")
175 assert(type(version) == "string")
176 assert(type(dependencies) == "table")
177 assert(type(deps_mode) == "string")
178 assert(type(rocks_provided) == "table")
179 187
180 if deps_mode == "none" then 188 if deps_mode == "none" then
181 return 189 return
@@ -200,11 +208,6 @@ function deps.report_missing_dependencies(name, version, dependencies, deps_mode
200end 208end
201 209
202function deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey) 210function deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey)
203 assert(dep:type() == "query")
204 assert(type(deps_mode) == "string" or deps_mode == nil)
205 assert(type(rocks_provided) == "table" or rocks_provided == nil)
206 assert(type(verify) == "boolean" or verify == nil)
207 assert(type(depskey) == "string")
208 211
209 deps_mode = deps_mode or "all" 212 deps_mode = deps_mode or "all"
210 rocks_provided = rocks_provided or {} 213 rocks_provided = rocks_provided or {}
@@ -224,9 +227,9 @@ function deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey
224 227
225 local url, search_err = search.find_suitable_rock(dep) 228 local url, search_err = search.find_suitable_rock(dep)
226 if not url then 229 if not url then
227 return nil, "Could not satisfy dependency "..tostring(dep)..": "..search_err 230 return nil, "Could not satisfy dependency " .. tostring(dep) .. ": " .. search_err
228 end 231 end
229 util.printout("Installing "..url) 232 util.printout("Installing " .. url)
230 local install_args = { 233 local install_args = {
231 rock = url, 234 rock = url,
232 deps_mode = deps_mode, 235 deps_mode = deps_mode,
@@ -235,7 +238,7 @@ function deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey
235 } 238 }
236 local ok, install_err, errcode = install.command(install_args) 239 local ok, install_err, errcode = install.command(install_args)
237 if not ok then 240 if not ok then
238 return nil, "Failed installing dependency: "..url.." - "..install_err, errcode 241 return nil, "Failed installing dependency: " .. url .. " - " .. install_err, errcode
239 end 242 end
240 243
241 found, where = match_dep(dep, get_versions) 244 found, where = match_dep(dep, get_versions)
@@ -246,15 +249,15 @@ function deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey
246end 249end
247 250
248local function check_supported_platforms(rockspec) 251local function check_supported_platforms(rockspec)
249 if rockspec.supported_platforms and next(rockspec.supported_platforms) then 252 if rockspec.supported_platforms and next(rockspec.supported_platforms) ~= nil then
250 local all_negative = true 253 local all_negative = true
251 local supported = false 254 local supported = false
252 for _, plat in pairs(rockspec.supported_platforms) do 255 for _, plat in ipairs(rockspec.supported_platforms) do
253 local neg 256 local neg
254 neg, plat = plat:match("^(!?)(.*)") 257 neg, plat = plat:match("^(!?)(.*)")
255 if neg == "!" then 258 if neg == "!" then
256 if cfg.is_platform(plat) then 259 if cfg.is_platform(plat) then
257 return nil, "This rockspec for "..rockspec.package.." does not support "..plat.." platforms." 260 return nil, "This rockspec for " .. rockspec.package .. " does not support " .. plat .. " platforms."
258 end 261 end
259 else 262 else
260 all_negative = false 263 all_negative = false
@@ -266,32 +269,26 @@ local function check_supported_platforms(rockspec)
266 end 269 end
267 if supported == false and not all_negative then 270 if supported == false and not all_negative then
268 local plats = cfg.print_platforms() 271 local plats = cfg.print_platforms()
269 return nil, "This rockspec for "..rockspec.package.." does not support "..plats.." platforms." 272 return nil, "This rockspec for " .. rockspec.package .. " does not support " .. plats .. " platforms."
270 end 273 end
271 end 274 end
272 275
273 return true 276 return true
274end 277end
275 278
276--- Check dependencies of a rock and attempt to install any missing ones.
277-- Packages are installed using the LuaRocks "install" command.
278-- Aborts the program if a dependency could not be fulfilled.
279-- @param rockspec table: A rockspec in table format.
280-- @param depskey string: Rockspec key to fetch to get dependency table
281-- ("dependencies", "build_dependencies", etc.).
282-- @param deps_mode string
283-- @param verify boolean
284-- @param deplock_dir string: dirname of the deplock file
285-- @return boolean or (nil, string, [string]): True if no errors occurred, or
286-- nil and an error message if any test failed, followed by an optional
287-- error code.
288function deps.fulfill_dependencies(rockspec, depskey, deps_mode, verify, deplock_dir)
289 assert(type(rockspec) == "table")
290 assert(type(depskey) == "string")
291 assert(type(deps_mode) == "string")
292 assert(type(verify) == "boolean" or verify == nil)
293 assert(type(deplock_dir) == "string" or deplock_dir == nil)
294 279
280
281
282
283
284
285
286
287
288
289
290
291function deps.fulfill_dependencies(rockspec, depskey, deps_mode, verify, deplock_dir)
295 local name = rockspec.name 292 local name = rockspec.name
296 local version = rockspec.version 293 local version = rockspec.version
297 local rocks_provided = rockspec.rocks_provided 294 local rocks_provided = rockspec.rocks_provided
@@ -301,16 +298,23 @@ function deps.fulfill_dependencies(rockspec, depskey, deps_mode, verify, deplock
301 util.printout("Using dependencies pinned in lockfile: " .. filename) 298 util.printout("Using dependencies pinned in lockfile: " .. filename)
302 299
303 local get_versions = prepare_get_versions("none", rocks_provided, depskey) 300 local get_versions = prepare_get_versions("none", rocks_provided, depskey)
301 local dnsnamestr, dversionstr
304 for dnsname, dversion in deplocks.each(depskey) do 302 for dnsname, dversion in deplocks.each(depskey) do
305 local dname, dnamespace = util.split_namespace(dnsname) 303 if type(dnsname) == "string" then
306 local dep = queries.new(dname, dnamespace, dversion) 304 dnsnamestr = dnsname
305 end
306 if type(dversion) == "string" then
307 dversionstr = dversion
308 end
309 local dname, dnamespace = util.split_namespace(dnsnamestr)
310 local dep = queries.new(dname, dnamespace, dversionstr)
307 311
308 util.printout(("%s %s is pinned to %s (%s)"):format( 312 util.printout(("%s %s is pinned to %s (%s)"):format(
309 name, version, tostring(dep), rock_status(dep, get_versions))) 313 name, version, tostring(dep), rock_status(dep, get_versions)))
310 314
311 local ok, err = deps.fulfill_dependency(dep, "none", rocks_provided, verify, depskey) 315 local okfullfill, errfullfill = deps.fulfill_dependency(dep, "none", rocks_provided, verify, depskey)
312 if not ok then 316 if not okfullfill then
313 return nil, err 317 return nil, errfullfill
314 end 318 end
315 end 319 end
316 util.printout() 320 util.printout()
@@ -324,28 +328,28 @@ function deps.fulfill_dependencies(rockspec, depskey, deps_mode, verify, deplock
324 return nil, err 328 return nil, err
325 end 329 end
326 330
327 deps.report_missing_dependencies(name, version, rockspec[depskey], deps_mode, rocks_provided) 331 deps.report_missing_dependencies(name, version, (rockspec)[depskey], deps_mode, rocks_provided)
328 332
329 util.printout() 333 util.printout()
330 334
331 local get_versions = prepare_get_versions(deps_mode, rocks_provided, depskey) 335 local get_versions = prepare_get_versions(deps_mode, rocks_provided, depskey)
332 for _, dep in ipairs(rockspec[depskey]) do 336 for _, dep in ipairs((rockspec)[depskey]) do
333 337
334 util.printout(("%s %s depends on %s (%s)"):format( 338 util.printout(("%s %s depends on %s (%s)"):format(
335 name, version, tostring(dep), rock_status(dep, get_versions))) 339 name, version, tostring(dep), rock_status(dep, get_versions)))
336 340
337 local ok, found_or_err, _, no_upgrade = deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey) 341 local okfulfill, found_or_err, _ = deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey)
338 if ok then 342 if okfulfill then
339 deplocks.add(depskey, dep.name, found_or_err) 343 deplocks.add(depskey, dep.name, found_or_err)
340 else 344 else
341 if no_upgrade then 345
342 util.printerr("This version of "..name.." is designed for use with") 346
343 util.printerr(tostring(dep)..", but is configured to avoid upgrading it") 347
344 util.printerr("automatically. Please upgrade "..dep.name.." with") 348
345 util.printerr(" luarocks install "..dep.name) 349
346 util.printerr("or look for a suitable version of "..name.." with") 350
347 util.printerr(" luarocks search "..name) 351
348 end 352
349 return nil, found_or_err 353 return nil, found_or_err
350 end 354 end
351 end 355 end
@@ -353,28 +357,28 @@ function deps.fulfill_dependencies(rockspec, depskey, deps_mode, verify, deplock
353 return true 357 return true
354end 358end
355 359
356--- If filename matches a pattern, return the capture. 360
357-- For example, given "libfoo.so" and "lib?.so" is a pattern, 361
358-- returns "foo" (which can then be used to build names 362
359-- based on other patterns. 363
360-- @param file string: a filename 364
361-- @param pattern string: a pattern, where ? is to be matched by the filename. 365
362-- @return string The pattern, if found, or nil. 366
363local function deconstruct_pattern(file, pattern) 367local function deconstruct_pattern(file, pattern)
364 local depattern = "^"..(pattern:gsub("%.", "%%."):gsub("%*", ".*"):gsub("?", "(.*)")).."$" 368 local depattern = "^" .. (pattern:gsub("%.", "%%."):gsub("%*", ".*"):gsub("?", "(.*)")) .. "$"
365 return (file:match(depattern)) 369 return (file:match(depattern))
366end 370end
367 371
368--- Construct all possible patterns for a name and add to the files array. 372
369-- Run through the patterns array replacing all occurrences of "?" 373
370-- with the given file name and store them in the files array. 374
371-- @param file string A raw name (e.g. "foo") 375
372-- @param array of string An array of patterns with "?" as the wildcard 376
373-- (e.g. {"?.so", "lib?.so"}) 377
374-- @param files The array of constructed names 378
375local function add_all_patterns(file, patterns, files) 379local function add_all_patterns(file, patterns, files)
376 for _, pattern in ipairs(patterns) do 380 for _, pattern in ipairs(patterns) do
377 table.insert(files, {#files + 1, (pattern:gsub("?", file))}) 381 table.insert(files, { #files + 1, (pattern:gsub("?", file)) })
378 end 382 end
379end 383end
380 384
@@ -388,7 +392,7 @@ local function get_external_deps_dirs(mode)
388 local dirs = { 392 local dirs = {
389 BINDIR = { subdir = subdirs.bin, testfile = "program", pattern = patterns.bin }, 393 BINDIR = { subdir = subdirs.bin, testfile = "program", pattern = patterns.bin },
390 INCDIR = { subdir = subdirs.include, testfile = "header", pattern = patterns.include }, 394 INCDIR = { subdir = subdirs.include, testfile = "header", pattern = patterns.include },
391 LIBDIR = { subdir = subdirs.lib, testfile = "library", pattern = patterns.lib } 395 LIBDIR = { subdir = subdirs.lib, testfile = "library", pattern = patterns.lib },
392 } 396 }
393 if mode == "install" then 397 if mode == "install" then
394 dirs.INCDIR = nil 398 dirs.INCDIR = nil
@@ -416,7 +420,7 @@ local function resolve_prefix(prefix, dirs)
416end 420end
417 421
418local function add_patterns_for_file(files, file, patterns) 422local function add_patterns_for_file(files, file, patterns)
419 -- If it doesn't look like it contains a filename extension 423
420 if not (file:match("%.[a-z]+$") or file:match("%.[a-z]+%.")) then 424 if not (file:match("%.[a-z]+$") or file:match("%.[a-z]+%.")) then
421 add_all_patterns(file, patterns, files) 425 add_all_patterns(file, patterns, files)
422 else 426 else
@@ -426,26 +430,35 @@ local function add_patterns_for_file(files, file, patterns)
426 add_all_patterns(matched, patterns, files) 430 add_all_patterns(matched, patterns, files)
427 end 431 end
428 end 432 end
429 table.insert(files, {#files + 1, file}) 433 table.insert(files, { #files + 1, file })
430 end 434 end
431end 435end
432 436
433local function check_external_dependency_at(prefix, name, ext_files, vars, dirs, err_files, cache) 437local function check_external_dependency_at(
438 prefix,
439 name,
440 ext_files,
441 vars,
442 dirs,
443 err_files,
444 cache)
445
434 local fs = require("luarocks.fs") 446 local fs = require("luarocks.fs")
435 cache = cache or {} 447 cache = cache or {}
436 448
437 for dirname, dirdata in util.sortedpairs(dirs) do 449 for dirname, dirdata in util.sortedpairs(dirs) do
438 local paths 450 local paths
439 local path_var_value = vars[name.."_"..dirname] 451 local path_var_value = vars[name .. "_" .. dirname]
452 local dirdatastr = dirdata.subdir
440 if path_var_value then 453 if path_var_value then
441 paths = { path_var_value } 454 paths = { path_var_value }
442 elseif type(dirdata.subdir) == "table" then 455 elseif type(dirdatastr) == "table" then
443 paths = {} 456 paths = {}
444 for i,v in ipairs(dirdata.subdir) do 457 for i, v in ipairs(dirdatastr) do
445 paths[i] = dir.path(prefix, v) 458 paths[i] = dir.path(prefix, v)
446 end 459 end
447 else 460 else
448 paths = { dir.path(prefix, dirdata.subdir) } 461 paths = { dir.path(prefix, dirdatastr) }
449 end 462 end
450 local file_or_files = ext_files[dirdata.testfile] 463 local file_or_files = ext_files[dirdata.testfile]
451 if file_or_files then 464 if file_or_files then
@@ -471,15 +484,15 @@ local function check_external_dependency_at(prefix, name, ext_files, vars, dirs,
471 for _, fa in ipairs(files) do 484 for _, fa in ipairs(files) do
472 485
473 local f = fa[2] 486 local f = fa[2]
474 -- small convenience hack 487
475 if f:match("%.so$") or f:match("%.dylib$") or f:match("%.dll$") then 488 if f:match("%.so$") or f:match("%.dylib$") or f:match("%.dll$") then
476 f = f:gsub("%.[^.]+$", "."..cfg.external_lib_extension) 489 f = f:gsub("%.[^.]+$", "." .. cfg.external_lib_extension)
477 end 490 end
478 491
479 local pattern 492 local pattern
480 if f:match("%*") then 493 if f:match("%*") then
481 pattern = "^" .. f:gsub("([-.+])", "%%%1"):gsub("%*", ".*") .. "$" 494 pattern = "^" .. f:gsub("([-.+])", "%%%1"):gsub("%*", ".*") .. "$"
482 f = "matching "..f 495 f = "matching " .. f
483 end 496 end
484 497
485 for _, d in ipairs(paths) do 498 for _, d in ipairs(paths) do
@@ -502,7 +515,7 @@ local function check_external_dependency_at(prefix, name, ext_files, vars, dirs,
502 dirdata.file = f 515 dirdata.file = f
503 break 516 break
504 else 517 else
505 table.insert(err_files[dirdata.testfile], f.." in "..d) 518 table.insert(err_files[dirdata.testfile], f .. " in " .. d)
506 end 519 end
507 end 520 end
508 if found then 521 if found then
@@ -513,9 +526,9 @@ local function check_external_dependency_at(prefix, name, ext_files, vars, dirs,
513 return nil, dirname, dirdata.testfile 526 return nil, dirname, dirdata.testfile
514 end 527 end
515 else 528 else
516 -- When we have a set of subdir suffixes, look for one that exists. 529
517 -- For these reason, we now put "lib" ahead of "" on Windows in our 530
518 -- default set. 531
519 dirdata.dir = paths[1] 532 dirdata.dir = paths[1]
520 for _, p in ipairs(paths) do 533 for _, p in ipairs(paths) do
521 if fs.exists(p) then 534 if fs.exists(p) then
@@ -527,18 +540,23 @@ local function check_external_dependency_at(prefix, name, ext_files, vars, dirs,
527 end 540 end
528 541
529 for dirname, dirdata in pairs(dirs) do 542 for dirname, dirdata in pairs(dirs) do
530 vars[name.."_"..dirname] = dirdata.dir 543 vars[name .. "_" .. dirname] = dirdata.dir
531 vars[name.."_"..dirname.."_FILE"] = dirdata.file 544 vars[name .. "_" .. dirname .. "_FILE"] = dirdata.file
532 end 545 end
533 vars[name.."_DIR"] = prefix 546 vars[name .. "_DIR"] = prefix
534 return true 547 return true
535end 548end
536 549
537local function check_external_dependency(name, ext_files, vars, mode, cache) 550local function check_external_dependency(
551 name,
552 ext_files,
553 vars,
554 mode,
555 cache)
538 local ok 556 local ok
539 local err_dirname 557 local err_dirname
540 local err_testfile 558 local err_testfile
541 local err_files = {program = {}, header = {}, library = {}} 559 local err_files = { program = {}, header = {}, library = {} }
542 560
543 local dirs = get_external_deps_dirs(mode) 561 local dirs = get_external_deps_dirs(mode)
544 562
@@ -572,7 +590,7 @@ local function check_external_dependency(name, ext_files, vars, mode, cache)
572end 590end
573 591
574function deps.autodetect_external_dependencies(build) 592function deps.autodetect_external_dependencies(build)
575 -- only applies to the 'builtin' build type 593
576 if not build or not build.modules then 594 if not build or not build.modules then
577 return nil 595 return nil
578 end 596 end
@@ -581,9 +599,12 @@ function deps.autodetect_external_dependencies(build)
581 local any = false 599 local any = false
582 for _, data in pairs(build.modules) do 600 for _, data in pairs(build.modules) do
583 if type(data) == "table" and data.libraries then 601 if type(data) == "table" and data.libraries then
584 local libraries = data.libraries 602 local libraries
585 if type(libraries) == "string" then 603 local librariesstr = data.libraries
586 libraries = { libraries } 604 if type(librariesstr) == "string" then
605 libraries = { librariesstr }
606 else
607 libraries = librariesstr
587 end 608 end
588 local incdirs = {} 609 local incdirs = {}
589 local libdirs = {} 610 local libdirs = {}
@@ -605,21 +626,20 @@ function deps.autodetect_external_dependencies(build)
605 return any and extdeps or nil 626 return any and extdeps or nil
606end 627end
607 628
608--- Set up path-related variables for external dependencies. 629
609-- For each key in the external_dependencies table in the 630
610-- rockspec file, four variables are created: <key>_DIR, <key>_BINDIR, 631
611-- <key>_INCDIR and <key>_LIBDIR. These are not overwritten 632
612-- if already set (e.g. by the LuaRocks config file or through the 633
613-- command-line). Values in the external_dependencies table 634
614-- are tables that may contain a "header" or a "library" field, 635
615-- with filenames to be tested for existence. 636
616-- @param rockspec table: The rockspec table. 637
617-- @param mode string: if "build" is given, checks all files; 638
618-- if "install" is given, do not scan for headers. 639
619-- @return boolean or (nil, string): True if no errors occurred, or 640
620-- nil and an error message if any test failed. 641
621function deps.check_external_deps(rockspec, mode) 642function deps.check_external_deps(rockspec, mode)
622 assert(rockspec:type() == "rockspec")
623 643
624 if not rockspec.external_dependencies then 644 if not rockspec.external_dependencies then
625 rockspec.external_dependencies = deps.autodetect_external_dependencies(rockspec.build) 645 rockspec.external_dependencies = deps.autodetect_external_dependencies(rockspec.build)
@@ -628,21 +648,21 @@ function deps.check_external_deps(rockspec, mode)
628 return true 648 return true
629 end 649 end
630 650
631 for name, ext_files in util.sortedpairs(rockspec.external_dependencies) do 651 for name, ext_files in util.sortedpairs(rockspec.external_dependencies.queries) do
632 local ok, err_dirname, err_testfile, err_files = check_external_dependency(name, ext_files, rockspec.variables, mode) 652 local ok, err_dirname, err_testfile, err_files = check_external_dependency(name, ext_files, rockspec.variables, mode)
633 if not ok then 653 if not ok then
634 local lines = {"Could not find "..err_testfile.." file for "..name} 654 local lines = { "Could not find " .. err_testfile .. " file for " .. name }
635 655
636 local err_paths = {} 656 local err_paths = {}
637 for _, err_file in ipairs(err_files[err_testfile]) do 657 for _, err_file in ipairs(err_files[err_testfile]) do
638 if not err_paths[err_file] then 658 if not err_paths[err_file] then
639 err_paths[err_file] = true 659 err_paths[err_file] = true
640 table.insert(lines, " No file "..err_file) 660 table.insert(lines, " No file " .. err_file)
641 end 661 end
642 end 662 end
643 663
644 table.insert(lines, "You may have to install "..name.." in your system and/or pass "..name.."_DIR or "..name.."_"..err_dirname.." to the luarocks command.") 664 table.insert(lines, "You may have to install " .. name .. " in your system and/or pass " .. name .. "_DIR or " .. name .. "_" .. err_dirname .. " to the luarocks command.")
645 table.insert(lines, "Example: luarocks install "..rockspec.name.." "..name.."_DIR=/usr/local") 665 table.insert(lines, "Example: luarocks install " .. rockspec.name .. " " .. name .. "_DIR=/usr/local")
646 666
647 return nil, table.concat(lines, "\n"), "dependency" 667 return nil, table.concat(lines, "\n"), "dependency"
648 end 668 end
@@ -650,18 +670,17 @@ function deps.check_external_deps(rockspec, mode)
650 return true 670 return true
651end 671end
652 672
653--- Recursively add satisfied dependencies of a package to a table, 673
654-- to build a transitive closure of all dependent packages. 674
655-- Additionally ensures that `dependencies` table of the manifest is up-to-date. 675
656-- @param results table: The results table being built, maps package names to versions. 676
657-- @param mdeps table: The manifest dependencies table. 677
658-- @param name string: Package name. 678
659-- @param version string: Package version. 679
660function deps.scan_deps(results, mdeps, name, version, deps_mode) 680function deps.scan_deps(results, mdeps, name, version, deps_mode)
661 assert(type(results) == "table") 681 assert(type(results) == "table")
662 assert(type(mdeps) == "table") 682 assert(type(mdeps) == "table")
663 assert(type(name) == "string" and not name:match("/")) 683 assert(not name:match("/"))
664 assert(type(version) == "string")
665 684
666 local fetch = require("luarocks.fetch") 685 local fetch = require("luarocks.fetch")
667 686
@@ -673,11 +692,11 @@ function deps.scan_deps(results, mdeps, name, version, deps_mode)
673 local dependencies = mdn[version] 692 local dependencies = mdn[version]
674 local rocks_provided 693 local rocks_provided
675 if not dependencies then 694 if not dependencies then
676 local rockspec, err = fetch.load_local_rockspec(path.rockspec_file(name, version), false) 695 local rockspec = fetch.load_local_rockspec(path.rockspec_file(name, version), false)
677 if not rockspec then 696 if not rockspec then
678 return 697 return
679 end 698 end
680 dependencies = rockspec.dependencies 699 dependencies = rockspec.dependencies.queries
681 rocks_provided = rockspec.rocks_provided 700 rocks_provided = rockspec.rocks_provided
682 mdn[version] = dependencies 701 mdn[version] = dependencies
683 else 702 else
@@ -736,13 +755,13 @@ local function find_lua_incdir(prefix, luaver, luajitver)
736 end 755 end
737 end 756 end
738 757
739 -- not found, will fallback to a default 758
740 return nil, mainerr 759 return nil, mainerr
741end 760end
742 761
743function deps.check_lua_incdir(vars) 762function deps.check_lua_incdir(vars)
744 if vars.LUA_INCDIR_OK == true 763 if vars.LUA_INCDIR_OK == true then
745 then return true 764 return true
746 end 765 end
747 766
748 local ljv = util.get_luajit_version() 767 local ljv = util.get_luajit_version()
@@ -769,8 +788,8 @@ function deps.check_lua_incdir(vars)
769end 788end
770 789
771function deps.check_lua_libdir(vars) 790function deps.check_lua_libdir(vars)
772 if vars.LUA_LIBDIR_OK == true 791 if vars.LUA_LIBDIR_OK == true then
773 then return true 792 return true
774 end 793 end
775 794
776 local fs = require("luarocks.fs") 795 local fs = require("luarocks.fs")
@@ -803,10 +822,10 @@ function deps.check_lua_libdir(vars)
803 local fd = io.open(filename, "r") 822 local fd = io.open(filename, "r")
804 if fd then 823 if fd then
805 if not vars.LUA_LIBDIR_FILE:match((cfg.lua_version:gsub("%.", "%%.?"))) then 824 if not vars.LUA_LIBDIR_FILE:match((cfg.lua_version:gsub("%.", "%%.?"))) then
806 -- if filename isn't versioned, check file contents 825
807 local txt = fd:read("*a") 826 local txt = fd:read("*a")
808 ok = txt:match("Lua " .. cfg.lua_version, 1, true) 827 ok = txt:find("Lua " .. cfg.lua_version, 1, true) or
809 or txt:match("lua" .. (cfg.lua_version:gsub("%.", "")), 1, true) 828 txt:find("lua" .. (cfg.lua_version:gsub("%.", "")), 1, true)
810 if not ok then 829 if not ok then
811 err = "Lua library at " .. filename .. " does not match Lua version " .. cfg.lua_version .. ". You can use `luarocks config variables.LUA_LIBDIR <path>` to set the correct location." 830 err = "Lua library at " .. filename .. " does not match Lua version " .. cfg.lua_version .. ". You can use `luarocks config variables.LUA_LIBDIR <path>` to set the correct location."
812 end 831 end
diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua
index df2fbbd5..1a9eefde 100644
--- a/src/luarocks/deps.lua
+++ b/src/luarocks/deps.lua
@@ -1,8 +1,7 @@
1local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local assert = _tl_compat and _tl_compat.assert or assert; local io = _tl_compat and _tl_compat.io or io; local ipairs = _tl_compat and _tl_compat.ipairs or ipairs; local pairs = _tl_compat and _tl_compat.pairs or pairs; local string = _tl_compat and _tl_compat.string or string; local table = _tl_compat and _tl_compat.table or table
2 1
2--- High-level dependency related functions.
3local deps = {} 3local deps = {}
4 4
5
6local cfg = require("luarocks.core.cfg") 5local cfg = require("luarocks.core.cfg")
7local manif = require("luarocks.manif") 6local manif = require("luarocks.manif")
8local path = require("luarocks.path") 7local path = require("luarocks.path")
@@ -13,55 +12,34 @@ local vers = require("luarocks.core.vers")
13local queries = require("luarocks.queries") 12local queries = require("luarocks.queries")
14local deplocks = require("luarocks.deplocks") 13local deplocks = require("luarocks.deplocks")
15 14
16 15--- Generate a function that matches dep queries against the manifest,
17 16-- taking into account rocks_provided, the list of versions to skip,
18 17-- and the lockfile.
19 18-- @param deps_mode "one", "none", "all" or "order"
20 19-- @param rocks_provided a one-level table mapping names to versions,
21 20-- listing rocks to consider provided by the VM
22 21-- @param rocks_provided table: A table of auto-provided dependencies.
23 22-- by this Lua implementation for the given dependency.
24 23-- @param depskey key to use when matching the lockfile ("dependencies",
25 24-- "build_dependencies", etc.)
26 25-- @param skip_set a two-level table mapping names to versions to
27 26-- boolean, listing rocks that should not be matched
28 27-- @return function(dep): {string}, {string:string}, string, boolean
29 28-- * array of matching versions
30 29-- * map of versions to locations
31 30-- * version matched via lockfile if any
32 31-- * true if rock matched via rocks_provided
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58local function prepare_get_versions(deps_mode, rocks_provided, depskey, skip_set) 32local function prepare_get_versions(deps_mode, rocks_provided, depskey, skip_set)
33 assert(type(deps_mode) == "string")
34 assert(type(rocks_provided) == "table")
35 assert(type(depskey) == "string")
36 assert(type(skip_set) == "table" or skip_set == nil)
59 37
60 return function(dep) 38 return function(dep)
61 local versions, locations 39 local versions, locations
62 local provided = rocks_provided[dep.name] 40 local provided = rocks_provided[dep.name]
63 if provided then 41 if provided then
64 42 -- Provided rocks have higher priority than manifest's rocks.
65 versions, locations = { provided }, {} 43 versions, locations = { provided }, {}
66 else 44 else
67 if deps_mode == "none" then 45 if deps_mode == "none" then
@@ -85,20 +63,21 @@ local function prepare_get_versions(deps_mode, rocks_provided, depskey, skip_set
85 end 63 end
86end 64end
87 65
88 66--- Attempt to match a dependency to an installed rock.
89 67-- @param get_versions a getter function obtained via prepare_get_versions
90 68-- @return (string, string, table) or (nil, nil, table):
91 69-- 1. latest installed version of the rock matching the dependency
92 70-- 2. location where the installed version is installed
93 71-- 3. the 'dep' query table
94 72-- 4. true if provided via VM
95 73-- or
96 74-- 1. nil
97 75-- 2. nil
98 76-- 3. either 'dep' or an alternative query to be used
99 77-- 4. false
100local function match_dep(dep, 78local function match_dep(dep, get_versions)
101 get_versions) 79 assert(type(dep) == "table")
80 assert(type(get_versions) == "function")
102 81
103 local versions, locations, lockversion, provided = get_versions(dep) 82 local versions, locations, lockversion, provided = get_versions(dep)
104 83
@@ -126,8 +105,9 @@ local function match_dep(dep,
126 return latest_vstring, locations[latest_vstring], dep, provided 105 return latest_vstring, locations[latest_vstring], dep, provided
127end 106end
128 107
129local function match_all_deps(dependencies, 108local function match_all_deps(dependencies, get_versions)
130 get_versions) 109 assert(type(dependencies) == "table")
110 assert(type(get_versions) == "function")
131 111
132 local matched, missing, no_upgrade = {}, {}, {} 112 local matched, missing, no_upgrade = {}, {}, {}
133 113
@@ -136,7 +116,7 @@ local function match_all_deps(dependencies,
136 found, _, dep, provided = match_dep(dep, get_versions) 116 found, _, dep, provided = match_dep(dep, get_versions)
137 if found then 117 if found then
138 if not provided then 118 if not provided then
139 matched[dep] = { name = dep.name, version = found } 119 matched[dep] = {name = dep.name, version = found}
140 end 120 end
141 else 121 else
142 if dep.constraints[1] and dep.constraints[1].no_upgrade then 122 if dep.constraints[1] and dep.constraints[1].no_upgrade then
@@ -149,41 +129,53 @@ local function match_all_deps(dependencies,
149 return matched, missing, no_upgrade 129 return matched, missing, no_upgrade
150end 130end
151 131
152 132--- Attempt to match dependencies of a rockspec to installed rocks.
153 133-- @param dependencies table: The table of dependencies.
154 134-- @param rocks_provided table: The table of auto-provided dependencies.
155 135-- @param skip_set table or nil: Program versions to not use as valid matches.
156 136-- Table where keys are program names and values are tables where keys
157 137-- are program versions and values are 'true'.
158 138-- @param deps_mode string: Which trees to check dependencies for
159 139-- @return table, table, table: A table where keys are dependencies parsed
160 140-- in table format and values are tables containing fields 'name' and
161 141-- version' representing matches; a table of missing dependencies
162 142-- parsed as tables; and a table of "no-upgrade" missing dependencies
163 143-- (to be used in plugin modules so that a plugin does not force upgrade of
164 144-- its parent application).
165function deps.match_deps(dependencies, rocks_provided, deps_mode, skip_set) 145function deps.match_deps(dependencies, rocks_provided, deps_mode, skip_set)
146 assert(type(dependencies) == "table")
147 assert(type(rocks_provided) == "table")
148 assert(type(skip_set) == "table" or skip_set == nil)
149 assert(type(deps_mode) == "string")
166 150
167 local get_versions = prepare_get_versions(deps_mode, rocks_provided, "dependencies", skip_set) 151 local get_versions = prepare_get_versions(deps_mode, rocks_provided, "dependencies", skip_set)
168 return match_all_deps(dependencies, get_versions) 152 return match_all_deps(dependencies, get_versions)
169end 153end
170 154
171local function rock_status(dep, get_versions) 155local function rock_status(dep, get_versions)
156 assert(dep:type() == "query")
157 assert(type(get_versions) == "function")
158
172 local installed, _, _, provided = match_dep(dep, get_versions) 159 local installed, _, _, provided = match_dep(dep, get_versions)
173 local installation_type = provided and "provided by VM" or "installed" 160 local installation_type = provided and "provided by VM" or "installed"
174 return installed and installed .. " " .. installation_type .. ": success" or "not installed" 161 return installed and installed.." "..installation_type..": success" or "not installed"
175end 162end
176 163
177 164--- Check depenendencies of a package and report any missing ones.
178 165-- @param name string: package name.
179 166-- @param version string: package version.
180 167-- @param dependencies table: array of dependencies.
181 168-- @param deps_mode string: Which trees to check dependencies for
182 169-- @param rocks_provided table: A table of auto-dependencies provided
183 170-- by this Lua implementation for the given dependency.
184 171-- "one" for the current default tree, "all" for all trees,
185 172-- "order" for all trees with priority >= the current default, "none" for no trees.
186function deps.report_missing_dependencies(name, version, dependencies, deps_mode, rocks_provided) 173function deps.report_missing_dependencies(name, version, dependencies, deps_mode, rocks_provided)
174 assert(type(name) == "string")
175 assert(type(version) == "string")
176 assert(type(dependencies) == "table")
177 assert(type(deps_mode) == "string")
178 assert(type(rocks_provided) == "table")
187 179
188 if deps_mode == "none" then 180 if deps_mode == "none" then
189 return 181 return
@@ -208,6 +200,11 @@ function deps.report_missing_dependencies(name, version, dependencies, deps_mode
208end 200end
209 201
210function deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey) 202function deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey)
203 assert(dep:type() == "query")
204 assert(type(deps_mode) == "string" or deps_mode == nil)
205 assert(type(rocks_provided) == "table" or rocks_provided == nil)
206 assert(type(verify) == "boolean" or verify == nil)
207 assert(type(depskey) == "string")
211 208
212 deps_mode = deps_mode or "all" 209 deps_mode = deps_mode or "all"
213 rocks_provided = rocks_provided or {} 210 rocks_provided = rocks_provided or {}
@@ -227,9 +224,9 @@ function deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey
227 224
228 local url, search_err = search.find_suitable_rock(dep) 225 local url, search_err = search.find_suitable_rock(dep)
229 if not url then 226 if not url then
230 return nil, "Could not satisfy dependency " .. tostring(dep) .. ": " .. search_err 227 return nil, "Could not satisfy dependency "..tostring(dep)..": "..search_err
231 end 228 end
232 util.printout("Installing " .. url) 229 util.printout("Installing "..url)
233 local install_args = { 230 local install_args = {
234 rock = url, 231 rock = url,
235 deps_mode = deps_mode, 232 deps_mode = deps_mode,
@@ -238,7 +235,7 @@ function deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey
238 } 235 }
239 local ok, install_err, errcode = install.command(install_args) 236 local ok, install_err, errcode = install.command(install_args)
240 if not ok then 237 if not ok then
241 return nil, "Failed installing dependency: " .. url .. " - " .. install_err, errcode 238 return nil, "Failed installing dependency: "..url.." - "..install_err, errcode
242 end 239 end
243 240
244 found, where = match_dep(dep, get_versions) 241 found, where = match_dep(dep, get_versions)
@@ -249,15 +246,15 @@ function deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey
249end 246end
250 247
251local function check_supported_platforms(rockspec) 248local function check_supported_platforms(rockspec)
252 if rockspec.supported_platforms and next(rockspec.supported_platforms) ~= nil then 249 if rockspec.supported_platforms and next(rockspec.supported_platforms) then
253 local all_negative = true 250 local all_negative = true
254 local supported = false 251 local supported = false
255 for _, plat in ipairs(rockspec.supported_platforms) do 252 for _, plat in pairs(rockspec.supported_platforms) do
256 local neg 253 local neg
257 neg, plat = plat:match("^(!?)(.*)") 254 neg, plat = plat:match("^(!?)(.*)")
258 if neg == "!" then 255 if neg == "!" then
259 if cfg.is_platform(plat) then 256 if cfg.is_platform(plat) then
260 return nil, "This rockspec for " .. rockspec.package .. " does not support " .. plat .. " platforms." 257 return nil, "This rockspec for "..rockspec.package.." does not support "..plat.." platforms."
261 end 258 end
262 else 259 else
263 all_negative = false 260 all_negative = false
@@ -269,26 +266,32 @@ local function check_supported_platforms(rockspec)
269 end 266 end
270 if supported == false and not all_negative then 267 if supported == false and not all_negative then
271 local plats = cfg.print_platforms() 268 local plats = cfg.print_platforms()
272 return nil, "This rockspec for " .. rockspec.package .. " does not support " .. plats .. " platforms." 269 return nil, "This rockspec for "..rockspec.package.." does not support "..plats.." platforms."
273 end 270 end
274 end 271 end
275 272
276 return true 273 return true
277end 274end
278 275
279 276--- Check dependencies of a rock and attempt to install any missing ones.
280 277-- Packages are installed using the LuaRocks "install" command.
281 278-- Aborts the program if a dependency could not be fulfilled.
282 279-- @param rockspec table: A rockspec in table format.
283 280-- @param depskey string: Rockspec key to fetch to get dependency table
284 281-- ("dependencies", "build_dependencies", etc.).
285 282-- @param deps_mode string
286 283-- @param verify boolean
287 284-- @param deplock_dir string: dirname of the deplock file
288 285-- @return boolean or (nil, string, [string]): True if no errors occurred, or
289 286-- nil and an error message if any test failed, followed by an optional
290 287-- error code.
291function deps.fulfill_dependencies(rockspec, depskey, deps_mode, verify, deplock_dir) 288function deps.fulfill_dependencies(rockspec, depskey, deps_mode, verify, deplock_dir)
289 assert(type(rockspec) == "table")
290 assert(type(depskey) == "string")
291 assert(type(deps_mode) == "string")
292 assert(type(verify) == "boolean" or verify == nil)
293 assert(type(deplock_dir) == "string" or deplock_dir == nil)
294
292 local name = rockspec.name 295 local name = rockspec.name
293 local version = rockspec.version 296 local version = rockspec.version
294 local rocks_provided = rockspec.rocks_provided 297 local rocks_provided = rockspec.rocks_provided
@@ -298,23 +301,16 @@ function deps.fulfill_dependencies(rockspec, depskey, deps_mode, verify, deplock
298 util.printout("Using dependencies pinned in lockfile: " .. filename) 301 util.printout("Using dependencies pinned in lockfile: " .. filename)
299 302
300 local get_versions = prepare_get_versions("none", rocks_provided, depskey) 303 local get_versions = prepare_get_versions("none", rocks_provided, depskey)
301 local dnsnamestr, dversionstr
302 for dnsname, dversion in deplocks.each(depskey) do 304 for dnsname, dversion in deplocks.each(depskey) do
303 if type(dnsname) == "string" then 305 local dname, dnamespace = util.split_namespace(dnsname)
304 dnsnamestr = dnsname 306 local dep = queries.new(dname, dnamespace, dversion)
305 end
306 if type(dversion) == "string" then
307 dversionstr = dversion
308 end
309 local dname, dnamespace = util.split_namespace(dnsnamestr)
310 local dep = queries.new(dname, dnamespace, dversionstr)
311 307
312 util.printout(("%s %s is pinned to %s (%s)"):format( 308 util.printout(("%s %s is pinned to %s (%s)"):format(
313 name, version, tostring(dep), rock_status(dep, get_versions))) 309 name, version, tostring(dep), rock_status(dep, get_versions)))
314 310
315 local okfullfill, errfullfill = deps.fulfill_dependency(dep, "none", rocks_provided, verify, depskey) 311 local ok, err = deps.fulfill_dependency(dep, "none", rocks_provided, verify, depskey)
316 if not okfullfill then 312 if not ok then
317 return nil, errfullfill 313 return nil, err
318 end 314 end
319 end 315 end
320 util.printout() 316 util.printout()
@@ -328,28 +324,28 @@ function deps.fulfill_dependencies(rockspec, depskey, deps_mode, verify, deplock
328 return nil, err 324 return nil, err
329 end 325 end
330 326
331 deps.report_missing_dependencies(name, version, (rockspec)[depskey], deps_mode, rocks_provided) 327 deps.report_missing_dependencies(name, version, rockspec[depskey], deps_mode, rocks_provided)
332 328
333 util.printout() 329 util.printout()
334 330
335 local get_versions = prepare_get_versions(deps_mode, rocks_provided, depskey) 331 local get_versions = prepare_get_versions(deps_mode, rocks_provided, depskey)
336 for _, dep in ipairs((rockspec)[depskey]) do 332 for _, dep in ipairs(rockspec[depskey]) do
337 333
338 util.printout(("%s %s depends on %s (%s)"):format( 334 util.printout(("%s %s depends on %s (%s)"):format(
339 name, version, tostring(dep), rock_status(dep, get_versions))) 335 name, version, tostring(dep), rock_status(dep, get_versions)))
340 336
341 local okfulfill, found_or_err, _ = deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey) 337 local ok, found_or_err, _, no_upgrade = deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey)
342 if okfulfill then 338 if ok then
343 deplocks.add(depskey, dep.name, found_or_err) 339 deplocks.add(depskey, dep.name, found_or_err)
344 else 340 else
345 341 if no_upgrade then
346 342 util.printerr("This version of "..name.." is designed for use with")
347 343 util.printerr(tostring(dep)..", but is configured to avoid upgrading it")
348 344 util.printerr("automatically. Please upgrade "..dep.name.." with")
349 345 util.printerr(" luarocks install "..dep.name)
350 346 util.printerr("or look for a suitable version of "..name.." with")
351 347 util.printerr(" luarocks search "..name)
352 348 end
353 return nil, found_or_err 349 return nil, found_or_err
354 end 350 end
355 end 351 end
@@ -357,28 +353,28 @@ function deps.fulfill_dependencies(rockspec, depskey, deps_mode, verify, deplock
357 return true 353 return true
358end 354end
359 355
360 356--- If filename matches a pattern, return the capture.
361 357-- For example, given "libfoo.so" and "lib?.so" is a pattern,
362 358-- returns "foo" (which can then be used to build names
363 359-- based on other patterns.
364 360-- @param file string: a filename
365 361-- @param pattern string: a pattern, where ? is to be matched by the filename.
366 362-- @return string The pattern, if found, or nil.
367local function deconstruct_pattern(file, pattern) 363local function deconstruct_pattern(file, pattern)
368 local depattern = "^" .. (pattern:gsub("%.", "%%."):gsub("%*", ".*"):gsub("?", "(.*)")) .. "$" 364 local depattern = "^"..(pattern:gsub("%.", "%%."):gsub("%*", ".*"):gsub("?", "(.*)")).."$"
369 return (file:match(depattern)) 365 return (file:match(depattern))
370end 366end
371 367
372 368--- Construct all possible patterns for a name and add to the files array.
373 369-- Run through the patterns array replacing all occurrences of "?"
374 370-- with the given file name and store them in the files array.
375 371-- @param file string A raw name (e.g. "foo")
376 372-- @param array of string An array of patterns with "?" as the wildcard
377 373-- (e.g. {"?.so", "lib?.so"})
378 374-- @param files The array of constructed names
379local function add_all_patterns(file, patterns, files) 375local function add_all_patterns(file, patterns, files)
380 for _, pattern in ipairs(patterns) do 376 for _, pattern in ipairs(patterns) do
381 table.insert(files, { #files + 1, (pattern:gsub("?", file)) }) 377 table.insert(files, {#files + 1, (pattern:gsub("?", file))})
382 end 378 end
383end 379end
384 380
@@ -392,7 +388,7 @@ local function get_external_deps_dirs(mode)
392 local dirs = { 388 local dirs = {
393 BINDIR = { subdir = subdirs.bin, testfile = "program", pattern = patterns.bin }, 389 BINDIR = { subdir = subdirs.bin, testfile = "program", pattern = patterns.bin },
394 INCDIR = { subdir = subdirs.include, testfile = "header", pattern = patterns.include }, 390 INCDIR = { subdir = subdirs.include, testfile = "header", pattern = patterns.include },
395 LIBDIR = { subdir = subdirs.lib, testfile = "library", pattern = patterns.lib }, 391 LIBDIR = { subdir = subdirs.lib, testfile = "library", pattern = patterns.lib }
396 } 392 }
397 if mode == "install" then 393 if mode == "install" then
398 dirs.INCDIR = nil 394 dirs.INCDIR = nil
@@ -420,7 +416,7 @@ local function resolve_prefix(prefix, dirs)
420end 416end
421 417
422local function add_patterns_for_file(files, file, patterns) 418local function add_patterns_for_file(files, file, patterns)
423 419 -- If it doesn't look like it contains a filename extension
424 if not (file:match("%.[a-z]+$") or file:match("%.[a-z]+%.")) then 420 if not (file:match("%.[a-z]+$") or file:match("%.[a-z]+%.")) then
425 add_all_patterns(file, patterns, files) 421 add_all_patterns(file, patterns, files)
426 else 422 else
@@ -430,35 +426,26 @@ local function add_patterns_for_file(files, file, patterns)
430 add_all_patterns(matched, patterns, files) 426 add_all_patterns(matched, patterns, files)
431 end 427 end
432 end 428 end
433 table.insert(files, { #files + 1, file }) 429 table.insert(files, {#files + 1, file})
434 end 430 end
435end 431end
436 432
437local function check_external_dependency_at( 433local function check_external_dependency_at(prefix, name, ext_files, vars, dirs, err_files, cache)
438 prefix,
439 name,
440 ext_files,
441 vars,
442 dirs,
443 err_files,
444 cache)
445
446 local fs = require("luarocks.fs") 434 local fs = require("luarocks.fs")
447 cache = cache or {} 435 cache = cache or {}
448 436
449 for dirname, dirdata in util.sortedpairs(dirs) do 437 for dirname, dirdata in util.sortedpairs(dirs) do
450 local paths 438 local paths
451 local path_var_value = vars[name .. "_" .. dirname] 439 local path_var_value = vars[name.."_"..dirname]
452 local dirdatastr = dirdata.subdir
453 if path_var_value then 440 if path_var_value then
454 paths = { path_var_value } 441 paths = { path_var_value }
455 elseif type(dirdatastr) == "table" then 442 elseif type(dirdata.subdir) == "table" then
456 paths = {} 443 paths = {}
457 for i, v in ipairs(dirdatastr) do 444 for i,v in ipairs(dirdata.subdir) do
458 paths[i] = dir.path(prefix, v) 445 paths[i] = dir.path(prefix, v)
459 end 446 end
460 else 447 else
461 paths = { dir.path(prefix, dirdatastr) } 448 paths = { dir.path(prefix, dirdata.subdir) }
462 end 449 end
463 local file_or_files = ext_files[dirdata.testfile] 450 local file_or_files = ext_files[dirdata.testfile]
464 if file_or_files then 451 if file_or_files then
@@ -484,15 +471,15 @@ local function check_external_dependency_at(
484 for _, fa in ipairs(files) do 471 for _, fa in ipairs(files) do
485 472
486 local f = fa[2] 473 local f = fa[2]
487 474 -- small convenience hack
488 if f:match("%.so$") or f:match("%.dylib$") or f:match("%.dll$") then 475 if f:match("%.so$") or f:match("%.dylib$") or f:match("%.dll$") then
489 f = f:gsub("%.[^.]+$", "." .. cfg.external_lib_extension) 476 f = f:gsub("%.[^.]+$", "."..cfg.external_lib_extension)
490 end 477 end
491 478
492 local pattern 479 local pattern
493 if f:match("%*") then 480 if f:match("%*") then
494 pattern = "^" .. f:gsub("([-.+])", "%%%1"):gsub("%*", ".*") .. "$" 481 pattern = "^" .. f:gsub("([-.+])", "%%%1"):gsub("%*", ".*") .. "$"
495 f = "matching " .. f 482 f = "matching "..f
496 end 483 end
497 484
498 for _, d in ipairs(paths) do 485 for _, d in ipairs(paths) do
@@ -515,7 +502,7 @@ local function check_external_dependency_at(
515 dirdata.file = f 502 dirdata.file = f
516 break 503 break
517 else 504 else
518 table.insert(err_files[dirdata.testfile], f .. " in " .. d) 505 table.insert(err_files[dirdata.testfile], f.." in "..d)
519 end 506 end
520 end 507 end
521 if found then 508 if found then
@@ -526,9 +513,9 @@ local function check_external_dependency_at(
526 return nil, dirname, dirdata.testfile 513 return nil, dirname, dirdata.testfile
527 end 514 end
528 else 515 else
529 516 -- When we have a set of subdir suffixes, look for one that exists.
530 517 -- For these reason, we now put "lib" ahead of "" on Windows in our
531 518 -- default set.
532 dirdata.dir = paths[1] 519 dirdata.dir = paths[1]
533 for _, p in ipairs(paths) do 520 for _, p in ipairs(paths) do
534 if fs.exists(p) then 521 if fs.exists(p) then
@@ -540,23 +527,18 @@ local function check_external_dependency_at(
540 end 527 end
541 528
542 for dirname, dirdata in pairs(dirs) do 529 for dirname, dirdata in pairs(dirs) do
543 vars[name .. "_" .. dirname] = dirdata.dir 530 vars[name.."_"..dirname] = dirdata.dir
544 vars[name .. "_" .. dirname .. "_FILE"] = dirdata.file 531 vars[name.."_"..dirname.."_FILE"] = dirdata.file
545 end 532 end
546 vars[name .. "_DIR"] = prefix 533 vars[name.."_DIR"] = prefix
547 return true 534 return true
548end 535end
549 536
550local function check_external_dependency( 537local function check_external_dependency(name, ext_files, vars, mode, cache)
551 name,
552 ext_files,
553 vars,
554 mode,
555 cache)
556 local ok 538 local ok
557 local err_dirname 539 local err_dirname
558 local err_testfile 540 local err_testfile
559 local err_files = { program = {}, header = {}, library = {} } 541 local err_files = {program = {}, header = {}, library = {}}
560 542
561 local dirs = get_external_deps_dirs(mode) 543 local dirs = get_external_deps_dirs(mode)
562 544
@@ -590,7 +572,7 @@ local function check_external_dependency(
590end 572end
591 573
592function deps.autodetect_external_dependencies(build) 574function deps.autodetect_external_dependencies(build)
593 575 -- only applies to the 'builtin' build type
594 if not build or not build.modules then 576 if not build or not build.modules then
595 return nil 577 return nil
596 end 578 end
@@ -599,12 +581,9 @@ function deps.autodetect_external_dependencies(build)
599 local any = false 581 local any = false
600 for _, data in pairs(build.modules) do 582 for _, data in pairs(build.modules) do
601 if type(data) == "table" and data.libraries then 583 if type(data) == "table" and data.libraries then
602 local libraries 584 local libraries = data.libraries
603 local librariesstr = data.libraries 585 if type(libraries) == "string" then
604 if type(librariesstr) == "string" then 586 libraries = { libraries }
605 libraries = { librariesstr }
606 else
607 libraries = librariesstr
608 end 587 end
609 local incdirs = {} 588 local incdirs = {}
610 local libdirs = {} 589 local libdirs = {}
@@ -626,20 +605,21 @@ function deps.autodetect_external_dependencies(build)
626 return any and extdeps or nil 605 return any and extdeps or nil
627end 606end
628 607
629 608--- Set up path-related variables for external dependencies.
630 609-- For each key in the external_dependencies table in the
631 610-- rockspec file, four variables are created: <key>_DIR, <key>_BINDIR,
632 611-- <key>_INCDIR and <key>_LIBDIR. These are not overwritten
633 612-- if already set (e.g. by the LuaRocks config file or through the
634 613-- command-line). Values in the external_dependencies table
635 614-- are tables that may contain a "header" or a "library" field,
636 615-- with filenames to be tested for existence.
637 616-- @param rockspec table: The rockspec table.
638 617-- @param mode string: if "build" is given, checks all files;
639 618-- if "install" is given, do not scan for headers.
640 619-- @return boolean or (nil, string): True if no errors occurred, or
641 620-- nil and an error message if any test failed.
642function deps.check_external_deps(rockspec, mode) 621function deps.check_external_deps(rockspec, mode)
622 assert(rockspec:type() == "rockspec")
643 623
644 if not rockspec.external_dependencies then 624 if not rockspec.external_dependencies then
645 rockspec.external_dependencies = deps.autodetect_external_dependencies(rockspec.build) 625 rockspec.external_dependencies = deps.autodetect_external_dependencies(rockspec.build)
@@ -648,21 +628,21 @@ function deps.check_external_deps(rockspec, mode)
648 return true 628 return true
649 end 629 end
650 630
651 for name, ext_files in util.sortedpairs(rockspec.external_dependencies.queries) do 631 for name, ext_files in util.sortedpairs(rockspec.external_dependencies) do
652 local ok, err_dirname, err_testfile, err_files = check_external_dependency(name, ext_files, rockspec.variables, mode) 632 local ok, err_dirname, err_testfile, err_files = check_external_dependency(name, ext_files, rockspec.variables, mode)
653 if not ok then 633 if not ok then
654 local lines = { "Could not find " .. err_testfile .. " file for " .. name } 634 local lines = {"Could not find "..err_testfile.." file for "..name}
655 635
656 local err_paths = {} 636 local err_paths = {}
657 for _, err_file in ipairs(err_files[err_testfile]) do 637 for _, err_file in ipairs(err_files[err_testfile]) do
658 if not err_paths[err_file] then 638 if not err_paths[err_file] then
659 err_paths[err_file] = true 639 err_paths[err_file] = true
660 table.insert(lines, " No file " .. err_file) 640 table.insert(lines, " No file "..err_file)
661 end 641 end
662 end 642 end
663 643
664 table.insert(lines, "You may have to install " .. name .. " in your system and/or pass " .. name .. "_DIR or " .. name .. "_" .. err_dirname .. " to the luarocks command.") 644 table.insert(lines, "You may have to install "..name.." in your system and/or pass "..name.."_DIR or "..name.."_"..err_dirname.." to the luarocks command.")
665 table.insert(lines, "Example: luarocks install " .. rockspec.name .. " " .. name .. "_DIR=/usr/local") 645 table.insert(lines, "Example: luarocks install "..rockspec.name.." "..name.."_DIR=/usr/local")
666 646
667 return nil, table.concat(lines, "\n"), "dependency" 647 return nil, table.concat(lines, "\n"), "dependency"
668 end 648 end
@@ -670,17 +650,18 @@ function deps.check_external_deps(rockspec, mode)
670 return true 650 return true
671end 651end
672 652
673 653--- Recursively add satisfied dependencies of a package to a table,
674 654-- to build a transitive closure of all dependent packages.
675 655-- Additionally ensures that `dependencies` table of the manifest is up-to-date.
676 656-- @param results table: The results table being built, maps package names to versions.
677 657-- @param mdeps table: The manifest dependencies table.
678 658-- @param name string: Package name.
679 659-- @param version string: Package version.
680function deps.scan_deps(results, mdeps, name, version, deps_mode) 660function deps.scan_deps(results, mdeps, name, version, deps_mode)
681 assert(type(results) == "table") 661 assert(type(results) == "table")
682 assert(type(mdeps) == "table") 662 assert(type(mdeps) == "table")
683 assert(not name:match("/")) 663 assert(type(name) == "string" and not name:match("/"))
664 assert(type(version) == "string")
684 665
685 local fetch = require("luarocks.fetch") 666 local fetch = require("luarocks.fetch")
686 667
@@ -692,11 +673,11 @@ function deps.scan_deps(results, mdeps, name, version, deps_mode)
692 local dependencies = mdn[version] 673 local dependencies = mdn[version]
693 local rocks_provided 674 local rocks_provided
694 if not dependencies then 675 if not dependencies then
695 local rockspec = fetch.load_local_rockspec(path.rockspec_file(name, version), false) 676 local rockspec, err = fetch.load_local_rockspec(path.rockspec_file(name, version), false)
696 if not rockspec then 677 if not rockspec then
697 return 678 return
698 end 679 end
699 dependencies = rockspec.dependencies.queries 680 dependencies = rockspec.dependencies
700 rocks_provided = rockspec.rocks_provided 681 rocks_provided = rockspec.rocks_provided
701 mdn[version] = dependencies 682 mdn[version] = dependencies
702 else 683 else
@@ -755,13 +736,13 @@ local function find_lua_incdir(prefix, luaver, luajitver)
755 end 736 end
756 end 737 end
757 738
758 739 -- not found, will fallback to a default
759 return nil, mainerr 740 return nil, mainerr
760end 741end
761 742
762function deps.check_lua_incdir(vars) 743function deps.check_lua_incdir(vars)
763 if vars.LUA_INCDIR_OK == true then 744 if vars.LUA_INCDIR_OK == true
764 return true 745 then return true
765 end 746 end
766 747
767 local ljv = util.get_luajit_version() 748 local ljv = util.get_luajit_version()
@@ -788,8 +769,8 @@ function deps.check_lua_incdir(vars)
788end 769end
789 770
790function deps.check_lua_libdir(vars) 771function deps.check_lua_libdir(vars)
791 if vars.LUA_LIBDIR_OK == true then 772 if vars.LUA_LIBDIR_OK == true
792 return true 773 then return true
793 end 774 end
794 775
795 local fs = require("luarocks.fs") 776 local fs = require("luarocks.fs")
@@ -822,10 +803,10 @@ function deps.check_lua_libdir(vars)
822 local fd = io.open(filename, "r") 803 local fd = io.open(filename, "r")
823 if fd then 804 if fd then
824 if not vars.LUA_LIBDIR_FILE:match((cfg.lua_version:gsub("%.", "%%.?"))) then 805 if not vars.LUA_LIBDIR_FILE:match((cfg.lua_version:gsub("%.", "%%.?"))) then
825 806 -- if filename isn't versioned, check file contents
826 local txt = fd:read("*a") 807 local txt = fd:read("*a")
827 ok = txt:find("Lua " .. cfg.lua_version, 1, true) or 808 ok = txt:match("Lua " .. cfg.lua_version, 1, true)
828 txt:find("lua" .. (cfg.lua_version:gsub("%.", "")), 1, true) 809 or txt:match("lua" .. (cfg.lua_version:gsub("%.", "")), 1, true)
829 if not ok then 810 if not ok then
830 err = "Lua library at " .. filename .. " does not match Lua version " .. cfg.lua_version .. ". You can use `luarocks config variables.LUA_LIBDIR <path>` to set the correct location." 811 err = "Lua library at " .. filename .. " does not match Lua version " .. cfg.lua_version .. ". You can use `luarocks config variables.LUA_LIBDIR <path>` to set the correct location."
831 end 812 end
diff --git a/src/luarocks/deps.tl b/src/luarocks/deps.tl
index dca855eb..d66ed4e8 100644
--- a/src/luarocks/deps.tl
+++ b/src/luarocks/deps.tl
@@ -696,7 +696,7 @@ function deps.scan_deps(results: {string: string}, mdeps: {string: {string: {Que
696 if not rockspec then 696 if not rockspec then
697 return 697 return
698 end 698 end
699 dependencies = rockspec.dependencies.queries 699 dependencies = rockspec.dependencies
700 rocks_provided = rockspec.rocks_provided 700 rocks_provided = rockspec.rocks_provided
701 mdn[version] = dependencies 701 mdn[version] = dependencies
702 else 702 else
diff --git a/src/luarocks/rockspecs-original.lua b/src/luarocks/rockspecs-original.lua
new file mode 100644
index 00000000..454bab77
--- /dev/null
+++ b/src/luarocks/rockspecs-original.lua
@@ -0,0 +1,183 @@
1local rockspecs = {}
2
3local cfg = require("luarocks.core.cfg")
4local dir = require("luarocks.dir")
5local path = require("luarocks.path")
6local queries = require("luarocks.queries")
7local type_rockspec = require("luarocks.type.rockspec")
8local util = require("luarocks.util")
9local vers = require("luarocks.core.vers")
10
11local vendored_build_type_set = {
12 ["builtin"] = true,
13 ["cmake"] = true,
14 ["command"] = true,
15 ["make"] = true,
16 ["module"] = true, -- compatibility alias
17 ["none"] = true,
18}
19
20local rockspec_mt = {}
21
22rockspec_mt.__index = rockspec_mt
23
24function rockspec_mt.type()
25 return "rockspec"
26end
27
28--- Perform platform-specific overrides on a table.
29-- Overrides values of table with the contents of the appropriate
30-- subset of its "platforms" field. The "platforms" field should
31-- be a table containing subtables keyed with strings representing
32-- platform names. Names that match the contents of the global
33-- detected platforms setting are used. For example, if
34-- platform "unix" is detected, then the fields of
35-- tbl.platforms.unix will overwrite those of tbl with the same
36-- names. For table values, the operation is performed recursively
37-- (tbl.platforms.foo.x.y.z overrides tbl.x.y.z; other contents of
38-- tbl.x are preserved).
39-- @param tbl table or nil: Table which may contain a "platforms" field;
40-- if it doesn't (or if nil is passed), this function does nothing.
41local function platform_overrides(tbl)
42 assert(type(tbl) == "table" or not tbl)
43
44 if not tbl then return end
45
46 if tbl.platforms then
47 for platform in cfg.each_platform() do
48 local platform_tbl = tbl.platforms[platform]
49 if platform_tbl then
50 util.deep_merge(tbl, platform_tbl)
51 end
52 end
53 end
54 tbl.platforms = nil
55end
56
57local function convert_dependencies(rockspec, key)
58 if rockspec[key] then
59 for i = 1, #rockspec[key] do
60 local parsed, err = queries.from_dep_string(rockspec[key][i])
61 if not parsed then
62 return nil, "Parse error processing dependency '"..rockspec[key][i].."': "..tostring(err)
63 end
64 rockspec[key][i] = parsed
65 end
66 else
67 rockspec[key] = {}
68 end
69 return true
70end
71
72--- Set up path-related variables for a given rock.
73-- Create a "variables" table in the rockspec table, containing
74-- adjusted variables according to the configuration file.
75-- @param rockspec table: The rockspec table.
76local function configure_paths(rockspec)
77 local vars = {}
78 for k,v in pairs(cfg.variables) do
79 vars[k] = v
80 end
81 local name, version = rockspec.name, rockspec.version
82 vars.PREFIX = path.install_dir(name, version)
83 vars.LUADIR = path.lua_dir(name, version)
84 vars.LIBDIR = path.lib_dir(name, version)
85 vars.CONFDIR = path.conf_dir(name, version)
86 vars.BINDIR = path.bin_dir(name, version)
87 vars.DOCDIR = path.doc_dir(name, version)
88 rockspec.variables = vars
89end
90
91function rockspecs.from_persisted_table(filename, rockspec, globals, quick)
92 assert(type(rockspec) == "table")
93 assert(type(globals) == "table" or globals == nil)
94 assert(type(filename) == "string")
95 assert(type(quick) == "boolean" or quick == nil)
96
97 if rockspec.rockspec_format then
98 if vers.compare_versions(rockspec.rockspec_format, type_rockspec.rockspec_format) then
99 return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks."
100 end
101 end
102
103 if not quick then
104 local ok, err = type_rockspec.check(rockspec, globals or {})
105 if not ok then
106 return nil, err
107 end
108 end
109
110 --- Check if rockspec format version satisfies version requirement.
111 -- @param rockspec table: The rockspec table.
112 -- @param version string: required version.
113 -- @return boolean: true if rockspec format matches version or is newer, false otherwise.
114 do
115 local parsed_format = vers.parse_version(rockspec.rockspec_format or "1.0")
116 rockspec.format_is_at_least = function(self, version)
117 return parsed_format >= vers.parse_version(version)
118 end
119 end
120
121 platform_overrides(rockspec.build)
122 platform_overrides(rockspec.dependencies)
123 platform_overrides(rockspec.build_dependencies)
124 platform_overrides(rockspec.test_dependencies)
125 platform_overrides(rockspec.external_dependencies)
126 platform_overrides(rockspec.source)
127 platform_overrides(rockspec.hooks)
128 platform_overrides(rockspec.test)
129
130 rockspec.name = rockspec.package:lower()
131
132 local protocol, pathname = dir.split_url(rockspec.source.url)
133 if dir.is_basic_protocol(protocol) then
134 rockspec.source.file = rockspec.source.file or dir.base_name(rockspec.source.url)
135 end
136 rockspec.source.protocol, rockspec.source.pathname = protocol, pathname
137
138 -- Temporary compatibility
139 if rockspec.source.cvs_module then rockspec.source.module = rockspec.source.cvs_module end
140 if rockspec.source.cvs_tag then rockspec.source.tag = rockspec.source.cvs_tag end
141
142 rockspec.local_abs_filename = filename
143 rockspec.source.dir_set = rockspec.source.dir ~= nil
144 rockspec.source.dir = rockspec.source.dir or rockspec.source.module
145
146 rockspec.rocks_provided = util.get_rocks_provided(rockspec)
147
148 for _, key in ipairs({"dependencies", "build_dependencies", "test_dependencies"}) do
149 local ok, err = convert_dependencies(rockspec, key)
150 if not ok then
151 return nil, err
152 end
153 end
154
155 if rockspec.build
156 and rockspec.build.type
157 and not vendored_build_type_set[rockspec.build.type] then
158 local build_pkg_name = "luarocks-build-" .. rockspec.build.type
159 if not rockspec.build_dependencies then
160 rockspec.build_dependencies = {}
161 end
162
163 local found = false
164 for _, dep in ipairs(rockspec.build_dependencies) do
165 if dep.name == build_pkg_name then
166 found = true
167 break
168 end
169 end
170
171 if not found then
172 table.insert(rockspec.build_dependencies, queries.from_dep_string(build_pkg_name))
173 end
174 end
175
176 if not quick then
177 configure_paths(rockspec)
178 end
179
180 return setmetatable(rockspec, rockspec_mt)
181end
182
183return rockspecs
diff --git a/src/luarocks/rockspecs.lua b/src/luarocks/rockspecs.lua
index 454bab77..2910ccf9 100644
--- a/src/luarocks/rockspecs.lua
+++ b/src/luarocks/rockspecs.lua
@@ -1,5 +1,7 @@
1local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local ipairs = _tl_compat and _tl_compat.ipairs or ipairs; local pairs = _tl_compat and _tl_compat.pairs or pairs; local table = _tl_compat and _tl_compat.table or table
1local rockspecs = {} 2local rockspecs = {}
2 3
4
3local cfg = require("luarocks.core.cfg") 5local cfg = require("luarocks.core.cfg")
4local dir = require("luarocks.dir") 6local dir = require("luarocks.dir")
5local path = require("luarocks.path") 7local path = require("luarocks.path")
@@ -8,45 +10,53 @@ local type_rockspec = require("luarocks.type.rockspec")
8local util = require("luarocks.util") 10local util = require("luarocks.util")
9local vers = require("luarocks.core.vers") 11local vers = require("luarocks.core.vers")
10 12
13local rockspec = require("luarocks.core.types.rockspec")
14
15
16
17
18
19
11local vendored_build_type_set = { 20local vendored_build_type_set = {
12 ["builtin"] = true, 21 ["builtin"] = true,
13 ["cmake"] = true, 22 ["cmake"] = true,
14 ["command"] = true, 23 ["command"] = true,
15 ["make"] = true, 24 ["make"] = true,
16 ["module"] = true, -- compatibility alias 25 ["module"] = true,
17 ["none"] = true, 26 ["none"] = true,
18} 27}
19 28
20local rockspec_mt = {} 29local rockspec_mt = {}
21 30
22rockspec_mt.__index = rockspec_mt 31rockspec_mt.__index = rockspec.Rockspec
23 32
24function rockspec_mt.type() 33function rockspec.Rockspec.type()
25 return "rockspec" 34 return "rockspec"
26end 35end
27 36
28--- Perform platform-specific overrides on a table. 37
29-- Overrides values of table with the contents of the appropriate 38
30-- subset of its "platforms" field. The "platforms" field should 39
31-- be a table containing subtables keyed with strings representing 40
32-- platform names. Names that match the contents of the global 41
33-- detected platforms setting are used. For example, if 42
34-- platform "unix" is detected, then the fields of 43
35-- tbl.platforms.unix will overwrite those of tbl with the same 44
36-- names. For table values, the operation is performed recursively 45
37-- (tbl.platforms.foo.x.y.z overrides tbl.x.y.z; other contents of 46
38-- tbl.x are preserved). 47
39-- @param tbl table or nil: Table which may contain a "platforms" field; 48
40-- if it doesn't (or if nil is passed), this function does nothing. 49
41local function platform_overrides(tbl) 50local function platform_overrides(tbl)
42 assert(type(tbl) == "table" or not tbl)
43 51
44 if not tbl then return end 52 if not tbl then return end
45 53
46 if tbl.platforms then 54 local tblp = tbl.platforms
55
56 if type(tblp) == "table" then
47 for platform in cfg.each_platform() do 57 for platform in cfg.each_platform() do
48 local platform_tbl = tbl.platforms[platform] 58 local platform_tbl = tblp[platform]
49 if platform_tbl then 59 if type(platform_tbl) == "table" then
50 util.deep_merge(tbl, platform_tbl) 60 util.deep_merge(tbl, platform_tbl)
51 end 61 end
52 end 62 end
@@ -54,28 +64,28 @@ local function platform_overrides(tbl)
54 tbl.platforms = nil 64 tbl.platforms = nil
55end 65end
56 66
57local function convert_dependencies(rockspec, key) 67local function convert_dependencies(dependencies)
58 if rockspec[key] then 68 if not dependencies then
59 for i = 1, #rockspec[key] do 69 return {}
60 local parsed, err = queries.from_dep_string(rockspec[key][i]) 70 end
61 if not parsed then 71 local qs = {}
62 return nil, "Parse error processing dependency '"..rockspec[key][i].."': "..tostring(err) 72 for i = 1, #dependencies do
63 end 73 local parsed, err = queries.from_dep_string(dependencies[i])
64 rockspec[key][i] = parsed 74 if not parsed then
75 return nil, "Parse error processing dependency '" .. dependencies[i] .. "': " .. tostring(err)
65 end 76 end
66 else 77 qs[i] = parsed
67 rockspec[key] = {}
68 end 78 end
69 return true 79 return qs
70end 80end
71 81
72--- Set up path-related variables for a given rock. 82
73-- Create a "variables" table in the rockspec table, containing 83
74-- adjusted variables according to the configuration file. 84
75-- @param rockspec table: The rockspec table. 85
76local function configure_paths(rockspec) 86local function configure_paths(rockspec)
77 local vars = {} 87 local vars = {}
78 for k,v in pairs(cfg.variables) do 88 for k, v in pairs(cfg.variables) do
79 vars[k] = v 89 vars[k] = v
80 end 90 end
81 local name, version = rockspec.name, rockspec.version 91 local name, version = rockspec.name, rockspec.version
@@ -89,14 +99,10 @@ local function configure_paths(rockspec)
89end 99end
90 100
91function rockspecs.from_persisted_table(filename, rockspec, globals, quick) 101function rockspecs.from_persisted_table(filename, rockspec, globals, quick)
92 assert(type(rockspec) == "table")
93 assert(type(globals) == "table" or globals == nil)
94 assert(type(filename) == "string")
95 assert(type(quick) == "boolean" or quick == nil)
96 102
97 if rockspec.rockspec_format then 103 if rockspec.rockspec_format then
98 if vers.compare_versions(rockspec.rockspec_format, type_rockspec.rockspec_format) then 104 if vers.compare_versions(rockspec.rockspec_format, type_rockspec.rockspec_format) then
99 return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks." 105 return nil, "Rockspec format " .. rockspec.rockspec_format .. " is not supported, please upgrade LuaRocks."
100 end 106 end
101 end 107 end
102 108
@@ -107,10 +113,10 @@ function rockspecs.from_persisted_table(filename, rockspec, globals, quick)
107 end 113 end
108 end 114 end
109 115
110 --- Check if rockspec format version satisfies version requirement. 116
111 -- @param rockspec table: The rockspec table. 117
112 -- @param version string: required version. 118
113 -- @return boolean: true if rockspec format matches version or is newer, false otherwise. 119
114 do 120 do
115 local parsed_format = vers.parse_version(rockspec.rockspec_format or "1.0") 121 local parsed_format = vers.parse_version(rockspec.rockspec_format or "1.0")
116 rockspec.format_is_at_least = function(self, version) 122 rockspec.format_is_at_least = function(self, version)
@@ -135,7 +141,7 @@ function rockspecs.from_persisted_table(filename, rockspec, globals, quick)
135 end 141 end
136 rockspec.source.protocol, rockspec.source.pathname = protocol, pathname 142 rockspec.source.protocol, rockspec.source.pathname = protocol, pathname
137 143
138 -- Temporary compatibility 144
139 if rockspec.source.cvs_module then rockspec.source.module = rockspec.source.cvs_module end 145 if rockspec.source.cvs_module then rockspec.source.module = rockspec.source.cvs_module end
140 if rockspec.source.cvs_tag then rockspec.source.tag = rockspec.source.cvs_tag end 146 if rockspec.source.cvs_tag then rockspec.source.tag = rockspec.source.cvs_tag end
141 147
@@ -145,23 +151,32 @@ function rockspecs.from_persisted_table(filename, rockspec, globals, quick)
145 151
146 rockspec.rocks_provided = util.get_rocks_provided(rockspec) 152 rockspec.rocks_provided = util.get_rocks_provided(rockspec)
147 153
148 for _, key in ipairs({"dependencies", "build_dependencies", "test_dependencies"}) do 154 local err
149 local ok, err = convert_dependencies(rockspec, key) 155 rockspec.dependencies.queries, err = convert_dependencies(rockspec.dependencies)
150 if not ok then 156 if err then
151 return nil, err 157 return nil, err
152 end
153 end 158 end
154 159
155 if rockspec.build 160 rockspec.build_dependencies.queries, err = convert_dependencies(rockspec.build_dependencies)
156 and rockspec.build.type 161 if err then
157 and not vendored_build_type_set[rockspec.build.type] then 162 return nil, err
163 end
164
165 rockspec.test_dependencies.queries, err = convert_dependencies(rockspec.test_dependencies)
166 if err then
167 return nil, err
168 end
169
170 if rockspec.build and
171 rockspec.build.type and
172 not vendored_build_type_set[rockspec.build.type] then
158 local build_pkg_name = "luarocks-build-" .. rockspec.build.type 173 local build_pkg_name = "luarocks-build-" .. rockspec.build.type
159 if not rockspec.build_dependencies then 174 if not rockspec.build_dependencies then
160 rockspec.build_dependencies = {} 175 rockspec.build_dependencies = {}
161 end 176 end
162 177
163 local found = false 178 local found = false
164 for _, dep in ipairs(rockspec.build_dependencies) do 179 for _, dep in ipairs(rockspec.build_dependencies.queries) do
165 if dep.name == build_pkg_name then 180 if dep.name == build_pkg_name then
166 found = true 181 found = true
167 break 182 break
@@ -169,7 +184,11 @@ function rockspecs.from_persisted_table(filename, rockspec, globals, quick)
169 end 184 end
170 185
171 if not found then 186 if not found then
172 table.insert(rockspec.build_dependencies, queries.from_dep_string(build_pkg_name)) 187 local query, errfromdep = queries.from_dep_string(build_pkg_name)
188 if errfromdep then
189 return nil, "Invalid dependency in rockspec: " .. err
190 end
191 table.insert(rockspec.build_dependencies.queries, query)
173 end 192 end
174 end 193 end
175 194
diff --git a/src/luarocks/rockspecs.tl b/src/luarocks/rockspecs.tl
index b65227da..c391f1e7 100644
--- a/src/luarocks/rockspecs.tl
+++ b/src/luarocks/rockspecs.tl
@@ -10,9 +10,9 @@ local type_rockspec = require("luarocks.type.rockspec")
10local util = require("luarocks.util") 10local util = require("luarocks.util")
11local vers = require("luarocks.core.vers") 11local vers = require("luarocks.core.vers")
12 12
13local type r = require("luarocks.core.types.rockspec") 13local rockspec = require("luarocks.core.types.rockspec")
14local type Rockspec = r.Rockspec 14local type Rockspec = rockspec.Rockspec
15local type Variables = r.Variables 15local type Variables = rockspec.Variables
16 16
17local type q = require("luarocks.core.types.query") 17local type q = require("luarocks.core.types.query")
18local type Query = q.Query 18local type Query = q.Query
@@ -28,9 +28,9 @@ local vendored_build_type_set: {string: boolean} = {
28 28
29local rockspec_mt: metatable<Rockspec> = {} 29local rockspec_mt: metatable<Rockspec> = {}
30 30
31rockspec_mt.__index = r.Rockspec 31rockspec_mt.__index = rockspec.Rockspec
32 32
33function r.Rockspec.type(): string 33function rockspec.Rockspec.type(): string
34 return "rockspec" 34 return "rockspec"
35end 35end
36 36