diff options
| author | V1K1NGbg <victor@ilchev.com> | 2024-08-04 20:32:46 +0300 |
|---|---|---|
| committer | V1K1NGbg <victor@ilchev.com> | 2024-08-05 20:51:31 +0300 |
| commit | a6cf146b49aa70e13bf00c2c06e2dd805fb209f4 (patch) | |
| tree | ab18c1a29c83b53ee2c3f74b4b6d302443305e6e /src | |
| parent | 0bc3de49cad9697e101535c1b83c86a55b3731b4 (diff) | |
| download | luarocks-a6cf146b49aa70e13bf00c2c06e2dd805fb209f4.tar.gz luarocks-a6cf146b49aa70e13bf00c2c06e2dd805fb209f4.tar.bz2 luarocks-a6cf146b49aa70e13bf00c2c06e2dd805fb209f4.zip | |
almost finished rockspecs and started fetch
Diffstat (limited to 'src')
| -rw-r--r-- | src/luarocks/core/cfg.d.tl | 123 | ||||
| -rw-r--r-- | src/luarocks/fetch.tl | 610 | ||||
| -rw-r--r-- | src/luarocks/fs.d.tl | 3 | ||||
| -rw-r--r-- | src/luarocks/path.tl | 10 | ||||
| -rw-r--r-- | src/luarocks/rockspecs.tl | 186 |
5 files changed, 908 insertions, 24 deletions
diff --git a/src/luarocks/core/cfg.d.tl b/src/luarocks/core/cfg.d.tl index 26aec8d9..722f1020 100644 --- a/src/luarocks/core/cfg.d.tl +++ b/src/luarocks/core/cfg.d.tl | |||
| @@ -8,6 +8,7 @@ local record cfg | |||
| 8 | rocks_subdir: string | 8 | rocks_subdir: string |
| 9 | lua_modules_path: string | 9 | lua_modules_path: string |
| 10 | lib_modules_path: string | 10 | lib_modules_path: string |
| 11 | aggressive_cache: boolean | ||
| 11 | rocks_trees: {string| Tree} | 12 | rocks_trees: {string| Tree} |
| 12 | lua_version: string | 13 | lua_version: string |
| 13 | deps_mode: string | 14 | deps_mode: string |
| @@ -15,6 +16,7 @@ local record cfg | |||
| 15 | deploy_lua_dir: string | 16 | deploy_lua_dir: string |
| 16 | deploy_lib_dir: string | 17 | deploy_lib_dir: string |
| 17 | lib_extension: string | 18 | lib_extension: string |
| 19 | local_cache: string | ||
| 18 | record Tree | 20 | record Tree |
| 19 | root: string | 21 | root: string |
| 20 | rocks_dir: string | 22 | rocks_dir: string |
| @@ -29,30 +31,116 @@ local record cfg | |||
| 29 | issues_url: string | 31 | issues_url: string |
| 30 | maintainer: string | 32 | maintainer: string |
| 31 | license: string | 33 | license: string |
| 34 | labels: any --! | ||
| 35 | end | ||
| 36 | |||
| 37 | record Variables | ||
| 38 | CVS: string | ||
| 39 | LUA: string | ||
| 40 | GPG: string | ||
| 41 | CURL: string | ||
| 42 | PREFIX: string | ||
| 43 | LUADIR: string | ||
| 44 | LIBDIR: string | ||
| 45 | CONFDIR: string | ||
| 46 | BINDIR: string | ||
| 47 | DOCDIR: string | ||
| 48 | CURLNOCERTFLAG: string | ||
| 49 | end | ||
| 50 | |||
| 51 | record Source | ||
| 52 | url: string | ||
| 53 | module: string | ||
| 54 | pathname: string | ||
| 55 | tag: string | ||
| 56 | md5: string | ||
| 57 | file: string | ||
| 58 | dir: string | ||
| 59 | branch: string | ||
| 60 | cvs_tag: string | ||
| 61 | cvs_module: string | ||
| 62 | protocol: string --! not in the rockspec definition but used | ||
| 63 | dir_set: boolean | ||
| 64 | platforms: any --! | ||
| 32 | end | 65 | end |
| 33 | 66 | ||
| 34 | record Test | 67 | record Test |
| 35 | type: string | 68 | type: string |
| 36 | platforms: {{string: any}} | 69 | platforms: any --! {{string: any}}? |
| 70 | end | ||
| 71 | |||
| 72 | record Install | ||
| 73 | lua: any | ||
| 74 | lib: any | ||
| 75 | conf: any | ||
| 76 | bin: any | ||
| 77 | end | ||
| 78 | |||
| 79 | record Build | ||
| 80 | type: string | ||
| 81 | modules: string | ||
| 82 | copy_directories: string | ||
| 83 | platforms: any --! | ||
| 84 | install: Install | ||
| 85 | end | ||
| 86 | |||
| 87 | record Dependencie --!1 --? Query?? | ||
| 88 | |||
| 89 | end | ||
| 90 | |||
| 91 | record Dependencies | ||
| 92 | {Dependencie} --!1 | ||
| 93 | platforms: any --! | ||
| 94 | end | ||
| 95 | |||
| 96 | record BuildDependencies | ||
| 97 | {Dependencie} --!1 | ||
| 98 | platforms: any --! | ||
| 99 | end | ||
| 100 | |||
| 101 | record SupportedPlatforms | ||
| 102 | end | ||
| 103 | |||
| 104 | record ExternalDependencies | ||
| 105 | {Dependencie} --!1 | ||
| 106 | platforms: any --! | ||
| 107 | end | ||
| 108 | |||
| 109 | record TestDependencies | ||
| 110 | {Dependencie} --!1 | ||
| 111 | platforms: any --! | ||
| 112 | end | ||
| 113 | |||
| 114 | record Hooks | ||
| 115 | post_install: string | ||
| 116 | platforms: any --! | ||
| 37 | end | 117 | end |
| 38 | 118 | ||
| 39 | record Rockspec --? luarocks-dev-1.rockspec | 119 | record Deploy |
| 120 | wrap_bin_scripts: boolean | ||
| 121 | end | ||
| 122 | |||
| 123 | record Rockspec | ||
| 40 | rockspec_format: string | 124 | rockspec_format: string |
| 41 | name: string --? package | 125 | name: string --! not in the rockspec definition but used |
| 126 | package: string | ||
| 42 | version: string | 127 | version: string |
| 43 | record source | 128 | local_abs_filename: string |
| 44 | url: string | 129 | rocks_provided: {string : string} |
| 45 | module: string | 130 | source: Source |
| 46 | pathname: string | ||
| 47 | tag: string | ||
| 48 | end | ||
| 49 | description: Description | 131 | description: Description |
| 50 | test_dependencies: {string} | 132 | build: Build |
| 133 | dependencies: Dependencies | ||
| 134 | build_dependencies: BuildDependencies | ||
| 135 | test_dependencies: TestDependencies | ||
| 136 | supported_platforms: SupportedPlatforms | ||
| 137 | external_dependencies: ExternalDependencies | ||
| 138 | variables: Variables | ||
| 139 | hooks: Hooks | ||
| 51 | test: Test | 140 | test: Test |
| 141 | deploy: Deploy | ||
| 142 | type: function(): string | ||
| 52 | format_is_at_least: function(Rockspec, string): boolean | 143 | format_is_at_least: function(Rockspec, string): boolean |
| 53 | record variables | ||
| 54 | CVS: string | ||
| 55 | end | ||
| 56 | end | 144 | end |
| 57 | 145 | ||
| 58 | record cache | 146 | record cache |
| @@ -61,12 +149,7 @@ local record cfg | |||
| 61 | rocks_provided: {string: string} --? right type? infered from src/luarocks/util | 149 | rocks_provided: {string: string} --? right type? infered from src/luarocks/util |
| 62 | end | 150 | end |
| 63 | 151 | ||
| 64 | record variables | 152 | variables: Variables |
| 65 | LUA: string | ||
| 66 | GPG: string | ||
| 67 | CURL: string | ||
| 68 | CURLNOCERTFLAG: string | ||
| 69 | end | ||
| 70 | rocks_provided: {Rockspec} | 153 | rocks_provided: {Rockspec} |
| 71 | -- persist | 154 | -- persist |
| 72 | home: string | 155 | home: string |
| @@ -92,6 +175,8 @@ local record cfg | |||
| 92 | -- loader | 175 | -- loader |
| 93 | init: function(): boolean, string, string | 176 | init: function(): boolean, string, string |
| 94 | init_package_paths: function | 177 | init_package_paths: function |
| 178 | -- rockspecs | ||
| 179 | each_platform: function(?string): (function():string) | ||
| 95 | end | 180 | end |
| 96 | 181 | ||
| 97 | return cfg \ No newline at end of file | 182 | return cfg \ No newline at end of file |
diff --git a/src/luarocks/fetch.tl b/src/luarocks/fetch.tl new file mode 100644 index 00000000..798fc3b7 --- /dev/null +++ b/src/luarocks/fetch.tl | |||
| @@ -0,0 +1,610 @@ | |||
| 1 | |||
| 2 | --- Functions related to fetching and loading local and remote files. | ||
| 3 | local fetch = {} | ||
| 4 | |||
| 5 | local fs = require("luarocks.fs") | ||
| 6 | local dir = require("luarocks.dir") | ||
| 7 | local rockspecs = require("luarocks.rockspecs") | ||
| 8 | local signing = require("luarocks.signing") | ||
| 9 | local persist = require("luarocks.persist") | ||
| 10 | local util = require("luarocks.util") | ||
| 11 | local cfg = require("luarocks.core.cfg") | ||
| 12 | |||
| 13 | |||
| 14 | --- Fetch a local or remote file, using a local cache directory. | ||
| 15 | -- Make a remote or local URL/pathname local, fetching the file if necessary. | ||
| 16 | -- Other "fetch" and "load" functions use this function to obtain files. | ||
| 17 | -- If a local pathname is given, it is returned as a result. | ||
| 18 | -- @param url string: a local pathname or a remote URL. | ||
| 19 | -- @param mirroring string: mirroring mode. | ||
| 20 | -- If set to "no_mirror", then rocks_servers mirror configuration is not used. | ||
| 21 | -- @return (string, nil, nil, boolean) or (nil, string, [string]): | ||
| 22 | -- in case of success: | ||
| 23 | -- * the absolute local pathname for the fetched file | ||
| 24 | -- * nil | ||
| 25 | -- * nil | ||
| 26 | -- * `true` if the file was fetched from cache | ||
| 27 | -- in case of failure: | ||
| 28 | -- * nil | ||
| 29 | -- * an error message | ||
| 30 | -- * an optional error code. | ||
| 31 | function fetch.fetch_caching(url: string, mirroring: string): string, string, string, boolean | ||
| 32 | local repo_url, filename = url:match("^(.*)/([^/]+)$") | ||
| 33 | local name = repo_url:gsub("[/:]","_") | ||
| 34 | local cache_dir = dir.path(cfg.local_cache, name) | ||
| 35 | local ok = fs.make_dir(cache_dir) | ||
| 36 | |||
| 37 | local cachefile = dir.path(cache_dir, filename) | ||
| 38 | local checkfile = cachefile .. ".check" | ||
| 39 | |||
| 40 | if (fs.file_age(checkfile) < 10 or | ||
| 41 | cfg.aggressive_cache and (not name:match("^manifest"))) and fs.exists(cachefile) | ||
| 42 | then | ||
| 43 | return cachefile, nil, nil, true | ||
| 44 | end | ||
| 45 | |||
| 46 | local lock, errlock | ||
| 47 | if ok then | ||
| 48 | lock, errlock = fs.lock_access(cache_dir) | ||
| 49 | end | ||
| 50 | |||
| 51 | if not (ok and lock) then | ||
| 52 | cfg.local_cache = fs.make_temp_dir("local_cache") | ||
| 53 | if not cfg.local_cache then | ||
| 54 | return nil, "Failed creating temporary local_cache directory" | ||
| 55 | end | ||
| 56 | cache_dir = dir.path(cfg.local_cache, name) | ||
| 57 | ok = fs.make_dir(cache_dir) | ||
| 58 | if not ok then | ||
| 59 | return nil, "Failed creating temporary cache directory "..cache_dir | ||
| 60 | end | ||
| 61 | lock = fs.lock_access(cache_dir) | ||
| 62 | end | ||
| 63 | |||
| 64 | local file, err, errcode, from_cache = fetch.fetch_url(url, cachefile, true, mirroring) | ||
| 65 | if not file then | ||
| 66 | fs.unlock_access(lock) | ||
| 67 | return nil, err or "Failed downloading "..url, errcode | ||
| 68 | end | ||
| 69 | |||
| 70 | local fd, err = io.open(checkfile, "wb") | ||
| 71 | if err then | ||
| 72 | fs.unlock_access(lock) | ||
| 73 | return nil, err | ||
| 74 | end | ||
| 75 | fd:write("!") | ||
| 76 | fd:close() | ||
| 77 | |||
| 78 | fs.unlock_access(lock) | ||
| 79 | return file, nil, nil, from_cache | ||
| 80 | end | ||
| 81 | |||
| 82 | local function ensure_trailing_slash(url) | ||
| 83 | return (url:gsub("/*$", "/")) | ||
| 84 | end | ||
| 85 | |||
| 86 | local function is_url_relative_to_rocks_servers(url, servers) | ||
| 87 | for _, item in ipairs(servers) do | ||
| 88 | if type(item) == "table" then | ||
| 89 | for i, s in ipairs(item) do | ||
| 90 | local base = ensure_trailing_slash(s) | ||
| 91 | if string.find(url, base, 1, true) == 1 then | ||
| 92 | return i, url:sub(#base + 1), item | ||
| 93 | end | ||
| 94 | end | ||
| 95 | end | ||
| 96 | end | ||
| 97 | end | ||
| 98 | |||
| 99 | local function download_with_mirrors(url, filename, cache, servers) | ||
| 100 | local idx, rest, mirrors = is_url_relative_to_rocks_servers(url, servers) | ||
| 101 | |||
| 102 | if not idx then | ||
| 103 | -- URL is not from a rock server | ||
| 104 | return fs.download(url, filename, cache) | ||
| 105 | end | ||
| 106 | |||
| 107 | -- URL is from a rock server: try to download it falling back to mirrors. | ||
| 108 | local err = "\n" | ||
| 109 | for i = idx, #mirrors do | ||
| 110 | local try_url = ensure_trailing_slash(mirrors[i]) .. rest | ||
| 111 | if i > idx then | ||
| 112 | util.warning("Failed downloading. Attempting mirror at " .. try_url) | ||
| 113 | end | ||
| 114 | local ok, name, from_cache = fs.download(try_url, filename, cache) | ||
| 115 | if ok then | ||
| 116 | return ok, name, from_cache | ||
| 117 | else | ||
| 118 | err = err .. name .. "\n" | ||
| 119 | end | ||
| 120 | end | ||
| 121 | |||
| 122 | return nil, err, "network" | ||
| 123 | end | ||
| 124 | |||
| 125 | --- Fetch a local or remote file. | ||
| 126 | -- Make a remote or local URL/pathname local, fetching the file if necessary. | ||
| 127 | -- Other "fetch" and "load" functions use this function to obtain files. | ||
| 128 | -- If a local pathname is given, it is returned as a result. | ||
| 129 | -- @param url string: a local pathname or a remote URL. | ||
| 130 | -- @param filename string or nil: this function attempts to detect the | ||
| 131 | -- resulting local filename of the remote file as the basename of the URL; | ||
| 132 | -- if that is not correct (due to a redirection, for example), the local | ||
| 133 | -- filename can be given explicitly as this second argument. | ||
| 134 | -- @param cache boolean: compare remote timestamps via HTTP HEAD prior to | ||
| 135 | -- re-downloading the file. | ||
| 136 | -- @param mirroring string: mirroring mode. | ||
| 137 | -- If set to "no_mirror", then rocks_servers mirror configuration is not used. | ||
| 138 | -- @return (string, nil, nil, boolean) or (nil, string, [string]): | ||
| 139 | -- in case of success: | ||
| 140 | -- * the absolute local pathname for the fetched file | ||
| 141 | -- * nil | ||
| 142 | -- * nil | ||
| 143 | -- * `true` if the file was fetched from cache | ||
| 144 | -- in case of failure: | ||
| 145 | -- * nil | ||
| 146 | -- * an error message | ||
| 147 | -- * an optional error code. | ||
| 148 | function fetch.fetch_url(url, filename, cache, mirroring) | ||
| 149 | assert(type(url) == "string") | ||
| 150 | assert(type(filename) == "string" or not filename) | ||
| 151 | |||
| 152 | local protocol, pathname = dir.split_url(url) | ||
| 153 | if protocol == "file" then | ||
| 154 | local fullname = fs.absolute_name(pathname) | ||
| 155 | if not fs.exists(fullname) then | ||
| 156 | local hint = (not pathname:match("^/")) | ||
| 157 | and (" - note that given path in rockspec is not absolute: " .. url) | ||
| 158 | or "" | ||
| 159 | return nil, "Local file not found: " .. fullname .. hint | ||
| 160 | end | ||
| 161 | filename = filename or dir.base_name(pathname) | ||
| 162 | local dstname = fs.absolute_name(dir.path(".", filename)) | ||
| 163 | local ok, err | ||
| 164 | if fullname == dstname then | ||
| 165 | ok = true | ||
| 166 | else | ||
| 167 | ok, err = fs.copy(fullname, dstname) | ||
| 168 | end | ||
| 169 | if ok then | ||
| 170 | return dstname | ||
| 171 | else | ||
| 172 | return nil, "Failed copying local file " .. fullname .. " to " .. dstname .. ": " .. err | ||
| 173 | end | ||
| 174 | elseif dir.is_basic_protocol(protocol) then | ||
| 175 | local ok, name, from_cache | ||
| 176 | if mirroring ~= "no_mirror" then | ||
| 177 | ok, name, from_cache = download_with_mirrors(url, filename, cache, cfg.rocks_servers) | ||
| 178 | else | ||
| 179 | ok, name, from_cache = fs.download(url, filename, cache) | ||
| 180 | end | ||
| 181 | if not ok then | ||
| 182 | return nil, "Failed downloading "..url..(name and " - "..name or ""), from_cache | ||
| 183 | end | ||
| 184 | return name, nil, nil, from_cache | ||
| 185 | else | ||
| 186 | return nil, "Unsupported protocol "..protocol | ||
| 187 | end | ||
| 188 | end | ||
| 189 | |||
| 190 | --- For remote URLs, create a temporary directory and download URL inside it. | ||
| 191 | -- This temporary directory will be deleted on program termination. | ||
| 192 | -- For local URLs, just return the local pathname and its directory. | ||
| 193 | -- @param url string: URL to be downloaded | ||
| 194 | -- @param tmpname string: name pattern to use for avoiding conflicts | ||
| 195 | -- when creating temporary directory. | ||
| 196 | -- @param filename string or nil: local filename of URL to be downloaded, | ||
| 197 | -- in case it can't be inferred from the URL. | ||
| 198 | -- @return (string, string) or (nil, string, [string]): absolute local pathname of | ||
| 199 | -- the fetched file and temporary directory name; or nil and an error message | ||
| 200 | -- followed by an optional error code | ||
| 201 | function fetch.fetch_url_at_temp_dir(url, tmpname, filename, cache) | ||
| 202 | assert(type(url) == "string") | ||
| 203 | assert(type(tmpname) == "string") | ||
| 204 | assert(type(filename) == "string" or not filename) | ||
| 205 | filename = filename or dir.base_name(url) | ||
| 206 | |||
| 207 | local protocol, pathname = dir.split_url(url) | ||
| 208 | if protocol == "file" then | ||
| 209 | if fs.exists(pathname) then | ||
| 210 | return pathname, dir.dir_name(fs.absolute_name(pathname)) | ||
| 211 | else | ||
| 212 | return nil, "File not found: "..pathname | ||
| 213 | end | ||
| 214 | else | ||
| 215 | local temp_dir, err = fs.make_temp_dir(tmpname) | ||
| 216 | if not temp_dir then | ||
| 217 | return nil, "Failed creating temporary directory "..tmpname..": "..err | ||
| 218 | end | ||
| 219 | util.schedule_function(fs.delete, temp_dir) | ||
| 220 | local ok, err = fs.change_dir(temp_dir) | ||
| 221 | if not ok then return nil, err end | ||
| 222 | |||
| 223 | local file, err, errcode | ||
| 224 | |||
| 225 | if cache then | ||
| 226 | local cachefile | ||
| 227 | cachefile, err, errcode = fetch.fetch_caching(url) | ||
| 228 | |||
| 229 | if cachefile then | ||
| 230 | file = dir.path(temp_dir, filename) | ||
| 231 | fs.copy(cachefile, file) | ||
| 232 | end | ||
| 233 | end | ||
| 234 | |||
| 235 | if not file then | ||
| 236 | file, err, errcode = fetch.fetch_url(url, filename, cache) | ||
| 237 | end | ||
| 238 | |||
| 239 | fs.pop_dir() | ||
| 240 | if not file then | ||
| 241 | return nil, "Error fetching file: "..err, errcode | ||
| 242 | end | ||
| 243 | |||
| 244 | return file, temp_dir | ||
| 245 | end | ||
| 246 | end | ||
| 247 | |||
| 248 | -- Determine base directory of a fetched URL by extracting its | ||
| 249 | -- archive and looking for a directory in the root. | ||
| 250 | -- @param file string: absolute local pathname of the fetched file | ||
| 251 | -- @param temp_dir string: temporary directory in which URL was fetched. | ||
| 252 | -- @param src_url string: URL to use when inferring base directory. | ||
| 253 | -- @param src_dir string or nil: expected base directory (inferred | ||
| 254 | -- from src_url if not given). | ||
| 255 | -- @return (string, string) or (string, nil) or (nil, string): | ||
| 256 | -- The inferred base directory and the one actually found (which may | ||
| 257 | -- be nil if not found), or nil followed by an error message. | ||
| 258 | -- The inferred dir is returned first to avoid confusion with errors, | ||
| 259 | -- because it is never nil. | ||
| 260 | function fetch.find_base_dir(file, temp_dir, src_url, src_dir) | ||
| 261 | local ok, err = fs.change_dir(temp_dir) | ||
| 262 | if not ok then return nil, err end | ||
| 263 | fs.unpack_archive(file) | ||
| 264 | |||
| 265 | if not src_dir then | ||
| 266 | local rockspec = { | ||
| 267 | source = { | ||
| 268 | file = file, | ||
| 269 | dir = src_dir, | ||
| 270 | url = src_url, | ||
| 271 | } | ||
| 272 | } | ||
| 273 | ok, err = fetch.find_rockspec_source_dir(rockspec, ".") | ||
| 274 | if ok then | ||
| 275 | src_dir = rockspec.source.dir | ||
| 276 | end | ||
| 277 | end | ||
| 278 | |||
| 279 | local inferred_dir = src_dir or dir.deduce_base_dir(src_url) | ||
| 280 | local found_dir = nil | ||
| 281 | if fs.exists(inferred_dir) then | ||
| 282 | found_dir = inferred_dir | ||
| 283 | else | ||
| 284 | util.printerr("Directory "..inferred_dir.." not found") | ||
| 285 | local files = fs.list_dir() | ||
| 286 | if files then | ||
| 287 | table.sort(files) | ||
| 288 | for i,filename in ipairs(files) do | ||
| 289 | if fs.is_dir(filename) then | ||
| 290 | util.printerr("Found "..filename) | ||
| 291 | found_dir = filename | ||
| 292 | break | ||
| 293 | end | ||
| 294 | end | ||
| 295 | end | ||
| 296 | end | ||
| 297 | fs.pop_dir() | ||
| 298 | return inferred_dir, found_dir | ||
| 299 | end | ||
| 300 | |||
| 301 | local function fetch_and_verify_signature_for(url, filename, tmpdir) | ||
| 302 | local sig_url = signing.signature_url(url) | ||
| 303 | local sig_file, err, errcode = fetch.fetch_url_at_temp_dir(sig_url, tmpdir) | ||
| 304 | if not sig_file then | ||
| 305 | return nil, "Could not fetch signature file for verification: " .. err, errcode | ||
| 306 | end | ||
| 307 | |||
| 308 | local ok, err = signing.verify_signature(filename, sig_file) | ||
| 309 | if not ok then | ||
| 310 | return nil, "Failed signature verification: " .. err | ||
| 311 | end | ||
| 312 | |||
| 313 | return fs.absolute_name(sig_file) | ||
| 314 | end | ||
| 315 | |||
| 316 | --- Obtain a rock and unpack it. | ||
| 317 | -- If a directory is not given, a temporary directory will be created, | ||
| 318 | -- which will be deleted on program termination. | ||
| 319 | -- @param rock_file string: URL or filename of the rock. | ||
| 320 | -- @param dest string or nil: if given, directory will be used as | ||
| 321 | -- a permanent destination. | ||
| 322 | -- @param verify boolean: if true, download and verify signature for rockspec | ||
| 323 | -- @return string or (nil, string, [string]): the directory containing the contents | ||
| 324 | -- of the unpacked rock. | ||
| 325 | function fetch.fetch_and_unpack_rock(url, dest, verify) | ||
| 326 | assert(type(url) == "string") | ||
| 327 | assert(type(dest) == "string" or not dest) | ||
| 328 | |||
| 329 | local name = dir.base_name(url):match("(.*)%.[^.]*%.rock") | ||
| 330 | local tmpname = "luarocks-rock-" .. name | ||
| 331 | |||
| 332 | local rock_file, err, errcode = fetch.fetch_url_at_temp_dir(url, tmpname, nil, true) | ||
| 333 | if not rock_file then | ||
| 334 | return nil, "Could not fetch rock file: " .. err, errcode | ||
| 335 | end | ||
| 336 | |||
| 337 | local sig_file | ||
| 338 | if verify then | ||
| 339 | sig_file, err = fetch_and_verify_signature_for(url, rock_file, tmpname) | ||
| 340 | if err then | ||
| 341 | return nil, err | ||
| 342 | end | ||
| 343 | end | ||
| 344 | |||
| 345 | rock_file = fs.absolute_name(rock_file) | ||
| 346 | |||
| 347 | local unpack_dir | ||
| 348 | if dest then | ||
| 349 | unpack_dir = dest | ||
| 350 | local ok, err = fs.make_dir(unpack_dir) | ||
| 351 | if not ok then | ||
| 352 | return nil, "Failed unpacking rock file: " .. err | ||
| 353 | end | ||
| 354 | else | ||
| 355 | unpack_dir, err = fs.make_temp_dir(name) | ||
| 356 | if not unpack_dir then | ||
| 357 | return nil, "Failed creating temporary dir: " .. err | ||
| 358 | end | ||
| 359 | end | ||
| 360 | if not dest then | ||
| 361 | util.schedule_function(fs.delete, unpack_dir) | ||
| 362 | end | ||
| 363 | local ok, err = fs.change_dir(unpack_dir) | ||
| 364 | if not ok then return nil, err end | ||
| 365 | ok, err = fs.unzip(rock_file) | ||
| 366 | if not ok then | ||
| 367 | return nil, "Failed unpacking rock file: " .. rock_file .. ": " .. err | ||
| 368 | end | ||
| 369 | if sig_file then | ||
| 370 | ok, err = fs.copy(sig_file, ".") | ||
| 371 | if not ok then | ||
| 372 | return nil, "Failed copying signature file" | ||
| 373 | end | ||
| 374 | end | ||
| 375 | fs.pop_dir() | ||
| 376 | return unpack_dir | ||
| 377 | end | ||
| 378 | |||
| 379 | --- Back-end function that actually loads the local rockspec. | ||
| 380 | -- Performs some validation and postprocessing of the rockspec contents. | ||
| 381 | -- @param rel_filename string: The local filename of the rockspec file. | ||
| 382 | -- @param quick boolean: if true, skips some steps when loading | ||
| 383 | -- rockspec. | ||
| 384 | -- @return table or (nil, string): A table representing the rockspec | ||
| 385 | -- or nil followed by an error message. | ||
| 386 | function fetch.load_local_rockspec(rel_filename, quick) | ||
| 387 | assert(type(rel_filename) == "string") | ||
| 388 | local abs_filename = fs.absolute_name(rel_filename) | ||
| 389 | |||
| 390 | local basename = dir.base_name(abs_filename) | ||
| 391 | if basename ~= "rockspec" then | ||
| 392 | if not basename:match("(.*)%-[^-]*%-[0-9]*") then | ||
| 393 | return nil, "Expected filename in format 'name-version-revision.rockspec'." | ||
| 394 | end | ||
| 395 | end | ||
| 396 | |||
| 397 | local tbl, err = persist.load_into_table(abs_filename) | ||
| 398 | if not tbl then | ||
| 399 | return nil, "Could not load rockspec file "..abs_filename.." ("..err..")" | ||
| 400 | end | ||
| 401 | |||
| 402 | local rockspec, err = rockspecs.from_persisted_table(abs_filename, tbl, err, quick) | ||
| 403 | if not rockspec then | ||
| 404 | return nil, abs_filename .. ": " .. err | ||
| 405 | end | ||
| 406 | |||
| 407 | local name_version = rockspec.package:lower() .. "-" .. rockspec.version | ||
| 408 | if basename ~= "rockspec" and basename ~= name_version .. ".rockspec" then | ||
| 409 | return nil, "Inconsistency between rockspec filename ("..basename..") and its contents ("..name_version..".rockspec)." | ||
| 410 | end | ||
| 411 | |||
| 412 | return rockspec | ||
| 413 | end | ||
| 414 | |||
| 415 | --- Load a local or remote rockspec into a table. | ||
| 416 | -- This is the entry point for the LuaRocks tools. | ||
| 417 | -- Only the LuaRocks runtime loader should use | ||
| 418 | -- load_local_rockspec directly. | ||
| 419 | -- @param filename string: Local or remote filename of a rockspec. | ||
| 420 | -- @param location string or nil: Where to download. If not given, | ||
| 421 | -- a temporary dir is created. | ||
| 422 | -- @param verify boolean: if true, download and verify signature for rockspec | ||
| 423 | -- @return table or (nil, string, [string]): A table representing the rockspec | ||
| 424 | -- or nil followed by an error message and optional error code. | ||
| 425 | function fetch.load_rockspec(url, location, verify) | ||
| 426 | assert(type(url) == "string") | ||
| 427 | |||
| 428 | local name | ||
| 429 | local basename = dir.base_name(url) | ||
| 430 | if basename == "rockspec" then | ||
| 431 | name = "rockspec" | ||
| 432 | else | ||
| 433 | name = basename:match("(.*)%.rockspec") | ||
| 434 | if not name then | ||
| 435 | return nil, "Filename '"..url.."' does not look like a rockspec." | ||
| 436 | end | ||
| 437 | end | ||
| 438 | |||
| 439 | local tmpname = "luarocks-rockspec-"..name | ||
| 440 | local filename, err, errcode | ||
| 441 | if location then | ||
| 442 | local ok, err = fs.change_dir(location) | ||
| 443 | if not ok then return nil, err end | ||
| 444 | filename, err = fetch.fetch_url(url) | ||
| 445 | fs.pop_dir() | ||
| 446 | else | ||
| 447 | filename, err, errcode = fetch.fetch_url_at_temp_dir(url, tmpname, nil, true) | ||
| 448 | end | ||
| 449 | if not filename then | ||
| 450 | return nil, err, errcode | ||
| 451 | end | ||
| 452 | |||
| 453 | if verify then | ||
| 454 | local _, err = fetch_and_verify_signature_for(url, filename, tmpname) | ||
| 455 | if err then | ||
| 456 | return nil, err | ||
| 457 | end | ||
| 458 | end | ||
| 459 | |||
| 460 | return fetch.load_local_rockspec(filename) | ||
| 461 | end | ||
| 462 | |||
| 463 | --- Download sources for building a rock using the basic URL downloader. | ||
| 464 | -- @param rockspec table: The rockspec table | ||
| 465 | -- @param extract boolean: Whether to extract the sources from | ||
| 466 | -- the fetched source tarball or not. | ||
| 467 | -- @param dest_dir string or nil: If set, will extract to the given directory; | ||
| 468 | -- if not given, will extract to a temporary directory. | ||
| 469 | -- @return (string, string) or (nil, string, [string]): The absolute pathname of | ||
| 470 | -- the fetched source tarball and the temporary directory created to | ||
| 471 | -- store it; or nil and an error message and optional error code. | ||
| 472 | function fetch.get_sources(rockspec, extract, dest_dir) | ||
| 473 | assert(rockspec:type() == "rockspec") | ||
| 474 | assert(type(extract) == "boolean") | ||
| 475 | assert(type(dest_dir) == "string" or not dest_dir) | ||
| 476 | |||
| 477 | local url = rockspec.source.url | ||
| 478 | local name = rockspec.name.."-"..rockspec.version | ||
| 479 | local filename = rockspec.source.file | ||
| 480 | local source_file, store_dir | ||
| 481 | local ok, err, errcode | ||
| 482 | if dest_dir then | ||
| 483 | ok, err = fs.change_dir(dest_dir) | ||
| 484 | if not ok then return nil, err, "dest_dir" end | ||
| 485 | source_file, err, errcode = fetch.fetch_url(url, filename) | ||
| 486 | fs.pop_dir() | ||
| 487 | store_dir = dest_dir | ||
| 488 | else | ||
| 489 | source_file, store_dir, errcode = fetch.fetch_url_at_temp_dir(url, "luarocks-source-"..name, filename) | ||
| 490 | end | ||
| 491 | if not source_file then | ||
| 492 | return nil, err or store_dir, errcode | ||
| 493 | end | ||
| 494 | if rockspec.source.md5 then | ||
| 495 | if not fs.check_md5(source_file, rockspec.source.md5) then | ||
| 496 | return nil, "MD5 check for "..filename.." has failed.", "md5" | ||
| 497 | end | ||
| 498 | end | ||
| 499 | if extract then | ||
| 500 | local ok, err = fs.change_dir(store_dir) | ||
| 501 | if not ok then return nil, err end | ||
| 502 | ok, err = fs.unpack_archive(rockspec.source.file) | ||
| 503 | if not ok then return nil, err end | ||
| 504 | ok, err = fetch.find_rockspec_source_dir(rockspec, ".") | ||
| 505 | if not ok then return nil, err end | ||
| 506 | fs.pop_dir() | ||
| 507 | end | ||
| 508 | return source_file, store_dir | ||
| 509 | end | ||
| 510 | |||
| 511 | function fetch.find_rockspec_source_dir(rockspec, store_dir) | ||
| 512 | local ok, err = fs.change_dir(store_dir) | ||
| 513 | if not ok then return nil, err end | ||
| 514 | |||
| 515 | local file_count, dir_count, found_dir = 0, 0, 0 | ||
| 516 | |||
| 517 | if rockspec.source.dir and fs.exists(rockspec.source.dir) then | ||
| 518 | ok, err = true, nil | ||
| 519 | elseif rockspec.source.file and rockspec.source.dir then | ||
| 520 | ok, err = nil, "Directory "..rockspec.source.dir.." not found inside archive "..rockspec.source.file | ||
| 521 | elseif not rockspec.source.dir_set then -- and rockspec:format_is_at_least("3.0") then | ||
| 522 | |||
| 523 | local name = dir.base_name(rockspec.source.file or rockspec.source.url or "") | ||
| 524 | |||
| 525 | if name:match("%.lua$") or name:match("%.c$") then | ||
| 526 | if fs.is_file(name) then | ||
| 527 | rockspec.source.dir = "." | ||
| 528 | ok, err = true, nil | ||
| 529 | end | ||
| 530 | end | ||
| 531 | |||
| 532 | if not rockspec.source.dir then | ||
| 533 | for file in fs.dir() do | ||
| 534 | file_count = file_count + 1 | ||
| 535 | if fs.is_dir(file) then | ||
| 536 | dir_count = dir_count + 1 | ||
| 537 | found_dir = file | ||
| 538 | end | ||
| 539 | end | ||
| 540 | |||
| 541 | if dir_count == 1 then | ||
| 542 | rockspec.source.dir = found_dir | ||
| 543 | ok, err = true, nil | ||
| 544 | else | ||
| 545 | ok, err = nil, "Could not determine source directory from rock contents (" .. tostring(file_count).." file(s), "..tostring(dir_count).." dir(s))" | ||
| 546 | end | ||
| 547 | end | ||
| 548 | else | ||
| 549 | ok, err = nil, "Could not determine source directory, please set source.dir in rockspec." | ||
| 550 | end | ||
| 551 | |||
| 552 | fs.pop_dir() | ||
| 553 | |||
| 554 | assert(rockspec.source.dir or not ok) | ||
| 555 | return ok, err | ||
| 556 | end | ||
| 557 | |||
| 558 | --- Download sources for building a rock, calling the appropriate protocol method. | ||
| 559 | -- @param rockspec table: The rockspec table | ||
| 560 | -- @param extract boolean: When downloading compressed formats, whether to extract | ||
| 561 | -- the sources from the fetched archive or not. | ||
| 562 | -- @param dest_dir string or nil: If set, will extract to the given directory. | ||
| 563 | -- if not given, will extract to a temporary directory. | ||
| 564 | -- @return (string, string) or (nil, string): The absolute pathname of | ||
| 565 | -- the fetched source tarball and the temporary directory created to | ||
| 566 | -- store it; or nil and an error message. | ||
| 567 | function fetch.fetch_sources(rockspec, extract, dest_dir) | ||
| 568 | assert(rockspec:type() == "rockspec") | ||
| 569 | assert(type(extract) == "boolean") | ||
| 570 | assert(type(dest_dir) == "string" or not dest_dir) | ||
| 571 | |||
| 572 | -- auto-convert git://github.com URLs to use git+https | ||
| 573 | -- see https://github.blog/2021-09-01-improving-git-protocol-security-github/ | ||
| 574 | if rockspec.source.url:match("^git://github%.com/") | ||
| 575 | or rockspec.source.url:match("^git://www%.github%.com/") then | ||
| 576 | rockspec.source.url = rockspec.source.url:gsub("^git://", "git+https://") | ||
| 577 | rockspec.source.protocol = "git+https" | ||
| 578 | end | ||
| 579 | |||
| 580 | local protocol = rockspec.source.protocol | ||
| 581 | local ok, err, proto | ||
| 582 | if dir.is_basic_protocol(protocol) then | ||
| 583 | proto = fetch | ||
| 584 | else | ||
| 585 | ok, proto = pcall(require, "luarocks.fetch."..protocol:gsub("[+-]", "_")) | ||
| 586 | if not ok then | ||
| 587 | return nil, "Unknown protocol "..protocol | ||
| 588 | end | ||
| 589 | end | ||
| 590 | |||
| 591 | if cfg.only_sources_from | ||
| 592 | and rockspec.source.pathname | ||
| 593 | and #rockspec.source.pathname > 0 then | ||
| 594 | if #cfg.only_sources_from == 0 then | ||
| 595 | return nil, "Can't download "..rockspec.source.url.." -- download from remote servers disabled" | ||
| 596 | elseif rockspec.source.pathname:find(cfg.only_sources_from, 1, true) ~= 1 then | ||
| 597 | return nil, "Can't download "..rockspec.source.url.." -- only downloading from "..cfg.only_sources_from | ||
| 598 | end | ||
| 599 | end | ||
| 600 | |||
| 601 | local source_file, store_dir = proto.get_sources(rockspec, extract, dest_dir) | ||
| 602 | if not source_file then return nil, store_dir end | ||
| 603 | |||
| 604 | ok, err = fetch.find_rockspec_source_dir(rockspec, store_dir) | ||
| 605 | if not ok then return nil, err, "source.dir", source_file, store_dir end | ||
| 606 | |||
| 607 | return source_file, store_dir | ||
| 608 | end | ||
| 609 | |||
| 610 | return fetch | ||
diff --git a/src/luarocks/fs.d.tl b/src/luarocks/fs.d.tl index bde6895a..3ea6d9ca 100644 --- a/src/luarocks/fs.d.tl +++ b/src/luarocks/fs.d.tl | |||
| @@ -35,6 +35,9 @@ local record fs | |||
| 35 | -- zip | 35 | -- zip |
| 36 | find: function(string): {string} | 36 | find: function(string): {string} |
| 37 | filter_file: function(function, string, string): boolean, string | 37 | filter_file: function(function, string, string): boolean, string |
| 38 | -- fetch | ||
| 39 | file_age: function(string): number | ||
| 40 | exists: function(string): boolean | ||
| 38 | end | 41 | end |
| 39 | 42 | ||
| 40 | return fs | 43 | return fs |
diff --git a/src/luarocks/path.tl b/src/luarocks/path.tl index 5682a2f7..f350f80c 100644 --- a/src/luarocks/path.tl +++ b/src/luarocks/path.tl | |||
| @@ -116,7 +116,7 @@ end | |||
| 116 | -- @param tree string or nil: If given, specifies the local tree to use. | 116 | -- @param tree string or nil: If given, specifies the local tree to use. |
| 117 | -- @return string: The resulting path -- does not guarantee that | 117 | -- @return string: The resulting path -- does not guarantee that |
| 118 | -- the package (and by extension, the path) exists. | 118 | -- the package (and by extension, the path) exists. |
| 119 | function path.lib_dir(name: string, version: string, tree: string | Tree): string | 119 | function path.lib_dir(name: string, version: string, tree?: string | Tree): string |
| 120 | assert(not name:match("/")) | 120 | assert(not name:match("/")) |
| 121 | return dir.path(path.rocks_dir(tree), name, version, "lib") | 121 | return dir.path(path.rocks_dir(tree), name, version, "lib") |
| 122 | end | 122 | end |
| @@ -127,7 +127,7 @@ end | |||
| 127 | -- @param tree string or nil: If given, specifies the local tree to use. | 127 | -- @param tree string or nil: If given, specifies the local tree to use. |
| 128 | -- @return string: The resulting path -- does not guarantee that | 128 | -- @return string: The resulting path -- does not guarantee that |
| 129 | -- the package (and by extension, the path) exists. | 129 | -- the package (and by extension, the path) exists. |
| 130 | function path.lua_dir(name: string, version: string, tree: string | Tree): string | 130 | function path.lua_dir(name: string, version: string, tree?: string | Tree): string |
| 131 | assert(not name:match("/")) | 131 | assert(not name:match("/")) |
| 132 | return dir.path(path.rocks_dir(tree), name, version, "lua") | 132 | return dir.path(path.rocks_dir(tree), name, version, "lua") |
| 133 | end | 133 | end |
| @@ -138,7 +138,7 @@ end | |||
| 138 | -- @param tree string or nil: If given, specifies the local tree to use. | 138 | -- @param tree string or nil: If given, specifies the local tree to use. |
| 139 | -- @return string: The resulting path -- does not guarantee that | 139 | -- @return string: The resulting path -- does not guarantee that |
| 140 | -- the package (and by extension, the path) exists. | 140 | -- the package (and by extension, the path) exists. |
| 141 | function path.doc_dir(name: string, version: string, tree: string | Tree): string | 141 | function path.doc_dir(name: string, version: string, tree?: string | Tree): string |
| 142 | assert(not name:match("/")) | 142 | assert(not name:match("/")) |
| 143 | return dir.path(path.rocks_dir(tree), name, version, "doc") | 143 | return dir.path(path.rocks_dir(tree), name, version, "doc") |
| 144 | end | 144 | end |
| @@ -149,7 +149,7 @@ end | |||
| 149 | -- @param tree string or nil: If given, specifies the local tree to use. | 149 | -- @param tree string or nil: If given, specifies the local tree to use. |
| 150 | -- @return string: The resulting path -- does not guarantee that | 150 | -- @return string: The resulting path -- does not guarantee that |
| 151 | -- the package (and by extension, the path) exists. | 151 | -- the package (and by extension, the path) exists. |
| 152 | function path.conf_dir(name: string, version: string, tree: string | Tree): string | 152 | function path.conf_dir(name: string, version: string, tree?: string | Tree): string |
| 153 | assert(not name:match("/")) | 153 | assert(not name:match("/")) |
| 154 | return dir.path(path.rocks_dir(tree), name, version, "conf") | 154 | return dir.path(path.rocks_dir(tree), name, version, "conf") |
| 155 | end | 155 | end |
| @@ -161,7 +161,7 @@ end | |||
| 161 | -- @param tree string or nil: If given, specifies the local tree to use. | 161 | -- @param tree string or nil: If given, specifies the local tree to use. |
| 162 | -- @return string: The resulting path -- does not guarantee that | 162 | -- @return string: The resulting path -- does not guarantee that |
| 163 | -- the package (and by extension, the path) exists. | 163 | -- the package (and by extension, the path) exists. |
| 164 | function path.bin_dir(name: string, version: string, tree: string | Tree): string | 164 | function path.bin_dir(name: string, version: string, tree?: string | Tree): string |
| 165 | assert(not name:match("/")) | 165 | assert(not name:match("/")) |
| 166 | return dir.path(path.rocks_dir(tree), name, version, "bin") | 166 | return dir.path(path.rocks_dir(tree), name, version, "bin") |
| 167 | end | 167 | end |
diff --git a/src/luarocks/rockspecs.tl b/src/luarocks/rockspecs.tl new file mode 100644 index 00000000..7d7835ae --- /dev/null +++ b/src/luarocks/rockspecs.tl | |||
| @@ -0,0 +1,186 @@ | |||
| 1 | local record rockspecs | ||
| 2 | end | ||
| 3 | |||
| 4 | local cfg = require("luarocks.core.cfg") | ||
| 5 | local dir = require("luarocks.dir") | ||
| 6 | local path = require("luarocks.path") | ||
| 7 | local queries = require("luarocks.queries") | ||
| 8 | local type_rockspec = require("luarocks.type.rockspec") | ||
| 9 | local util = require("luarocks.util") | ||
| 10 | local vers = require("luarocks.core.vers") | ||
| 11 | |||
| 12 | local type Rockspec = cfg.Rockspec | ||
| 13 | local type Variables = cfg.Variables | ||
| 14 | local type Dependencie = cfg.Dependencie | ||
| 15 | |||
| 16 | local vendored_build_type_set: {string: boolean} = { | ||
| 17 | ["builtin"] = true, | ||
| 18 | ["cmake"] = true, | ||
| 19 | ["command"] = true, | ||
| 20 | ["make"] = true, | ||
| 21 | ["module"] = true, -- compatibility alias | ||
| 22 | ["none"] = true, | ||
| 23 | } | ||
| 24 | |||
| 25 | local rockspec_mt: metatable<Rockspec> = {} | ||
| 26 | |||
| 27 | rockspec_mt.__index = cfg.Rockspec | ||
| 28 | |||
| 29 | function cfg.Rockspec.type(): string | ||
| 30 | return "rockspec" | ||
| 31 | end | ||
| 32 | |||
| 33 | --- Perform platform-specific overrides on a table. | ||
| 34 | -- Overrides values of table with the contents of the appropriate | ||
| 35 | -- subset of its "platforms" field. The "platforms" field should | ||
| 36 | -- be a table containing subtables keyed with strings representing | ||
| 37 | -- platform names. Names that match the contents of the global | ||
| 38 | -- detected platforms setting are used. For example, if | ||
| 39 | -- platform "unix" is detected, then the fields of | ||
| 40 | -- tbl.platforms.unix will overwrite those of tbl with the same | ||
| 41 | -- names. For table values, the operation is performed recursively | ||
| 42 | -- (tbl.platforms.foo.x.y.z overrides tbl.x.y.z; other contents of | ||
| 43 | -- tbl.x are preserved). | ||
| 44 | -- @param tbl table or nil: Table which may contain a "platforms" field; | ||
| 45 | -- if it doesn't (or if nil is passed), this function does nothing. | ||
| 46 | local function platform_overrides(tbl?: {any: any}) | ||
| 47 | |||
| 48 | if not tbl then return end | ||
| 49 | |||
| 50 | local tblp = tbl.platforms | ||
| 51 | |||
| 52 | if tblp is {any: any} then | ||
| 53 | for platform in cfg.each_platform() do | ||
| 54 | local platform_tbl = tblp[platform] | ||
| 55 | if platform_tbl is {any: any} then | ||
| 56 | util.deep_merge(tbl, platform_tbl) | ||
| 57 | end | ||
| 58 | end | ||
| 59 | end | ||
| 60 | tbl.platforms = nil | ||
| 61 | end | ||
| 62 | |||
| 63 | local function convert_dependencies(rockspec: {string: any}, key: string): boolean, string | ||
| 64 | local deps: {Dependencie} = rockspec[key] as {Dependencie} | ||
| 65 | if deps then | ||
| 66 | for i = 1, #deps do | ||
| 67 | local parsed, err = queries.from_dep_string(deps[i]) | ||
| 68 | if not parsed then | ||
| 69 | return nil, "Parse error processing dependency '"..deps[i].."': "..tostring(err) | ||
| 70 | end | ||
| 71 | deps[i] = parsed | ||
| 72 | end | ||
| 73 | else | ||
| 74 | deps = {} | ||
| 75 | end | ||
| 76 | return true | ||
| 77 | end | ||
| 78 | |||
| 79 | --- Set up path-related variables for a given rock. | ||
| 80 | -- Create a "variables" table in the rockspec table, containing | ||
| 81 | -- adjusted variables according to the configuration file. | ||
| 82 | -- @param rockspec table: The rockspec table. | ||
| 83 | local function configure_paths(rockspec: Rockspec) | ||
| 84 | local vars: {string: string} = {} | ||
| 85 | for k,v in pairs(cfg.variables as {string: string}) do | ||
| 86 | vars[k] = v | ||
| 87 | end | ||
| 88 | local name, version = rockspec.name, rockspec.version | ||
| 89 | vars.PREFIX = path.install_dir(name, version) | ||
| 90 | vars.LUADIR = path.lua_dir(name, version) | ||
| 91 | vars.LIBDIR = path.lib_dir(name, version) | ||
| 92 | vars.CONFDIR = path.conf_dir(name, version) | ||
| 93 | vars.BINDIR = path.bin_dir(name, version) | ||
| 94 | vars.DOCDIR = path.doc_dir(name, version) | ||
| 95 | rockspec.variables = vars as Variables | ||
| 96 | end | ||
| 97 | |||
| 98 | function rockspecs.from_persisted_table(filename: string, rockspec: Rockspec, globals?: {string: any}, quick?: boolean): Rockspec, string | ||
| 99 | |||
| 100 | if rockspec.rockspec_format then | ||
| 101 | if vers.compare_versions(rockspec.rockspec_format, type_rockspec.rockspec_format) then | ||
| 102 | return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks." | ||
| 103 | end | ||
| 104 | end | ||
| 105 | |||
| 106 | if not quick then | ||
| 107 | local ok, err = type_rockspec.check(rockspec as {any: any}, globals or {}) | ||
| 108 | if not ok then | ||
| 109 | return nil, err | ||
| 110 | end | ||
| 111 | end | ||
| 112 | |||
| 113 | --- Check if rockspec format version satisfies version requirement. | ||
| 114 | -- @param rockspec table: The rockspec table. | ||
| 115 | -- @param version string: required version. | ||
| 116 | -- @return boolean: true if rockspec format matches version or is newer, false otherwise. | ||
| 117 | do | ||
| 118 | local parsed_format = vers.parse_version(rockspec.rockspec_format or "1.0") | ||
| 119 | rockspec.format_is_at_least = function(self: Rockspec, version: string): boolean | ||
| 120 | return parsed_format >= vers.parse_version(version) | ||
| 121 | end | ||
| 122 | end | ||
| 123 | |||
| 124 | platform_overrides(rockspec.build as {any : any}) --! | ||
| 125 | platform_overrides(rockspec.dependencies as {any : any}) | ||
| 126 | platform_overrides(rockspec.build_dependencies as {any : any}) | ||
| 127 | platform_overrides(rockspec.test_dependencies as {any : any}) | ||
| 128 | platform_overrides(rockspec.external_dependencies as {any : any}) | ||
| 129 | platform_overrides(rockspec.source as {any : any}) | ||
| 130 | platform_overrides(rockspec.hooks as {any : any}) | ||
| 131 | platform_overrides(rockspec.test as {any : any}) | ||
| 132 | |||
| 133 | rockspec.name = rockspec.package:lower() | ||
| 134 | |||
| 135 | local protocol, pathname = dir.split_url(rockspec.source.url) | ||
| 136 | if dir.is_basic_protocol(protocol) then | ||
| 137 | rockspec.source.file = rockspec.source.file or dir.base_name(rockspec.source.url) | ||
| 138 | end | ||
| 139 | rockspec.source.protocol, rockspec.source.pathname = protocol, pathname | ||
| 140 | |||
| 141 | -- Temporary compatibility | ||
| 142 | if rockspec.source.cvs_module then rockspec.source.module = rockspec.source.cvs_module end | ||
| 143 | if rockspec.source.cvs_tag then rockspec.source.tag = rockspec.source.cvs_tag end | ||
| 144 | |||
| 145 | rockspec.local_abs_filename = filename | ||
| 146 | rockspec.source.dir_set = rockspec.source.dir ~= nil | ||
| 147 | rockspec.source.dir = rockspec.source.dir or rockspec.source.module | ||
| 148 | |||
| 149 | rockspec.rocks_provided = util.get_rocks_provided(rockspec) | ||
| 150 | |||
| 151 | for _, key in ipairs({"dependencies", "build_dependencies", "test_dependencies"}) do | ||
| 152 | local ok, err = convert_dependencies(rockspec, key) | ||
| 153 | if not ok then | ||
| 154 | return nil, err | ||
| 155 | end | ||
| 156 | end | ||
| 157 | |||
| 158 | if rockspec.build | ||
| 159 | and rockspec.build.type | ||
| 160 | and not vendored_build_type_set[rockspec.build.type] then | ||
| 161 | local build_pkg_name = "luarocks-build-" .. rockspec.build.type | ||
| 162 | if not rockspec.build_dependencies then | ||
| 163 | rockspec.build_dependencies = {} | ||
| 164 | end | ||
| 165 | |||
| 166 | local found = false | ||
| 167 | for _, dep in ipairs(rockspec.build_dependencies) do | ||
| 168 | if dep.name == build_pkg_name then | ||
| 169 | found = true | ||
| 170 | break | ||
| 171 | end | ||
| 172 | end | ||
| 173 | |||
| 174 | if not found then | ||
| 175 | table.insert(rockspec.build_dependencies, queries.from_dep_string(build_pkg_name)) | ||
| 176 | end | ||
| 177 | end | ||
| 178 | |||
| 179 | if not quick then | ||
| 180 | configure_paths(rockspec) | ||
| 181 | end | ||
| 182 | |||
| 183 | return setmetatable(rockspec, rockspec_mt) | ||
| 184 | end | ||
| 185 | |||
| 186 | return rockspecs | ||
