/src/luarocks/manif.lua
http://github.com/keplerproject/luarocks · Lua · 269 lines · 195 code · 29 blank · 45 comment · 66 complexity · 077c4da2b5789936eb8a009dd393629c MD5 · raw file
- --- Module for handling manifest files and tables.
- -- Manifest files describe the contents of a LuaRocks tree or server.
- -- They are loaded into manifest tables, which are then used for
- -- performing searches, matching dependencies, etc.
- local manif = {}
- local core = require("luarocks.core.manif")
- local persist = require("luarocks.persist")
- local fetch = require("luarocks.fetch")
- local dir = require("luarocks.dir")
- local fs = require("luarocks.fs")
- local cfg = require("luarocks.core.cfg")
- local path = require("luarocks.path")
- local util = require("luarocks.util")
- local queries = require("luarocks.queries")
- local type_manifest = require("luarocks.type.manifest")
- manif.cache_manifest = core.cache_manifest
- manif.load_rocks_tree_manifests = core.load_rocks_tree_manifests
- manif.scan_dependencies = core.scan_dependencies
- manif.rock_manifest_cache = {}
- local function check_manifest(repo_url, manifest, globals)
- local ok, err = type_manifest.check(manifest, globals)
- if not ok then
- core.cache_manifest(repo_url, cfg.lua_version, nil)
- return nil, "Error checking manifest: "..err, "type"
- end
- return manifest
- end
- local postprocess_dependencies
- do
- local postprocess_check = setmetatable({}, { __mode = "k" })
- postprocess_dependencies = function(manifest)
- if postprocess_check[manifest] then
- return
- end
- if manifest.dependencies then
- for name, versions in pairs(manifest.dependencies) do
- for version, entries in pairs(versions) do
- for k, v in pairs(entries) do
- entries[k] = queries.from_persisted_table(v)
- end
- end
- end
- end
- postprocess_check[manifest] = true
- end
- end
- function manif.load_rock_manifest(name, version, root)
- assert(type(name) == "string" and not name:match("/"))
- assert(type(version) == "string")
- local name_version = name.."/"..version
- if manif.rock_manifest_cache[name_version] then
- return manif.rock_manifest_cache[name_version].rock_manifest
- end
- local pathname = path.rock_manifest_file(name, version, root)
- local rock_manifest = persist.load_into_table(pathname)
- if not rock_manifest then
- return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks tree?"
- end
- manif.rock_manifest_cache[name_version] = rock_manifest
- return rock_manifest.rock_manifest
- end
- --- Load a local or remote manifest describing a repository.
- -- All functions that use manifest tables assume they were obtained
- -- through this function.
- -- @param repo_url string: URL or pathname for the repository.
- -- @param lua_version string: Lua version in "5.x" format, defaults to installed version.
- -- @param versioned_only boolean: If true, do not fall back to the main manifest
- -- if a versioned manifest was not found.
- -- @return table or (nil, string, [string]): A table representing the manifest,
- -- or nil followed by an error message and an optional error code.
- function manif.load_manifest(repo_url, lua_version, versioned_only)
- assert(type(repo_url) == "string")
- assert(type(lua_version) == "string" or not lua_version)
- lua_version = lua_version or cfg.lua_version
- local cached_manifest = core.get_cached_manifest(repo_url, lua_version)
- if cached_manifest then
- postprocess_dependencies(cached_manifest)
- return cached_manifest
- end
- local filenames = {
- "manifest-"..lua_version..".zip",
- "manifest-"..lua_version,
- not versioned_only and "manifest" or nil,
- }
- local protocol, repodir = dir.split_url(repo_url)
- local pathname, from_cache
- if protocol == "file" then
- for _, filename in ipairs(filenames) do
- pathname = dir.path(repodir, filename)
- if fs.exists(pathname) then
- break
- end
- end
- else
- local err, errcode
- for _, filename in ipairs(filenames) do
- pathname, err, errcode, from_cache = fetch.fetch_caching(dir.path(repo_url, filename))
- if pathname then
- break
- end
- end
- if not pathname then
- return nil, err, errcode
- end
- end
- if pathname:match(".*%.zip$") then
- pathname = fs.absolute_name(pathname)
- local nozip = pathname:match("(.*)%.zip$")
- if not from_cache then
- local dirname = dir.dir_name(pathname)
- fs.change_dir(dirname)
- fs.delete(nozip)
- local ok, err = fs.unzip(pathname)
- fs.pop_dir()
- if not ok then
- fs.delete(pathname)
- fs.delete(pathname..".timestamp")
- return nil, "Failed extracting manifest file: " .. err
- end
- end
- pathname = nozip
- end
- local manifest, err, errcode = core.manifest_loader(pathname, repo_url, lua_version)
- if not manifest then
- return nil, err, errcode
- end
- postprocess_dependencies(manifest)
- return check_manifest(repo_url, manifest, err)
- end
- --- Get type and name of an item (a module or a command) provided by a file.
- -- @param deploy_type string: rock manifest subtree the file comes from ("bin", "lua", or "lib").
- -- @param file_path string: path to the file relatively to deploy_type subdirectory.
- -- @return (string, string): item type ("module" or "command") and name.
- function manif.get_provided_item(deploy_type, file_path)
- assert(type(deploy_type) == "string")
- assert(type(file_path) == "string")
- local item_type = deploy_type == "bin" and "command" or "module"
- local item_name = item_type == "command" and file_path or path.path_to_module(file_path)
- return item_type, item_name
- end
- local function get_providers(item_type, item_name, repo)
- assert(type(item_type) == "string")
- assert(type(item_name) == "string")
- local rocks_dir = path.rocks_dir(repo or cfg.root_dir)
- local manifest = manif.load_manifest(rocks_dir)
- return manifest and manifest[item_type .. "s"][item_name]
- end
- --- Given a name of a module or a command, figure out which rock name and version
- -- correspond to it in the rock tree manifest.
- -- @param item_type string: "module" or "command".
- -- @param item_name string: module or command name.
- -- @param root string or nil: A local root dir for a rocks tree. If not given, the default is used.
- -- @return (string, string) or nil: name and version of the provider rock or nil if there
- -- is no provider.
- function manif.get_current_provider(item_type, item_name, repo)
- local providers = get_providers(item_type, item_name, repo)
- if providers then
- return providers[1]:match("([^/]*)/([^/]*)")
- end
- end
- function manif.get_next_provider(item_type, item_name, repo)
- local providers = get_providers(item_type, item_name, repo)
- if providers and providers[2] then
- return providers[2]:match("([^/]*)/([^/]*)")
- end
- end
- --- Given a name of a module or a command provided by a package, figure out
- -- which file provides it.
- -- @param name string: package name.
- -- @param version string: package version.
- -- @param item_type string: "module" or "command".
- -- @param item_name string: module or command name.
- -- @param root string or nil: A local root dir for a rocks tree. If not given, the default is used.
- -- @return (string, string): rock manifest subtree the file comes from ("bin", "lua", or "lib")
- -- and path to the providing file relatively to that subtree.
- function manif.get_providing_file(name, version, item_type, item_name, repo)
- local rocks_dir = path.rocks_dir(repo or cfg.root_dir)
- local manifest = manif.load_manifest(rocks_dir)
- local entry_table = manifest.repository[name][version][1]
- local file_path = entry_table[item_type .. "s"][item_name]
- if item_type == "command" then
- return "bin", file_path
- end
- -- A module can be in "lua" or "lib". Decide based on extension first:
- -- most likely Lua modules are in "lua/" and C modules are in "lib/".
- if file_path:match("%." .. cfg.lua_extension .. "$") then
- return "lua", file_path
- elseif file_path:match("%." .. cfg.lib_extension .. "$") then
- return "lib", file_path
- end
- -- Fallback to rock manifest scanning.
- local rock_manifest = manif.load_rock_manifest(name, version, repo and repo.root)
- local subtree = rock_manifest.lib
- for path_part in file_path:gmatch("[^/]+") do
- if type(subtree) == "table" then
- subtree = subtree[path_part]
- else
- -- Assume it's in "lua/" if it's not in "lib/".
- return "lua", file_path
- end
- end
- return type(subtree) == "string" and "lib" or "lua", file_path
- end
- --- Get all versions of a package listed in a manifest file.
- -- @param name string: a package name.
- -- @param deps_mode string: "one", to use only the currently
- -- configured tree; "order" to select trees based on order
- -- (use the current tree and all trees below it on the list)
- -- or "all", to use all trees.
- -- @return table: An array of strings listing installed
- -- versions of a package, and a table indicating where they are found.
- function manif.get_versions(dep, deps_mode)
- assert(type(dep) == "table")
- assert(type(deps_mode) == "string")
-
- local name = dep.name
- local namespace = dep.namespace
- local version_set = {}
- path.map_trees(deps_mode, function(tree)
- local manifest = manif.load_manifest(path.rocks_dir(tree))
- if manifest and manifest.repository[name] then
- for version in pairs(manifest.repository[name]) do
- if dep.namespace then
- local ns_file = path.rock_namespace_file(name, version, tree)
- local fd = io.open(ns_file, "r")
- if fd then
- local ns = fd:read("*a")
- fd:close()
- if ns == namespace then
- version_set[version] = tree
- end
- end
- else
- version_set[version] = tree
- end
- end
- end
- end)
- return util.keys(version_set), version_set
- end
- return manif