diff options
Diffstat (limited to 'src/luarocks/deps.lua')
-rw-r--r-- | src/luarocks/deps.lua | 150 |
1 files changed, 8 insertions, 142 deletions
diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua index 1c75a694..6548e56e 100644 --- a/src/luarocks/deps.lua +++ b/src/luarocks/deps.lua | |||
@@ -1,147 +1,13 @@ | |||
1 | 1 | ||
2 | --- Dependency handling functions. | 2 | --- High-level dependency related functions. |
3 | -- Dependencies are represented in LuaRocks through strings with | ||
4 | -- a package name followed by a comma-separated list of constraints. | ||
5 | -- Each constraint consists of an operator and a version number. | ||
6 | -- In this string format, version numbers are represented as | ||
7 | -- naturally as possible, like they are used by upstream projects | ||
8 | -- (e.g. "2.0beta3"). Internally, LuaRocks converts them to a purely | ||
9 | -- numeric representation, allowing comparison following some | ||
10 | -- "common sense" heuristics. The precise specification of the | ||
11 | -- comparison criteria is the source code of this module, but the | ||
12 | -- test/test_deps.lua file included with LuaRocks provides some | ||
13 | -- insights on what these criteria are. | ||
14 | local deps = {} | 3 | local deps = {} |
15 | setmetatable(deps, { __index = require("luarocks.core.deps") }) | ||
16 | 4 | ||
17 | local cfg = require("luarocks.core.cfg") | 5 | local cfg = require("luarocks.core.cfg") |
18 | local manif = require("luarocks.core.manif") | 6 | local manif = require("luarocks.core.manif") |
19 | local path = require("luarocks.path") | 7 | local path = require("luarocks.path") |
20 | local dir = require("luarocks.dir") | 8 | local dir = require("luarocks.dir") |
21 | local util = require("luarocks.util") | 9 | local util = require("luarocks.util") |
22 | 10 | local vers = require("luarocks.vers") | |
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 | |||
32 | local operators = { | ||
33 | ["=="] = "==", | ||
34 | ["~="] = "~=", | ||
35 | [">"] = ">", | ||
36 | ["<"] = "<", | ||
37 | [">="] = ">=", | ||
38 | ["<="] = "<=", | ||
39 | ["~>"] = "~>", | ||
40 | -- plus some convenience translations | ||
41 | [""] = "==", | ||
42 | ["="] = "==", | ||
43 | ["!="] = "~=" | ||
44 | } | ||
45 | |||
46 | --- Consumes a constraint from a string, converting it to table format. | ||
47 | -- For example, a string ">= 1.0, > 2.0" is converted to a table in the | ||
48 | -- format {op = ">=", version={1,0}} and the rest, "> 2.0", is returned | ||
49 | -- back to the caller. | ||
50 | -- @param input string: A list of constraints in string format. | ||
51 | -- @return (table, string) or nil: A table representing the same | ||
52 | -- constraints and the string with the unused input, or nil if the | ||
53 | -- input string is invalid. | ||
54 | local function parse_constraint(input) | ||
55 | assert(type(input) == "string") | ||
56 | |||
57 | local no_upgrade, op, version, rest = input:match("^(@?)([<>=~!]*)%s*([%w%.%_%-]+)[%s,]*(.*)") | ||
58 | local _op = operators[op] | ||
59 | version = deps.parse_version(version) | ||
60 | if not _op then | ||
61 | return nil, "Encountered bad constraint operator: '"..tostring(op).."' in '"..input.."'" | ||
62 | end | ||
63 | if not version then | ||
64 | return nil, "Could not parse version from constraint: '"..input.."'" | ||
65 | end | ||
66 | return { op = _op, version = version, no_upgrade = no_upgrade=="@" and true or nil }, rest | ||
67 | end | ||
68 | |||
69 | --- Convert a list of constraints from string to table format. | ||
70 | -- For example, a string ">= 1.0, < 2.0" is converted to a table in the format | ||
71 | -- {{op = ">=", version={1,0}}, {op = "<", version={2,0}}}. | ||
72 | -- Version tables use a metatable allowing later comparison through | ||
73 | -- relational operators. | ||
74 | -- @param input string: A list of constraints in string format. | ||
75 | -- @return table or nil: A table representing the same constraints, | ||
76 | -- or nil if the input string is invalid. | ||
77 | function deps.parse_constraints(input) | ||
78 | assert(type(input) == "string") | ||
79 | |||
80 | local constraints, oinput, constraint = {}, input | ||
81 | while #input > 0 do | ||
82 | constraint, input = parse_constraint(input) | ||
83 | if constraint then | ||
84 | table.insert(constraints, constraint) | ||
85 | else | ||
86 | return nil, "Failed to parse constraint '"..tostring(oinput).."' with error: ".. input | ||
87 | end | ||
88 | end | ||
89 | return constraints | ||
90 | end | ||
91 | |||
92 | --- Convert a dependency from string to table format. | ||
93 | -- For example, a string "foo >= 1.0, < 2.0" | ||
94 | -- is converted to a table in the format | ||
95 | -- {name = "foo", constraints = {{op = ">=", version={1,0}}, | ||
96 | -- {op = "<", version={2,0}}}}. Version tables use a metatable | ||
97 | -- allowing later comparison through relational operators. | ||
98 | -- @param dep string: A dependency in string format | ||
99 | -- as entered in rockspec files. | ||
100 | -- @return table or nil: A table representing the same dependency relation, | ||
101 | -- or nil if the input string is invalid. | ||
102 | function deps.parse_dep(dep) | ||
103 | assert(type(dep) == "string") | ||
104 | |||
105 | local name, rest = dep:match("^%s*([a-zA-Z0-9][a-zA-Z0-9%.%-%_]*)%s*(.*)") | ||
106 | if not name then return nil, "failed to extract dependency name from '"..tostring(dep).."'" end | ||
107 | local constraints, err = deps.parse_constraints(rest) | ||
108 | if not constraints then return nil, err end | ||
109 | return { name = name, constraints = constraints } | ||
110 | end | ||
111 | |||
112 | --- Convert a version table to a string. | ||
113 | -- @param v table: The version table | ||
114 | -- @param internal boolean or nil: Whether to display versions in their | ||
115 | -- internal representation format or how they were specified. | ||
116 | -- @return string: The dependency information pretty-printed as a string. | ||
117 | function deps.show_version(v, internal) | ||
118 | assert(type(v) == "table") | ||
119 | assert(type(internal) == "boolean" or not internal) | ||
120 | |||
121 | return (internal | ||
122 | and table.concat(v, ":")..(v.revision and tostring(v.revision) or "") | ||
123 | or v.string) | ||
124 | end | ||
125 | |||
126 | --- Convert a dependency in table format to a string. | ||
127 | -- @param dep table: The dependency in table format | ||
128 | -- @param internal boolean or nil: Whether to display versions in their | ||
129 | -- internal representation format or how they were specified. | ||
130 | -- @return string: The dependency information pretty-printed as a string. | ||
131 | function deps.show_dep(dep, internal) | ||
132 | assert(type(dep) == "table") | ||
133 | assert(type(internal) == "boolean" or not internal) | ||
134 | |||
135 | if #dep.constraints > 0 then | ||
136 | local pretty = {} | ||
137 | for _, c in ipairs(dep.constraints) do | ||
138 | table.insert(pretty, c.op .. " " .. deps.show_version(c.version, internal)) | ||
139 | end | ||
140 | return dep.name.." "..table.concat(pretty, ", ") | ||
141 | else | ||
142 | return dep.name | ||
143 | end | ||
144 | end | ||
145 | 11 | ||
146 | --- Attempt to match a dependency to an installed rock. | 12 | --- Attempt to match a dependency to an installed rock. |
147 | -- @param dep table: A dependency parsed in table format. | 13 | -- @param dep table: A dependency parsed in table format. |
@@ -167,8 +33,8 @@ local function match_dep(dep, blacklist, deps_mode, rocks_provided) | |||
167 | local latest_version | 33 | local latest_version |
168 | for _, vstring in ipairs(versions) do | 34 | for _, vstring in ipairs(versions) do |
169 | if not blacklist or not blacklist[vstring] then | 35 | if not blacklist or not blacklist[vstring] then |
170 | local version = deps.parse_version(vstring) | 36 | local version = vers.parse_version(vstring) |
171 | if deps.match_constraints(version, dep.constraints) then | 37 | if vers.match_constraints(version, dep.constraints) then |
172 | if not latest_version or version > latest_version then | 38 | if not latest_version or version > latest_version then |
173 | latest_version = version | 39 | latest_version = version |
174 | end | 40 | end |
@@ -249,7 +115,7 @@ function deps.report_missing_dependencies(name, version, dependencies, deps_mode | |||
249 | first_missing_dep = false | 115 | first_missing_dep = false |
250 | end | 116 | end |
251 | 117 | ||
252 | util.printout((" %s (%s)"):format(deps.show_dep(dep), rock_status(dep.name, deps_mode, rocks_provided))) | 118 | util.printout((" %s (%s)"):format(vers.show_dep(dep), rock_status(dep.name, deps_mode, rocks_provided))) |
253 | end | 119 | end |
254 | end | 120 | end |
255 | end | 121 | end |
@@ -306,11 +172,11 @@ function deps.fulfill_dependencies(rockspec, deps_mode) | |||
306 | end | 172 | end |
307 | 173 | ||
308 | util.printout(("%s %s depends on %s (%s)"):format( | 174 | util.printout(("%s %s depends on %s (%s)"):format( |
309 | rockspec.name, rockspec.version, deps.show_dep(dep), rock_status(dep.name, deps_mode, rockspec.rocks_provided))) | 175 | rockspec.name, rockspec.version, vers.show_dep(dep), rock_status(dep.name, deps_mode, rockspec.rocks_provided))) |
310 | 176 | ||
311 | if dep.constraints[1] and dep.constraints[1].no_upgrade then | 177 | if dep.constraints[1] and dep.constraints[1].no_upgrade then |
312 | util.printerr("This version of "..rockspec.name.." is designed for use with") | 178 | util.printerr("This version of "..rockspec.name.." is designed for use with") |
313 | util.printerr(deps.show_dep(dep)..", but is configured to avoid upgrading it") | 179 | util.printerr(vers.show_dep(dep)..", but is configured to avoid upgrading it") |
314 | util.printerr("automatically. Please upgrade "..dep.name.." with") | 180 | util.printerr("automatically. Please upgrade "..dep.name.." with") |
315 | util.printerr(" luarocks install "..dep.name) | 181 | util.printerr(" luarocks install "..dep.name) |
316 | util.printerr("or choose an older version of "..rockspec.name.." with") | 182 | util.printerr("or choose an older version of "..rockspec.name.." with") |
@@ -320,7 +186,7 @@ function deps.fulfill_dependencies(rockspec, deps_mode) | |||
320 | 186 | ||
321 | local url, search_err = search.find_suitable_rock(dep) | 187 | local url, search_err = search.find_suitable_rock(dep) |
322 | if not url then | 188 | if not url then |
323 | return nil, "Could not satisfy dependency "..deps.show_dep(dep)..": "..search_err | 189 | return nil, "Could not satisfy dependency "..vers.show_dep(dep)..": "..search_err |
324 | end | 190 | end |
325 | util.printout("Installing "..url) | 191 | util.printout("Installing "..url) |
326 | local ok, install_err, errcode = install.command({deps_mode = deps_mode}, url) | 192 | local ok, install_err, errcode = install.command({deps_mode = deps_mode}, url) |