Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
luarocks/src/luarocks/deps.lua
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
777 lines (686 sloc)
27.2 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- High-level dependency related functions. | |
| local deps = {} | |
| local cfg = require("luarocks.core.cfg") | |
| local manif = require("luarocks.manif") | |
| local path = require("luarocks.path") | |
| local dir = require("luarocks.dir") | |
| local fun = require("luarocks.fun") | |
| local util = require("luarocks.util") | |
| local vers = require("luarocks.core.vers") | |
| local queries = require("luarocks.queries") | |
| local builtin = require("luarocks.build.builtin") | |
| local deplocks = require("luarocks.deplocks") | |
| --- Generate a function that matches dep queries against the manifest, | |
| -- taking into account rocks_provided, the list of versions to skip, | |
| -- and the lockfile. | |
| -- @param deps_mode "one", "none", "all" or "order" | |
| -- @param rocks_provided a one-level table mapping names to versions, | |
| -- listing rocks to consider provided by the VM | |
| -- @param rocks_provided table: A table of auto-provided dependencies. | |
| -- by this Lua implementation for the given dependency. | |
| -- @param depskey key to use when matching the lockfile ("dependencies", | |
| -- "build_dependencies", etc.) | |
| -- @param skip_set a two-level table mapping names to versions to | |
| -- boolean, listing rocks that should not be matched | |
| -- @return function(dep): {string}, {string:string}, string, boolean | |
| -- * array of matching versions | |
| -- * map of versions to locations | |
| -- * version matched via lockfile if any | |
| -- * true if rock matched via rocks_provided | |
| local function prepare_get_versions(deps_mode, rocks_provided, depskey, skip_set) | |
| assert(type(deps_mode) == "string") | |
| assert(type(rocks_provided) == "table") | |
| assert(type(depskey) == "string") | |
| assert(type(skip_set) == "table" or skip_set == nil) | |
| return function(dep) | |
| local versions, locations | |
| local provided = rocks_provided[dep.name] | |
| if provided then | |
| -- Provided rocks have higher priority than manifest's rocks. | |
| versions, locations = { provided }, {} | |
| else | |
| if deps_mode == "none" then | |
| deps_mode = "one" | |
| end | |
| versions, locations = manif.get_versions(dep, deps_mode) | |
| end | |
| if skip_set and skip_set[dep.name] then | |
| for i = #versions, 1, -1 do | |
| local v = versions[i] | |
| if skip_set[dep.name][v] then | |
| table.remove(versions, i) | |
| end | |
| end | |
| end | |
| local lockversion = deplocks.get(depskey, dep.name) | |
| return versions, locations, lockversion, provided ~= nil | |
| end | |
| end | |
| --- Attempt to match a dependency to an installed rock. | |
| -- @param get_versions a getter function obtained via prepare_get_versions | |
| -- @return (string, string, table) or (nil, nil, table): | |
| -- 1. latest installed version of the rock matching the dependency | |
| -- 2. location where the installed version is installed | |
| -- 3. the 'dep' query table | |
| -- 4. true if provided via VM | |
| -- or | |
| -- 1. nil | |
| -- 2. nil | |
| -- 3. either 'dep' or an alternative query to be used | |
| -- 4. false | |
| local function match_dep(dep, get_versions) | |
| assert(type(dep) == "table") | |
| assert(type(get_versions) == "function") | |
| local versions, locations, lockversion, provided = get_versions(dep) | |
| local latest_version | |
| local latest_vstring | |
| for _, vstring in ipairs(versions) do | |
| local version = vers.parse_version(vstring) | |
| if vers.match_constraints(version, dep.constraints) then | |
| if not latest_version or version > latest_version then | |
| latest_version = version | |
| latest_vstring = vstring | |
| end | |
| end | |
| end | |
| if lockversion and not locations[lockversion] then | |
| local latest_matching_msg = "" | |
| if latest_vstring and latest_vstring ~= lockversion then | |
| latest_matching_msg = " (latest matching is " .. latest_vstring .. ")" | |
| end | |
| util.printout("Forcing " .. dep.name .. " to pinned version " .. lockversion .. latest_matching_msg) | |
| return nil, nil, queries.new(dep.name, dep.namespace, lockversion) | |
| end | |
| return latest_vstring, locations[latest_vstring], dep, provided | |
| end | |
| local function match_all_deps(dependencies, get_versions) | |
| assert(type(dependencies) == "table") | |
| assert(type(get_versions) == "function") | |
| local matched, missing, no_upgrade = {}, {}, {} | |
| for _, dep in ipairs(dependencies) do | |
| local found, _, provided | |
| found, _, dep, provided = match_dep(dep, get_versions) | |
| if found then | |
| if not provided then | |
| matched[dep] = {name = dep.name, version = found} | |
| end | |
| else | |
| if dep.constraints[1] and dep.constraints[1].no_upgrade then | |
| no_upgrade[dep.name] = dep | |
| else | |
| missing[dep.name] = dep | |
| end | |
| end | |
| end | |
| return matched, missing, no_upgrade | |
| end | |
| --- Attempt to match dependencies of a rockspec to installed rocks. | |
| -- @param dependencies table: The table of dependencies. | |
| -- @param rocks_provided table: The table of auto-provided dependencies. | |
| -- @param skip_set table or nil: Program versions to not use as valid matches. | |
| -- Table where keys are program names and values are tables where keys | |
| -- are program versions and values are 'true'. | |
| -- @param deps_mode string: Which trees to check dependencies for | |
| -- @return table, table, table: A table where keys are dependencies parsed | |
| -- in table format and values are tables containing fields 'name' and | |
| -- version' representing matches; a table of missing dependencies | |
| -- parsed as tables; and a table of "no-upgrade" missing dependencies | |
| -- (to be used in plugin modules so that a plugin does not force upgrade of | |
| -- its parent application). | |
| function deps.match_deps(dependencies, rocks_provided, skip_set, deps_mode) | |
| assert(type(dependencies) == "table") | |
| assert(type(rocks_provided) == "table") | |
| assert(type(skip_set) == "table" or skip_set == nil) | |
| assert(type(deps_mode) == "string") | |
| local get_versions = prepare_get_versions(deps_mode, rocks_provided, "dependencies", skip_set) | |
| return match_all_deps(dependencies, get_versions) | |
| end | |
| local function rock_status(dep, get_versions) | |
| assert(dep:type() == "query") | |
| assert(type(get_versions) == "function") | |
| local installed, _, _, provided = match_dep(dep, get_versions) | |
| local installation_type = provided and "provided by VM" or "installed" | |
| return installed and installed.." "..installation_type or "not installed" | |
| end | |
| --- Check depenendencies of a package and report any missing ones. | |
| -- @param name string: package name. | |
| -- @param version string: package version. | |
| -- @param dependencies table: array of dependencies. | |
| -- @param deps_mode string: Which trees to check dependencies for | |
| -- @param rocks_provided table: A table of auto-dependencies provided | |
| -- by this Lua implementation for the given dependency. | |
| -- "one" for the current default tree, "all" for all trees, | |
| -- "order" for all trees with priority >= the current default, "none" for no trees. | |
| function deps.report_missing_dependencies(name, version, dependencies, deps_mode, rocks_provided) | |
| assert(type(name) == "string") | |
| assert(type(version) == "string") | |
| assert(type(dependencies) == "table") | |
| assert(type(deps_mode) == "string") | |
| assert(type(rocks_provided) == "table") | |
| if deps_mode == "none" then | |
| return | |
| end | |
| local get_versions = prepare_get_versions(deps_mode, rocks_provided, "dependencies") | |
| local first_missing_dep = true | |
| for _, dep in ipairs(dependencies) do | |
| local found, _ | |
| found, _, dep = match_dep(dep, get_versions) | |
| if not found then | |
| if first_missing_dep then | |
| util.printout(("Missing dependencies for %s %s:"):format(name, version)) | |
| first_missing_dep = false | |
| end | |
| util.printout((" %s (%s)"):format(tostring(dep), rock_status(dep, get_versions))) | |
| end | |
| end | |
| end | |
| function deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey) | |
| assert(dep:type() == "query") | |
| assert(type(deps_mode) == "string" or deps_mode == nil) | |
| assert(type(rocks_provided) == "table" or rocks_provided == nil) | |
| assert(type(verify) == "boolean" or verify == nil) | |
| assert(type(depskey) == "string") | |
| deps_mode = deps_mode or "all" | |
| rocks_provided = rocks_provided or {} | |
| local get_versions = prepare_get_versions(deps_mode, rocks_provided, depskey) | |
| local found, where | |
| found, where, dep = match_dep(dep, get_versions) | |
| if found then | |
| local tree_manifests = manif.load_rocks_tree_manifests(deps_mode) | |
| manif.scan_dependencies(dep.name, found, tree_manifests, deplocks.proxy(depskey)) | |
| return true, found, where | |
| end | |
| local search = require("luarocks.search") | |
| local install = require("luarocks.cmd.install") | |
| local url, search_err = search.find_suitable_rock(dep) | |
| if not url then | |
| return nil, "Could not satisfy dependency "..tostring(dep)..": "..search_err | |
| end | |
| util.printout("Installing "..url) | |
| local install_args = { | |
| rock = url, | |
| deps_mode = deps_mode, | |
| namespace = dep.namespace, | |
| verify = verify, | |
| } | |
| local ok, install_err, errcode = install.command(install_args) | |
| if not ok then | |
| return nil, "Failed installing dependency: "..url.." - "..install_err, errcode | |
| end | |
| found, where = match_dep(dep, get_versions) | |
| assert(found) | |
| return true, found, where | |
| end | |
| local function check_supported_platforms(rockspec) | |
| if rockspec.supported_platforms and next(rockspec.supported_platforms) then | |
| local all_negative = true | |
| local supported = false | |
| for _, plat in pairs(rockspec.supported_platforms) do | |
| local neg | |
| neg, plat = plat:match("^(!?)(.*)") | |
| if neg == "!" then | |
| if cfg.is_platform(plat) then | |
| return nil, "This rockspec for "..rockspec.package.." does not support "..plat.." platforms." | |
| end | |
| else | |
| all_negative = false | |
| if cfg.is_platform(plat) then | |
| supported = true | |
| break | |
| end | |
| end | |
| end | |
| if supported == false and not all_negative then | |
| local plats = cfg.print_platforms() | |
| return nil, "This rockspec for "..rockspec.package.." does not support "..plats.." platforms." | |
| end | |
| end | |
| return true | |
| end | |
| --- Check dependencies of a rock and attempt to install any missing ones. | |
| -- Packages are installed using the LuaRocks "install" command. | |
| -- Aborts the program if a dependency could not be fulfilled. | |
| -- @param rockspec table: A rockspec in table format. | |
| -- @param depskey string: Rockspec key to fetch to get dependency table | |
| -- ("dependencies", "build_dependencies", etc.). | |
| -- @param deps_mode string | |
| -- @param verify boolean | |
| -- @param deplock_dir string: dirname of the deplock file | |
| -- @return boolean or (nil, string, [string]): True if no errors occurred, or | |
| -- nil and an error message if any test failed, followed by an optional | |
| -- error code. | |
| function deps.fulfill_dependencies(rockspec, depskey, deps_mode, verify, deplock_dir) | |
| assert(type(rockspec) == "table") | |
| assert(type(depskey) == "string") | |
| assert(type(deps_mode) == "string") | |
| assert(type(verify) == "boolean" or verify == nil) | |
| assert(type(deplock_dir) == "string" or deplock_dir == nil) | |
| local name = rockspec.name | |
| local version = rockspec.version | |
| local rocks_provided = rockspec.rocks_provided | |
| local ok, filename, err = deplocks.load(name, deplock_dir or ".") | |
| if filename then | |
| util.printout("Using dependencies pinned in lockfile: " .. filename) | |
| local get_versions = prepare_get_versions("none", rocks_provided, depskey) | |
| for dnsname, dversion in deplocks.each(depskey) do | |
| local dname, dnamespace = util.split_namespace(dnsname) | |
| local dep = queries.new(dname, dnamespace, dversion) | |
| util.printout(("%s %s is pinned to %s (%s)"):format( | |
| name, version, tostring(dep), rock_status(dep, get_versions))) | |
| local ok, err = deps.fulfill_dependency(dep, "none", rocks_provided, verify, depskey) | |
| if not ok then | |
| return nil, err | |
| end | |
| end | |
| util.printout() | |
| return true | |
| elseif err then | |
| util.warning(err) | |
| end | |
| ok, err = check_supported_platforms(rockspec) | |
| if not ok then | |
| return nil, err | |
| end | |
| deps.report_missing_dependencies(name, version, rockspec[depskey], deps_mode, rocks_provided) | |
| util.printout() | |
| local get_versions = prepare_get_versions(deps_mode, rocks_provided, depskey) | |
| for _, dep in ipairs(rockspec[depskey]) do | |
| util.printout(("%s %s depends on %s (%s)"):format( | |
| name, version, tostring(dep), rock_status(dep, get_versions))) | |
| local ok, found_or_err, _, no_upgrade = deps.fulfill_dependency(dep, deps_mode, rocks_provided, verify, depskey) | |
| if ok then | |
| deplocks.add(depskey, dep.name, found_or_err) | |
| else | |
| if no_upgrade then | |
| util.printerr("This version of "..name.." is designed for use with") | |
| util.printerr(tostring(dep)..", but is configured to avoid upgrading it") | |
| util.printerr("automatically. Please upgrade "..dep.name.." with") | |
| util.printerr(" luarocks install "..dep.name) | |
| util.printerr("or look for a suitable version of "..name.." with") | |
| util.printerr(" luarocks search "..name) | |
| end | |
| return nil, found_or_err | |
| end | |
| end | |
| return true | |
| end | |
| --- If filename matches a pattern, return the capture. | |
| -- For example, given "libfoo.so" and "lib?.so" is a pattern, | |
| -- returns "foo" (which can then be used to build names | |
| -- based on other patterns. | |
| -- @param file string: a filename | |
| -- @param pattern string: a pattern, where ? is to be matched by the filename. | |
| -- @return string The pattern, if found, or nil. | |
| local function deconstruct_pattern(file, pattern) | |
| local depattern = "^"..(pattern:gsub("%.", "%%."):gsub("%*", ".*"):gsub("?", "(.*)")).."$" | |
| return (file:match(depattern)) | |
| end | |
| --- Construct all possible patterns for a name and add to the files array. | |
| -- Run through the patterns array replacing all occurrences of "?" | |
| -- with the given file name and store them in the files array. | |
| -- @param file string A raw name (e.g. "foo") | |
| -- @param array of string An array of patterns with "?" as the wildcard | |
| -- (e.g. {"?.so", "lib?.so"}) | |
| -- @param files The array of constructed names | |
| local function add_all_patterns(file, patterns, files) | |
| for _, pattern in ipairs(patterns) do | |
| table.insert(files, {#files + 1, (pattern:gsub("?", file))}) | |
| end | |
| end | |
| local function get_external_deps_dirs(mode) | |
| local patterns = cfg.external_deps_patterns | |
| local subdirs = cfg.external_deps_subdirs | |
| if mode == "install" then | |
| patterns = cfg.runtime_external_deps_patterns | |
| subdirs = cfg.runtime_external_deps_subdirs | |
| end | |
| local dirs = { | |
| BINDIR = { subdir = subdirs.bin, testfile = "program", pattern = patterns.bin }, | |
| INCDIR = { subdir = subdirs.include, testfile = "header", pattern = patterns.include }, | |
| LIBDIR = { subdir = subdirs.lib, testfile = "library", pattern = patterns.lib } | |
| } | |
| if mode == "install" then | |
| dirs.INCDIR = nil | |
| end | |
| return dirs | |
| end | |
| local function resolve_prefix(prefix, dirs) | |
| if type(prefix) == "string" then | |
| return prefix | |
| elseif type(prefix) == "table" then | |
| if prefix.bin then | |
| dirs.BINDIR.subdir = prefix.bin | |
| end | |
| if prefix.include then | |
| if dirs.INCDIR then | |
| dirs.INCDIR.subdir = prefix.include | |
| end | |
| end | |
| if prefix.lib then | |
| dirs.LIBDIR.subdir = prefix.lib | |
| end | |
| return prefix.prefix | |
| end | |
| end | |
| local function add_patterns_for_file(files, file, patterns) | |
| -- If it doesn't look like it contains a filename extension | |
| if not (file:match("%.[a-z]+$") or file:match("%.[a-z]+%.")) then | |
| add_all_patterns(file, patterns, files) | |
| else | |
| for _, pattern in ipairs(patterns) do | |
| local matched = deconstruct_pattern(file, pattern) | |
| if matched then | |
| add_all_patterns(matched, patterns, files) | |
| end | |
| end | |
| table.insert(files, {#files + 1, file}) | |
| end | |
| end | |
| local function check_external_dependency_at(prefix, name, ext_files, vars, dirs, err_files, cache) | |
| local fs = require("luarocks.fs") | |
| cache = cache or {} | |
| for dirname, dirdata in util.sortedpairs(dirs) do | |
| local paths | |
| local path_var_value = vars[name.."_"..dirname] | |
| if path_var_value then | |
| paths = { path_var_value } | |
| elseif type(dirdata.subdir) == "table" then | |
| paths = {} | |
| for i,v in ipairs(dirdata.subdir) do | |
| paths[i] = dir.path(prefix, v) | |
| end | |
| else | |
| paths = { dir.path(prefix, dirdata.subdir) } | |
| end | |
| dirdata.dir = paths[1] | |
| local file_or_files = ext_files[dirdata.testfile] | |
| if file_or_files then | |
| local files = {} | |
| if type(file_or_files) == "string" then | |
| add_patterns_for_file(files, file_or_files, dirdata.pattern) | |
| elseif type(file_or_files) == "table" then | |
| for _, f in ipairs(file_or_files) do | |
| add_patterns_for_file(files, f, dirdata.pattern) | |
| end | |
| end | |
| local found = false | |
| table.sort(files, function(a, b) | |
| if (not a[2]:match("%*")) and b[2]:match("%*") then | |
| return true | |
| elseif a[2]:match("%*") and (not b[2]:match("%*")) then | |
| return false | |
| else | |
| return a[1] < b[1] | |
| end | |
| end) | |
| for _, fa in ipairs(files) do | |
| local f = fa[2] | |
| -- small convenience hack | |
| if f:match("%.so$") or f:match("%.dylib$") or f:match("%.dll$") then | |
| f = f:gsub("%.[^.]+$", "."..cfg.external_lib_extension) | |
| end | |
| local pattern | |
| if f:match("%*") then | |
| pattern = "^" .. f:gsub("([-.+])", "%%%1"):gsub("%*", ".*") .. "$" | |
| f = "matching "..f | |
| end | |
| for _, d in ipairs(paths) do | |
| if pattern then | |
| if not cache[d] then | |
| cache[d] = fs.list_dir(d) | |
| end | |
| local match = string.match | |
| for _, entry in ipairs(cache[d]) do | |
| if match(entry, pattern) then | |
| found = true | |
| break | |
| end | |
| end | |
| else | |
| found = fs.is_file(dir.path(d, f)) | |
| end | |
| if found then | |
| dirdata.dir = d | |
| dirdata.file = f | |
| break | |
| else | |
| table.insert(err_files[dirdata.testfile], f.." in "..d) | |
| end | |
| end | |
| if found then | |
| break | |
| end | |
| end | |
| if not found then | |
| return nil, dirname, dirdata.testfile | |
| end | |
| end | |
| end | |
| for dirname, dirdata in pairs(dirs) do | |
| vars[name.."_"..dirname] = dirdata.dir | |
| vars[name.."_"..dirname.."_FILE"] = dirdata.file | |
| end | |
| vars[name.."_DIR"] = prefix | |
| return true | |
| end | |
| local function check_external_dependency(name, ext_files, vars, mode, cache) | |
| local ok | |
| local err_dirname | |
| local err_testfile | |
| local err_files = {program = {}, header = {}, library = {}} | |
| local dirs = get_external_deps_dirs(mode) | |
| local prefixes | |
| if vars[name .. "_DIR"] then | |
| prefixes = { vars[name .. "_DIR"] } | |
| elseif vars.DEPS_DIR then | |
| prefixes = { vars.DEPS_DIR } | |
| else | |
| prefixes = cfg.external_deps_dirs | |
| end | |
| for _, prefix in ipairs(prefixes) do | |
| prefix = resolve_prefix(prefix, dirs) | |
| if cfg.is_platform("mingw32") and name == "LUA" then | |
| dirs.LIBDIR.pattern = fun.filter(util.deep_copy(dirs.LIBDIR.pattern), function(s) | |
| return not s:match("%.a$") | |
| end) | |
| elseif cfg.is_platform("windows") and name == "LUA" then | |
| dirs.LIBDIR.pattern = fun.filter(util.deep_copy(dirs.LIBDIR.pattern), function(s) | |
| return not s:match("%.dll$") | |
| end) | |
| end | |
| ok, err_dirname, err_testfile = check_external_dependency_at(prefix, name, ext_files, vars, dirs, err_files, cache) | |
| if ok then | |
| return true | |
| end | |
| end | |
| return nil, err_dirname, err_testfile, err_files | |
| end | |
| --- Set up path-related variables for external dependencies. | |
| -- For each key in the external_dependencies table in the | |
| -- rockspec file, four variables are created: <key>_DIR, <key>_BINDIR, | |
| -- <key>_INCDIR and <key>_LIBDIR. These are not overwritten | |
| -- if already set (e.g. by the LuaRocks config file or through the | |
| -- command-line). Values in the external_dependencies table | |
| -- are tables that may contain a "header" or a "library" field, | |
| -- with filenames to be tested for existence. | |
| -- @param rockspec table: The rockspec table. | |
| -- @param mode string: if "build" is given, checks all files; | |
| -- if "install" is given, do not scan for headers. | |
| -- @return boolean or (nil, string): True if no errors occurred, or | |
| -- nil and an error message if any test failed. | |
| function deps.check_external_deps(rockspec, mode) | |
| assert(rockspec:type() == "rockspec") | |
| if not rockspec.external_dependencies then | |
| rockspec.external_dependencies = builtin.autodetect_external_dependencies(rockspec.build) | |
| end | |
| if not rockspec.external_dependencies then | |
| return true | |
| end | |
| for name, ext_files in util.sortedpairs(rockspec.external_dependencies) do | |
| local ok, err_dirname, err_testfile, err_files = check_external_dependency(name, ext_files, rockspec.variables, mode) | |
| if not ok then | |
| local lines = {"Could not find "..err_testfile.." file for "..name} | |
| local err_paths = {} | |
| for _, err_file in ipairs(err_files[err_testfile]) do | |
| if not err_paths[err_file] then | |
| err_paths[err_file] = true | |
| table.insert(lines, " No file "..err_file) | |
| end | |
| end | |
| table.insert(lines, "You may have to install "..name.." in your system and/or pass "..name.."_DIR or "..name.."_"..err_dirname.." to the luarocks command.") | |
| table.insert(lines, "Example: luarocks install "..rockspec.name.." "..name.."_DIR=/usr/local") | |
| return nil, table.concat(lines, "\n"), "dependency" | |
| end | |
| end | |
| return true | |
| end | |
| --- Recursively add satisfied dependencies of a package to a table, | |
| -- to build a transitive closure of all dependent packages. | |
| -- Additionally ensures that `dependencies` table of the manifest is up-to-date. | |
| -- @param results table: The results table being built, maps package names to versions. | |
| -- @param manifest table: The manifest table containing dependencies. | |
| -- @param name string: Package name. | |
| -- @param version string: Package version. | |
| function deps.scan_deps(results, manifest, name, version, deps_mode) | |
| assert(type(results) == "table") | |
| assert(type(manifest) == "table") | |
| assert(type(name) == "string" and not name:match("/")) | |
| assert(type(version) == "string") | |
| local fetch = require("luarocks.fetch") | |
| if results[name] then | |
| return | |
| end | |
| if not manifest.dependencies then manifest.dependencies = {} end | |
| local md = manifest.dependencies | |
| if not md[name] then md[name] = {} end | |
| local mdn = md[name] | |
| local dependencies = mdn[version] | |
| local rocks_provided | |
| if not dependencies then | |
| local rockspec, err = fetch.load_local_rockspec(path.rockspec_file(name, version), false) | |
| if not rockspec then | |
| util.printerr("Couldn't load rockspec for "..name.." "..version..": "..err) | |
| return | |
| end | |
| dependencies = rockspec.dependencies | |
| rocks_provided = rockspec.rocks_provided | |
| mdn[version] = dependencies | |
| else | |
| rocks_provided = util.get_rocks_provided() | |
| end | |
| local get_versions = prepare_get_versions(deps_mode, rocks_provided, "dependencies") | |
| local matched = match_all_deps(dependencies, get_versions) | |
| results[name] = version | |
| for _, match in pairs(matched) do | |
| deps.scan_deps(results, manifest, match.name, match.version, deps_mode) | |
| end | |
| end | |
| local function lua_h_exists(d, luaver) | |
| local n = tonumber(luaver) | |
| local major = math.floor(n) | |
| local minor = (n - major) * 10 | |
| local luanum = math.floor(major * 100 + minor) | |
| local lua_h = dir.path(d, "lua.h") | |
| local fd = io.open(lua_h) | |
| if fd then | |
| local data = fd:read("*a") | |
| fd:close() | |
| if data:match("LUA_VERSION_NUM%s*" .. tostring(luanum)) then | |
| return d | |
| end | |
| return nil, "Lua header found at " .. d .. " does not match Lua version " .. luaver .. ". You may want to override this by configuring LUA_INCDIR.", "dependency", 2 | |
| end | |
| return nil, "Failed finding Lua header files. You may need to install them or configure LUA_INCDIR.", "dependency", 1 | |
| end | |
| local function find_lua_incdir(prefix, luaver, luajitver) | |
| luajitver = luajitver and luajitver:gsub("%-.*", "") | |
| local shortv = luaver:gsub("%.", "") | |
| local incdirs = { | |
| prefix .. "/include/lua/" .. luaver, | |
| prefix .. "/include/lua" .. luaver, | |
| prefix .. "/include/lua-" .. luaver, | |
| prefix .. "/include/lua" .. shortv, | |
| prefix .. "/include", | |
| prefix, | |
| luajitver and (prefix .. "/include/luajit-" .. (luajitver:match("^(%d+%.%d+)") or "")), | |
| } | |
| local errprio = 0 | |
| local mainerr | |
| for _, d in ipairs(incdirs) do | |
| local ok, err, _, prio = lua_h_exists(d, luaver) | |
| if ok then | |
| return d | |
| end | |
| if prio > errprio then | |
| mainerr = err | |
| errprio = prio | |
| end | |
| end | |
| -- not found, will fallback to a default | |
| return nil, mainerr | |
| end | |
| function deps.check_lua_incdir(vars) | |
| local ljv = util.get_luajit_version() | |
| if vars.LUA_INCDIR then | |
| return lua_h_exists(vars.LUA_INCDIR, cfg.lua_version) | |
| end | |
| if vars.LUA_DIR then | |
| local d, err = find_lua_incdir(vars.LUA_DIR, cfg.lua_version, ljv) | |
| if d then | |
| vars.LUA_INCDIR = d | |
| return true | |
| end | |
| return nil, err | |
| end | |
| return nil, "Failed finding Lua header files. You may need to install them or configure LUA_INCDIR.", "dependency" | |
| end | |
| function deps.check_lua_libdir(vars) | |
| local fs = require("luarocks.fs") | |
| local ljv = util.get_luajit_version() | |
| if vars.LUA_LIBDIR and vars.LUALIB and fs.exists(dir.path(vars.LUA_LIBDIR, vars.LUALIB)) then | |
| return true | |
| end | |
| local shortv = cfg.lua_version:gsub("%.", "") | |
| local libnames = { | |
| "lua" .. cfg.lua_version, | |
| "lua" .. shortv, | |
| "lua-" .. cfg.lua_version, | |
| "lua-" .. shortv, | |
| "lua", | |
| } | |
| if ljv then | |
| table.insert(libnames, 1, "luajit-" .. cfg.lua_version) | |
| end | |
| local cache = {} | |
| local save_LUA_INCDIR = vars.LUA_INCDIR | |
| local ok = check_external_dependency("LUA", { library = libnames }, vars, "build", cache) | |
| vars.LUA_INCDIR = save_LUA_INCDIR | |
| local err | |
| if ok then | |
| local filename = dir.path(vars.LUA_LIBDIR, vars.LUA_LIBDIR_FILE) | |
| local fd = io.open(filename, "r") | |
| if fd then | |
| if not vars.LUA_LIBDIR_FILE:match((cfg.lua_version:gsub("%.", "%%.?"))) then | |
| -- if filename isn't versioned, check file contents | |
| local txt = fd:read("*a") | |
| ok = txt:match("Lua " .. cfg.lua_version, 1, true) | |
| or txt:match("lua" .. (cfg.lua_version:gsub("%.", "")), 1, true) | |
| if not ok then | |
| err = "Lua library at " .. filename .. " does not match Lua version " .. cfg.lua_version .. ". You may want to override this by configuring LUA_LIBDIR." | |
| end | |
| end | |
| fd:close() | |
| end | |
| end | |
| if ok then | |
| vars.LUALIB = vars.LUA_LIBDIR_FILE | |
| return true | |
| else | |
| err = err or "Failed finding Lua library. You may need to configure LUA_LIBDIR." | |
| return nil, err, "dependency" | |
| end | |
| end | |
| function deps.get_deps_mode(args) | |
| return args.deps_mode or cfg.deps_mode | |
| end | |
| return deps |