more fixes
This commit is contained in:
151
lua/dep.lua
151
lua/dep.lua
@ -2,15 +2,10 @@ local logger = require('dep.log')
|
|||||||
local git = require('dep.git')
|
local git = require('dep.git')
|
||||||
local packager = require('dep.package')
|
local packager = require('dep.package')
|
||||||
|
|
||||||
---all functions for convenience
|
-- all functions for convenience
|
||||||
---@type table
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
---@type boolean
|
-- performance logging
|
||||||
local initialized
|
|
||||||
|
|
||||||
---performance logging
|
|
||||||
---@type table
|
|
||||||
local perf = {}
|
local perf = {}
|
||||||
|
|
||||||
--- get execution time of a function
|
--- get execution time of a function
|
||||||
@ -30,13 +25,13 @@ function M.registertree(speclist, overrides)
|
|||||||
overrides = overrides or {}
|
overrides = overrides or {}
|
||||||
|
|
||||||
-- recurse the packages
|
-- recurse the packages
|
||||||
|
local over = overrides
|
||||||
for _, spec in pairs(speclist) do
|
for _, spec in pairs(speclist) do
|
||||||
|
|
||||||
-- make sure the overrides override and take into account the packages spec
|
-- make sure the overrides override and take into account the packages spec
|
||||||
---@diagnostic disable-next-line: missing-fields
|
---@diagnostic disable-next-line: missing-fields
|
||||||
overrides = {
|
over = {
|
||||||
pin = overrides.pin or spec.pin,
|
pin = over.pin or spec.pin,
|
||||||
disable = overrides.disable or spec.disable
|
disable = over.disable or spec.disable
|
||||||
}
|
}
|
||||||
|
|
||||||
local ok = packager:new(spec, overrides)
|
local ok = packager:new(spec, overrides)
|
||||||
@ -48,8 +43,48 @@ function M.registertree(speclist, overrides)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- clean out old packages
|
||||||
|
function M.clean()
|
||||||
|
vim.loop.fs_scandir(
|
||||||
|
packager.get_base_dir(),
|
||||||
|
vim.schedule_wrap(function(err, handle)
|
||||||
|
if err then
|
||||||
|
logger:log("error", string.format("failed to clean; reason: %s", err))
|
||||||
|
else
|
||||||
|
local queue = {}
|
||||||
|
|
||||||
|
while handle do
|
||||||
|
local name = vim.loop.fs_scandir_next(handle)
|
||||||
|
if name then
|
||||||
|
queue[name] = packager.get_base_dir()..name
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- keep packages that still exist
|
||||||
|
for _, package in pairs(packager.get_packages()) do
|
||||||
|
queue[package.name] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
for name, dir in pairs(queue) do
|
||||||
|
local co = coroutine.create(function()
|
||||||
|
local ok = vim.fn.delete(dir, "rf")
|
||||||
|
if ok then
|
||||||
|
logger:log("clean", string.format("deleted %s", name))
|
||||||
|
else
|
||||||
|
logger:log("error", string.format("failed to delete %s", name))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
coroutine.resume(co)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
--- reload all packages in package table spec
|
--- reload all packages in package table spec
|
||||||
---@param force boolean|nil force all packages to load
|
---@param force boolean? force all packages to load
|
||||||
function M.reload(force)
|
function M.reload(force)
|
||||||
local reloaded = packager.get_root():loadtree(force)
|
local reloaded = packager.get_root():loadtree(force)
|
||||||
|
|
||||||
@ -72,63 +107,6 @@ function M.reload(force)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- check if there's a circular dependency in the package tree
|
|
||||||
function M.findcycle()
|
|
||||||
local index = 0
|
|
||||||
local indexes = {}
|
|
||||||
local lowlink = {}
|
|
||||||
local stack = {}
|
|
||||||
|
|
||||||
-- use tarjan algorithm to find circular dependencies (strongly connected
|
|
||||||
-- components)
|
|
||||||
local function connect(package)
|
|
||||||
indexes[package.id], lowlink[package.id] = index, index
|
|
||||||
stack[#stack + 1], stack[package.id] = package, true
|
|
||||||
index = index + 1
|
|
||||||
|
|
||||||
for i = 1, #package.dependents do
|
|
||||||
local dependent = package.dependents[i]
|
|
||||||
|
|
||||||
if not indexes[dependent.id] then
|
|
||||||
local cycle = connect(dependent)
|
|
||||||
if cycle then
|
|
||||||
return cycle
|
|
||||||
else
|
|
||||||
lowlink[package.id] = math.min(lowlink[package.id], lowlink[dependent.id])
|
|
||||||
end
|
|
||||||
elseif stack[dependent.id] then
|
|
||||||
lowlink[package.id] = math.min(lowlink[package.id], indexes[dependent.id])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if lowlink[package.id] == indexes[package.id] then
|
|
||||||
local cycle = { package }
|
|
||||||
local node
|
|
||||||
|
|
||||||
repeat
|
|
||||||
node = stack[#stack]
|
|
||||||
stack[#stack], stack[node.id] = nil, nil
|
|
||||||
cycle[#cycle + 1] = node
|
|
||||||
until node == package
|
|
||||||
|
|
||||||
-- a node is by definition strongly connected to itself ignore single-node
|
|
||||||
-- components unless it explicitly specified itself as a dependency
|
|
||||||
if #cycle > 2 or package.dependents[package.id] then
|
|
||||||
return cycle
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, package in pairs(packager.get_packages()) do
|
|
||||||
if not indexes[package.id] then
|
|
||||||
local cycle = connect(package)
|
|
||||||
if cycle then
|
|
||||||
return cycle
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- sync a tree of plugins
|
--- sync a tree of plugins
|
||||||
---@param tree package[] tree of plugins
|
---@param tree package[] tree of plugins
|
||||||
---@param cb function? callback
|
---@param cb function? callback
|
||||||
@ -141,16 +119,15 @@ function M.synctree(tree, cb)
|
|||||||
has_errors = has_errors or err
|
has_errors = has_errors or err
|
||||||
|
|
||||||
if progress == #tree then
|
if progress == #tree then
|
||||||
-- TODO: implement clean
|
|
||||||
-- clean()
|
|
||||||
M.reload()
|
|
||||||
|
|
||||||
if has_errors then
|
if has_errors then
|
||||||
logger:log("error", "there were errors during sync; see :messages or :DepLog for more information")
|
logger:log("error", "there were errors during sync; see :messages or :DepLog for more information")
|
||||||
else
|
else
|
||||||
logger:log("update", "synchronized %s %s", #tree, #tree == 1 and "package" or "packages")
|
logger:log("update", "synchronized %s %s", #tree, #tree == 1 and "package" or "packages")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
M.clean()
|
||||||
|
M.reload()
|
||||||
|
|
||||||
if cb then
|
if cb then
|
||||||
cb()
|
cb()
|
||||||
end
|
end
|
||||||
@ -158,7 +135,10 @@ function M.synctree(tree, cb)
|
|||||||
end
|
end
|
||||||
|
|
||||||
for _, package in pairs(tree) do
|
for _, package in pairs(tree) do
|
||||||
|
local co = coroutine.create(function()
|
||||||
git.sync(package, done)
|
git.sync(package, done)
|
||||||
|
end)
|
||||||
|
coroutine.resume(co)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -167,8 +147,8 @@ return function(opts)
|
|||||||
logger.pipe = logger:setup()
|
logger.pipe = logger:setup()
|
||||||
|
|
||||||
--- make comparison for table.sort
|
--- make comparison for table.sort
|
||||||
---@param a table package spec a
|
---@param a package package spec a
|
||||||
---@param b table package spec b
|
---@param b package package spec b
|
||||||
---@return boolean
|
---@return boolean
|
||||||
local function comp(a, b)
|
local function comp(a, b)
|
||||||
-- NOTE: this doesn't have to be in any real order, it just has to be
|
-- NOTE: this doesn't have to be in any real order, it just has to be
|
||||||
@ -177,7 +157,7 @@ return function(opts)
|
|||||||
return a.id < b.id
|
return a.id < b.id
|
||||||
end
|
end
|
||||||
|
|
||||||
initialized, err = pcall(function()
|
local initialized, err = pcall(function()
|
||||||
packager.set_base_dir(opts.base_dir or vim.fn.stdpath("data").."/site/pack/deps/opt/")
|
packager.set_base_dir(opts.base_dir or vim.fn.stdpath("data").."/site/pack/deps/opt/")
|
||||||
M.benchmark("load", function()
|
M.benchmark("load", function()
|
||||||
-- register all packages
|
-- register all packages
|
||||||
@ -199,7 +179,10 @@ return function(opts)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- make sure there arent any circular dependencies
|
-- make sure there arent any circular dependencies
|
||||||
M.findcycle()
|
local ok = packager.findcycle(packager.get_packages())
|
||||||
|
if type(ok) == "table" then
|
||||||
|
logger:log("error", "found a cycle in the package spec here: %s", vim.inspect(ok))
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- load packages
|
-- load packages
|
||||||
@ -218,12 +201,13 @@ return function(opts)
|
|||||||
|
|
||||||
-- get all package that need syncing
|
-- get all package that need syncing
|
||||||
local targets = {}
|
local targets = {}
|
||||||
for i, package in pairs(packager.get_packages()) do
|
for _, package in pairs(packager.get_packages()) do
|
||||||
if shouldsync(package) then
|
if shouldsync(package) then
|
||||||
targets[i] = package
|
table.insert(targets, package)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- install all targets
|
||||||
M.synctree(targets)
|
M.synctree(targets)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@ -231,17 +215,18 @@ return function(opts)
|
|||||||
logger:log("error", err)
|
logger:log("error", err)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- add some user commands
|
||||||
vim.api.nvim_create_user_command("DepLog", function()
|
vim.api.nvim_create_user_command("DepLog", function()
|
||||||
vim.cmd('vsp '..logger.path)
|
vim.cmd('vsp '..logger.path)
|
||||||
vim.opt_local.readonly = true
|
vim.opt_local.readonly = true
|
||||||
|
|
||||||
|
-- make the log auto update while it's open
|
||||||
local w = vim.uv.new_fs_event()
|
local w = vim.uv.new_fs_event()
|
||||||
local function watch_file(fname)
|
local function watch_file(fname)
|
||||||
local fullpath = vim.api.nvim_call_function(
|
local fullpath = vim.api.nvim_call_function(
|
||||||
'fnamemodify', { fname, ':p' })
|
'fnamemodify', { fname, ':p' })
|
||||||
w:start(fullpath, {}, vim.schedule_wrap(function(...)
|
w:start(fullpath, {}, vim.schedule_wrap(function(...)
|
||||||
vim.api.nvim_command('checktime')
|
vim.api.nvim_command('checktime')
|
||||||
-- Debounce: stop/start.
|
|
||||||
w:stop()
|
w:stop()
|
||||||
watch_file(fname)
|
watch_file(fname)
|
||||||
end))
|
end))
|
||||||
@ -258,5 +243,11 @@ return function(opts)
|
|||||||
M.reload()
|
M.reload()
|
||||||
end, {})
|
end, {})
|
||||||
|
|
||||||
|
vim.api.nvim_create_user_command("DepClean", function()
|
||||||
|
-- clean AND reload to make sure that all old packages are gone
|
||||||
|
M.clean()
|
||||||
|
M.reload()
|
||||||
|
end, {})
|
||||||
|
|
||||||
logger:cleanup()
|
logger:cleanup()
|
||||||
end
|
end
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
-- TODO: clean this up, it's a mess
|
||||||
|
-- the nesting of all the proc calls is really annoying, and I need to find a
|
||||||
|
-- cleaner way to do it
|
||||||
|
|
||||||
local logger = require('dep.log')
|
local logger = require('dep.log')
|
||||||
local proc = require('dep.proc')
|
local proc = require('dep.proc')
|
||||||
|
|
||||||
@ -7,31 +11,47 @@ local git = {}
|
|||||||
---@param package package package to update/install
|
---@param package package package to update/install
|
||||||
---@param cb function callback
|
---@param cb function callback
|
||||||
function git.sync(package, cb)
|
function git.sync(package, cb)
|
||||||
|
local function sync()
|
||||||
|
-- update or install
|
||||||
if package.exists then
|
if package.exists then
|
||||||
git.update(package, cb)
|
git.update(package, cb)
|
||||||
else
|
else
|
||||||
git.install(package, cb)
|
git.install(package, cb)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- handle arbitrary branches here
|
||||||
|
if package.branch then
|
||||||
|
proc.git_resolve_branch(package.url, package.branch, function(err, message)
|
||||||
|
if not err then
|
||||||
|
package.branch = message
|
||||||
|
sync()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
sync()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- configure a package
|
||||||
|
---@param package table package spec
|
||||||
|
local function configurepkg(package)
|
||||||
|
package:runhooks("on_config")
|
||||||
|
|
||||||
|
logger:log("config", "package: %s configured", package.id)
|
||||||
|
package.configured = true
|
||||||
end
|
end
|
||||||
|
|
||||||
--- install a given package
|
--- install a given package
|
||||||
---@param package package package to install
|
---@param package package package to install
|
||||||
---@param cb function callback
|
---@param cb function callback
|
||||||
function git.install(package, cb)
|
function git.install(package, cb)
|
||||||
local function configurepkg()
|
|
||||||
package:runhooks("on_config")
|
|
||||||
|
|
||||||
logger:log("config", "package: %s configured", package.id)
|
|
||||||
package.configured = true
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
if not package.enabled then
|
if not package.enabled then
|
||||||
cb()
|
cb()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
logger:log("error", "%s: doesn't exist", package.id)
|
|
||||||
proc.git_clone(package.dir, package.url, package.branch, function(err, message)
|
proc.git_clone(package.dir, package.url, package.branch, function(err, message)
|
||||||
if err then
|
if err then
|
||||||
logger:log("error", "failed to install %s; reason: %s",
|
logger:log("error", "failed to install %s; reason: %s",
|
||||||
@ -44,15 +64,15 @@ function git.install(package, cb)
|
|||||||
else
|
else
|
||||||
package.exists = true
|
package.exists = true
|
||||||
package:unconfiguretree()
|
package:unconfiguretree()
|
||||||
configurepkg()
|
|
||||||
logger:log("install", "installed %s", package.id)
|
logger:log("install", "installed %s", package.id)
|
||||||
|
configurepkg(package)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
package.exists = true
|
package.exists = true
|
||||||
package:unconfiguretree()
|
package:unconfiguretree()
|
||||||
configurepkg()
|
|
||||||
logger:log("install", "installed %s", package.id)
|
logger:log("install", "installed %s", package.id)
|
||||||
|
configurepkg(package)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -74,15 +94,6 @@ function git.update(package, cb)
|
|||||||
logger:log("error", "failed to update %s; reason: %s", package.id, err)
|
logger:log("error", "failed to update %s; reason: %s", package.id, err)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- configure a package
|
|
||||||
---@param pkg table package spec
|
|
||||||
local function configurepkg(pkg)
|
|
||||||
package:runhooks("on_config")
|
|
||||||
|
|
||||||
logger:log("config", "package: %s configured", pkg.id)
|
|
||||||
package.configured = true
|
|
||||||
end
|
|
||||||
|
|
||||||
if package.pin then
|
if package.pin then
|
||||||
cb()
|
cb()
|
||||||
return
|
return
|
||||||
@ -112,8 +123,8 @@ function git.update(package, cb)
|
|||||||
cb(err)
|
cb(err)
|
||||||
else
|
else
|
||||||
package:unconfiguretree()
|
package:unconfiguretree()
|
||||||
configurepkg(package)
|
|
||||||
logger:log("update", "updated %s; %s -> %s", package.id, before, after)
|
logger:log("update", "updated %s; %s -> %s", package.id, before, after)
|
||||||
|
configurepkg(package)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
@ -124,7 +135,7 @@ function git.update(package, cb)
|
|||||||
log_err(message)
|
log_err(message)
|
||||||
cb(err)
|
cb(err)
|
||||||
else
|
else
|
||||||
proc.git_rev_parse(package.dir, "FETCH_HEAD", function(err, after)
|
proc.git_rev_parse(package.dir, "FETCH_HEAD^{commit}", function(err, after)
|
||||||
if err then
|
if err then
|
||||||
log_err(after)
|
log_err(after)
|
||||||
cb(err)
|
cb(err)
|
||||||
@ -137,8 +148,8 @@ function git.update(package, cb)
|
|||||||
log_err(message)
|
log_err(message)
|
||||||
else
|
else
|
||||||
package:unconfiguretree()
|
package:unconfiguretree()
|
||||||
configurepkg(package)
|
|
||||||
logger:log("update", "updated %s; %s -> %s", package.id, before, after)
|
logger:log("update", "updated %s; %s -> %s", package.id, before, after)
|
||||||
|
configurepkg(package)
|
||||||
end
|
end
|
||||||
|
|
||||||
cb(err)
|
cb(err)
|
||||||
|
@ -76,7 +76,7 @@ function logger:log(level, message, ...)
|
|||||||
|
|
||||||
-- write to the pipe if it's open
|
-- write to the pipe if it's open
|
||||||
if logger.pipe then
|
if logger.pipe then
|
||||||
logger.pipe:write(string.format("[%s] %s:%s: %s\n", os.date("%Y/%m/%d"), source.short_src:gsub('.*%/', ''), source.currentline, message))
|
logger.pipe:write(string.format("[%s] %s:%s: %s\n", os.date("%T"), source.short_src:gsub('.*%/', ''), source.currentline, message))
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
@ -23,13 +23,13 @@ local logger = require('dep.log')
|
|||||||
---@field lazy boolean if the package is lazy loaded in any way
|
---@field lazy boolean if the package is lazy loaded in any way
|
||||||
---@field added boolean if the package has been added in vim
|
---@field added boolean if the package has been added in vim
|
||||||
---@field configured boolean if the package has been configured
|
---@field configured boolean if the package has been configured
|
||||||
|
---@field lazied boolean if the packages lazy loading has been set
|
||||||
---@field loaded boolean if a package has been loaded
|
---@field loaded boolean if a package has been loaded
|
||||||
---@field subtree_loaded boolean is the subtree has been loaded
|
---@field subtree_loaded boolean is the subtree has been loaded
|
||||||
---@field on_config function[] table of functions to run on config
|
---@field on_config function[] table of functions to run on config
|
||||||
---@field on_setup function[] table of function to run on setup
|
---@field on_setup function[] table of function to run on setup
|
||||||
---@field on_load function[] table of functions to run on load
|
---@field on_load function[] table of functions to run on load
|
||||||
---@field lazy_load function[] table of functions to run which will tell the
|
---@field lazy_load function[] table of functions to run which will tell the package when to load
|
||||||
--- package when to load
|
|
||||||
---@field requirements package[] this package's requirements
|
---@field requirements package[] this package's requirements
|
||||||
---@field dependents package[] packages that require this package
|
---@field dependents package[] packages that require this package
|
||||||
---@field perf table performance metrics for the package
|
---@field perf table performance metrics for the package
|
||||||
@ -71,7 +71,7 @@ local function check_spec(spec)
|
|||||||
|
|
||||||
local name = spec[1]:match("^[%w-_.]+/([%w-_.]+)$")
|
local name = spec[1]:match("^[%w-_.]+/([%w-_.]+)$")
|
||||||
if not name then
|
if not name then
|
||||||
logger:log("spec",'invalid name "%s"; must be in the format "user/package"', spec[1])
|
logger:log("spec", 'invalid name "%s"; must be in the format "user/package"', spec[1])
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -153,6 +153,7 @@ local function check_spec(spec)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- turn an id into a spec
|
||||||
if (is == "string") then
|
if (is == "string") then
|
||||||
spec.reqs = { spec.reqs }
|
spec.reqs = { spec.reqs }
|
||||||
end
|
end
|
||||||
@ -165,6 +166,7 @@ local function check_spec(spec)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- turn an id into a spec
|
||||||
if (is == "string") then
|
if (is == "string") then
|
||||||
spec.deps = { spec.deps }
|
spec.deps = { spec.deps }
|
||||||
end
|
end
|
||||||
@ -212,31 +214,33 @@ function package:new(spec, overrides)
|
|||||||
local id = spec[1]
|
local id = spec[1]
|
||||||
|
|
||||||
local o = packages[id] or {}
|
local o = packages[id] or {}
|
||||||
|
self.__index = self
|
||||||
setmetatable(o, self)
|
setmetatable(o, self)
|
||||||
|
|
||||||
-- if package hasn't been registered already, get the inital spec regisitered
|
-- if package hasn't been registered already, get the inital spec regisitered
|
||||||
if not o.id then
|
if not o.id then
|
||||||
o.id = id -- id of the package
|
o.id = id
|
||||||
o.enabled = true -- whether it's going to be used
|
o.enabled = true
|
||||||
o.exists = false -- if the package exists on the filesystem
|
o.exists = false
|
||||||
o.lazy = false -- if the package is lazy loaded in any way
|
o.lazy = false
|
||||||
o.added = false -- if the package has been added in vim
|
o.added = false
|
||||||
o.configured = false -- if the package has been configured
|
o.lazied = false
|
||||||
o.loaded = false -- if a package has been loaded
|
o.configured = false
|
||||||
|
o.loaded = false
|
||||||
o.subtree_loaded = false
|
o.subtree_loaded = false
|
||||||
o.on_config = {} -- table of functions to run on config
|
o.on_config = {}
|
||||||
o.on_setup = {} -- table of function to run on setup
|
o.on_setup = {}
|
||||||
o.on_load = {} -- table of functions to run on load
|
o.on_load = {}
|
||||||
o.lazy_load = {} -- table of functions to run which will tell the package
|
o.lazy_load = {}
|
||||||
-- when to load
|
|
||||||
o.requirements = {} -- this package's requirements
|
o.requirements = {}
|
||||||
o.dependents = {} -- packages that require this package
|
o.dependents = {}
|
||||||
o.perf = {}
|
o.perf = {}
|
||||||
|
|
||||||
packages[id] = o
|
packages[id] = o
|
||||||
end
|
end
|
||||||
|
|
||||||
o.name = spec.as or o.name or id
|
o.name = spec.as or o.name or id:match("^[%w-_.]+/([%w-_.]+)$")
|
||||||
o.url = spec.url or o.url or ("https://github.com/"..id..".git")
|
o.url = spec.url or o.url or ("https://github.com/"..id..".git")
|
||||||
o.branch = spec.branch or o.branch
|
o.branch = spec.branch or o.branch
|
||||||
o.dir = base_dir..o.name
|
o.dir = base_dir..o.name
|
||||||
@ -287,26 +291,32 @@ function package:new(spec, overrides)
|
|||||||
if spec.deps then
|
if spec.deps then
|
||||||
---it is the correct type as asserted in check_spec()
|
---it is the correct type as asserted in check_spec()
|
||||||
---@diagnostic disable-next-line: param-type-mismatch
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
for _, v in pairs(spec.deps) do
|
for _, dep in pairs(spec.deps) do
|
||||||
local pkg = package:new(v)
|
local pkg = package:new(dep)
|
||||||
if type(pkg) ~= "table" then
|
if not pkg then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
o:link_dependency(nil, pkg)
|
o:link_dependency(o, pkg)
|
||||||
|
|
||||||
-- if the child package is lazy loaded make sure the child package
|
-- if the child package is lazy loaded make sure the child package
|
||||||
-- is only loaded when the parent package has finished loading
|
-- is only loaded when the parent package has finished loading
|
||||||
if package.lazy then
|
if o.lazy then
|
||||||
table.insert(package.on_load, function()
|
table.insert(o.on_load, function()
|
||||||
o:loadtree(true)
|
local ok = o:loadtree(true)
|
||||||
|
if not ok then
|
||||||
|
logger:log("lazy",
|
||||||
|
"failed to run loadtree for %s, some packages may not be loaded",
|
||||||
|
o.id)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- tell the dep that it's gonna be lazy
|
||||||
|
pkg.lazy = true
|
||||||
table.insert(pkg.lazy_load, function(_) end)
|
table.insert(pkg.lazy_load, function(_) end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.__index = self
|
|
||||||
|
|
||||||
return o
|
return o
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -316,14 +326,23 @@ function package.set_base_dir(_base_dir)
|
|||||||
base_dir = _base_dir
|
base_dir = _base_dir
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- get the base directory for packages
|
||||||
|
---@return string base_dir
|
||||||
|
---@nodiscard
|
||||||
|
function package.get_base_dir()
|
||||||
|
return base_dir
|
||||||
|
end
|
||||||
|
|
||||||
--- get the root directory
|
--- get the root directory
|
||||||
---@return package root
|
---@return package root
|
||||||
|
---@nodiscard
|
||||||
function package.get_root()
|
function package.get_root()
|
||||||
return root
|
return root
|
||||||
end
|
end
|
||||||
|
|
||||||
--- get the packages in dep
|
--- get the packages in dep
|
||||||
---@return package root
|
---@return package root
|
||||||
|
---@nodiscard
|
||||||
function package.get_packages()
|
function package.get_packages()
|
||||||
return packages
|
return packages
|
||||||
end
|
end
|
||||||
@ -376,12 +395,12 @@ function package:ensureadded(force)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- run setup hooks
|
||||||
|
pkg:runhooks("on_setup")
|
||||||
|
|
||||||
-- now start loading our plugin
|
-- now start loading our plugin
|
||||||
local start = os.clock()
|
local start = os.clock()
|
||||||
|
|
||||||
-- run setup hooks
|
|
||||||
self:runhooks("on_setup")
|
|
||||||
|
|
||||||
-- trigger the packadd for the plugin
|
-- trigger the packadd for the plugin
|
||||||
---@diagnostic disable-next-line: param-type-mismatch
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
local ok, err = pcall(vim.cmd, "packadd "..pkg.name)
|
local ok, err = pcall(vim.cmd, "packadd "..pkg.name)
|
||||||
@ -394,23 +413,24 @@ function package:ensureadded(force)
|
|||||||
logger:log("vim", "packadd completed for %s", pkg.id)
|
logger:log("vim", "packadd completed for %s", pkg.id)
|
||||||
|
|
||||||
-- set the package to loaded
|
-- set the package to loaded
|
||||||
self.loaded = true
|
pkg.loaded = true
|
||||||
logger:log("load", "loaded %s", self.id)
|
logger:log("load", "loaded %s", pkg.id)
|
||||||
|
|
||||||
-- trigger the on_load hooks
|
-- trigger the on_load hooks
|
||||||
ok, err = self:runhooks("on_load")
|
ok, err = pkg:runhooks("on_load")
|
||||||
if not ok then
|
if not ok then
|
||||||
logger:log("error", "failed to load %s; reason: %s", self.id, err)
|
logger:log("error", "failed to load %s; reason: %s", pkg.id, err)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- make sure the package is lazy loaded if need be
|
-- make sure the package is lazy loaded if need be
|
||||||
if not self.added and not self.lazy or force then
|
if not self.added and not self.loaded and not self.lazy or force then
|
||||||
loadpkg(self)
|
loadpkg(self)
|
||||||
elseif not self.added and self.lazy then
|
elseif not self.added and self.lazy then
|
||||||
logger:log("lazy", "registering %d lazy hooks for %s", #self.lazy_load,
|
logger:log("lazy", "registering %d lazy hooks for %s", #self.lazy_load,
|
||||||
self.id)
|
self.id)
|
||||||
|
self.lazied = true
|
||||||
for _, load_cond in pairs(self.lazy_load) do
|
for _, load_cond in pairs(self.lazy_load) do
|
||||||
-- configure the lazy loader for the user
|
-- configure the lazy loader for the user
|
||||||
local l = require('lazy.utils'):new()
|
local l = require('lazy.utils'):new()
|
||||||
@ -436,26 +456,31 @@ end
|
|||||||
--- load all packages in package tree
|
--- load all packages in package tree
|
||||||
---@param force boolean? force lazy packages to load
|
---@param force boolean? force lazy packages to load
|
||||||
---@return boolean boolean if tree was successfully loaded
|
---@return boolean boolean if tree was successfully loaded
|
||||||
|
---@nodiscard
|
||||||
function package:loadtree(force)
|
function package:loadtree(force)
|
||||||
|
-- if the package doesn't exist or isn't enabled then don't load it
|
||||||
if not self.exists or not self.enabled then
|
if not self.exists or not self.enabled then
|
||||||
logger:log("load", "package %s doesn't exist or is not enabled", self.id)
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.subtree_loaded then
|
-- if the subtree is loaded then it's already loaded unless it needs forcing
|
||||||
logger:log("load", "package %s's subtree is already loaded", self.id)
|
if not force and self.subtree_loaded then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- if the package isn't lazy check that it's requirements are loaded
|
||||||
if not self.lazy then
|
if not self.lazy then
|
||||||
for _, requirement in pairs(self.requirements) do
|
for _, requirement in pairs(self.requirements) do
|
||||||
if not requirement.loaded then
|
if not requirement.loaded and not requirement.lazy then
|
||||||
logger:log("load", "package %s requires %s to be loaded first", self.id, requirement.id)
|
logger:log("error", "failed to load %s; requirement: %s isn't loaded",
|
||||||
|
self.id, requirement.id)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- if the package isn't loaded and isn't lazy then it should probably be
|
||||||
|
-- loaded
|
||||||
if not self.loaded then
|
if not self.loaded then
|
||||||
local ok, err = self:ensureadded(force)
|
local ok, err = self:ensureadded(force)
|
||||||
if not ok then
|
if not ok then
|
||||||
@ -464,8 +489,9 @@ function package:loadtree(force)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
package.subtree_loaded = true
|
self.subtree_loaded = true
|
||||||
|
|
||||||
|
-- make sure the dependants are loaded
|
||||||
for _, dependant in pairs(self.dependents) do
|
for _, dependant in pairs(self.dependents) do
|
||||||
self.subtree_loaded = dependant:loadtree(force) and self.subtree_loaded
|
self.subtree_loaded = dependant:loadtree(force) and self.subtree_loaded
|
||||||
end
|
end
|
||||||
@ -490,4 +516,68 @@ function package:unconfiguretree()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- check a list of packages for any cycles
|
||||||
|
---@param pkgs package[] list of packages
|
||||||
|
---@return package[]|false cycle the cycle that was found or false if not found
|
||||||
|
---@nodisacard
|
||||||
|
function package.findcycle(pkgs)
|
||||||
|
local index = 0
|
||||||
|
local indexes = {}
|
||||||
|
local lowlink = {}
|
||||||
|
local stack = {}
|
||||||
|
|
||||||
|
--- use tarjan algorithm to find circular dependencies (strongly connected
|
||||||
|
--- components)
|
||||||
|
---@param pkg package
|
||||||
|
local function connect(pkg)
|
||||||
|
indexes[pkg.id], lowlink[pkg.id] = index, index
|
||||||
|
stack[#stack + 1], stack[pkg.id] = pkg, true
|
||||||
|
index = index + 1
|
||||||
|
|
||||||
|
for i = 1, #pkg.dependents do
|
||||||
|
local dependent = pkg.dependents[i]
|
||||||
|
|
||||||
|
if not indexes[dependent.id] then
|
||||||
|
local cycle = connect(dependent)
|
||||||
|
if cycle then
|
||||||
|
return cycle
|
||||||
|
else
|
||||||
|
lowlink[pkg.id] = math.min(lowlink[pkg.id], lowlink[dependent.id])
|
||||||
|
end
|
||||||
|
elseif stack[dependent.id] then
|
||||||
|
lowlink[pkg.id] = math.min(lowlink[pkg.id], indexes[dependent.id])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if lowlink[pkg.id] == indexes[pkg.id] then
|
||||||
|
local cycle = { pkg }
|
||||||
|
local node
|
||||||
|
|
||||||
|
repeat
|
||||||
|
node = stack[#stack]
|
||||||
|
stack[#stack], stack[node.id] = nil, nil
|
||||||
|
cycle[#cycle + 1] = node
|
||||||
|
until node == pkg
|
||||||
|
|
||||||
|
-- a node is by definition strongly connected to itself ignore single-node
|
||||||
|
-- components unless it explicitly specified itself as a dependency
|
||||||
|
if #cycle > 2 or pkg.dependents[pkg.id] then
|
||||||
|
return cycle
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- actually check the cycle
|
||||||
|
for _, pkg in pairs(pkgs) do
|
||||||
|
if not indexes[package.id] then
|
||||||
|
local cycle = connect(pkg)
|
||||||
|
if cycle then
|
||||||
|
return cycle
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
return package
|
return package
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
local proc = {}
|
local proc = {}
|
||||||
|
|
||||||
|
--- execute a process
|
||||||
|
---@param process string the program
|
||||||
|
---@param args string[] the args
|
||||||
|
---@param cwd string? the pwd
|
||||||
|
---@param env table env
|
||||||
|
---@param cb function callback
|
||||||
function proc.exec(process, args, cwd, env, cb)
|
function proc.exec(process, args, cwd, env, cb)
|
||||||
local buffer = {}
|
local buffer = {}
|
||||||
|
|
||||||
local function cb_output(_, data, _)
|
local function cb_output(_, data, _)
|
||||||
table.insert(buffer, table.concat(data))
|
table.insert(buffer, table.concat(data))
|
||||||
end
|
end
|
||||||
local function cb_exit(job_id, exit_code, _)
|
local function cb_exit(_, exit_code, _)
|
||||||
local output = table.concat(buffer)
|
local output = table.concat(buffer)
|
||||||
cb(exit_code ~= 0, output)
|
cb(exit_code ~= 0, output)
|
||||||
end
|
end
|
||||||
@ -62,27 +68,31 @@ function proc.git_checkout(dir, branch, commit, cb)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function proc.git_resolve_branch(url, branch, cb)
|
function proc.git_resolve_branch(url, branch, cb)
|
||||||
if string.match(branch or "", "*") ~= "*" then
|
-- if the branch doesn't contain a * then return the branch
|
||||||
|
if not string.match(branch, "*") then
|
||||||
cb(false, branch)
|
cb(false, branch)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local buffer = {}
|
|
||||||
|
|
||||||
|
local buffer = {}
|
||||||
local function cb_output(_, data, _)
|
local function cb_output(_, data, _)
|
||||||
if data[1] ~= "" then
|
if data[1] ~= "" then
|
||||||
buffer = data
|
buffer = data
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
vim.fn.jobstart({ "git", "ls-remote", "--tags", "--sort", "v:refname", url, },
|
vim.fn.jobstart({ "git", "ls-remote", "--tags", "--sort", "v:refname", url },
|
||||||
{
|
{
|
||||||
cwd = nil,
|
cwd = nil,
|
||||||
env = { GIT_TERMINAL_PROMPT = 0 },
|
env = git_env,
|
||||||
stdin = nil,
|
stdin = nil,
|
||||||
on_stdout = cb_output,
|
on_stdout = cb_output,
|
||||||
on_stderr = cb_output,
|
on_stderr = cb_output,
|
||||||
on_exit = function(_, exit_code, _)
|
on_exit = function(_, exit_code, _)
|
||||||
if exit_code == 0 then
|
if exit_code ~= 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- get a list of all versions
|
-- get a list of all versions
|
||||||
local versions = {}
|
local versions = {}
|
||||||
for _, v in pairs(buffer) do
|
for _, v in pairs(buffer) do
|
||||||
@ -92,8 +102,7 @@ function proc.git_resolve_branch(url, branch, cb)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local tag = string.sub(v, s, e)
|
local tag = string.sub(v, s, e)
|
||||||
tag = string.gsub(tag, "refs/tags/", "")
|
tag = tag:gsub("refs/tags/", ""):gsub("%^{}", "")
|
||||||
tag = string.gsub(tag, "%^{}", "")
|
|
||||||
|
|
||||||
table.insert(versions, tag)
|
table.insert(versions, tag)
|
||||||
::continue::
|
::continue::
|
||||||
@ -113,7 +122,6 @@ function proc.git_resolve_branch(url, branch, cb)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ end
|
|||||||
---@param opts vim.api.keyset.user_command? options
|
---@param opts vim.api.keyset.user_command? options
|
||||||
function lazy:cmd(name, opts)
|
function lazy:cmd(name, opts)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
vim.api.nvim_create_user_command(name, function(o)
|
vim.api.nvim_create_user_command(name, opts['callback'] or function()
|
||||||
self:cleanup()
|
self:cleanup()
|
||||||
end, opts)
|
end, opts)
|
||||||
|
|
||||||
@ -49,9 +49,8 @@ end
|
|||||||
---@param opts vim.api.keyset.create_autocmd? options
|
---@param opts vim.api.keyset.create_autocmd? options
|
||||||
function lazy:auto(event, opts)
|
function lazy:auto(event, opts)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
opts['once'] = true
|
opts['once'] = opts['once'] or true
|
||||||
|
opts['callback'] = opts['callback'] or function()
|
||||||
opts['callback'] = function()
|
|
||||||
self:cleanup()
|
self:cleanup()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -64,7 +63,7 @@ end
|
|||||||
---@param opts vim.keymap.set.Opts? options
|
---@param opts vim.keymap.set.Opts? options
|
||||||
function lazy:keymap(mode, bind, opts)
|
function lazy:keymap(mode, bind, opts)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
vim.keymap.set(mode, bind, function()
|
vim.keymap.set(mode, bind, opts['callback'] or function()
|
||||||
self:cleanup()
|
self:cleanup()
|
||||||
|
|
||||||
-- register keymap unload
|
-- register keymap unload
|
||||||
|
Reference in New Issue
Block a user