mirror of https://github.com/folke/lazy.nvim.git
feat: new task pipeline runner
This commit is contained in:
parent
97f44f9f65
commit
ab1b512545
|
@ -1,109 +1,86 @@
|
||||||
local Config = require("lazy.core.config")
|
local Config = require("lazy.core.config")
|
||||||
local Task = require("lazy.manage.task")
|
|
||||||
local Runner = require("lazy.manage.runner")
|
local Runner = require("lazy.manage.runner")
|
||||||
local Plugin = require("lazy.core.plugin")
|
local Plugin = require("lazy.core.plugin")
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
---@alias ManagerOpts {wait?: boolean, plugins?: LazyPlugin[], clear?: boolean, show?: boolean}
|
---@class ManagerOpts
|
||||||
|
---@field wait? boolean
|
||||||
|
---@field clear? boolean
|
||||||
|
---@field interactive? boolean
|
||||||
|
|
||||||
---@param operation TaskType
|
---@param ropts RunnerOpts
|
||||||
---@param opts? ManagerOpts
|
---@param opts? ManagerOpts
|
||||||
---@param filter? fun(plugin:LazyPlugin):boolean?
|
function M.run(ropts, opts)
|
||||||
function M.run(operation, opts, filter)
|
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
local plugins = opts.plugins or Config.plugins
|
if opts.interactive == nil then
|
||||||
|
opts.interactive = Config.options.interactive
|
||||||
|
end
|
||||||
|
if ropts.interactive == nil then
|
||||||
|
ropts.interactive = opts.interactive
|
||||||
|
end
|
||||||
|
|
||||||
if opts.clear then
|
if opts.clear then
|
||||||
M.clear()
|
M.clear()
|
||||||
end
|
end
|
||||||
|
|
||||||
if opts.show then
|
if opts.interactive then
|
||||||
require("lazy.view").show()
|
require("lazy.view").show()
|
||||||
end
|
end
|
||||||
|
|
||||||
---@type Runner
|
---@type Runner
|
||||||
local runner = Runner.new()
|
local runner = Runner.new(ropts)
|
||||||
|
runner:start()
|
||||||
-- install missing plugins
|
|
||||||
for _, plugin in pairs(plugins) do
|
|
||||||
if filter == nil or filter(plugin) then
|
|
||||||
runner:add(Task.new(plugin, operation))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
vim.cmd([[do User LazyRender]])
|
vim.cmd([[do User LazyRender]])
|
||||||
|
|
||||||
-- wait for install to finish
|
|
||||||
runner:wait(function()
|
|
||||||
-- check if we need to do any post-install hooks
|
|
||||||
for _, plugin in ipairs(runner:plugins()) do
|
|
||||||
if plugin.dirty then
|
|
||||||
runner:add(Task.new(plugin, "docs"))
|
|
||||||
if plugin.opt == false or plugin.run then
|
|
||||||
runner:add(Task.new(plugin, "run"))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
plugin.dirty = false
|
|
||||||
if opts.show and operation == "update" and plugin.updated and plugin.updated.from ~= plugin.updated.to then
|
|
||||||
runner:add(Task.new(plugin, "log", {
|
|
||||||
log = {
|
|
||||||
from = plugin.updated.from,
|
|
||||||
to = plugin.updated.to,
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- wait for post-install to finish
|
-- wait for post-install to finish
|
||||||
runner:wait(function()
|
runner:wait(function()
|
||||||
vim.cmd([[do User LazyRender]])
|
vim.cmd([[do User LazyRender]])
|
||||||
end)
|
end)
|
||||||
end)
|
|
||||||
|
|
||||||
if opts.wait then
|
if opts.wait then
|
||||||
runner:wait()
|
runner:wait()
|
||||||
end
|
end
|
||||||
return runner
|
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param opts? ManagerOpts
|
---@param opts? ManagerOpts
|
||||||
function M.install(opts)
|
function M.install(opts)
|
||||||
---@param plugin LazyPlugin
|
M.run({
|
||||||
M.run("install", opts, function(plugin)
|
pipeline = { "git.install", { "plugin.docs", "plugin.run" } },
|
||||||
|
plugins = function(plugin)
|
||||||
return plugin.uri and not plugin.installed
|
return plugin.uri and not plugin.installed
|
||||||
end)
|
end,
|
||||||
|
}, opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param opts? ManagerOpts
|
---@param opts? ManagerOpts
|
||||||
function M.update(opts)
|
function M.update(opts)
|
||||||
---@param plugin LazyPlugin
|
M.run({
|
||||||
M.run("update", opts, function(plugin)
|
pipeline = { "git.update", { "plugin.docs", "plugin.run" }, "git.log" },
|
||||||
|
plugins = function(plugin)
|
||||||
return plugin.uri and plugin.installed
|
return plugin.uri and plugin.installed
|
||||||
end)
|
end,
|
||||||
|
}, opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param opts? ManagerOpts
|
---@param opts? ManagerOpts
|
||||||
function M.log(opts)
|
function M.log(opts)
|
||||||
---@param plugin LazyPlugin
|
M.run({
|
||||||
M.run("log", opts, function(plugin)
|
pipeline = { "git.log" },
|
||||||
|
plugins = function(plugin)
|
||||||
return plugin.uri and plugin.installed
|
return plugin.uri and plugin.installed
|
||||||
end)
|
end,
|
||||||
end
|
}, opts)
|
||||||
|
|
||||||
---@param opts? ManagerOpts
|
|
||||||
function M.docs(opts)
|
|
||||||
---@param plugin LazyPlugin
|
|
||||||
M.run("docs", opts, function(plugin)
|
|
||||||
return plugin.installed
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param opts? ManagerOpts
|
---@param opts? ManagerOpts
|
||||||
function M.clean(opts)
|
function M.clean(opts)
|
||||||
opts = opts or {}
|
|
||||||
Plugin.update_state(true)
|
Plugin.update_state(true)
|
||||||
opts.plugins = vim.tbl_values(Config.to_clean)
|
M.run({
|
||||||
M.run("clean", opts)
|
pipeline = { "plugin.clean" },
|
||||||
|
plugins = Config.to_clean,
|
||||||
|
}, opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.clear()
|
function M.clear()
|
||||||
|
@ -114,7 +91,7 @@ function M.clear()
|
||||||
if plugin.tasks then
|
if plugin.tasks then
|
||||||
---@param task LazyTask
|
---@param task LazyTask
|
||||||
plugin.tasks = vim.tbl_filter(function(task)
|
plugin.tasks = vim.tbl_filter(function(task)
|
||||||
return task.running
|
return task:is_running()
|
||||||
end, plugin.tasks)
|
end, plugin.tasks)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,24 +1,124 @@
|
||||||
|
local Task = require("lazy.manage.task")
|
||||||
|
local Config = require("lazy.core.config")
|
||||||
|
|
||||||
|
---@alias LazyPipeline (TaskType|TaskType[])[]
|
||||||
|
|
||||||
|
---@class RunnerOpts
|
||||||
|
---@field pipeline LazyPipeline
|
||||||
|
---@field interactive? boolean
|
||||||
|
---@field plugins? LazyPlugin[]|fun(plugin:LazyPlugin):any?
|
||||||
|
|
||||||
---@class Runner
|
---@class Runner
|
||||||
---@field _tasks LazyTask[]
|
---@field _tasks LazyTask[]
|
||||||
|
---@field _plugins LazyPlugin[]
|
||||||
|
---@field _running boolean
|
||||||
|
---@field _on_done fun()[]
|
||||||
|
---@field _waiting fun()[]
|
||||||
|
---@field _opts RunnerOpts
|
||||||
local Runner = {}
|
local Runner = {}
|
||||||
|
|
||||||
function Runner.new()
|
---@param opts RunnerOpts
|
||||||
local self = setmetatable({}, {
|
function Runner.new(opts)
|
||||||
__index = Runner,
|
local self = setmetatable({}, { __index = Runner })
|
||||||
})
|
self._opts = opts or {}
|
||||||
self._tasks = {}
|
self._tasks = {}
|
||||||
|
|
||||||
|
local plugins = self._opts.plugins
|
||||||
|
if type(plugins) == "function" then
|
||||||
|
self._plugins = vim.tbl_filter(plugins, Config.plugins)
|
||||||
|
else
|
||||||
|
self._plugins = plugins or Config.plugins
|
||||||
|
end
|
||||||
|
self._running = false
|
||||||
|
self._on_done = {}
|
||||||
|
self._waiting = {}
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param task LazyTask
|
---@param plugin LazyPlugin
|
||||||
function Runner:add(task)
|
---@param pipeline LazyPipeline
|
||||||
table.insert(self._tasks, task)
|
function Runner:_run(plugin, pipeline)
|
||||||
|
if #pipeline == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local ops = table.remove(pipeline, 1)
|
||||||
|
if ops == "wait" then
|
||||||
|
return table.insert(self._waiting, function()
|
||||||
|
self:_run(plugin, pipeline)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
ops = type(ops) == "string" and { ops } or ops
|
||||||
|
---@cast ops TaskType[]
|
||||||
|
|
||||||
|
---@type LazyTask[]
|
||||||
|
local tasks = {}
|
||||||
|
|
||||||
|
local function on_done()
|
||||||
|
for _, task in ipairs(tasks) do
|
||||||
|
if task.error or not task:is_done() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self:_run(plugin, pipeline)
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, op in ipairs(ops) do
|
||||||
|
local task = self:queue(plugin, op, { on_done = on_done })
|
||||||
|
if task then
|
||||||
|
table.insert(tasks, task)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, task in ipairs(tasks) do
|
||||||
task:start()
|
task:start()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Runner:is_empty()
|
---@param plugin LazyPlugin
|
||||||
return #self._tasks == 0
|
---@param task_type TaskType
|
||||||
|
---@param opts? TaskOptions
|
||||||
|
---@return LazyTask?
|
||||||
|
function Runner:queue(plugin, task_type, opts)
|
||||||
|
local def = vim.split(task_type, ".", { plain = true })
|
||||||
|
assert(#def == 2)
|
||||||
|
---@type LazyTaskDef
|
||||||
|
local task_def = require("lazy.manage.task." .. def[1])[def[2]]
|
||||||
|
assert(task_def)
|
||||||
|
if not task_def.needed or task_def.needed(plugin, self._opts) then
|
||||||
|
local task = Task.new(plugin, def[2], task_def.run, opts)
|
||||||
|
table.insert(self._tasks, task)
|
||||||
|
return task
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Runner:start()
|
||||||
|
for _, plugin in pairs(self._plugins) do
|
||||||
|
self:_run(plugin, vim.deepcopy(self._opts.pipeline))
|
||||||
|
end
|
||||||
|
self._running = true
|
||||||
|
local check = vim.loop.new_check()
|
||||||
|
|
||||||
|
check:start(function()
|
||||||
|
for _, task in ipairs(self._tasks) do
|
||||||
|
if task:is_running() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #self._waiting > 0 then
|
||||||
|
for _, cb in ipairs(self._waiting) do
|
||||||
|
cb()
|
||||||
|
end
|
||||||
|
self._waiting = {}
|
||||||
|
return
|
||||||
|
end
|
||||||
|
check:stop()
|
||||||
|
self._running = false
|
||||||
|
for _, cb in ipairs(self._on_done) do
|
||||||
|
vim.schedule(cb)
|
||||||
|
end
|
||||||
|
self._on_done = {}
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@return LazyPlugin[]
|
---@return LazyPlugin[]
|
||||||
|
@ -33,33 +133,19 @@ function Runner:tasks()
|
||||||
return self._tasks
|
return self._tasks
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Execute the callback async when done.
|
||||||
|
-- When no callback is specified, this will wait sync
|
||||||
---@param cb? fun()
|
---@param cb? fun()
|
||||||
function Runner:wait(cb)
|
function Runner:wait(cb)
|
||||||
if #self._tasks == 0 then
|
if #self._tasks == 0 or not self._running then
|
||||||
return cb and cb()
|
return cb and cb()
|
||||||
end
|
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
|
if cb then
|
||||||
vim.schedule(cb)
|
table.insert(self._on_done, cb)
|
||||||
end
|
else
|
||||||
end)
|
-- sync wait
|
||||||
|
while self._running do
|
||||||
if not cb then
|
|
||||||
while not done do
|
|
||||||
vim.wait(100)
|
vim.wait(100)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
local Util = require("lazy.util")
|
||||||
|
|
||||||
|
---@type table<string, LazyTaskDef>
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
M.log = {
|
||||||
|
needed = function(plugin, opts)
|
||||||
|
if opts.interactive ~= true or not Util.file_exists(plugin.dir .. "/.git") then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return plugin.updated == nil or plugin.updated.from ~= plugin.updated.to
|
||||||
|
end,
|
||||||
|
run = function(self)
|
||||||
|
local args = {
|
||||||
|
"log",
|
||||||
|
"--pretty=format:%h %s (%cr)",
|
||||||
|
"--abbrev-commit",
|
||||||
|
"--decorate",
|
||||||
|
"--date=short",
|
||||||
|
"--color=never",
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.plugin.updated then
|
||||||
|
table.insert(args, self.plugin.updated.from .. ".." .. (self.plugin.updated.to or "HEAD"))
|
||||||
|
else
|
||||||
|
table.insert(args, "--since=7 days ago")
|
||||||
|
end
|
||||||
|
|
||||||
|
self:spawn("git", {
|
||||||
|
args = args,
|
||||||
|
cwd = self.plugin.dir,
|
||||||
|
})
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
M.update = {
|
||||||
|
run = function(self)
|
||||||
|
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
|
||||||
|
else
|
||||||
|
local args = {
|
||||||
|
"pull",
|
||||||
|
"--tags",
|
||||||
|
"--recurse-submodules",
|
||||||
|
"--update-shallow",
|
||||||
|
"--progress",
|
||||||
|
}
|
||||||
|
local git = assert(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 = 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,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
M.install = {
|
||||||
|
run = function(self)
|
||||||
|
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)
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
return M
|
|
@ -1,36 +1,40 @@
|
||||||
local Process = require("lazy.manage.process")
|
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
|
---@class LazyTask
|
||||||
---@field plugin LazyPlugin
|
---@field plugin LazyPlugin
|
||||||
---@field type TaskType
|
---@field type TaskType
|
||||||
---@field running boolean
|
---@field output string
|
||||||
---@field opts TaskOptions
|
---@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 = {}
|
local Task = {}
|
||||||
|
|
||||||
---@alias TaskType "update"|"install"|"run"|"clean"|"log"|"docs"
|
---@alias TaskType "update"|"install"|"run"|"clean"|"log"|"docs"
|
||||||
|
|
||||||
---@class TaskOptions
|
---@class TaskOptions
|
||||||
---@field on_done? fun(task:LazyTask)
|
---@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 plugin LazyPlugin
|
||||||
---@param type TaskType
|
---@param type TaskType
|
||||||
---@param opts? TaskOptions
|
---@param opts? TaskOptions
|
||||||
function Task.new(plugin, type, opts)
|
---@param task fun(task:LazyTask)
|
||||||
|
function Task.new(plugin, type, task, opts)
|
||||||
local self = setmetatable({}, {
|
local self = setmetatable({}, {
|
||||||
__index = Task,
|
__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.plugin = plugin
|
||||||
self.type = type
|
self.type = type
|
||||||
self.output = ""
|
self.output = ""
|
||||||
|
@ -40,10 +44,40 @@ function Task.new(plugin, type, opts)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function Task:_done()
|
function Task:has_started()
|
||||||
self.running = false
|
return self._started
|
||||||
if self.opts.on_done then
|
end
|
||||||
self.opts.on_done(self)
|
|
||||||
|
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
|
end
|
||||||
vim.cmd("do User LazyRender")
|
vim.cmd("do User LazyRender")
|
||||||
vim.api.nvim_exec_autocmds("User", {
|
vim.api.nvim_exec_autocmds("User", {
|
||||||
|
@ -52,99 +86,25 @@ function Task:_done()
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function Task:clean()
|
---@param fn fun()
|
||||||
local dir = self.plugin.dir:gsub("/+$", "")
|
function Task:schedule(fn)
|
||||||
local stat = vim.loop.fs_lstat(dir)
|
local done = false
|
||||||
|
table.insert(self._running, function()
|
||||||
if stat.type == "directory" then
|
return not done
|
||||||
Util.walk(dir, function(path, _, type)
|
|
||||||
if type == "directory" then
|
|
||||||
vim.loop.fs_rmdir(path)
|
|
||||||
else
|
|
||||||
vim.loop.fs_unlink(path)
|
|
||||||
end
|
|
||||||
end)
|
end)
|
||||||
vim.loop.fs_rmdir(dir)
|
vim.schedule(function()
|
||||||
else
|
---@type boolean, string|any
|
||||||
vim.loop.fs_unlink(dir)
|
local ok, err = pcall(fn)
|
||||||
|
if not ok then
|
||||||
|
self.error = err or "failed"
|
||||||
end
|
end
|
||||||
|
done = true
|
||||||
self.plugin.installed = false
|
self:_check()
|
||||||
self:_done()
|
end)
|
||||||
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,
|
|
||||||
})
|
|
||||||
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()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param cmd string
|
---@param cmd string
|
||||||
---@param opts ProcessOpts
|
---@param opts? ProcessOpts
|
||||||
function Task:spawn(cmd, opts)
|
function Task:spawn(cmd, opts)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
local on_line = opts.on_line
|
local on_line = opts.on_line
|
||||||
|
@ -152,116 +112,42 @@ function Task:spawn(cmd, opts)
|
||||||
|
|
||||||
function opts.on_line(line)
|
function opts.on_line(line)
|
||||||
self.status = line
|
self.status = line
|
||||||
|
|
||||||
if on_line then
|
if on_line then
|
||||||
pcall(on_line, line)
|
pcall(on_line, line)
|
||||||
end
|
end
|
||||||
|
|
||||||
vim.cmd("do User LazyRender")
|
vim.cmd("do User LazyRender")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param output string
|
||||||
function opts.on_exit(ok, output)
|
function opts.on_exit(ok, output)
|
||||||
self.output = output
|
self.output = self.output .. output
|
||||||
|
|
||||||
if not ok then
|
if not ok then
|
||||||
self.error = output
|
self.error = self.error and (self.error .. "\n" .. output) or output
|
||||||
end
|
end
|
||||||
|
|
||||||
if on_exit then
|
if on_exit then
|
||||||
pcall(on_exit, ok, output)
|
pcall(on_exit, ok, output)
|
||||||
end
|
end
|
||||||
|
self:_check()
|
||||||
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()
|
|
||||||
elseif self.type == "log" then
|
|
||||||
self:log()
|
|
||||||
elseif self.type == "docs" then
|
|
||||||
self:docs()
|
|
||||||
end
|
end
|
||||||
|
local proc = Process.spawn(cmd, opts)
|
||||||
|
table.insert(self._running, function()
|
||||||
|
return proc and not proc:is_closing()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if not ok then
|
|
||||||
self.error = err or "failed"
|
|
||||||
self:_done()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Task:log()
|
---@param tasks (LazyTask?)[]
|
||||||
if not Util.file_exists(self.plugin.dir .. "/.git") then
|
function Task.all_done(tasks)
|
||||||
self:_done()
|
for _, task in ipairs(tasks) do
|
||||||
return
|
if task and not task:is_done() then
|
||||||
|
return false
|
||||||
end
|
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
|
end
|
||||||
|
return true
|
||||||
self:spawn("git", {
|
|
||||||
args = args,
|
|
||||||
cwd = self.plugin.dir,
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Task:update()
|
function Task:wait()
|
||||||
if Util.file_exists(self.plugin.uri) then
|
while self:is_running() do
|
||||||
if vim.loop.fs_realpath(self.plugin.uri) ~= vim.loop.fs_realpath(self.plugin.dir) then
|
vim.wait(10)
|
||||||
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",
|
|
||||||
"--tags",
|
|
||||||
"--recurse-submodules",
|
|
||||||
"--update-shallow",
|
|
||||||
"--progress",
|
|
||||||
}
|
|
||||||
local git = assert(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 = 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,
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
local Util = require("lazy.util")
|
||||||
|
local Loader = require("lazy.core.loader")
|
||||||
|
|
||||||
|
---@type table<string, LazyTaskDef>
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
M.run = {
|
||||||
|
needed = function(plugin)
|
||||||
|
return plugin.dirty and (plugin.opt == false or plugin.run)
|
||||||
|
end,
|
||||||
|
run = function(self)
|
||||||
|
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
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
M.clean = {
|
||||||
|
run = function(self)
|
||||||
|
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
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
M.docs = {
|
||||||
|
needed = function(plugin)
|
||||||
|
return plugin.dirty
|
||||||
|
end,
|
||||||
|
run = function(self)
|
||||||
|
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
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
return M
|
|
@ -50,7 +50,7 @@ function M:update()
|
||||||
if plugin.tasks then
|
if plugin.tasks then
|
||||||
for _, task in ipairs(plugin.tasks) do
|
for _, task in ipairs(plugin.tasks) do
|
||||||
self.progress.total = self.progress.total + 1
|
self.progress.total = self.progress.total + 1
|
||||||
if not task.running then
|
if not task:is_running() then
|
||||||
self.progress.done = self.progress.done + 1
|
self.progress.done = self.progress.done + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -215,7 +215,7 @@ function M:diagnostics(plugin)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for _, task in ipairs(plugin.tasks or {}) do
|
for _, task in ipairs(plugin.tasks or {}) do
|
||||||
if task.running then
|
if task:is_running() then
|
||||||
self:diagnostic({
|
self:diagnostic({
|
||||||
severity = vim.diagnostic.severity.WARN,
|
severity = vim.diagnostic.severity.WARN,
|
||||||
message = task.type .. (task.status == "" and "" or (": " .. task.status)),
|
message = task.type .. (task.status == "" and "" or (": " .. task.status)),
|
||||||
|
|
|
@ -25,7 +25,7 @@ return {
|
||||||
{
|
{
|
||||||
filter = function(plugin)
|
filter = function(plugin)
|
||||||
return has_task(plugin, function(task)
|
return has_task(plugin, function(task)
|
||||||
return task.running
|
return task:is_running()
|
||||||
end)
|
end)
|
||||||
end,
|
end,
|
||||||
title = "Working",
|
title = "Working",
|
||||||
|
|
Loading…
Reference in New Issue