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 | |
parent | 0e98fd4c368080ab4ce834b0d35ff11f989923d9 (diff) | |
download | luarocks-515bce044a68283f460b37a08f4c6ec24ec98d53.tar.gz luarocks-515bce044a68283f460b37a08f4c6ec24ec98d53.tar.bz2 luarocks-515bce044a68283f460b37a08f4c6ec24ec98d53.zip |
manif
-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 | ||