aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorV1K1NGbg <victor@ilchev.com>2024-08-05 14:19:05 +0300
committerV1K1NGbg <victor@ilchev.com>2024-08-05 20:51:31 +0300
commit515bce044a68283f460b37a08f4c6ec24ec98d53 (patch)
tree0cbc3420d368b7342de6151967d184a828457890
parent0e98fd4c368080ab4ce834b0d35ff11f989923d9 (diff)
downloadluarocks-515bce044a68283f460b37a08f4c6ec24ec98d53.tar.gz
luarocks-515bce044a68283f460b37a08f4c6ec24ec98d53.tar.bz2
luarocks-515bce044a68283f460b37a08f4c6ec24ec98d53.zip
manif
-rw-r--r--src/luarocks/core/cfg.d.tl1
-rw-r--r--src/luarocks/manif.tl225
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.
5local 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})
9end
10
11local core = require("luarocks.core.manif")
12local persist = require("luarocks.persist")
13local fetch = require("luarocks.fetch")
14local dir = require("luarocks.dir")
15local fs = require("luarocks.fs")
16local cfg = require("luarocks.core.cfg")
17local path = require("luarocks.path")
18local util = require("luarocks.util")
19local queries = require("luarocks.queries")
20local type_manifest = require("luarocks.type.manifest")
21
22local type Manifest = core.Manifest
23local type Tree_manifest = core.Tree_manifest
24local type Tree = cfg.Tree
25
26manif.cache_manifest = core.cache_manifest
27manif.load_rocks_tree_manifests = core.load_rocks_tree_manifests
28manif.scan_dependencies = core.scan_dependencies
29
30manif.rock_manifest_cache = {}
31
32local 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
39end
40
41local postprocess_dependencies: function(Manifest)
42do
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
59end
60
61function 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
75end
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.
86function 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)
146end
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.
152function 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
156end
157
158local 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]
162end
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.
171function 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
176end
177
178function 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
183end
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.
193function 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
223end
224
225return manif