Mercurial > repo
view share/lua/5.2/luarocks/fetch.lua @ 12518:2d8fe55c6e65 draft default tip
<int-e> learn The password of the month is release incident pilot.
author | HackEso <hackeso@esolangs.org> |
---|---|
date | Sun, 03 Nov 2024 00:31:02 +0000 |
parents | d137f631bad5 |
children |
line wrap: on
line source
--- Functions related to fetching and loading local and remote files. module("luarocks.fetch", package.seeall) local fs = require("luarocks.fs") local dir = require("luarocks.dir") local type_check = require("luarocks.type_check") local path = require("luarocks.path") local deps = require("luarocks.deps") local persist = require("luarocks.persist") local util = require("luarocks.util") local cfg = require("luarocks.cfg") --- Fetch a local or remote file. -- Make a remote or local URL/pathname local, fetching the file if necessary. -- Other "fetch" and "load" functions use this function to obtain files. -- If a local pathname is given, it is returned as a result. -- @param url string: a local pathname or a remote URL. -- @param filename string or nil: this function attempts to detect the -- resulting local filename of the remote file as the basename of the URL; -- if that is not correct (due to a redirection, for example), the local -- filename can be given explicitly as this second argument. -- @return string or (nil, string, [string]): the absolute local pathname for the -- fetched file, or nil and a message in case of errors, followed by -- an optional error code. function fetch_url(url, filename) assert(type(url) == "string") assert(type(filename) == "string" or not filename) local protocol, pathname = dir.split_url(url) if protocol == "file" then return fs.absolute_name(pathname) elseif protocol == "http" or protocol == "ftp" or protocol == "https" then local ok, err = fs.download(url, filename) if not ok then return nil, "Failed downloading "..url..(err and " - "..err or ""), "network" end return dir.path(fs.current_dir(), filename or dir.base_name(url)) else return nil, "Unsupported protocol "..protocol end end --- For remote URLs, create a temporary directory and download URL inside it. -- This temporary directory will be deleted on program termination. -- For local URLs, just return the local pathname and its directory. -- @param url string: URL to be downloaded -- @param tmpname string: name pattern to use for avoiding conflicts -- when creating temporary directory. -- @param filename string or nil: local filename of URL to be downloaded, -- in case it can't be inferred from the URL. -- @return (string, string) or (nil, string, [string]): absolute local pathname of -- the fetched file and temporary directory name; or nil and an error message -- followed by an optional error code function fetch_url_at_temp_dir(url, tmpname, filename) assert(type(url) == "string") assert(type(tmpname) == "string") assert(type(filename) == "string" or not filename) filename = filename or dir.base_name(url) local protocol, pathname = dir.split_url(url) if protocol == "file" then if fs.exists(pathname) then return pathname, dir.dir_name(fs.absolute_name(pathname)) else return nil, "File not found: "..pathname end else local temp_dir = fs.make_temp_dir(tmpname) if not temp_dir then return nil, "Failed creating temporary directory." end util.schedule_function(fs.delete, temp_dir) fs.change_dir(temp_dir) local file, err, errcode = fetch_url(url, filename) fs.pop_dir() if not file then return nil, "Error fetching file: "..err, errcode end return file, temp_dir end end --- Obtain a rock and unpack it. -- If a directory is not given, a temporary directory will be created, -- which will be deleted on program termination. -- @param rock_file string: URL or filename of the rock. -- @param dest string or nil: if given, directory will be used as -- a permanent destination. -- @return string or (nil, string, [string]): the directory containing the contents -- of the unpacked rock. function fetch_and_unpack_rock(rock_file, dest) assert(type(rock_file) == "string") assert(type(dest) == "string" or not dest) local name = dir.base_name(rock_file):match("(.*)%.[^.]*%.rock") local rock_file, err, errcode = fetch_url_at_temp_dir(rock_file,"luarocks-rock-"..name) if not rock_file then return nil, "Could not fetch rock file: " .. err, errcode end rock_file = fs.absolute_name(rock_file) local unpack_dir if dest then unpack_dir = dest fs.make_dir(unpack_dir) else unpack_dir = fs.make_temp_dir(name) end if not dest then util.schedule_function(fs.delete, unpack_dir) end fs.change_dir(unpack_dir) local ok = fs.unzip(rock_file) if not ok then return nil, "Failed unpacking rock file: " .. rock_file end fs.pop_dir() return unpack_dir end --- Back-end function that actually loads the local rockspec. -- Performs some validation and postprocessing of the rockspec contents. -- @param filename string: The local filename of the rockspec file. -- @return table or (nil, string): A table representing the rockspec -- or nil followed by an error message. function load_local_rockspec(filename) assert(type(filename) == "string") filename = fs.absolute_name(filename) local rockspec, err = persist.load_into_table(filename) if not rockspec then return nil, "Could not load rockspec file "..filename.." ("..err..")" end local ok, err = type_check.type_check_rockspec(rockspec) if not ok then return nil, filename..": "..err end if rockspec.rockspec_format then if deps.compare_versions(rockspec.rockspec_format, type_check.rockspec_format) then return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks." end end util.platform_overrides(rockspec.build) util.platform_overrides(rockspec.dependencies) util.platform_overrides(rockspec.external_dependencies) util.platform_overrides(rockspec.source) util.platform_overrides(rockspec.hooks) local basename = dir.base_name(filename) if basename == "rockspec" then rockspec.name = rockspec.package:lower() else rockspec.name = basename:match("(.*)-[^-]*-[0-9]*") if not rockspec.name then return nil, "Expected filename in format 'name-version-revision.rockspec'." end end local protocol, pathname = dir.split_url(rockspec.source.url) if protocol == "http" or protocol == "https" or protocol == "ftp" or protocol == "file" then rockspec.source.file = rockspec.source.file or dir.base_name(rockspec.source.url) end rockspec.source.protocol, rockspec.source.pathname = protocol, pathname -- Temporary compatibility if rockspec.source.cvs_module then rockspec.source.module = rockspec.source.cvs_module end if rockspec.source.cvs_tag then rockspec.source.tag = rockspec.source.cvs_tag end local name_version = rockspec.package:lower() .. "-" .. rockspec.version if basename ~= "rockspec" and basename ~= name_version .. ".rockspec" then return nil, "Inconsistency between rockspec filename ("..basename..") and its contents ("..name_version..".rockspec)." end rockspec.local_filename = filename local filebase = rockspec.source.file or rockspec.source.url local base = dir.base_name(filebase) base = base:gsub("%.[^.]*$", ""):gsub("%.tar$", "") rockspec.source.dir = rockspec.source.dir or rockspec.source.module or ((filebase:match(".lua$") or filebase:match(".c$")) and ".") or base if rockspec.dependencies then for i = 1, #rockspec.dependencies do local parsed = deps.parse_dep(rockspec.dependencies[i]) if not parsed then return nil, "Parse error processing dependency '"..rockspec.dependencies[i].."'" end rockspec.dependencies[i] = parsed end else rockspec.dependencies = {} end local ok, err = path.configure_paths(rockspec) if err then return nil, "Error verifying paths: "..err end return rockspec end --- Load a local or remote rockspec into a table. -- This is the entry point for the LuaRocks tools. -- Only the LuaRocks runtime loader should use -- load_local_rockspec directly. -- @param filename string: Local or remote filename of a rockspec. -- @param location string or nil: Where to download. If not given, -- a temporary dir is created. -- @return table or (nil, string, [string]): A table representing the rockspec -- or nil followed by an error message and optional error code. function load_rockspec(filename, location) assert(type(filename) == "string") local name local basename = dir.base_name(filename) if basename == "rockspec" then name = "rockspec" else name = basename:match("(.*)%.rockspec") if not name and not basename == "rockspec" then return nil, "Filename '"..filename.."' does not look like a rockspec." end end local err, errcode if location then fs.change_dir(location) filename, err = fetch_url(filename) fs.pop_dir() else filename, err, errcode = fetch_url_at_temp_dir(filename,"luarocks-rockspec-"..name) end if not filename then return nil, err, errcode end return load_local_rockspec(filename) end --- Download sources for building a rock using the basic URL downloader. -- @param rockspec table: The rockspec table -- @param extract boolean: Whether to extract the sources from -- the fetched source tarball or not. -- @param dest_dir string or nil: If set, will extract to the given directory. -- @return (string, string) or (nil, string, [string]): The absolute pathname of -- the fetched source tarball and the temporary directory created to -- store it; or nil and an error message and optional error code. function get_sources(rockspec, extract, dest_dir) assert(type(rockspec) == "table") assert(type(extract) == "boolean") assert(type(dest_dir) == "string" or not dest_dir) local url = rockspec.source.url local name = rockspec.name.."-"..rockspec.version local filename = rockspec.source.file local source_file, store_dir, err, errcode if dest_dir then fs.change_dir(dest_dir) source_file, err, errcode = fetch_url(url, filename) fs.pop_dir() store_dir = dest_dir else source_file, store_dir, errcode = fetch_url_at_temp_dir(url, "luarocks-source-"..name, filename) end if not source_file then return nil, err or store_dir, errcode end if rockspec.source.md5 then if not fs.check_md5(source_file, rockspec.source.md5) then return nil, "MD5 check for "..filename.." has failed." end end if extract then fs.change_dir(store_dir) fs.unpack_archive(rockspec.source.file) if not fs.exists(rockspec.source.dir) then return nil, "Directory "..rockspec.source.dir.." not found inside archive "..rockspec.source.file end fs.pop_dir() end return source_file, store_dir end --- Download sources for building a rock, calling the appropriate protocol method. -- @param rockspec table: The rockspec table -- @param extract boolean: When downloading compressed formats, whether to extract -- the sources from the fetched archive or not. -- @param dest_dir string or nil: If set, will extract to the given directory. -- @return (string, string) or (nil, string): The absolute pathname of -- the fetched source tarball and the temporary directory created to -- store it; or nil and an error message. function fetch_sources(rockspec, extract, dest_dir) assert(type(rockspec) == "table") assert(type(extract) == "boolean") assert(type(dest_dir) == "string" or not dest_dir) local protocol = rockspec.source.protocol local ok, proto if protocol == "http" or protocol == "https" or protocol == "ftp" or protocol == "file" then proto = require("luarocks.fetch") else ok, proto = pcall(require, "luarocks.fetch."..protocol:gsub("[+-]", "_")) if not ok then return nil, "Unknown protocol "..protocol end end if cfg.only_sources_from and rockspec.source.pathname and #rockspec.source.pathname > 0 then if #cfg.only_sources_from == 0 then return nil, "Can't download "..rockspec.source.url.." -- download from remote servers disabled" elseif rockspec.source.pathname:find(cfg.only_sources_from, 1, true) ~= 1 then return nil, "Can't download "..rockspec.source.url.." -- only downloading from "..cfg.only_sources_from end end return proto.get_sources(rockspec, extract, dest_dir) end