diff options
author | V1K1NGbg <victor@ilchev.com> | 2024-07-30 19:24:01 +0300 |
---|---|---|
committer | V1K1NGbg <victor@ilchev.com> | 2024-08-05 20:51:31 +0300 |
commit | a94eeb7279af61565d55cf446a286b0b9f2c1fe3 (patch) | |
tree | 59dbe15bbc6602763dc8fdb75fd492e4c508776c | |
parent | a50299e1d6b280f5ca635b2c7ac9fe889befd6d6 (diff) | |
download | luarocks-a94eeb7279af61565d55cf446a286b0b9f2c1fe3.tar.gz luarocks-a94eeb7279af61565d55cf446a286b0b9f2c1fe3.tar.bz2 luarocks-a94eeb7279af61565d55cf446a286b0b9f2c1fe3.zip |
results, queries in progress
-rw-r--r-- | src/luarocks/core/cfg.d.tl | 4 | ||||
-rw-r--r-- | src/luarocks/queries.tl | 234 | ||||
-rw-r--r-- | src/luarocks/results.tl | 30 |
3 files changed, 256 insertions, 12 deletions
diff --git a/src/luarocks/core/cfg.d.tl b/src/luarocks/core/cfg.d.tl index fccfe0e3..eff86971 100644 --- a/src/luarocks/core/cfg.d.tl +++ b/src/luarocks/core/cfg.d.tl | |||
@@ -54,7 +54,7 @@ local record cfg | |||
54 | record cache | 54 | record cache |
55 | luajit_version_checked: boolean | 55 | luajit_version_checked: boolean |
56 | luajit_version: string | 56 | luajit_version: string |
57 | rocks_provided: {string: string} --? right type? infered from util | 57 | rocks_provided: {string: string} --? right type? infered from src/luarocks/util |
58 | end | 58 | end |
59 | 59 | ||
60 | record variables | 60 | record variables |
@@ -64,6 +64,8 @@ local record cfg | |||
64 | rocks_provided: {Rockspec} | 64 | rocks_provided: {Rockspec} |
65 | -- persist | 65 | -- persist |
66 | home: string | 66 | home: string |
67 | -- queries | ||
68 | arch: string | ||
67 | end | 69 | end |
68 | 70 | ||
69 | return cfg \ No newline at end of file | 71 | return cfg \ No newline at end of file |
diff --git a/src/luarocks/queries.tl b/src/luarocks/queries.tl new file mode 100644 index 00000000..b5996dbe --- /dev/null +++ b/src/luarocks/queries.tl | |||
@@ -0,0 +1,234 @@ | |||
1 | |||
2 | local record queries | ||
3 | record Constraint | ||
4 | version: vers.Version | ||
5 | op: string | ||
6 | no_upgrade: boolean | ||
7 | end | ||
8 | |||
9 | record Query | ||
10 | name: string | ||
11 | namespace: string | ||
12 | constraints: {Constraint} | ||
13 | substring: boolean | ||
14 | arch: {string: boolean} | ||
15 | end | ||
16 | end | ||
17 | |||
18 | local vers = require("luarocks.core.vers") | ||
19 | local util = require("luarocks.util") | ||
20 | local cfg = require("luarocks.core.cfg") | ||
21 | |||
22 | -- local type Config = cfg | ||
23 | |||
24 | local type Query = queries.Query | ||
25 | local type Constraint = queries.Constraint | ||
26 | |||
27 | local query_mt: metatable<Query> = {} | ||
28 | |||
29 | query_mt.__index = query_mt | ||
30 | |||
31 | function query_mt.type() | ||
32 | return "query" | ||
33 | end | ||
34 | |||
35 | -- Fallback default value for the `arch` field, if not explicitly set. | ||
36 | query_mt.arch = { | ||
37 | src = true, | ||
38 | all = true, | ||
39 | rockspec = true, | ||
40 | installed = true, | ||
41 | -- [cfg.arch] = true, -- this is set later | ||
42 | } | ||
43 | |||
44 | -- Fallback default value for the `substring` field, if not explicitly set. | ||
45 | query_mt.substring = false | ||
46 | |||
47 | --- Convert the arch field of a query table to table format. | ||
48 | -- @param input string, table or nil | ||
49 | local function arch_to_table(input: string | {string: boolean}): {string: boolean} | ||
50 | if input is {string: boolean} then | ||
51 | return input | ||
52 | elseif input is string then | ||
53 | local arch = {} | ||
54 | for a in input:gmatch("[%w_-]+") do | ||
55 | arch[a] = true | ||
56 | end | ||
57 | return arch | ||
58 | end | ||
59 | end | ||
60 | |||
61 | --- Prepare a query in dependency table format. | ||
62 | -- @param name string: the package name. | ||
63 | -- @param namespace string?: the package namespace. | ||
64 | -- @param version string?: the package version. | ||
65 | -- @param substring boolean?: match substrings of the name | ||
66 | -- (default is false, match full name) | ||
67 | -- @param arch string?: a string with pipe-separated accepted arch values | ||
68 | -- @param operator string?: operator for version matching (default is "==") | ||
69 | -- @return table: A query in table format | ||
70 | function queries.new(name: string, namespace?: string, version?: string, substring?: boolean, arch?: string, operator?: string): Query | ||
71 | -- assert(type(namespace) == "string" or not namespace) --! optional parameters? | ||
72 | -- assert(type(version) == "string" or not version) | ||
73 | -- assert(type(substring) == "boolean" or not substring) | ||
74 | -- assert(type(arch) == "string" or not arch) | ||
75 | -- assert(type(operator) == "string" or not operator) | ||
76 | |||
77 | operator = operator or "==" | ||
78 | |||
79 | local self: Query = { | ||
80 | name = name, | ||
81 | namespace = namespace, | ||
82 | constraints = {}, | ||
83 | substring = substring, | ||
84 | arch = arch_to_table(arch), | ||
85 | } | ||
86 | if version then | ||
87 | table.insert(self.constraints, { op = operator, version = vers.parse_version(version)}) | ||
88 | end | ||
89 | |||
90 | query_mt.arch[cfg.arch] = true | ||
91 | return setmetatable(self, query_mt) | ||
92 | end | ||
93 | |||
94 | -- Query for all packages | ||
95 | -- @param arch string (optional) | ||
96 | function queries.all(arch?: string): Query | ||
97 | -- assert(type(arch) == "string" or not arch) --! optional | ||
98 | |||
99 | return queries.new("", nil, nil, true, arch) | ||
100 | end | ||
101 | |||
102 | do | ||
103 | local parse_constraints: function(string): {Constraint}, string | ||
104 | do | ||
105 | local parse_constraint: function(string): Constraint, string | ||
106 | do | ||
107 | local operators: {string: string} = { | ||
108 | ["=="] = "==", | ||
109 | ["~="] = "~=", | ||
110 | [">"] = ">", | ||
111 | ["<"] = "<", | ||
112 | [">="] = ">=", | ||
113 | ["<="] = "<=", | ||
114 | ["~>"] = "~>", | ||
115 | -- plus some convenience translations | ||
116 | [""] = "==", | ||
117 | ["="] = "==", | ||
118 | ["!="] = "~=" | ||
119 | } | ||
120 | |||
121 | --- Consumes a constraint from a string, converting it to table format. | ||
122 | -- For example, a string ">= 1.0, > 2.0" is converted to a table in the | ||
123 | -- format {op = ">=", version={1,0}} and the rest, "> 2.0", is returned | ||
124 | -- back to the caller. | ||
125 | -- @param input string: A list of constraints in string format. | ||
126 | -- @return (table, string) or nil: A table representing the same | ||
127 | -- constraints and the string with the unused input, or nil if the | ||
128 | -- input string is invalid. | ||
129 | parse_constraint = function(input: string): {string: any}, string | ||
130 | |||
131 | local no_upgrade, op, versionstr, rest = input:match("^(@?)([<>=~!]*)%s*([%w%.%_%-]+)[%s,]*(.*)") | ||
132 | local _op = operators[op] | ||
133 | local version = vers.parse_version(versionstr) | ||
134 | if not _op then | ||
135 | return nil, "Encountered bad constraint operator: '"..tostring(op).."' in '"..input.."'" | ||
136 | end | ||
137 | if not version then | ||
138 | return nil, "Could not parse version from constraint: '"..input.."'" | ||
139 | end | ||
140 | return { op = _op, version = version, no_upgrade = no_upgrade=="@" and true or nil }, rest --? false instead of nil | ||
141 | end | ||
142 | end | ||
143 | |||
144 | --- Convert a list of constraints from string to table format. | ||
145 | -- For example, a string ">= 1.0, < 2.0" is converted to a table in the format | ||
146 | -- {{op = ">=", version={1,0}}, {op = "<", version={2,0}}}. | ||
147 | -- Version tables use a metatable allowing later comparison through | ||
148 | -- relational operators. | ||
149 | -- @param input string: A list of constraints in string format. | ||
150 | -- @return table or nil: A table representing the same constraints, | ||
151 | -- or nil if the input string is invalid. | ||
152 | parse_constraints = function(input: string): {Constraint}, string | ||
153 | |||
154 | local constraints, oinput = {}, input | ||
155 | local constraint: Constraint | ||
156 | while #input > 0 do | ||
157 | constraint, input = parse_constraint(input) | ||
158 | if constraint then | ||
159 | table.insert(constraints, constraint) | ||
160 | else | ||
161 | return nil, "Failed to parse constraint '"..tostring(oinput).."' with error: ".. input | ||
162 | end | ||
163 | end | ||
164 | return constraints | ||
165 | end | ||
166 | end | ||
167 | |||
168 | --- Prepare a query in dependency table format. | ||
169 | -- @param depstr string: A dependency in string format | ||
170 | -- as entered in rockspec files. | ||
171 | -- @return table: A query in table format, or nil and an error message in case of errors. | ||
172 | function queries.from_dep_string(depstr: string): Query, string | ||
173 | |||
174 | local ns_name, rest = depstr:match("^%s*([a-zA-Z0-9%.%-%_]*/?[a-zA-Z0-9][a-zA-Z0-9%.%-%_]*)%s*([^/]*)") | ||
175 | if not ns_name then | ||
176 | return nil, "failed to extract dependency name from '"..depstr.."'" | ||
177 | end | ||
178 | |||
179 | ns_name = ns_name:lower() | ||
180 | |||
181 | local constraints, err = parse_constraints(rest) | ||
182 | if not constraints then | ||
183 | return nil, err | ||
184 | end | ||
185 | |||
186 | local name, namespace = util.split_namespace(ns_name) | ||
187 | |||
188 | local self = { | ||
189 | name = name, | ||
190 | namespace = namespace, | ||
191 | constraints = constraints, | ||
192 | } | ||
193 | |||
194 | query_mt.arch[cfg.arch] = true | ||
195 | return setmetatable(self, query_mt) | ||
196 | end | ||
197 | end | ||
198 | |||
199 | function queries.from_persisted_table(tbl: Query): Query | ||
200 | query_mt.arch[cfg.arch] = true | ||
201 | return setmetatable(tbl, query_mt) | ||
202 | end | ||
203 | |||
204 | --- Build a string representation of a query package name. | ||
205 | -- Includes namespace, name and version, but not arch or constraints. | ||
206 | -- @param query table: a query table | ||
207 | -- @return string: a result such as `my_user/my_rock 1.0` or `my_rock`. | ||
208 | function query_mt.__tostring(self: Query): string | ||
209 | -- function query_mt:__tostring(): string | ||
210 | local out = {} | ||
211 | if self.namespace then | ||
212 | table.insert(out, self.namespace) | ||
213 | table.insert(out, "/") | ||
214 | end | ||
215 | table.insert(out, self.name) | ||
216 | |||
217 | if #self.constraints > 0 then | ||
218 | local pretty = {} | ||
219 | for _, c in ipairs(self.constraints) do | ||
220 | local v = c.version.string | ||
221 | if c.op == "==" then | ||
222 | table.insert(pretty, v) | ||
223 | else | ||
224 | table.insert(pretty, c.op .. " " .. v) | ||
225 | end | ||
226 | end | ||
227 | table.insert(out, " ") | ||
228 | table.insert(out, table.concat(pretty, ", ")) | ||
229 | end | ||
230 | |||
231 | return table.concat(out) | ||
232 | end | ||
233 | |||
234 | return queries --! src/luarocks/queries.tl:32 \ No newline at end of file | ||
diff --git a/src/luarocks/results.tl b/src/luarocks/results.tl index a5bc25fe..7417db7a 100644 --- a/src/luarocks/results.tl +++ b/src/luarocks/results.tl | |||
@@ -1,10 +1,19 @@ | |||
1 | local record results | 1 | local record results |
2 | record Results --? name | ||
3 | name: string | ||
4 | version: string | ||
5 | namespace: string | ||
6 | arch: string | ||
7 | repo: string | ||
8 | end | ||
2 | end | 9 | end |
3 | 10 | ||
4 | local vers = require("luarocks.core.vers") | 11 | local vers = require("luarocks.core.vers") |
5 | local util = require("luarocks.util") | 12 | local util = require("luarocks.util") |
6 | 13 | ||
7 | local result_mt: metatable<any> = {} | 14 | local type Results = results.Results |
15 | |||
16 | local result_mt: metatable<Results> = {} | ||
8 | 17 | ||
9 | result_mt.__index = result_mt | 18 | result_mt.__index = result_mt |
10 | 19 | ||
@@ -12,18 +21,18 @@ function result_mt.type() | |||
12 | return "result" | 21 | return "result" |
13 | end | 22 | end |
14 | 23 | ||
15 | function results.new(name, version, repo, arch, namespace) | 24 | function results.new(name: string, version: string, repo: string, arch?: string, namespace?: string): Results, boolean |
16 | assert(type(name) == "string" and not name:match("/")) | 25 | |
17 | assert(type(version) == "string") | 26 | assert(not name:match("/")) |
18 | assert(type(repo) == "string") | 27 | -- assert(type(arch) == "string" or not arch) --! arch?: string |
19 | assert(type(arch) == "string" or not arch) | 28 | -- assert(type(namespace) == "string" or not namespace) --! namespace?: string |
20 | assert(type(namespace) == "string" or not namespace) | 29 | |
21 | 30 | ||
22 | if not namespace then | 31 | if not namespace then |
23 | name, namespace = util.split_namespace(name) | 32 | name, namespace = util.split_namespace(name) |
24 | end | 33 | end |
25 | 34 | ||
26 | local self = { | 35 | local self: Results = { |
27 | name = name, | 36 | name = name, |
28 | version = version, | 37 | version = version, |
29 | namespace = namespace, | 38 | namespace = namespace, |
@@ -41,7 +50,7 @@ end | |||
41 | -- @param query table: A query in dependency table format. | 50 | -- @param query table: A query in dependency table format. |
42 | -- @param name string: A package name. | 51 | -- @param name string: A package name. |
43 | -- @return boolean: True if names match, false otherwise. | 52 | -- @return boolean: True if names match, false otherwise. |
44 | local function match_name(query, name) | 53 | local function match_name(query: query, name: string): boolean |
45 | if query.substring then | 54 | if query.substring then |
46 | return name:find(query.name, 0, true) and true or false | 55 | return name:find(query.name, 0, true) and true or false |
47 | else | 56 | else |
@@ -52,8 +61,7 @@ end | |||
52 | --- Returns true if the result satisfies a given query. | 61 | --- Returns true if the result satisfies a given query. |
53 | -- @param query: a query. | 62 | -- @param query: a query. |
54 | -- @return boolean. | 63 | -- @return boolean. |
55 | function result_mt:satisfies(query) | 64 | function result_mt:satisfies(query: query): Results, boolean |
56 | assert(query:type() == "query") | ||
57 | return match_name(query, self.name) | 65 | return match_name(query, self.name) |
58 | and (query.arch[self.arch] or query.arch["any"]) | 66 | and (query.arch[self.arch] or query.arch["any"]) |
59 | and ((not query.namespace) or (query.namespace == self.namespace)) | 67 | and ((not query.namespace) or (query.namespace == self.namespace)) |