diff options
Diffstat (limited to 'src/luarocks/deps.lua')
-rw-r--r-- | src/luarocks/deps.lua | 215 |
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. |
14 | local deps = {} | 14 | local deps = {} |
15 | package.loaded["luarocks.deps"] = deps | 15 | setmetatable(deps, { __index = require("luarocks.core.deps") }) |
16 | 16 | ||
17 | local cfg = require("luarocks.cfg") | 17 | local cfg = require("luarocks.core.cfg") |
18 | local manif_core = require("luarocks.manif_core") | 18 | local manif = require("luarocks.core.manif") |
19 | local path = require("luarocks.path") | 19 | local path = require("luarocks.path") |
20 | local dir = require("luarocks.dir") | 20 | local dir = require("luarocks.dir") |
21 | local util = require("luarocks.util") | 21 | local 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. | ||
27 | function 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) | ||
30 | end | ||
31 | |||
23 | local operators = { | 32 | local operators = { |
24 | ["=="] = "==", | 33 | ["=="] = "==", |
25 | ["~="] = "~=", | 34 | ["~="] = "~=", |
@@ -34,139 +43,6 @@ local operators = { | |||
34 | ["!="] = "~=" | 43 | ["!="] = "~=" |
35 | } | 44 | } |
36 | 45 | ||
37 | local deltas = { | ||
38 | scm = 1100, | ||
39 | cvs = 1000, | ||
40 | rc = -1000, | ||
41 | pre = -10000, | ||
42 | beta = -100000, | ||
43 | alpha = -1000000 | ||
44 | } | ||
45 | |||
46 | local 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 | |||
89 | local version_cache = {} | ||
90 | setmetatable(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. | ||
105 | function 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 | ||
151 | end | ||
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. | ||
157 | function deps.compare_versions(a, b) | ||
158 | return deps.parse_version(a) > deps.parse_version(b) | ||
159 | end | ||
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. | ||
165 | function 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) | ||
168 | end | ||
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 | |||
201 | function deps.parse_constraints(input) | 77 | function 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 |
268 | end | 144 | end |
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. | ||
282 | local 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 | ||
298 | end | ||
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. | ||
305 | function 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 | ||
327 | end | ||
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 |