From 4941a48407f08544c5517542ffc11b0c26fd4236 Mon Sep 17 00:00:00 2001 From: Hisham Muhammad <hisham@gobolinux.org> Date: Thu, 29 Mar 2018 19:11:26 -0300 Subject: Beginning support for namespaced queries --- src/luarocks/cmd/install.lua | 3 +- src/luarocks/cmd/list.lua | 7 ++-- src/luarocks/cmd/purge.lua | 5 +-- src/luarocks/cmd/remove.lua | 3 +- src/luarocks/cmd/search.lua | 4 +- src/luarocks/deps.lua | 6 +-- src/luarocks/download.lua | 6 +-- src/luarocks/manif/writer.lua | 5 +-- src/luarocks/queries.lua | 96 +++++++++++++++++++++++++++++++++++++++++++ src/luarocks/remove.lua | 7 ++-- src/luarocks/search.lua | 66 ++++++----------------------- 11 files changed, 132 insertions(+), 76 deletions(-) create mode 100644 src/luarocks/queries.lua diff --git a/src/luarocks/cmd/install.lua b/src/luarocks/cmd/install.lua index 018e9246..6901a680 100644 --- a/src/luarocks/cmd/install.lua +++ b/src/luarocks/cmd/install.lua @@ -11,6 +11,7 @@ local deps = require("luarocks.deps") local writer = require("luarocks.manif.writer") local remove = require("luarocks.remove") local search = require("luarocks.search") +local queries = require("luarocks.queries") local cfg = require("luarocks.core.cfg") install.help_summary = "Install a rock." @@ -174,7 +175,7 @@ function install.command(flags, name, version) writer.check_dependencies(nil, deps.get_deps_mode(flags)) return name, version else - local url, err = search.find_suitable_rock(search.make_query(name:lower(), version)) + local url, err = search.find_suitable_rock(queries.new(name:lower(), version)) if not url then return nil, err end diff --git a/src/luarocks/cmd/list.lua b/src/luarocks/cmd/list.lua index ed94bc68..e07c4ff3 100644 --- a/src/luarocks/cmd/list.lua +++ b/src/luarocks/cmd/list.lua @@ -4,6 +4,7 @@ local list = {} local search = require("luarocks.search") +local queries = require("luarocks.queries") local vers = require("luarocks.vers") local cfg = require("luarocks.core.cfg") local util = require("luarocks.util") @@ -31,8 +32,7 @@ local function check_outdated(trees, query) table.sort(versions, vers.compare_versions) local latest_installed = versions[1] - local query_available = search.make_query(name:lower()) - query.exact_name = true + local query_available = queries.new(name:lower(), nil, false) local results_available, err = search.search_repos(query_available) if results_available[name] then @@ -69,8 +69,7 @@ end -- @param version string or nil: a version may also be passed. -- @return boolean: True if succeeded, nil on errors. function list.command(flags, filter, version) - local query = search.make_query(filter and filter:lower() or "", version) - query.exact_name = false + local query = queries.new(filter and filter:lower() or "", version, true) local trees = cfg.rocks_trees if flags["tree"] then trees = { flags["tree"] } diff --git a/src/luarocks/cmd/purge.lua b/src/luarocks/cmd/purge.lua index bbce9f8c..15efb0ef 100644 --- a/src/luarocks/cmd/purge.lua +++ b/src/luarocks/cmd/purge.lua @@ -12,6 +12,7 @@ local repos = require("luarocks.repos") local writer = require("luarocks.manif.writer") local cfg = require("luarocks.core.cfg") local remove = require("luarocks.remove") +local queries = require("luarocks.queries") purge.help_summary = "Remove all installed rocks from a tree." purge.help_arguments = "--tree=<tree> [--old-versions]" @@ -37,8 +38,6 @@ function purge.command(flags) end local results = {} - local query = search.make_query("") - query.exact_name = false if not fs.is_dir(tree) then return nil, "Directory not found: "..tree end @@ -46,7 +45,7 @@ function purge.command(flags) local ok, err = fs.check_command_permissions(flags) if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end - search.manifest_search(results, path.rocks_dir(tree), query) + search.manifest_search(results, path.rocks_dir(tree), queries.all()) local sort = function(a,b) return vers.compare_versions(b,a) end if flags["old-versions"] then diff --git a/src/luarocks/cmd/remove.lua b/src/luarocks/cmd/remove.lua index b8148ba7..2624854d 100644 --- a/src/luarocks/cmd/remove.lua +++ b/src/luarocks/cmd/remove.lua @@ -11,6 +11,7 @@ local search = require("luarocks.search") local path = require("luarocks.path") local deps = require("luarocks.deps") local writer = require("luarocks.manif.writer") +local queries = require("luarocks.queries") cmd_remove.help_summary = "Uninstall a rock." cmd_remove.help_arguments = "[--force|--force-fast] <name> [<version>]" @@ -50,7 +51,7 @@ function cmd_remove.command(flags, name, version) local results = {} name = name:lower() - search.manifest_search(results, cfg.rocks_dir, search.make_query(name, version)) + search.manifest_search(results, cfg.rocks_dir, queries.new(name, version)) if not results[name] then return nil, "Could not find rock '"..name..(version and " "..version or "").."' in "..path.rocks_tree_to_string(cfg.root_dir) end diff --git a/src/luarocks/cmd/search.lua b/src/luarocks/cmd/search.lua index d12f5314..ccdbda7b 100644 --- a/src/luarocks/cmd/search.lua +++ b/src/luarocks/cmd/search.lua @@ -6,6 +6,7 @@ local cmd_search = {} local cfg = require("luarocks.core.cfg") local util = require("luarocks.util") local search = require("luarocks.search") +local queries = require("luarocks.queries") cmd_search.help_summary = "Query the LuaRocks servers." cmd_search.help_arguments = "[--source] [--binary] { <name> [<version>] | --all }" @@ -55,8 +56,7 @@ function cmd_search.command(flags, name, version) return nil, "Enter name and version or use --all. "..util.see_help("search") end - local query = search.make_query(name:lower(), version) - query.exact_name = false + local query = queries.new(name:lower(), version, true) local results, err = search.search_repos(query) local porcelain = flags["porcelain"] local full_name = name .. (version and " " .. version or "") diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua index 015e2527..229c3843 100644 --- a/src/luarocks/deps.lua +++ b/src/luarocks/deps.lua @@ -8,6 +8,7 @@ local path = require("luarocks.path") local dir = require("luarocks.dir") local util = require("luarocks.util") local vers = require("luarocks.vers") +local queries = require("luarocks.queries") --- Attempt to match a dependency to an installed rock. -- @param dep table: A dependency parsed in table format. @@ -90,8 +91,7 @@ local function values_set(tbl) end local function rock_status(name, deps_mode, rocks_provided) - local search = require("luarocks.search") - local installed = match_dep(search.make_query(name), nil, deps_mode, rocks_provided) + local installed = match_dep(queries.new(name), nil, deps_mode, rocks_provided) local installation_type = rocks_provided[name] and "provided by VM" or "installed" return installed and installed.." "..installation_type or "not installed" end @@ -184,7 +184,7 @@ function deps.fulfill_dependencies(rockspec, deps_mode) return nil, "Failed matching dependencies" end - local url, search_err = search.find_suitable_rock(dep) + local url, search_err = search.find_suitable_rock(queries.from_constraints(dep.name, dep.constraints)) if not url then return nil, "Could not satisfy dependency "..vers.show_dep(dep)..": "..search_err end diff --git a/src/luarocks/download.lua b/src/luarocks/download.lua index ec9996b2..77564b52 100644 --- a/src/luarocks/download.lua +++ b/src/luarocks/download.lua @@ -3,6 +3,7 @@ local download = {} local path = require("luarocks.path") local fetch = require("luarocks.fetch") local search = require("luarocks.search") +local queries = require("luarocks.queries") local fs = require("luarocks.fs") local dir = require("luarocks.dir") local cfg = require("luarocks.core.cfg") @@ -22,12 +23,11 @@ local function get_file(filename) end function download.download(arch, name, version, all) - local query = search.make_query(name, version) - if arch then query.arch = arch end + local substring = (all and name == "") + local query = queries.new(name, version, substring, arch) local search_err if all then - if name == "" then query.exact_name = false end local results = search.search_repos(query) local has_result = false local all_ok = true diff --git a/src/luarocks/manif/writer.lua b/src/luarocks/manif/writer.lua index 2d17d328..e6edd27d 100644 --- a/src/luarocks/manif/writer.lua +++ b/src/luarocks/manif/writer.lua @@ -13,6 +13,7 @@ local fetch = require("luarocks.fetch") local path = require("luarocks.path") local persist = require("luarocks.persist") local manif = require("luarocks.manif") +local queries = require("luarocks.queries") --- Update storage table to account for items provided by a package. -- @param storage table: a table storing items in the following format: @@ -296,9 +297,7 @@ function writer.make_manifest(repo, deps_mode, remote) return nil, "Cannot access repository at "..repo end - local query = search.make_query("") - query.exact_name = false - query.arch = "any" + local query = queries.all("any") local results = search.disk_search(repo, query) local manifest = { repository = {}, modules = {}, commands = {} } diff --git a/src/luarocks/queries.lua b/src/luarocks/queries.lua new file mode 100644 index 00000000..5bd7462e --- /dev/null +++ b/src/luarocks/queries.lua @@ -0,0 +1,96 @@ + +local queries = {} + +local vers = require("luarocks.vers") +local cfg = require("luarocks.core.cfg") + +local safer = require("safer") + +--- Convert the arch field of a query table to table format. +-- @param input string, table or nil +local function arch_to_table(input) + if type(input) == "table" then + return input + elseif type(input) == "string" then + local arch = {} + for a in input:gmatch("[%w_-]+") do + arch[a] = true + end + return arch + else + local arch = {} + arch["src"] = true + arch["all"] = true + arch["rockspec"] = true + arch["installed"] = true + arch[cfg.arch] = true + return arch + end +end + +-- Split name and namespace of a package name. +-- @param name a name that may be in "namespace/name" format +-- @return string, string? - name and optionally a namespace +local function split_namespace(name) + local p1, p2 = name:match("^([^/]+)/([^/]+)$") + if p1 then + return p2, p1 + end + return name +end + +--- Prepare a query in dependency table format. +-- @param name string: The query name. +-- @param version string or nil: +-- @param substring boolean: match substrings of the name +-- (default is false, match full name) +-- @param arch string: a string with pipe-separated accepted arch values +-- @param operator string: operator for version matching (default is "==") +-- @return table: A query in table format +function queries.new(name, version, substring, arch, operator) + assert(type(name) == "string") + assert(type(version) == "string" or not version) + assert(type(substring) == "boolean" or not substring) + assert(type(arch) == "string" or not arch) + assert(type(operator) == "string" or not operator) + + operator = operator or "==" + + local namespace + name, namespace = split_namespace(name) + + local query = { + name = name, + namespace = namespace, + constraints = {}, + substring = substring, + arch = arch_to_table(arch), + } + if version then + table.insert(query.constraints, { op = operator, version = vers.parse_version(version)}) + end + return safer.readonly(query) +end + +-- Query for all packages +-- @param arch string (optional) +function queries.all(arch) + assert(type(arch) == "string" or not arch) + + return queries.new("", nil, true, arch) +end + +function queries.from_constraints(name, constraints) + local namespace + name, namespace = split_namespace(name) + local query = { + name = name, + namespace = namespace, + constraints = constraints, + substring = false, + arch = arch_to_table(nil), + } + return safer.readonly(query) +end + +return queries diff --git a/src/luarocks/remove.lua b/src/luarocks/remove.lua index 6cc8334f..a469d149 100644 --- a/src/luarocks/remove.lua +++ b/src/luarocks/remove.lua @@ -7,6 +7,7 @@ local repos = require("luarocks.repos") local path = require("luarocks.path") local util = require("luarocks.util") local cfg = require("luarocks.core.cfg") +local queries = require("luarocks.queries") --- Obtain a list of packages that depend on the given set of packages -- (where all packages of the set are versions of one program). @@ -22,8 +23,7 @@ local function check_dependents(name, versions, deps_mode) blacklist[name][version] = true end local local_rocks = {} - local query_all = search.make_query("") - query_all.exact_name = false + local query_all = queries.all() search.manifest_search(local_rocks, cfg.rocks_dir, query_all) local_rocks[name] = nil for rock_name, rock_versions in pairs(local_rocks) do @@ -105,7 +105,8 @@ end function remove.remove_other_versions(name, version, force, fast) local results = {} - search.manifest_search(results, cfg.rocks_dir, { name = name, exact_name = true, constraints = {{ op = "~=", version = version}} }) + local query = queries.new(name, version, false, nil, "~=") + search.manifest_search(results, cfg.rocks_dir, query) if results[name] then return remove.remove_search_results(results, name, cfg.deps_mode, force, fast) end diff --git a/src/luarocks/search.lua b/src/luarocks/search.lua index 35010c2b..4e0cb847 100644 --- a/src/luarocks/search.lua +++ b/src/luarocks/search.lua @@ -6,29 +6,7 @@ local manif = require("luarocks.manif") local vers = require("luarocks.vers") local cfg = require("luarocks.core.cfg") local util = require("luarocks.util") - ---- Convert the arch field of a query table to table format. --- @param query table: A query table. -local function query_arch_as_table(query) - local format = type(query.arch) - if format == "table" then - return - elseif format == "nil" then - local accept = {} - accept["src"] = true - accept["all"] = true - accept["rockspec"] = true - accept["installed"] = true - accept[cfg.arch] = true - query.arch = accept - elseif format == "string" then - local accept = {} - for a in query.arch:gmatch("[%w_-]+") do - accept[a] = true - end - query.arch = accept - end -end +local queries = require("luarocks.queries") --- Store a search result (a rock or rockspec) in the results table. -- @param results table: The results table, where keys are package names and @@ -56,7 +34,7 @@ function search.store_result(results, name, version, arch, repo) end --- Test the name field of a query. --- If query has a boolean field exact_name set to false, +-- If query has a boolean field substring set to true, -- then substring match is performed; otherwise, exact string -- comparison is done. -- @param query table: A query in dependency table format. @@ -65,7 +43,7 @@ end local function match_name(query, name) assert(type(query) == "table") assert(type(name) == "string") - if query.exact_name == false then + if query.substring then return name:find(query.name, 0, true) and true or false else return name == query.name @@ -84,7 +62,7 @@ end -- @param version string: The version of the package being tested. -- @param arch string: The arch of the package being tested. -- @param query table: A table describing the query in dependency --- format (for example, {name = "filesystem", exact_name = false, +-- format (for example, {name = "filesystem", substring = true, -- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec"). -- If the arch field is omitted, the local architecture (cfg.arch) -- is used. The special value "any" is also recognized, returning all @@ -102,7 +80,7 @@ end --- Perform search on a local repository. -- @param repo string: The pathname of the local repository. -- @param query table: A table describing the query in dependency --- format (for example, {name = "filesystem", exact_name = false, +-- format (for example, {name = "filesystem", substring = true, -- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec"). -- If the arch field is omitted, the local architecture (cfg.arch) -- is used. The special value "any" is also recognized, returning all @@ -123,7 +101,6 @@ function search.disk_search(repo, query, results) if not results then results = {} end - query_arch_as_table(query) for name in fs.dir(repo) do local pathname = dir.path(repo, name) @@ -149,7 +126,7 @@ end -- @param repo string: The URL of a rocks server or -- the pathname of a rocks tree (as returned by path.rocks_dir()). -- @param query table: A table describing the query in dependency --- format (for example, {name = "filesystem", exact_name = false, +-- format (for example, {name = "filesystem", substring = true, -- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec"). -- If the arch field is omitted, the local architecture (cfg.arch) -- is used. The special value "any" is also recognized, returning all @@ -160,8 +137,11 @@ function search.manifest_search(results, repo, query, lua_version) assert(type(results) == "table") assert(type(repo) == "string") assert(type(query) == "table") - - query_arch_as_table(query) + + if query.namespace then + repo = repo .. "/manifests/" .. query.namespace + end + local manifest, err, errcode = manif.load_manifest(repo, lua_version) if not manifest then return nil, err, errcode @@ -216,24 +196,6 @@ function search.search_repos(query, lua_version) return results end ---- Prepare a query in dependency table format. --- @param name string: The query name. --- @param version string or nil: --- @return table: A query in table format -function search.make_query(name, version) - assert(type(name) == "string") - assert(type(version) == "string" or not version) - - local query = { - name = name, - constraints = {} - } - if version then - table.insert(query.constraints, { op = "==", version = vers.parse_version(version)}) - end - return query -end - --- Get the URL for the latest in a set of versions. -- @param name string: The package name to be used in the URL. -- @param versions table: An array of version informations, as stored @@ -369,8 +331,7 @@ function search.act_on_src_or_rockspec(action, name, version, ...) assert(type(name) == "string") assert(type(version) == "string" or not version) - local query = search.make_query(name, version) - query.arch = "src|rockspec" + local query = queries.new(name, version, nil, "src|rockspec") local url, err = search.find_suitable_rock(query) if not url then return nil, "Could not find a result named "..name..(version and " "..version or "")..": "..err @@ -380,8 +341,7 @@ end function search.pick_installed_rock(name, version, given_tree) local results = {} - local query = search.make_query(name, version) - query.exact_name = true + local query = queries.new(name, version, true) local tree_map = {} local trees = cfg.rocks_trees if given_tree then -- cgit v1.2.3-55-g6feb