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 /src | |
| parent | a50299e1d6b280f5ca635b2c7ac9fe889befd6d6 (diff) | |
| download | luarocks-a94eeb7279af61565d55cf446a286b0b9f2c1fe3.tar.gz luarocks-a94eeb7279af61565d55cf446a286b0b9f2c1fe3.tar.bz2 luarocks-a94eeb7279af61565d55cf446a286b0b9f2c1fe3.zip | |
results, queries in progress
Diffstat (limited to 'src')
| -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)) |
