mirror of https://github.com/folke/lazy.nvim.git
feat: plugin manager tasks
This commit is contained in:
parent
0219a531ed
commit
a612e6f6f4
|
@ -0,0 +1,90 @@
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
---@alias ProcessOpts {args: string[], cwd?: string, on_line?:fun(string), on_exit?: fun(ok:boolean, output:string)}
|
||||||
|
|
||||||
|
function M.spawn(cmd, opts)
|
||||||
|
opts = opts or {}
|
||||||
|
local env = {
|
||||||
|
"GIT_TERMINAL_PROMPT=0",
|
||||||
|
"GIT_SSH_COMMAND=ssh -oBatchMode=yes",
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value in
|
||||||
|
pairs(vim.loop.os_environ() --[[@as string[] ]])
|
||||||
|
do
|
||||||
|
table.insert(env, key .. "=" .. value)
|
||||||
|
end
|
||||||
|
|
||||||
|
local stdout = vim.loop.new_pipe()
|
||||||
|
local stderr = vim.loop.new_pipe()
|
||||||
|
|
||||||
|
local output = ""
|
||||||
|
---@type vim.loop.Process
|
||||||
|
local handle = nil
|
||||||
|
|
||||||
|
handle = vim.loop.spawn(cmd, {
|
||||||
|
stdio = { nil, stdout, stderr },
|
||||||
|
args = opts.args,
|
||||||
|
cwd = opts.cwd,
|
||||||
|
env = env,
|
||||||
|
}, function(exit_code)
|
||||||
|
handle:close()
|
||||||
|
stdout:close()
|
||||||
|
stderr:close()
|
||||||
|
local check = vim.loop.new_check()
|
||||||
|
check:start(function()
|
||||||
|
if not stdout:is_closing() or not stderr:is_closing() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
check:stop()
|
||||||
|
if opts.on_exit then
|
||||||
|
output = output:gsub("[^\r\n]+\r", "")
|
||||||
|
|
||||||
|
vim.schedule(function()
|
||||||
|
opts.on_exit(exit_code == 0, output)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
if not handle then
|
||||||
|
if opts.on_exit then
|
||||||
|
opts.on_exit(false, "Failed to spawn process " .. cmd .. " " .. vim.inspect(opts))
|
||||||
|
end
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local function on_output(err, data)
|
||||||
|
assert(not err, err)
|
||||||
|
|
||||||
|
if data then
|
||||||
|
output = output .. data:gsub("\r\n", "\n")
|
||||||
|
local lines = vim.split(vim.trim(output:gsub("\r$", "")):gsub("[^\n\r]+\r", ""), "\n")
|
||||||
|
|
||||||
|
if opts.on_line then
|
||||||
|
vim.schedule(function()
|
||||||
|
opts.on_line(lines[#lines])
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.loop.read_start(stdout, on_output)
|
||||||
|
vim.loop.read_start(stderr, on_output)
|
||||||
|
|
||||||
|
return handle
|
||||||
|
end
|
||||||
|
|
||||||
|
-- FIXME: can be removed?
|
||||||
|
function M.all_done(slot0)
|
||||||
|
for slot4, slot5 in ipairs(slot0) do
|
||||||
|
if slot5 and not slot5:is_closing() then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
|
@ -0,0 +1,68 @@
|
||||||
|
---@class Runner
|
||||||
|
---@field _tasks LazyTask[]
|
||||||
|
local Runner = {}
|
||||||
|
|
||||||
|
function Runner.new()
|
||||||
|
local self = setmetatable({}, {
|
||||||
|
__index = Runner,
|
||||||
|
})
|
||||||
|
self._tasks = {}
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param task LazyTask
|
||||||
|
function Runner:add(task)
|
||||||
|
table.insert(self._tasks, task)
|
||||||
|
task:start()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Runner:is_empty()
|
||||||
|
return #self._tasks == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
---@return LazyPlugin[]
|
||||||
|
function Runner:plugins()
|
||||||
|
---@param task LazyTask
|
||||||
|
return vim.tbl_map(function(task)
|
||||||
|
return task.plugin
|
||||||
|
end, self._tasks)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Runner:tasks()
|
||||||
|
return self._tasks
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param cb? fun()
|
||||||
|
function Runner:wait(cb)
|
||||||
|
if #self._tasks == 0 then
|
||||||
|
return cb and cb()
|
||||||
|
end
|
||||||
|
|
||||||
|
local done = false
|
||||||
|
local check = vim.loop.new_check()
|
||||||
|
|
||||||
|
check:start(function()
|
||||||
|
for _, task in ipairs(self._tasks) do
|
||||||
|
if task.running then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
check:stop()
|
||||||
|
|
||||||
|
done = true
|
||||||
|
|
||||||
|
if cb then
|
||||||
|
vim.schedule(cb)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if not cb then
|
||||||
|
while not done do
|
||||||
|
vim.wait(100)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Runner
|
|
@ -0,0 +1,206 @@
|
||||||
|
local Process = require("lazy.process")
|
||||||
|
local Loader = require("lazy.loader")
|
||||||
|
|
||||||
|
---@class LazyTask
|
||||||
|
---@field plugin LazyPlugin
|
||||||
|
---@field type TaskType
|
||||||
|
---@field running boolean
|
||||||
|
local Task = {}
|
||||||
|
|
||||||
|
---@alias TaskType "update"|"install"|"run"|"clean"
|
||||||
|
|
||||||
|
---@param plugin LazyPlugin
|
||||||
|
---@param type TaskType
|
||||||
|
function Task.new(plugin, type)
|
||||||
|
local self = setmetatable({}, {
|
||||||
|
__index = Task,
|
||||||
|
})
|
||||||
|
self.plugin = plugin
|
||||||
|
self.type = type
|
||||||
|
self.output = ""
|
||||||
|
self.status = ""
|
||||||
|
plugin.tasks = plugin.tasks or {}
|
||||||
|
table.insert(plugin.tasks, self)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function Task:_done()
|
||||||
|
self.running = false
|
||||||
|
|
||||||
|
vim.cmd("do User LazyRender")
|
||||||
|
end
|
||||||
|
|
||||||
|
function Task:clean()
|
||||||
|
local function rm(path)
|
||||||
|
for _, entry in ipairs(Util.scandir(path)) do
|
||||||
|
if entry.type == "directory" then
|
||||||
|
rm(entry.path)
|
||||||
|
else
|
||||||
|
vim.loop.fs_unlink(entry.path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.loop.fs_rmdir(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
local stat = vim.loop.fs_stat(self.plugin.dir)
|
||||||
|
|
||||||
|
if stat.type == "directory" then
|
||||||
|
rm(self.plugin.dir)
|
||||||
|
else
|
||||||
|
vim.loop.fs_unlink(self.plugin.dir)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.plugin.installed = false
|
||||||
|
self.running = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Task:install()
|
||||||
|
if Util.file_exists(self.plugin.uri) then
|
||||||
|
vim.loop.fs_symlink(self.plugin.uri, self.plugin.dir, {
|
||||||
|
dir = true,
|
||||||
|
})
|
||||||
|
vim.opt.runtimepath:append(self.plugin.uri)
|
||||||
|
self:_done()
|
||||||
|
else
|
||||||
|
local args = {
|
||||||
|
"clone",
|
||||||
|
self.plugin.uri,
|
||||||
|
"--depth=1",
|
||||||
|
"--recurse-submodules",
|
||||||
|
"--shallow-submodules",
|
||||||
|
"--progress",
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.plugin.branch then
|
||||||
|
vim.list_extend(args, {
|
||||||
|
"-b",
|
||||||
|
self.plugin.branch,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(args, self.plugin.dir)
|
||||||
|
self:spawn("git", {
|
||||||
|
args = args,
|
||||||
|
on_exit = function(ok)
|
||||||
|
if ok then
|
||||||
|
self.plugin.installed = true
|
||||||
|
self.plugin.dirty = true
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Task:run()
|
||||||
|
Loader.load(self.plugin)
|
||||||
|
|
||||||
|
local run = self.plugin.run
|
||||||
|
|
||||||
|
if run then
|
||||||
|
if type(run) == "string" and run:sub(1, 1) == ":" then
|
||||||
|
vim.cmd(run:sub(2))
|
||||||
|
elseif type(run) == "function" then
|
||||||
|
run()
|
||||||
|
else
|
||||||
|
local args = vim.split(run, "%s+")
|
||||||
|
|
||||||
|
return self:spawn(table.remove(args, 1), {
|
||||||
|
args = args,
|
||||||
|
cwd = self.plugin.dir,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:_done()
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param cmd string
|
||||||
|
---@param opts ProcessOpts
|
||||||
|
function Task:spawn(cmd, opts)
|
||||||
|
opts = opts or {}
|
||||||
|
local on_line = opts.on_line
|
||||||
|
local on_exit = opts.on_exit
|
||||||
|
|
||||||
|
function opts.on_line(line)
|
||||||
|
self.status = line
|
||||||
|
|
||||||
|
if on_line then
|
||||||
|
pcall(on_line, line)
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.cmd("do User LazyRender")
|
||||||
|
end
|
||||||
|
|
||||||
|
function opts.on_exit(ok, output)
|
||||||
|
self.output = output
|
||||||
|
|
||||||
|
if not ok then
|
||||||
|
self.error = output
|
||||||
|
end
|
||||||
|
|
||||||
|
if on_exit then
|
||||||
|
pcall(on_exit, ok, output)
|
||||||
|
end
|
||||||
|
|
||||||
|
self:_done()
|
||||||
|
end
|
||||||
|
|
||||||
|
Process.spawn(cmd, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Task:start()
|
||||||
|
self.running = true
|
||||||
|
local ok, err = pcall(function()
|
||||||
|
if self.type == "update" then
|
||||||
|
self:update()
|
||||||
|
elseif self.type == "install" then
|
||||||
|
self:install()
|
||||||
|
elseif self.type == "run" then
|
||||||
|
self:run()
|
||||||
|
elseif self.type == "clean" then
|
||||||
|
self:clean()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if not ok then
|
||||||
|
self.error = err or "failed"
|
||||||
|
|
||||||
|
self:_done()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Task:update()
|
||||||
|
if Util.file_exists(self.plugin.uri) then
|
||||||
|
if vim.loop.fs_realpath(self.plugin.uri) ~= vim.loop.fs_realpath(self.plugin.dir) then
|
||||||
|
vim.loop.fs_unlink(self.plugin.dir)
|
||||||
|
vim.loop.fs_symlink(self.plugin.uri, self.plugin.dir, {
|
||||||
|
dir = true,
|
||||||
|
})
|
||||||
|
vim.opt.runtimepath:append(self.plugin.uri)
|
||||||
|
end
|
||||||
|
|
||||||
|
self:_done()
|
||||||
|
else
|
||||||
|
local args = {
|
||||||
|
"pull",
|
||||||
|
"--recurse-submodules",
|
||||||
|
"--update-shallow",
|
||||||
|
"--progress",
|
||||||
|
}
|
||||||
|
local git = Util.git_info(self.plugin.dir)
|
||||||
|
|
||||||
|
self:spawn("git", {
|
||||||
|
args = args,
|
||||||
|
cwd = self.plugin.dir,
|
||||||
|
on_exit = function(ok)
|
||||||
|
if ok then
|
||||||
|
local git_new = Util.git_info(self.plugin.dir)
|
||||||
|
self.plugin.dirty = not vim.deep_equal(git, git_new)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Task
|
Loading…
Reference in New Issue