mirror of
https://github.com/folke/lazy.nvim.git
synced 2025-07-31 16:14:54 +02:00
Previously, rockspec.lua checked if Lua 5.1 was installed to determine if LuaRocks could build packages for Lua 5.1. This was not sufficient since the Lua version does not matter as long as the development headers for Lua 5.1 are available. So Lua 5.1 could be installed and the LuaRocks packages could still fail to install. Note: this also checks if a suitable version of Lua is installed since the command will fail if Lua is not installed at all.
359 lines
8.6 KiB
Lua
359 lines
8.6 KiB
Lua
--# selene:allow(incorrect_standard_library_use)
|
|
local Community = require("lazy.community")
|
|
|
|
local Config = require("lazy.core.config")
|
|
local Health = require("lazy.health")
|
|
local Util = require("lazy.util")
|
|
local Process = require("lazy.manage.process")
|
|
|
|
---@class RockSpec
|
|
---@field rockspec_format string
|
|
---@field package string
|
|
---@field version string
|
|
---@field dependencies string[]
|
|
---@field build? {type?: string, modules?: any[]}
|
|
---@field source? {url?: string}
|
|
|
|
---@class RockManifest
|
|
---@field repository table<string, table<string,any>>
|
|
|
|
local M = {}
|
|
|
|
M.skip = { "lua" }
|
|
M.rewrites = {
|
|
["plenary.nvim"] = { "nvim-lua/plenary.nvim", lazy = true },
|
|
}
|
|
|
|
M.python = { "python3", "python" }
|
|
|
|
---@class HereRocks
|
|
M.hererocks = {}
|
|
|
|
---@param task LazyTask
|
|
function M.hererocks.build(task)
|
|
local root = Config.options.rocks.root .. "/hererocks"
|
|
|
|
---@param p string
|
|
local python = vim.tbl_filter(function(p)
|
|
return vim.fn.executable(p) == 1
|
|
end, M.python)[1]
|
|
|
|
task:spawn(python, {
|
|
args = {
|
|
"hererocks.py",
|
|
"--verbose",
|
|
"-l",
|
|
"5.1",
|
|
"-r",
|
|
"latest",
|
|
root,
|
|
},
|
|
cwd = task.plugin.dir,
|
|
})
|
|
end
|
|
|
|
---@param bin string
|
|
function M.hererocks.bin(bin)
|
|
local hererocks = Config.options.rocks.root .. "/hererocks/bin"
|
|
return Util.norm(hererocks .. "/" .. bin)
|
|
end
|
|
|
|
-- check if hererocks is building
|
|
---@return boolean?
|
|
function M.hererocks.building()
|
|
return vim.tbl_get(Config.plugins.hererocks or {}, "_", "build")
|
|
end
|
|
|
|
---@param opts? LazyHealth
|
|
---@param luarocks_cmd string
|
|
---@return boolean
|
|
function M.check_lua51_headers(opts, luarocks_cmd)
|
|
local cmd = { luarocks_cmd, "--lua-version=5.1", "config", "variables.LUA_INCDIR" }
|
|
local _, exit_code = Process.exec(cmd)
|
|
|
|
if exit_code ~= 0 then
|
|
opts.error("Lua 5.1 headers not found. Install the Lua 5.1 development package for your system.")
|
|
return false
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
---@param opts? LazyHealth
|
|
function M.check(opts)
|
|
opts = vim.tbl_extend("force", {
|
|
error = Util.error,
|
|
warn = Util.warn,
|
|
ok = function() end,
|
|
}, opts or {})
|
|
|
|
local ok = false
|
|
if Config.hererocks() then
|
|
if M.hererocks.building() then
|
|
ok = true
|
|
else
|
|
ok = Health.have(M.python, opts)
|
|
ok = Health.have(M.hererocks.bin("luarocks")) and ok
|
|
if ok then
|
|
local luarocks_cmd = M.hererocks.bin("luarocks")
|
|
if Util.is_win then
|
|
luarocks_cmd = luarocks_cmd .. ".bat"
|
|
end
|
|
ok = M.check_lua51_headers(opts, luarocks_cmd)
|
|
end
|
|
end
|
|
else
|
|
ok = Health.have("luarocks", opts)
|
|
if ok then
|
|
local luarocks_cmd = "luarocks"
|
|
if Util.is_win then
|
|
luarocks_cmd = luarocks_cmd .. ".bat"
|
|
end
|
|
ok = M.check_lua51_headers(opts, luarocks_cmd)
|
|
end
|
|
end
|
|
return ok
|
|
end
|
|
|
|
---@async
|
|
---@param task LazyTask
|
|
function M.build(task)
|
|
M.check({
|
|
error = function(msg)
|
|
task:error(msg:gsub("[{}]", "`"))
|
|
end,
|
|
warn = function(msg)
|
|
task:warn(msg)
|
|
end,
|
|
ok = function(msg) end,
|
|
})
|
|
|
|
if task:has_warnings() then
|
|
task:log({
|
|
"",
|
|
"This plugin requires `luarocks`. Try one of the following:",
|
|
" - fix your `luarocks` installation",
|
|
Config.hererocks() and " - disable *hererocks* with `opts.rocks.hererocks = false`"
|
|
or " - enable `hererocks` with `opts.rocks.hererocks = true`",
|
|
" - disable `luarocks` support completely with `opts.rocks.enabled = false`",
|
|
})
|
|
task:warn("\nWill try building anyway, but will likely fail...")
|
|
|
|
task:warn("\n" .. string.rep("-", 80) .. "\n")
|
|
|
|
task:set_level(vim.log.levels.WARN)
|
|
end
|
|
|
|
if task.plugin.name == "hererocks" then
|
|
return M.hererocks.build(task)
|
|
end
|
|
|
|
local env = {}
|
|
local luarocks = "luarocks"
|
|
if Config.hererocks() then
|
|
-- hererocks is still building, so skip for now
|
|
-- a new build will happen in the next round
|
|
if M.hererocks.building() then
|
|
return
|
|
end
|
|
|
|
local sep = Util.is_win and ";" or ":"
|
|
local hererocks = Config.options.rocks.root .. "/hererocks/bin"
|
|
if Util.is_win then
|
|
hererocks = hererocks:gsub("/", "\\")
|
|
end
|
|
local path = vim.split(vim.env.PATH, sep)
|
|
table.insert(path, 1, hererocks)
|
|
env = {
|
|
PATH = table.concat(path, sep),
|
|
}
|
|
if Util.is_win then
|
|
luarocks = luarocks .. ".bat"
|
|
end
|
|
end
|
|
|
|
local pkg = task.plugin._.pkg
|
|
assert(pkg, "missing rockspec pkg for " .. task.plugin.name .. "\nThis shouldn't happen, please report.")
|
|
|
|
local rockspec = M.rockspec(task.plugin.dir .. "/" .. pkg.file) or {}
|
|
assert(
|
|
rockspec.package,
|
|
"missing rockspec package name for " .. task.plugin.name .. "\nThis shouldn't happen, please report."
|
|
)
|
|
|
|
local root = Config.options.rocks.root .. "/" .. task.plugin.name
|
|
local ok = task:spawn(luarocks, {
|
|
args = {
|
|
"--tree",
|
|
root,
|
|
"--server",
|
|
Config.options.rocks.server,
|
|
"--lua-version",
|
|
"5.1",
|
|
"install", -- use install so that we can make use of pre-built rocks
|
|
"--force-fast",
|
|
"--deps-mode",
|
|
"one",
|
|
rockspec.package,
|
|
},
|
|
cwd = task.plugin.dir,
|
|
env = env,
|
|
})
|
|
|
|
if ok then
|
|
return
|
|
end
|
|
|
|
task:warn("Failed installing " .. rockspec.package .. " with `luarocks`.")
|
|
task:warn("\n" .. string.rep("-", 80) .. "\n")
|
|
task:warn("Trying to build from source.")
|
|
|
|
-- install failed, so try building from source
|
|
task:set_level() -- reset level
|
|
ok = task:spawn(luarocks, {
|
|
args = {
|
|
"--tree",
|
|
root,
|
|
"--dev",
|
|
"--lua-version",
|
|
"5.1",
|
|
"make",
|
|
"--force-fast",
|
|
"--deps-mode",
|
|
"one",
|
|
},
|
|
cwd = task.plugin.dir,
|
|
env = env,
|
|
})
|
|
if not ok then
|
|
require("lazy.manage.task.fs").clean.run(task, { rocks_only = true })
|
|
end
|
|
end
|
|
|
|
---@param rockspec RockSpec
|
|
function M.is_simple_build(rockspec)
|
|
local type = vim.tbl_get(rockspec, "build", "type")
|
|
return type == nil or type == "none" or (type == "builtin" and not rockspec.build.modules)
|
|
end
|
|
|
|
---@param file string
|
|
---@return table?
|
|
function M.parse(file)
|
|
local ret = {}
|
|
local ok = pcall(function()
|
|
loadfile(file, nil, ret)()
|
|
end) and ret or nil
|
|
return ok and ret or nil
|
|
end
|
|
|
|
---@param plugin LazyPlugin
|
|
function M.deps(plugin)
|
|
local root = Config.options.rocks.root .. "/" .. plugin.name
|
|
---@type RockManifest?
|
|
local manifest = M.parse(root .. "/lib/luarocks/rocks-5.1/manifest")
|
|
return manifest and vim.tbl_keys(manifest.repository or {})
|
|
end
|
|
|
|
---@param file string
|
|
---@return RockSpec?
|
|
function M.rockspec(file)
|
|
return M.parse(file)
|
|
end
|
|
|
|
---@param plugin LazyPlugin
|
|
function M.find_rockspec(plugin)
|
|
local rockspec_file ---@type string?
|
|
Util.ls(plugin.dir, function(path, name, t)
|
|
if t == "file" then
|
|
for _, suffix in ipairs({ "scm", "git", "dev" }) do
|
|
suffix = suffix .. "-1.rockspec"
|
|
if name:sub(-#suffix) == suffix then
|
|
rockspec_file = path
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
return rockspec_file
|
|
end
|
|
|
|
---@param plugin LazyPlugin
|
|
---@return LazyPkgSpec?
|
|
function M.get(plugin)
|
|
if Community.get_spec(plugin.name) then
|
|
return {
|
|
file = "community",
|
|
source = "lazy",
|
|
spec = Community.get_spec(plugin.name),
|
|
}
|
|
end
|
|
|
|
local rockspec_file = M.find_rockspec(plugin)
|
|
local rockspec = rockspec_file and M.rockspec(rockspec_file)
|
|
if not rockspec then
|
|
return
|
|
end
|
|
|
|
local has_lua = not not vim.uv.fs_stat(plugin.dir .. "/lua")
|
|
|
|
---@type LazyPluginSpec
|
|
local specs = {}
|
|
|
|
---@param dep string
|
|
local rocks = vim.tbl_filter(function(dep)
|
|
local name = dep:gsub("%s.*", "")
|
|
local url = Community.get_url(name)
|
|
local spec = Community.get_spec(name)
|
|
|
|
if spec then
|
|
-- community spec
|
|
table.insert(specs, spec)
|
|
return false
|
|
elseif url then
|
|
-- Neovim plugin rock
|
|
table.insert(specs, { url })
|
|
return false
|
|
end
|
|
return not vim.tbl_contains(M.skip, name)
|
|
end, rockspec.dependencies or {})
|
|
|
|
local use =
|
|
-- package without a /lua directory
|
|
not has_lua
|
|
-- has dependencies that are not skipped,
|
|
-- not in community specs,
|
|
-- and don't have a rockspec mapping
|
|
or #rocks > 0
|
|
-- has a complex build process
|
|
or not M.is_simple_build(rockspec)
|
|
|
|
if not use then
|
|
-- community specs only
|
|
return #specs > 0
|
|
and {
|
|
file = vim.fn.fnamemodify(rockspec_file, ":t"),
|
|
spec = {
|
|
plugin.name,
|
|
specs = specs,
|
|
build = false,
|
|
},
|
|
}
|
|
or nil
|
|
end
|
|
|
|
local lazy = nil
|
|
if not has_lua then
|
|
lazy = false
|
|
end
|
|
|
|
return {
|
|
file = vim.fn.fnamemodify(rockspec_file, ":t"),
|
|
spec = {
|
|
plugin.name,
|
|
build = "rockspec",
|
|
lazy = lazy,
|
|
},
|
|
}
|
|
end
|
|
|
|
return M
|