From 66459e17a7f356827d1ee2592e847d0e939acf0f Mon Sep 17 00:00:00 2001 From: V1K1NGbg Date: Thu, 22 Aug 2024 17:48:57 -0300 Subject: Teal: convert luarocks.search --- src/luarocks/search.lua | 393 ------------------------------------------------ src/luarocks/search.tl | 386 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 386 insertions(+), 393 deletions(-) delete mode 100644 src/luarocks/search.lua create mode 100644 src/luarocks/search.tl (limited to 'src') diff --git a/src/luarocks/search.lua b/src/luarocks/search.lua deleted file mode 100644 index 180f8f45..00000000 --- a/src/luarocks/search.lua +++ /dev/null @@ -1,393 +0,0 @@ -local search = {} - -local dir = require("luarocks.dir") -local path = require("luarocks.path") -local manif = require("luarocks.manif") -local vers = require("luarocks.core.vers") -local cfg = require("luarocks.core.cfg") -local util = require("luarocks.util") -local queries = require("luarocks.queries") -local results = require("luarocks.results") - ---- Store a search result (a rock or rockspec) in the result tree. --- @param result_tree table: The result tree, where keys are package names and --- values are tables matching version strings to arrays of --- tables with fields "arch" and "repo". --- @param result table: A result. -function search.store_result(result_tree, result) - assert(type(result_tree) == "table") - assert(result:type() == "result") - - local name = result.name - local version = result.version - - if not result_tree[name] then result_tree[name] = {} end - if not result_tree[name][version] then result_tree[name][version] = {} end - table.insert(result_tree[name][version], { - arch = result.arch, - repo = result.repo, - namespace = result.namespace, - }) -end - ---- Store a match in a result tree if version matches query. --- Name, version, arch and repository path are stored in a given --- table, optionally checking if version and arch (if given) match --- a query. --- @param result_tree table: The result tree, where keys are package names and --- values are tables matching version strings to arrays of --- tables with fields "arch" and "repo". --- @param result table: a result object. --- @param query table: a query object. -local function store_if_match(result_tree, result, query) - assert(result:type() == "result") - assert(query:type() == "query") - - if result:satisfies(query) then - search.store_result(result_tree, result) - end -end - ---- Perform search on a local repository. --- @param repo string: The pathname of the local repository. --- @param query table: a query object. --- @param result_tree table or nil: If given, this table will store the --- result tree; if not given, a new table will be created. --- @return table: The result tree, where keys are package names and --- values are tables matching version strings to arrays of --- tables with fields "arch" and "repo". --- If a table was given in the "result_tree" parameter, that is the result value. -function search.disk_search(repo, query, result_tree) - assert(type(repo) == "string") - assert(query:type() == "query") - assert(type(result_tree) == "table" or not result_tree) - - local fs = require("luarocks.fs") - - if not result_tree then - result_tree = {} - end - - for name in fs.dir(repo) do - local pathname = dir.path(repo, name) - local rname, rversion, rarch = path.parse_name(name) - - if rname and (pathname:match(".rockspec$") or pathname:match(".rock$")) then - local result = results.new(rname, rversion, repo, rarch) - store_if_match(result_tree, result, query) - elseif fs.is_dir(pathname) then - for version in fs.dir(pathname) do - if version:match("-%d+$") then - local namespace = path.read_namespace(name, version, repo) - local result = results.new(name, version, repo, "installed", namespace) - store_if_match(result_tree, result, query) - end - end - end - end - return result_tree -end - ---- Perform search on a rocks server or tree. --- @param result_tree table: The result tree, where keys are package names and --- values are tables matching version strings to arrays of --- tables with fields "arch" and "repo". --- @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 query object. --- @param lua_version string: Lua version in "5.x" format, defaults to installed version. --- @param is_local boolean --- @return true or, in case of errors, nil, an error message and an optional error code. -local function manifest_search(result_tree, repo, query, lua_version, is_local) - assert(type(result_tree) == "table") - assert(type(repo) == "string") - assert(query:type() == "query") - - -- FIXME do not add this in local repos - if (not is_local) and query.namespace then - repo = repo .. "/manifests/" .. query.namespace - end - - local manifest, err, errcode = manif.load_manifest(repo, lua_version, not is_local) - if not manifest then - return nil, err, errcode - end - for name, versions in pairs(manifest.repository) do - for version, items in pairs(versions) do - local namespace = is_local and path.read_namespace(name, version, repo) or query.namespace - for _, item in ipairs(items) do - local result = results.new(name, version, repo, item.arch, namespace) - store_if_match(result_tree, result, query) - end - end - end - return true -end - -local function remote_manifest_search(result_tree, repo, query, lua_version) - return manifest_search(result_tree, repo, query, lua_version, false) -end - -function search.local_manifest_search(result_tree, repo, query, lua_version) - return manifest_search(result_tree, repo, query, lua_version, true) -end - ---- Search on all configured rocks servers. --- @param query table: a query object. --- @param lua_version string: Lua version in "5.x" format, defaults to installed version. --- @return table: A table where keys are package names --- and values are tables matching version strings to arrays of --- tables with fields "arch" and "repo". -function search.search_repos(query, lua_version) - assert(query:type() == "query") - - local result_tree = {} - for _, repo in ipairs(cfg.rocks_servers) do - if type(repo) == "string" then - repo = { repo } - end - for _, mirror in ipairs(repo) do - if not cfg.disabled_servers[mirror] then - local protocol, pathname = dir.split_url(mirror) - if protocol == "file" then - mirror = pathname - end - local ok, err, errcode = remote_manifest_search(result_tree, mirror, query, lua_version) - if errcode == "network" then - cfg.disabled_servers[mirror] = true - end - if ok then - break - else - util.warning("Failed searching manifest: "..err) - if errcode == "downloader" then - break - end - end - end - end - end - -- search through rocks in rocks_provided - local provided_repo = "provided by VM or rocks_provided" - for name, version in pairs(util.get_rocks_provided()) do - local result = results.new(name, version, provided_repo, "installed") - store_if_match(result_tree, result, query) - end - return result_tree -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 --- in search result trees. --- @return string or nil: the URL for the latest version if one could --- be picked, or nil. -local function pick_latest_version(name, versions) - assert(type(name) == "string" and not name:match("/")) - assert(type(versions) == "table") - - local vtables = {} - for v, _ in pairs(versions) do - table.insert(vtables, vers.parse_version(v)) - end - table.sort(vtables) - local version = vtables[#vtables].string - local items = versions[version] - if items then - local pick = 1 - for i, item in ipairs(items) do - if (item.arch == 'src' and items[pick].arch == 'rockspec') - or (item.arch ~= 'src' and item.arch ~= 'rockspec') then - pick = i - end - end - return path.make_url(items[pick].repo, name, version, items[pick].arch) - end - return nil -end - --- Find out which other Lua versions provide rock versions matching a query, --- @param query table: a query object. --- @return table: array of Lua versions supported, in "5.x" format. -local function supported_lua_versions(query) - assert(query:type() == "query") - local result_tree = {} - - for lua_version in util.lua_versions() do - if lua_version ~= cfg.lua_version then - util.printout("Checking for Lua " .. lua_version .. "...") - if search.search_repos(query, lua_version)[query.name] then - table.insert(result_tree, lua_version) - end - end - end - - return result_tree -end - ---- Attempt to get a single URL for a given search for a rock. --- @param query table: a query object. --- @return string or (nil, string, string): URL for latest matching version --- of the rock if it was found, or nil followed by an error message --- and an error code. -function search.find_suitable_rock(query) - assert(query:type() == "query") - - local rocks_provided = util.get_rocks_provided() - - if rocks_provided[query.name] ~= nil then - -- Do not install versions listed in rocks_provided. - return nil, "Rock "..query.name.." "..rocks_provided[query.name].. - " is already provided by VM or via 'rocks_provided' in the config file.", "provided" - end - - local result_tree = search.search_repos(query) - local first_rock = next(result_tree) - if not first_rock then - return nil, "No results matching query were found for Lua " .. cfg.lua_version .. ".", "notfound" - elseif next(result_tree, first_rock) then - -- Shouldn't happen as query must match only one package. - return nil, "Several rocks matched query.", "manyfound" - else - return pick_latest_version(query.name, result_tree[first_rock]) - end -end - -function search.find_src_or_rockspec(name, namespace, version, check_lua_versions) - local query = queries.new(name, namespace, version, false, "src|rockspec") - local url, err = search.find_rock_checking_lua_versions(query, check_lua_versions) - if not url then - return nil, "Could not find a result named "..tostring(query)..": "..err - end - return url -end - -function search.find_rock_checking_lua_versions(query, check_lua_versions) - local url, err, errcode = search.find_suitable_rock(query) - if url then - return url - end - - if errcode == "notfound" then - local add - if check_lua_versions then - util.printout(query.name .. " not found for Lua " .. cfg.lua_version .. ".") - util.printout("Checking if available for other Lua versions...") - - -- Check if constraints are satisfiable with other Lua versions. - local lua_versions = supported_lua_versions(query) - - if #lua_versions ~= 0 then - -- Build a nice message in "only Lua 5.x and 5.y but not 5.z." format - for i, lua_version in ipairs(lua_versions) do - lua_versions[i] = "Lua "..lua_version - end - - local versions_message = "only "..table.concat(lua_versions, " and ").. - " but not Lua "..cfg.lua_version.."." - - if #query.constraints == 0 then - add = query.name.." supports "..versions_message - elseif #query.constraints == 1 and query.constraints[1].op == "==" then - add = query.name.." "..query.constraints[1].version.string.." supports "..versions_message - else - add = "Matching "..query.name.." versions support "..versions_message - end - else - add = query.name.." is not available for any Lua versions." - end - else - add = "To check if it is available for other Lua versions, use --check-lua-versions." - end - err = err .. "\n" .. add - end - - return nil, err -end - ---- Print a list of rocks/rockspecs on standard output. --- @param result_tree table: A result tree. --- @param porcelain boolean or nil: A flag to force machine-friendly output. -function search.print_result_tree(result_tree, porcelain) - assert(type(result_tree) == "table") - assert(type(porcelain) == "boolean" or not porcelain) - - if porcelain then - for package, versions in util.sortedpairs(result_tree) do - for version, repos in util.sortedpairs(versions, vers.compare_versions) do - for _, repo in ipairs(repos) do - local nrepo = dir.normalize(repo.repo) - util.printout(package, version, repo.arch, nrepo, repo.namespace) - end - end - end - return - end - - for package, versions in util.sortedpairs(result_tree) do - local namespaces = {} - for version, repos in util.sortedpairs(versions, vers.compare_versions) do - for _, repo in ipairs(repos) do - local key = repo.namespace or "" - local list = namespaces[key] or {} - namespaces[key] = list - - repo.repo = dir.normalize(repo.repo) - table.insert(list, " "..version.." ("..repo.arch..") - "..path.root_dir(repo.repo)) - end - end - for key, list in util.sortedpairs(namespaces) do - util.printout(key == "" and package or key .. "/" .. package) - for _, line in ipairs(list) do - util.printout(line) - end - util.printout() - end - end -end - -function search.pick_installed_rock(query, given_tree) - assert(query:type() == "query") - - local result_tree = {} - local tree_map = {} - local trees = cfg.rocks_trees - if given_tree then - trees = { given_tree } - end - for _, tree in ipairs(trees) do - local rocks_dir = path.rocks_dir(tree) - tree_map[rocks_dir] = tree - search.local_manifest_search(result_tree, rocks_dir, query) - end - if not next(result_tree) then - return nil, "cannot find package "..tostring(query).."\nUse 'list' to find installed rocks." - end - - if not result_tree[query.name] and next(result_tree, next(result_tree)) then - local out = { "multiple installed packages match the name '"..tostring(query).."':\n\n" } - for name, _ in util.sortedpairs(result_tree) do - table.insert(out, " " .. name .. "\n") - end - table.insert(out, "\nPlease specify a single rock.\n") - return nil, table.concat(out) - end - - local repo_url - - local name, versions - if result_tree[query.name] then - name, versions = query.name, result_tree[query.name] - else - name, versions = util.sortedpairs(result_tree)() - end - - local version, repositories = util.sortedpairs(versions, vers.compare_versions)() - for _, rp in ipairs(repositories) do repo_url = rp.repo end - - local repo = tree_map[repo_url] - return name, version, repo, repo_url -end - -return search - diff --git a/src/luarocks/search.tl b/src/luarocks/search.tl new file mode 100644 index 00000000..31c42ee9 --- /dev/null +++ b/src/luarocks/search.tl @@ -0,0 +1,386 @@ +local search = {} + +local dir = require("luarocks.dir") +local path = require("luarocks.path") +local manif = require("luarocks.manif") +local vers = require("luarocks.core.vers") +local cfg = require("luarocks.core.cfg") +local util = require("luarocks.util") +local queries = require("luarocks.queries") +local results = require("luarocks.results") + +local type Result = require("luarocks.core.types.result").Result + +local type Query = require("luarocks.core.types.query").Query + +local type Tree = require("luarocks.core.types.tree").Tree + +--- Store a search result (a rock or rockspec) in the result tree. +-- @param result_tree table: The result tree, where keys are package names and +-- values are tables matching version strings to arrays of +-- tables with fields "arch" and "repo". +-- @param result table: A result. +function search.store_result(result_tree: {string: {string: {Result}}}, result: Result) + + local name = result.name + local version = result.version + + if not result_tree[name] then result_tree[name] = {} end + if not result_tree[name][version] then result_tree[name][version] = {} end + table.insert(result_tree[name][version], { + arch = result.arch, + repo = result.repo, + namespace = result.namespace, + } as Result) +end + +--- Store a match in a result tree if version matches query. +-- Name, version, arch and repository path are stored in a given +-- table, optionally checking if version and arch (if given) match +-- a query. +-- @param result_tree table: The result tree, where keys are package names and +-- values are tables matching version strings to arrays of +-- tables with fields "arch" and "repo". +-- @param result table: a result object. +-- @param query table: a query object. +local function store_if_match(result_tree: {string: {string: {Result}}}, result: Result, query: Query) + + if result:satisfies(query) then + search.store_result(result_tree, result) + end +end + +--- Perform search on a local repository. +-- @param repo string: The pathname of the local repository. +-- @param query table: a query object. +-- @param result_tree table or nil: If given, this table will store the +-- result tree; if not given, a new table will be created. +-- @return table: The result tree, where keys are package names and +-- values are tables matching version strings to arrays of +-- tables with fields "arch" and "repo". +-- If a table was given in the "result_tree" parameter, that is the result value. +function search.disk_search(repo: string, query: Query, result_tree?: {string: {string: {Result}}}): {string: {string: {Result}}} + + local fs = require("luarocks.fs") + + if not result_tree then + result_tree = {} + end + + for name in fs.dir(repo) do + local pathname = dir.path(repo, name) + local rname, rversion, rarch = path.parse_name(name) + + if rname and (pathname:match(".rockspec$") or pathname:match(".rock$")) then + local result = results.new(rname, rversion, repo, rarch) + store_if_match(result_tree, result, query) + elseif fs.is_dir(pathname) then + for version in fs.dir(pathname) do + if version:match("-%d+$") then + local namespace = path.read_namespace(name, version, repo) + local result = results.new(name, version, repo, "installed", namespace) + store_if_match(result_tree, result, query) + end + end + end + end + return result_tree +end + +--- Perform search on a rocks server or tree. +-- @param result_tree table: The result tree, where keys are package names and +-- values are tables matching version strings to arrays of +-- tables with fields "arch" and "repo". +-- @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 query object. +-- @param lua_version string: Lua version in "5.x" format, defaults to installed version. +-- @param is_local boolean +-- @return true or, in case of errors, nil, an error message and an optional error code. +local function manifest_search(result_tree: {string: {string: {Result}}}, repo: string, query: Query, lua_version: string, is_local: boolean): boolean, string, string + + -- FIXME do not add this in local repos + if (not is_local) and query.namespace then + repo = repo .. "/manifests/" .. query.namespace + end + + local manifest, err, errcode = manif.load_manifest(repo, lua_version, not is_local) + if not manifest then + return nil, err, errcode + end + for name, versions in pairs(manifest.repository) do + for version, items in pairs(versions) do + local namespace = is_local and path.read_namespace(name, version, repo) or query.namespace + for _, item in ipairs(items) do + local result = results.new(name, version, repo, item.arch, namespace) + store_if_match(result_tree, result, query) + end + end + end + return true +end + +local function remote_manifest_search(result_tree: {string: {string: {Result}}}, repo: string, query: Query, lua_version?: string): boolean, string, string + return manifest_search(result_tree, repo, query, lua_version, false) +end + +function search.local_manifest_search(result_tree: {string: {string: {Result}}}, repo: string, query: Query, lua_version?: string): boolean, string, string + return manifest_search(result_tree, repo, query, lua_version, true) +end + +--- Search on all configured rocks servers. +-- @param query table: a query object. +-- @param lua_version string: Lua version in "5.x" format, defaults to installed version. +-- @return table: A table where keys are package names +-- and values are tables matching version strings to arrays of +-- tables with fields "arch" and "repo". +function search.search_repos(query: Query, lua_version?: string): {string : {string : {Result}}} + + local result_tree = {} + local repo = {} + for _, repostr in ipairs(cfg.rocks_servers) do + if repostr is string then + repo = { repostr } + else + repo = repostr + end + for _, mirror in ipairs(repo) do + if not cfg.disabled_servers[mirror] then + local protocol, pathname = dir.split_url(mirror) + if protocol == "file" then + mirror = pathname + end + local ok, err, errcode = remote_manifest_search(result_tree, mirror, query, lua_version) + if errcode == "network" then + cfg.disabled_servers[mirror] = true + end + if ok then + break + else + util.warning("Failed searching manifest: "..err) + if errcode == "downloader" then + break + end + end + end + end + end + -- search through rocks in rocks_provided + local provided_repo = "provided by VM or rocks_provided" + for name, version in pairs(util.get_rocks_provided()) do + local result = results.new(name, version, provided_repo, "installed") + store_if_match(result_tree, result, query) + end + return result_tree +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 +-- in search result trees. +-- @return string or nil: the URL for the latest version if one could +-- be picked, or nil. +local function pick_latest_version(name: string, versions: {string: {Result}}): string + assert(not name:match("/")) + + local vtables = {} + for v, _ in pairs(versions) do + table.insert(vtables, vers.parse_version(v)) + end + table.sort(vtables) + local version = vtables[#vtables].string + local items = versions[version] + if items then + local pick = 1 + for i, item in ipairs(items) do + if (item.arch == 'src' and items[pick].arch == 'rockspec') + or (item.arch ~= 'src' and item.arch ~= 'rockspec') then + pick = i + end + end + return path.make_url(items[pick].repo, name, version, items[pick].arch) + end + return nil +end + +-- Find out which other Lua versions provide rock versions matching a query, +-- @param query table: a query object. +-- @return table: array of Lua versions supported, in "5.x" format. +local function supported_lua_versions(query: Query): {string} + local result_tree = {} + + for lua_version in util.lua_versions() do + if lua_version ~= cfg.lua_version then + util.printout("Checking for Lua " .. lua_version .. "...") + if search.search_repos(query, lua_version)[query.name] then + table.insert(result_tree, lua_version) + end + end + end + + return result_tree +end + +--- Attempt to get a single URL for a given search for a rock. +-- @param query table: a query object. +-- @return string or (nil, string, string): URL for latest matching version +-- of the rock if it was found, or nil followed by an error message +-- and an error code. +function search.find_suitable_rock(query: Query): string, string, string + + local rocks_provided = util.get_rocks_provided() + + if rocks_provided[query.name] then + -- Do not install versions listed in rocks_provided. + return nil, "Rock "..query.name.." "..rocks_provided[query.name].. + " is already provided by VM or via 'rocks_provided' in the config file.", "provided" + end + + local result_tree = search.search_repos(query) + local first_rock = next(result_tree) + if not first_rock then + return nil, "No results matching query were found for Lua " .. cfg.lua_version .. ".", "notfound" + elseif next(result_tree, first_rock) then + -- Shouldn't happen as query must match only one package. + return nil, "Several rocks matched query.", "manyfound" + else + return pick_latest_version(query.name, result_tree[first_rock]) + end +end + +function search.find_rock_checking_lua_versions(query: Query, check_lua_versions: boolean): string, string + local url, err, errcode = search.find_suitable_rock(query) + if url then + return url + end + + if errcode == "notfound" then + local add: string + if check_lua_versions then + util.printout(query.name .. " not found for Lua " .. cfg.lua_version .. ".") + util.printout("Checking if available for other Lua versions...") + + -- Check if constraints are satisfiable with other Lua versions. + local lua_versions = supported_lua_versions(query) + + if #lua_versions ~= 0 then + -- Build a nice message in "only Lua 5.x and 5.y but not 5.z." format + for i, lua_version in ipairs(lua_versions) do + lua_versions[i] = "Lua "..lua_version + end + + local versions_message = "only "..table.concat(lua_versions, " and ").. + " but not Lua "..cfg.lua_version.."." + + if #query.constraints == 0 then + add = query.name.." supports "..versions_message + elseif #query.constraints == 1 and query.constraints[1].op == "==" then + local queryversion = tostring(query.constraints[1].version) + add = query.name.." "..queryversion.." supports "..versions_message + else + add = "Matching "..query.name.." versions support "..versions_message + end + else + add = query.name.." is not available for any Lua versions." + end + else + add = "To check if it is available for other Lua versions, use --check-lua-versions." + end + err = err .. "\n" .. add + end + + return nil, err +end + +function search.find_src_or_rockspec(name: string, namespace: string, version: string, check_lua_versions: boolean): string, string + local query = queries.new(name, namespace, version, false, "src|rockspec") + local url, err = search.find_rock_checking_lua_versions(query, check_lua_versions) + if not url then + return nil, "Could not find a result named "..tostring(query)..": "..err + end + return url +end + +--- Print a list of rocks/rockspecs on standard output. +-- @param result_tree table: A result tree. +-- @param porcelain boolean or nil: A flag to force machine-friendly output. +function search.print_result_tree(result_tree: {string: {string: {Result}}}, porcelain?: boolean) + + if porcelain then + for packagestr, versions in util.sortedpairs(result_tree) do + for version, repos in util.sortedpairs(versions, vers.compare_versions) do + for _, repo in ipairs(repos) do + local nrepo = dir.normalize(repo.repo) + util.printout(packagestr, version, repo.arch, nrepo, repo.namespace) + end + end + end + return + end + + for packagestr, versions in util.sortedpairs(result_tree) do + local namespaces: {string: {string}} = {} + for version, repos in util.sortedpairs(versions, vers.compare_versions) do + for _, repo in ipairs(repos) do + local key = repo.namespace or "" + local list = namespaces[key] or {} + namespaces[key] = list + + repo.repo = dir.normalize(repo.repo) + table.insert(list, " "..version.." ("..repo.arch..") - "..path.root_dir(repo.repo)) + end + end + for key, list in util.sortedpairs(namespaces) do + util.printout(key == "" and packagestr or key .. "/" .. packagestr) + for _, line in ipairs(list) do + util.printout(line) + end + util.printout() + end + end +end + +function search.pick_installed_rock(query: Query, given_tree: string | Tree): string, string, string | Tree, string + + local result_tree = {} + local tree_map = {} + local trees = cfg.rocks_trees + if given_tree then + trees = { given_tree } + end + for _, tree in ipairs(trees) do + local rocks_dir = path.rocks_dir(tree) + tree_map[rocks_dir] = tree + search.local_manifest_search(result_tree, rocks_dir, query) + end + if not next(result_tree) then + return nil, "cannot find package "..tostring(query).."\nUse 'list' to find installed rocks." + end + + if not result_tree[query.name] and next(result_tree, next(result_tree) as string) then + local out = { "multiple installed packages match the name '"..tostring(query).."':\n\n" } + for name, _ in util.sortedpairs(result_tree) do + table.insert(out, " " .. name .. "\n") + end + table.insert(out, "\nPlease specify a single rock.\n") + return nil, table.concat(out) + end + + local repo_url: string + + local name, versions: string, {string : {Result}} + if result_tree[query.name] then + name, versions = query.name, result_tree[query.name] + else + name, versions = util.sortedpairs(result_tree)() + end + + local version, repositories = util.sortedpairs(versions, vers.compare_versions)() + for _, rp in ipairs(repositories) do repo_url = rp.repo end + + local repo = tree_map[repo_url] + return name, version, repo, repo_url +end + +return search + -- cgit v1.2.3-55-g6feb