aboutsummaryrefslogtreecommitdiff
path: root/src/luarocks/deps.lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/luarocks/deps.lua')
-rw-r--r--src/luarocks/deps.lua215
1 files changed, 16 insertions, 199 deletions
diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua
index 0d85d33e..acbf1dd6 100644
--- a/src/luarocks/deps.lua
+++ b/src/luarocks/deps.lua
@@ -12,14 +12,23 @@
12-- test/test_deps.lua file included with LuaRocks provides some 12-- test/test_deps.lua file included with LuaRocks provides some
13-- insights on what these criteria are. 13-- insights on what these criteria are.
14local deps = {} 14local deps = {}
15package.loaded["luarocks.deps"] = deps 15setmetatable(deps, { __index = require("luarocks.core.deps") })
16 16
17local cfg = require("luarocks.cfg") 17local cfg = require("luarocks.core.cfg")
18local manif_core = require("luarocks.manif_core") 18local manif = require("luarocks.core.manif")
19local path = require("luarocks.path") 19local path = require("luarocks.path")
20local dir = require("luarocks.dir") 20local dir = require("luarocks.dir")
21local util = require("luarocks.util") 21local util = require("luarocks.util")
22 22
23--- Check if rockspec format version satisfies version requirement.
24-- @param rockspec table: The rockspec table.
25-- @param version string: required version.
26-- @return boolean: true if rockspec format matches version or is newer, false otherwise.
27function deps.format_is_at_least(rockspec, version)
28 local rockspec_format = rockspec.rockspec_format or "1.0"
29 return deps.parse_version(rockspec_format) >= deps.parse_version(version)
30end
31
23local operators = { 32local operators = {
24 ["=="] = "==", 33 ["=="] = "==",
25 ["~="] = "~=", 34 ["~="] = "~=",
@@ -34,139 +43,6 @@ local operators = {
34 ["!="] = "~=" 43 ["!="] = "~="
35} 44}
36 45
37local deltas = {
38 scm = 1100,
39 cvs = 1000,
40 rc = -1000,
41 pre = -10000,
42 beta = -100000,
43 alpha = -1000000
44}
45
46local version_mt = {
47 --- Equality comparison for versions.
48 -- All version numbers must be equal.
49 -- If both versions have revision numbers, they must be equal;
50 -- otherwise the revision number is ignored.
51 -- @param v1 table: version table to compare.
52 -- @param v2 table: version table to compare.
53 -- @return boolean: true if they are considered equivalent.
54 __eq = function(v1, v2)
55 if #v1 ~= #v2 then
56 return false
57 end
58 for i = 1, #v1 do
59 if v1[i] ~= v2[i] then
60 return false
61 end
62 end
63 if v1.revision and v2.revision then
64 return (v1.revision == v2.revision)
65 end
66 return true
67 end,
68 --- Size comparison for versions.
69 -- All version numbers are compared.
70 -- If both versions have revision numbers, they are compared;
71 -- otherwise the revision number is ignored.
72 -- @param v1 table: version table to compare.
73 -- @param v2 table: version table to compare.
74 -- @return boolean: true if v1 is considered lower than v2.
75 __lt = function(v1, v2)
76 for i = 1, math.max(#v1, #v2) do
77 local v1i, v2i = v1[i] or 0, v2[i] or 0
78 if v1i ~= v2i then
79 return (v1i < v2i)
80 end
81 end
82 if v1.revision and v2.revision then
83 return (v1.revision < v2.revision)
84 end
85 return false
86 end
87}
88
89local version_cache = {}
90setmetatable(version_cache, {
91 __mode = "kv"
92})
93
94--- Parse a version string, converting to table format.
95-- A version table contains all components of the version string
96-- converted to numeric format, stored in the array part of the table.
97-- If the version contains a revision, it is stored numerically
98-- in the 'revision' field. The original string representation of
99-- the string is preserved in the 'string' field.
100-- Returned version tables use a metatable
101-- allowing later comparison through relational operators.
102-- @param vstring string: A version number in string format.
103-- @return table or nil: A version table or nil
104-- if the input string contains invalid characters.
105function deps.parse_version(vstring)
106 if not vstring then return nil end
107 assert(type(vstring) == "string")
108
109 local cached = version_cache[vstring]
110 if cached then
111 return cached
112 end
113
114 local version = {}
115 local i = 1
116
117 local function add_token(number)
118 version[i] = version[i] and version[i] + number/100000 or number
119 i = i + 1
120 end
121
122 -- trim leading and trailing spaces
123 vstring = vstring:match("^%s*(.*)%s*$")
124 version.string = vstring
125 -- store revision separately if any
126 local main, revision = vstring:match("(.*)%-(%d+)$")
127 if revision then
128 vstring = main
129 version.revision = tonumber(revision)
130 end
131 while #vstring > 0 do
132 -- extract a number
133 local token, rest = vstring:match("^(%d+)[%.%-%_]*(.*)")
134 if token then
135 add_token(tonumber(token))
136 else
137 -- extract a word
138 token, rest = vstring:match("^(%a+)[%.%-%_]*(.*)")
139 if not token then
140 util.printerr("Warning: version number '"..vstring.."' could not be parsed.")
141 version[i] = 0
142 break
143 end
144 version[i] = deltas[token] or (token:byte() / 1000)
145 end
146 vstring = rest
147 end
148 setmetatable(version, version_mt)
149 version_cache[vstring] = version
150 return version
151end
152
153--- Utility function to compare version numbers given as strings.
154-- @param a string: one version.
155-- @param b string: another version.
156-- @return boolean: True if a > b.
157function deps.compare_versions(a, b)
158 return deps.parse_version(a) > deps.parse_version(b)
159end
160
161--- Check if rockspec format version satisfies version requirement.
162-- @param rockspec table: The rockspec table.
163-- @param version string: required version.
164-- @return boolean: true if rockspec format matches version or is newer, false otherwise.
165function deps.format_is_at_least(rockspec, version)
166 local rockspec_format = rockspec.rockspec_format or "1.0"
167 return deps.parse_version(rockspec_format) >= deps.parse_version(version)
168end
169
170--- Consumes a constraint from a string, converting it to table format. 46--- Consumes a constraint from a string, converting it to table format.
171-- For example, a string ">= 1.0, > 2.0" is converted to a table in the 47-- For example, a string ">= 1.0, > 2.0" is converted to a table in the
172-- format {op = ">=", version={1,0}} and the rest, "> 2.0", is returned 48-- format {op = ">=", version={1,0}} and the rest, "> 2.0", is returned
@@ -201,7 +77,7 @@ end
201function deps.parse_constraints(input) 77function deps.parse_constraints(input)
202 assert(type(input) == "string") 78 assert(type(input) == "string")
203 79
204 local constraints, constraint, oinput = {}, nil, input 80 local constraints, oinput, constraint = {}, input
205 while #input > 0 do 81 while #input > 0 do
206 constraint, input = parse_constraint(input) 82 constraint, input = parse_constraint(input)
207 if constraint then 83 if constraint then
@@ -267,65 +143,6 @@ function deps.show_dep(dep, internal)
267 end 143 end
268end 144end
269 145
270--- A more lenient check for equivalence between versions.
271-- This returns true if the requested components of a version
272-- match and ignore the ones that were not given. For example,
273-- when requesting "2", then "2", "2.1", "2.3.5-9"... all match.
274-- When requesting "2.1", then "2.1", "2.1.3" match, but "2.2"
275-- doesn't.
276-- @param version string or table: Version to be tested; may be
277-- in string format or already parsed into a table.
278-- @param requested string or table: Version requested; may be
279-- in string format or already parsed into a table.
280-- @return boolean: True if the tested version matches the requested
281-- version, false otherwise.
282local function partial_match(version, requested)
283 assert(type(version) == "string" or type(version) == "table")
284 assert(type(requested) == "string" or type(version) == "table")
285
286 if type(version) ~= "table" then version = deps.parse_version(version) end
287 if type(requested) ~= "table" then requested = deps.parse_version(requested) end
288 if not version or not requested then return false end
289
290 for i, ri in ipairs(requested) do
291 local vi = version[i] or 0
292 if ri ~= vi then return false end
293 end
294 if requested.revision then
295 return requested.revision == version.revision
296 end
297 return true
298end
299
300--- Check if a version satisfies a set of constraints.
301-- @param version table: A version in table format
302-- @param constraints table: An array of constraints in table format.
303-- @return boolean: True if version satisfies all constraints,
304-- false otherwise.
305function deps.match_constraints(version, constraints)
306 assert(type(version) == "table")
307 assert(type(constraints) == "table")
308 local ok = true
309 setmetatable(version, version_mt)
310 for _, constr in pairs(constraints) do
311 if type(constr.version) == "string" then
312 constr.version = deps.parse_version(constr.version)
313 end
314 local constr_version, constr_op = constr.version, constr.op
315 setmetatable(constr_version, version_mt)
316 if constr_op == "==" then ok = version == constr_version
317 elseif constr_op == "~=" then ok = version ~= constr_version
318 elseif constr_op == ">" then ok = version > constr_version
319 elseif constr_op == "<" then ok = version < constr_version
320 elseif constr_op == ">=" then ok = version >= constr_version
321 elseif constr_op == "<=" then ok = version <= constr_version
322 elseif constr_op == "~>" then ok = partial_match(version, constr_version)
323 end
324 if not ok then break end
325 end
326 return ok
327end
328
329--- Attempt to match a dependency to an installed rock. 146--- Attempt to match a dependency to an installed rock.
330-- @param dep table: A dependency parsed in table format. 147-- @param dep table: A dependency parsed in table format.
331-- @param blacklist table: Versions that can't be accepted. Table where keys 148-- @param blacklist table: Versions that can't be accepted. Table where keys
@@ -344,7 +161,7 @@ local function match_dep(dep, blacklist, deps_mode, rocks_provided)
344 -- Provided rocks have higher priority than manifest's rocks. 161 -- Provided rocks have higher priority than manifest's rocks.
345 versions = { provided } 162 versions = { provided }
346 else 163 else
347 versions = manif_core.get_versions(dep.name, deps_mode) 164 versions = manif.get_versions(dep.name, deps_mode)
348 end 165 end
349 166
350 local latest_version 167 local latest_version
@@ -431,7 +248,8 @@ function deps.fulfill_dependencies(rockspec, deps_mode)
431 end 248 end
432 local supported = nil 249 local supported = nil
433 for _, plat in pairs(rockspec.supported_platforms) do 250 for _, plat in pairs(rockspec.supported_platforms) do
434 local neg, plat = plat:match("^(!?)(.*)") 251 local neg
252 neg, plat = plat:match("^(!?)(.*)")
435 if neg == "!" then 253 if neg == "!" then
436 if deps.platforms_set[plat] then 254 if deps.platforms_set[plat] then
437 return nil, "This rockspec for "..rockspec.package.." does not support "..plat.." platforms." 255 return nil, "This rockspec for "..rockspec.package.." does not support "..plat.." platforms."
@@ -704,7 +522,6 @@ function deps.scan_deps(results, missing, manifest, name, version, deps_mode)
704 522
705 local fetch = require("luarocks.fetch") 523 local fetch = require("luarocks.fetch")
706 524
707 local err
708 if results[name] then 525 if results[name] then
709 return results, missing 526 return results, missing
710 end 527 end