diff options
| author | V1K1NGbg <victor@ilchev.com> | 2024-08-05 14:19:05 +0300 |
|---|---|---|
| committer | V1K1NGbg <victor@ilchev.com> | 2024-08-05 20:51:31 +0300 |
| commit | 515bce044a68283f460b37a08f4c6ec24ec98d53 (patch) | |
| tree | 0cbc3420d368b7342de6151967d184a828457890 /src | |
| parent | 0e98fd4c368080ab4ce834b0d35ff11f989923d9 (diff) | |
| download | luarocks-515bce044a68283f460b37a08f4c6ec24ec98d53.tar.gz luarocks-515bce044a68283f460b37a08f4c6ec24ec98d53.tar.bz2 luarocks-515bce044a68283f460b37a08f4c6ec24ec98d53.zip | |
manif
Diffstat (limited to 'src')
| -rw-r--r-- | src/luarocks/core/cfg.d.tl | 1 | ||||
| -rw-r--r-- | src/luarocks/manif.tl | 225 |
2 files changed, 225 insertions, 1 deletions
diff --git a/src/luarocks/core/cfg.d.tl b/src/luarocks/core/cfg.d.tl index dd398bd1..95d3aae7 100644 --- a/src/luarocks/core/cfg.d.tl +++ b/src/luarocks/core/cfg.d.tl | |||
| @@ -24,7 +24,6 @@ local record cfg | |||
| 24 | lua_dir: string | 24 | lua_dir: string |
| 25 | lib_dir: string | 25 | lib_dir: string |
| 26 | end | 26 | end |
| 27 | -- util | ||
| 28 | record Description | 27 | record Description |
| 29 | summary: string | 28 | summary: string |
| 30 | detailed: string | 29 | detailed: string |
diff --git a/src/luarocks/manif.tl b/src/luarocks/manif.tl new file mode 100644 index 00000000..a7949932 --- /dev/null +++ b/src/luarocks/manif.tl | |||
| @@ -0,0 +1,225 @@ | |||
| 1 | --- Module for handling manifest files and tables. | ||
| 2 | -- Manifest files describe the contents of a LuaRocks tree or server. | ||
| 3 | -- They are loaded into manifest tables, which are then used for | ||
| 4 | -- performing searches, matching dependencies, etc. | ||
| 5 | local record manif | ||
| 6 | cache_manifest: function(string, string, Manifest) | ||
| 7 | load_rocks_tree_manifests: function(? string): {Tree_manifest} | ||
| 8 | scan_dependencies: function(string, string, {Tree_manifest}, {any : any}) | ||
| 9 | end | ||
| 10 | |||
| 11 | local core = require("luarocks.core.manif") | ||
| 12 | local persist = require("luarocks.persist") | ||
| 13 | local fetch = require("luarocks.fetch") | ||
| 14 | local dir = require("luarocks.dir") | ||
| 15 | local fs = require("luarocks.fs") | ||
| 16 | local cfg = require("luarocks.core.cfg") | ||
| 17 | local path = require("luarocks.path") | ||
| 18 | local util = require("luarocks.util") | ||
| 19 | local queries = require("luarocks.queries") | ||
| 20 | local type_manifest = require("luarocks.type.manifest") | ||
| 21 | |||
| 22 | local type Manifest = core.Manifest | ||
| 23 | local type Tree_manifest = core.Tree_manifest | ||
| 24 | local type Tree = cfg.Tree | ||
| 25 | |||
| 26 | manif.cache_manifest = core.cache_manifest | ||
| 27 | manif.load_rocks_tree_manifests = core.load_rocks_tree_manifests | ||
| 28 | manif.scan_dependencies = core.scan_dependencies | ||
| 29 | |||
| 30 | manif.rock_manifest_cache = {} | ||
| 31 | |||
| 32 | local function check_manifest(repo_url: string, manifest: {any: any}, globals: {string: any}): Manifest, string, string | ||
| 33 | local ok, err = type_manifest.check(manifest, globals) | ||
| 34 | if not ok then | ||
| 35 | core.cache_manifest(repo_url, cfg.lua_version, nil) | ||
| 36 | return nil, "Error checking manifest: "..err, "type" | ||
| 37 | end | ||
| 38 | return manifest | ||
| 39 | end | ||
| 40 | |||
| 41 | local postprocess_dependencies: function(Manifest) | ||
| 42 | do | ||
| 43 | local postprocess_check = setmetatable({}, { __mode = "k" }) | ||
| 44 | postprocess_dependencies = function(manifest: Manifest) | ||
| 45 | if postprocess_check[manifest] then | ||
| 46 | return | ||
| 47 | end | ||
| 48 | if manifest.dependencies then | ||
| 49 | for _, versions in pairs(manifest.dependencies) do | ||
| 50 | for _, entries in pairs(versions) do | ||
| 51 | for k, v in pairs(entries) do | ||
| 52 | entries[k] = queries.from_persisted_table(v) | ||
| 53 | end | ||
| 54 | end | ||
| 55 | end | ||
| 56 | end | ||
| 57 | postprocess_check[manifest] = true | ||
| 58 | end | ||
| 59 | end | ||
| 60 | |||
| 61 | function manif.load_rock_manifest(name: string, version: string, root?: string | Tree) | ||
| 62 | assert(not name:match("/")) | ||
| 63 | |||
| 64 | local name_version = name.."/"..version | ||
| 65 | if manif.rock_manifest_cache[name_version] then | ||
| 66 | return manif.rock_manifest_cache[name_version].rock_manifest | ||
| 67 | end | ||
| 68 | local pathname = path.rock_manifest_file(name, version, root) | ||
| 69 | local rock_manifest = persist.load_into_table(pathname) | ||
| 70 | if not rock_manifest then | ||
| 71 | return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks tree?" | ||
| 72 | end | ||
| 73 | manif.rock_manifest_cache[name_version] = rock_manifest | ||
| 74 | return rock_manifest.rock_manifest | ||
| 75 | end | ||
| 76 | |||
| 77 | --- Load a local or remote manifest describing a repository. | ||
| 78 | -- All functions that use manifest tables assume they were obtained | ||
| 79 | -- through this function. | ||
| 80 | -- @param repo_url string: URL or pathname for the repository. | ||
| 81 | -- @param lua_version string: Lua version in "5.x" format, defaults to installed version. | ||
| 82 | -- @param versioned_only boolean: If true, do not fall back to the main manifest | ||
| 83 | -- if a versioned manifest was not found. | ||
| 84 | -- @return table or (nil, string, [string]): A table representing the manifest, | ||
| 85 | -- or nil followed by an error message and an optional error code. | ||
| 86 | function manif.load_manifest(repo_url: string, lua_version?: string, versioned_only?: boolean): Manifest, string, string | ||
| 87 | lua_version = lua_version or cfg.lua_version | ||
| 88 | |||
| 89 | local cached_manifest = core.get_cached_manifest(repo_url, lua_version) | ||
| 90 | if cached_manifest then | ||
| 91 | postprocess_dependencies(cached_manifest) | ||
| 92 | return cached_manifest | ||
| 93 | end | ||
| 94 | |||
| 95 | local filenames = { | ||
| 96 | "manifest-"..lua_version..".zip", | ||
| 97 | "manifest-"..lua_version, | ||
| 98 | not versioned_only and "manifest" or nil, | ||
| 99 | } | ||
| 100 | |||
| 101 | local protocol, repodir = dir.split_url(repo_url) | ||
| 102 | local pathname, from_cache: string, boolean | ||
| 103 | if protocol == "file" then | ||
| 104 | for _, filename in ipairs(filenames) do | ||
| 105 | pathname = dir.path(repodir, filename) | ||
| 106 | if fs.exists(pathname) then | ||
| 107 | break | ||
| 108 | end | ||
| 109 | end | ||
| 110 | else | ||
| 111 | local err, errcode: string, string | ||
| 112 | for _, filename in ipairs(filenames) do | ||
| 113 | pathname, err, errcode, from_cache = fetch.fetch_caching(dir.path(repo_url, filename), "no_mirror") | ||
| 114 | if pathname then | ||
| 115 | break | ||
| 116 | end | ||
| 117 | end | ||
| 118 | if not pathname then | ||
| 119 | return nil, err, errcode | ||
| 120 | end | ||
| 121 | end | ||
| 122 | if pathname:match(".*%.zip$") then | ||
| 123 | pathname = fs.absolute_name(pathname) | ||
| 124 | local nozip = pathname:match("(.*)%.zip$") | ||
| 125 | if not from_cache then | ||
| 126 | local dirname = dir.dir_name(pathname) | ||
| 127 | fs.change_dir(dirname) | ||
| 128 | fs.delete(nozip) | ||
| 129 | local ok, err = fs.unzip(pathname) | ||
| 130 | fs.pop_dir() | ||
| 131 | if not ok then | ||
| 132 | fs.delete(pathname) | ||
| 133 | fs.delete(pathname..".timestamp") | ||
| 134 | return nil, "Failed extracting manifest file: " .. err | ||
| 135 | end | ||
| 136 | end | ||
| 137 | pathname = nozip | ||
| 138 | end | ||
| 139 | local manifest, err, errcode = core.manifest_loader(pathname, repo_url, lua_version) | ||
| 140 | if not manifest and err is string then --! | ||
| 141 | return nil, err, errcode | ||
| 142 | end | ||
| 143 | |||
| 144 | postprocess_dependencies(manifest) | ||
| 145 | return check_manifest(repo_url, manifest, err) | ||
| 146 | end | ||
| 147 | |||
| 148 | --- Get type and name of an item (a module or a command) provided by a file. | ||
| 149 | -- @param deploy_type string: rock manifest subtree the file comes from ("bin", "lua", or "lib"). | ||
| 150 | -- @param file_path string: path to the file relatively to deploy_type subdirectory. | ||
| 151 | -- @return (string, string): item type ("module" or "command") and name. | ||
| 152 | function manif.get_provided_item(deploy_type: string, file_path: string): string, string | ||
| 153 | local item_type = deploy_type == "bin" and "command" or "module" | ||
| 154 | local item_name = item_type == "command" and file_path or path.path_to_module(file_path) | ||
| 155 | return item_type, item_name | ||
| 156 | end | ||
| 157 | |||
| 158 | local function get_providers(item_type: string, item_name: string, repo: string | Tree) | ||
| 159 | local rocks_dir = path.rocks_dir(repo or cfg.root_dir) | ||
| 160 | local manifest = manif.load_manifest(rocks_dir) | ||
| 161 | return manifest and manifest[item_type .. "s"][item_name] | ||
| 162 | end | ||
| 163 | |||
| 164 | --- Given a name of a module or a command, figure out which rock name and version | ||
| 165 | -- correspond to it in the rock tree manifest. | ||
| 166 | -- @param item_type string: "module" or "command". | ||
| 167 | -- @param item_name string: module or command name. | ||
| 168 | -- @param root string or nil: A local root dir for a rocks tree. If not given, the default is used. | ||
| 169 | -- @return (string, string) or nil: name and version of the provider rock or nil if there | ||
| 170 | -- is no provider. | ||
| 171 | function manif.get_current_provider(item_type: string, item_name: string, repo: string | Tree): string | ||
| 172 | local providers = get_providers(item_type, item_name, repo) | ||
| 173 | if providers then | ||
| 174 | return providers[1]:match("([^/]*)/([^/]*)") | ||
| 175 | end | ||
| 176 | end | ||
| 177 | |||
| 178 | function manif.get_next_provider(item_type: string, item_name: string, repo: string | Tree): string | ||
| 179 | local providers = get_providers(item_type, item_name, repo) | ||
| 180 | if providers and providers[2] then | ||
| 181 | return providers[2]:match("([^/]*)/([^/]*)") | ||
| 182 | end | ||
| 183 | end | ||
| 184 | |||
| 185 | --- Get all versions of a package listed in a manifest file. | ||
| 186 | -- @param name string: a package name. | ||
| 187 | -- @param deps_mode string: "one", to use only the currently | ||
| 188 | -- configured tree; "order" to select trees based on order | ||
| 189 | -- (use the current tree and all trees below it on the list) | ||
| 190 | -- or "all", to use all trees. | ||
| 191 | -- @return table: An array of strings listing installed | ||
| 192 | -- versions of a package, and a table indicating where they are found. | ||
| 193 | function manif.get_versions(dep, deps_mode: string): {string}, {string: string | Tree} | ||
| 194 | -- assert(type(dep) == "table") --! | ||
| 195 | |||
| 196 | local name: string = dep.name | ||
| 197 | local namespace: string = dep.namespace | ||
| 198 | |||
| 199 | local version_set = {} | ||
| 200 | path.map_trees(deps_mode, function(tree) | ||
| 201 | local manifest = manif.load_manifest(path.rocks_dir(tree)) | ||
| 202 | |||
| 203 | if manifest and manifest.repository[name] then | ||
| 204 | for version in pairs(manifest.repository[name]) do | ||
| 205 | if dep.namespace then | ||
| 206 | local ns_file = path.rock_namespace_file(name, version, tree) | ||
| 207 | local fd = io.open(ns_file, "r") | ||
| 208 | if fd then | ||
| 209 | local ns = fd:read("*a") | ||
| 210 | fd:close() | ||
| 211 | if ns == namespace then | ||
| 212 | version_set[version] = tree | ||
| 213 | end | ||
| 214 | end | ||
| 215 | else | ||
| 216 | version_set[version] = tree | ||
| 217 | end | ||
| 218 | end | ||
| 219 | end | ||
| 220 | end) | ||
| 221 | |||
| 222 | return util.keys(version_set), version_set | ||
| 223 | end | ||
| 224 | |||
| 225 | return manif | ||
