mirror of
https://github.com/folke/lazy.nvim.git
synced 2025-04-18 20:36:45 +00:00
feat: new task pipeline runner
This commit is contained in:
parent
97f44f9f65
commit
ab1b512545
7 changed files with 427 additions and 298 deletions
|
@ -1,36 +1,40 @@
|
|||
local Process = require("lazy.manage.process")
|
||||
local Loader = require("lazy.core.loader")
|
||||
local Util = require("lazy.util")
|
||||
|
||||
---@class LazyTaskDef
|
||||
---@field needed? fun(plugin:LazyPlugin, opts:RunnerOpts):any?
|
||||
---@field run fun(task:LazyTask)
|
||||
|
||||
---@alias LazyTaskState fun():boolean?
|
||||
|
||||
---@class LazyTask
|
||||
---@field plugin LazyPlugin
|
||||
---@field type TaskType
|
||||
---@field running boolean
|
||||
---@field opts TaskOptions
|
||||
---@field output string
|
||||
---@field status string
|
||||
---@field error? string
|
||||
---@field private _task fun(task:LazyTask)
|
||||
---@field private _running LazyPluginState[]
|
||||
---@field private _started boolean
|
||||
---@field private _opts TaskOptions
|
||||
local Task = {}
|
||||
|
||||
---@alias TaskType "update"|"install"|"run"|"clean"|"log"|"docs"
|
||||
|
||||
---@class TaskOptions
|
||||
---@field on_done? fun(task:LazyTask)
|
||||
local options = {
|
||||
log = {
|
||||
since = "7 days ago",
|
||||
---@type string
|
||||
from = nil,
|
||||
---@type string
|
||||
to = nil,
|
||||
},
|
||||
}
|
||||
|
||||
---@param plugin LazyPlugin
|
||||
---@param type TaskType
|
||||
---@param opts? TaskOptions
|
||||
function Task.new(plugin, type, opts)
|
||||
---@param task fun(task:LazyTask)
|
||||
function Task.new(plugin, type, task, opts)
|
||||
local self = setmetatable({}, {
|
||||
__index = Task,
|
||||
})
|
||||
self.opts = vim.tbl_deep_extend("force", {}, options, opts or {})
|
||||
self._opts = opts or {}
|
||||
self._running = {}
|
||||
self._task = task
|
||||
self._started = false
|
||||
self.plugin = plugin
|
||||
self.type = type
|
||||
self.output = ""
|
||||
|
@ -40,10 +44,40 @@ function Task.new(plugin, type, opts)
|
|||
return self
|
||||
end
|
||||
|
||||
function Task:_done()
|
||||
self.running = false
|
||||
if self.opts.on_done then
|
||||
self.opts.on_done(self)
|
||||
function Task:has_started()
|
||||
return self._started
|
||||
end
|
||||
|
||||
function Task:is_done()
|
||||
return self:has_started() and not self:is_running()
|
||||
end
|
||||
|
||||
function Task:is_running()
|
||||
for _, state in ipairs(self._running) do
|
||||
if state() then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function Task:start()
|
||||
self._started = true
|
||||
---@type boolean, string|any
|
||||
local ok, err = pcall(self._task, self)
|
||||
if not ok then
|
||||
self.error = err or "failed"
|
||||
end
|
||||
self:_check()
|
||||
end
|
||||
|
||||
---@private
|
||||
function Task:_check()
|
||||
if self:is_running() then
|
||||
return
|
||||
end
|
||||
if self._opts.on_done then
|
||||
self._opts.on_done(self)
|
||||
end
|
||||
vim.cmd("do User LazyRender")
|
||||
vim.api.nvim_exec_autocmds("User", {
|
||||
|
@ -52,99 +86,25 @@ function Task:_done()
|
|||
})
|
||||
end
|
||||
|
||||
function Task:clean()
|
||||
local dir = self.plugin.dir:gsub("/+$", "")
|
||||
local stat = vim.loop.fs_lstat(dir)
|
||||
|
||||
if stat.type == "directory" then
|
||||
Util.walk(dir, function(path, _, type)
|
||||
if type == "directory" then
|
||||
vim.loop.fs_rmdir(path)
|
||||
else
|
||||
vim.loop.fs_unlink(path)
|
||||
end
|
||||
end)
|
||||
vim.loop.fs_rmdir(dir)
|
||||
else
|
||||
vim.loop.fs_unlink(dir)
|
||||
end
|
||||
|
||||
self.plugin.installed = false
|
||||
self:_done()
|
||||
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",
|
||||
"--filter=blob:none",
|
||||
-- "--filter=tree:0",
|
||||
"--recurse-submodules",
|
||||
"--single-branch",
|
||||
"--shallow-submodules",
|
||||
"--progress",
|
||||
}
|
||||
|
||||
if self.plugin.branch then
|
||||
vim.list_extend(args, {
|
||||
"-b",
|
||||
self.plugin.branch,
|
||||
})
|
||||
---@param fn fun()
|
||||
function Task:schedule(fn)
|
||||
local done = false
|
||||
table.insert(self._running, function()
|
||||
return not done
|
||||
end)
|
||||
vim.schedule(function()
|
||||
---@type boolean, string|any
|
||||
local ok, err = pcall(fn)
|
||||
if not ok then
|
||||
self.error = err or "failed"
|
||||
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, { task = "run" }, { load_start = true })
|
||||
|
||||
local run = self.plugin.run
|
||||
if run then
|
||||
if type(run) == "string" and run:sub(1, 1) == ":" then
|
||||
local cmd = vim.api.nvim_parse_cmd(run:sub(2), {})
|
||||
self.output = vim.api.nvim_cmd(cmd, { output = true })
|
||||
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
|
||||
-- FIXME: the spawn above wont be finished yet
|
||||
self:_done()
|
||||
end
|
||||
|
||||
function Task:docs()
|
||||
local docs = self.plugin.dir .. "/doc/"
|
||||
if Util.file_exists(docs) then
|
||||
self.output = vim.api.nvim_cmd({ cmd = "helptags", args = { docs } }, { output = true })
|
||||
end
|
||||
self:_done()
|
||||
done = true
|
||||
self:_check()
|
||||
end)
|
||||
end
|
||||
|
||||
---@param cmd string
|
||||
---@param opts ProcessOpts
|
||||
---@param opts? ProcessOpts
|
||||
function Task:spawn(cmd, opts)
|
||||
opts = opts or {}
|
||||
local on_line = opts.on_line
|
||||
|
@ -152,116 +112,42 @@ function Task:spawn(cmd, opts)
|
|||
|
||||
function opts.on_line(line)
|
||||
self.status = line
|
||||
|
||||
if on_line then
|
||||
pcall(on_line, line)
|
||||
end
|
||||
|
||||
vim.cmd("do User LazyRender")
|
||||
end
|
||||
|
||||
---@param output string
|
||||
function opts.on_exit(ok, output)
|
||||
self.output = output
|
||||
|
||||
self.output = self.output .. output
|
||||
if not ok then
|
||||
self.error = output
|
||||
self.error = self.error and (self.error .. "\n" .. output) or output
|
||||
end
|
||||
|
||||
if on_exit then
|
||||
pcall(on_exit, ok, output)
|
||||
end
|
||||
|
||||
self:_done()
|
||||
self:_check()
|
||||
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()
|
||||
elseif self.type == "log" then
|
||||
self:log()
|
||||
elseif self.type == "docs" then
|
||||
self:docs()
|
||||
end
|
||||
local proc = Process.spawn(cmd, opts)
|
||||
table.insert(self._running, function()
|
||||
return proc and not proc:is_closing()
|
||||
end)
|
||||
|
||||
if not ok then
|
||||
self.error = err or "failed"
|
||||
self:_done()
|
||||
end
|
||||
end
|
||||
|
||||
function Task:log()
|
||||
if not Util.file_exists(self.plugin.dir .. "/.git") then
|
||||
self:_done()
|
||||
return
|
||||
end
|
||||
|
||||
local args = {
|
||||
"log",
|
||||
"--pretty=format:%h %s (%cr)",
|
||||
"--abbrev-commit",
|
||||
"--decorate",
|
||||
"--date=short",
|
||||
"--color=never",
|
||||
}
|
||||
|
||||
if self.opts.log.from then
|
||||
table.insert(args, self.opts.log.from .. ".." .. (self.opts.log.to or "HEAD"))
|
||||
else
|
||||
table.insert(args, "--since=" .. self.opts.log.since)
|
||||
end
|
||||
|
||||
self:spawn("git", {
|
||||
args = args,
|
||||
cwd = self.plugin.dir,
|
||||
})
|
||||
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)
|
||||
---@param tasks (LazyTask?)[]
|
||||
function Task.all_done(tasks)
|
||||
for _, task in ipairs(tasks) do
|
||||
if task and not task:is_done() then
|
||||
return false
|
||||
end
|
||||
self:_done()
|
||||
else
|
||||
local args = {
|
||||
"pull",
|
||||
"--tags",
|
||||
"--recurse-submodules",
|
||||
"--update-shallow",
|
||||
"--progress",
|
||||
}
|
||||
local git = assert(Util.git_info(self.plugin.dir))
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
self:spawn("git", {
|
||||
args = args,
|
||||
cwd = self.plugin.dir,
|
||||
on_exit = function(ok)
|
||||
if ok then
|
||||
local git_new = assert(Util.git_info(self.plugin.dir))
|
||||
self.plugin.updated = {
|
||||
from = git.hash,
|
||||
to = git_new.hash,
|
||||
}
|
||||
self.plugin.dirty = not vim.deep_equal(git, git_new)
|
||||
end
|
||||
end,
|
||||
})
|
||||
function Task:wait()
|
||||
while self:is_running() do
|
||||
vim.wait(10)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue