more fixes

This commit is contained in:
2025-04-23 00:15:13 -05:00
parent 254436c24d
commit c29395004d
6 changed files with 282 additions and 183 deletions

View File

@ -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 proc = require('dep.proc')
@ -7,31 +11,47 @@ local git = {}
---@param package package package to update/install
---@param cb function callback
function git.sync(package, cb)
if package.exists then
git.update(package, cb)
else
git.install(package, cb)
local function sync()
-- update or install
if package.exists then
git.update(package, cb)
else
git.install(package, cb)
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
--- install a given package
---@param package package package to install
---@param cb function callback
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
cb()
return
end
logger:log("error", "%s: doesn't exist", package.id)
proc.git_clone(package.dir, package.url, package.branch, function(err, message)
if err then
logger:log("error", "failed to install %s; reason: %s",
@ -44,15 +64,15 @@ function git.install(package, cb)
else
package.exists = true
package:unconfiguretree()
configurepkg()
logger:log("install", "installed %s", package.id)
configurepkg(package)
end
end)
else
package.exists = true
package:unconfiguretree()
configurepkg()
logger:log("install", "installed %s", package.id)
configurepkg(package)
end
end
@ -74,15 +94,6 @@ function git.update(package, cb)
logger:log("error", "failed to update %s; reason: %s", package.id, err)
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
cb()
return
@ -112,8 +123,8 @@ function git.update(package, cb)
cb(err)
else
package:unconfiguretree()
configurepkg(package)
logger:log("update", "updated %s; %s -> %s", package.id, before, after)
configurepkg(package)
end
end)
end
@ -124,7 +135,7 @@ function git.update(package, cb)
log_err(message)
cb(err)
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
log_err(after)
cb(err)
@ -137,8 +148,8 @@ function git.update(package, cb)
log_err(message)
else
package:unconfiguretree()
configurepkg(package)
logger:log("update", "updated %s; %s -> %s", package.id, before, after)
configurepkg(package)
end
cb(err)

View File

@ -76,7 +76,7 @@ function logger:log(level, message, ...)
-- write to the pipe if it's open
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

View File

@ -23,13 +23,13 @@ local logger = require('dep.log')
---@field lazy boolean if the package is lazy loaded in any way
---@field added boolean if the package has been added in vim
---@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 subtree_loaded boolean is the subtree has been loaded
---@field on_config function[] table of functions to run on config
---@field on_setup function[] table of function to run on setup
---@field on_load function[] table of functions to run on load
---@field lazy_load function[] table of functions to run which will tell the
--- package when to load
---@field lazy_load function[] table of functions to run which will tell the package when to load
---@field requirements package[] this package's requirements
---@field dependents package[] packages that require this 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-_.]+)$")
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
end
end
@ -153,6 +153,7 @@ local function check_spec(spec)
return false
end
-- turn an id into a spec
if (is == "string") then
spec.reqs = { spec.reqs }
end
@ -165,6 +166,7 @@ local function check_spec(spec)
return false
end
-- turn an id into a spec
if (is == "string") then
spec.deps = { spec.deps }
end
@ -212,31 +214,33 @@ function package:new(spec, overrides)
local id = spec[1]
local o = packages[id] or {}
self.__index = self
setmetatable(o, self)
-- if package hasn't been registered already, get the inital spec regisitered
if not o.id then
o.id = id -- id of the package
o.enabled = true -- whether it's going to be used
o.exists = false -- if the package exists on the filesystem
o.lazy = false -- if the package is lazy loaded in any way
o.added = false -- if the package has been added in vim
o.configured = false -- if the package has been configured
o.loaded = false -- if a package has been loaded
o.id = id
o.enabled = true
o.exists = false
o.lazy = false
o.added = false
o.lazied = false
o.configured = false
o.loaded = false
o.subtree_loaded = false
o.on_config = {} -- table of functions to run on config
o.on_setup = {} -- table of function to run on setup
o.on_load = {} -- table of functions to run on load
o.lazy_load = {} -- table of functions to run which will tell the package
-- when to load
o.requirements = {} -- this package's requirements
o.dependents = {} -- packages that require this package
o.on_config = {}
o.on_setup = {}
o.on_load = {}
o.lazy_load = {}
o.requirements = {}
o.dependents = {}
o.perf = {}
packages[id] = o
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.branch = spec.branch or o.branch
o.dir = base_dir..o.name
@ -287,26 +291,32 @@ function package:new(spec, overrides)
if spec.deps then
---it is the correct type as asserted in check_spec()
---@diagnostic disable-next-line: param-type-mismatch
for _, v in pairs(spec.deps) do
local pkg = package:new(v)
if type(pkg) ~= "table" then
for _, dep in pairs(spec.deps) do
local pkg = package:new(dep)
if not pkg then
return false
end
o:link_dependency(nil, pkg)
o:link_dependency(o, pkg)
-- if the child package is lazy loaded make sure the child package
-- is only loaded when the parent package has finished loading
if package.lazy then
table.insert(package.on_load, function()
o:loadtree(true)
if o.lazy then
table.insert(o.on_load, function()
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)
-- tell the dep that it's gonna be lazy
pkg.lazy = true
table.insert(pkg.lazy_load, function(_) end)
end
end
end
self.__index = self
return o
end
@ -316,14 +326,23 @@ function package.set_base_dir(_base_dir)
base_dir = _base_dir
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
---@return package root
---@nodiscard
function package.get_root()
return root
end
--- get the packages in dep
---@return package root
---@nodiscard
function package.get_packages()
return packages
end
@ -376,12 +395,12 @@ function package:ensureadded(force)
end
end
-- run setup hooks
pkg:runhooks("on_setup")
-- now start loading our plugin
local start = os.clock()
-- run setup hooks
self:runhooks("on_setup")
-- trigger the packadd for the plugin
---@diagnostic disable-next-line: param-type-mismatch
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)
-- set the package to loaded
self.loaded = true
logger:log("load", "loaded %s", self.id)
pkg.loaded = true
logger:log("load", "loaded %s", pkg.id)
-- trigger the on_load hooks
ok, err = self:runhooks("on_load")
ok, err = pkg:runhooks("on_load")
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
end
end
-- 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)
elseif not self.added and self.lazy then
logger:log("lazy", "registering %d lazy hooks for %s", #self.lazy_load,
self.id)
self.lazied = true
for _, load_cond in pairs(self.lazy_load) do
-- configure the lazy loader for the user
local l = require('lazy.utils'):new()
@ -436,26 +456,31 @@ end
--- load all packages in package tree
---@param force boolean? force lazy packages to load
---@return boolean boolean if tree was successfully loaded
---@nodiscard
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
logger:log("load", "package %s doesn't exist or is not enabled", self.id)
return false
end
if self.subtree_loaded then
logger:log("load", "package %s's subtree is already loaded", self.id)
-- if the subtree is loaded then it's already loaded unless it needs forcing
if not force and self.subtree_loaded then
return true
end
-- if the package isn't lazy check that it's requirements are loaded
if not self.lazy then
for _, requirement in pairs(self.requirements) do
if not requirement.loaded then
logger:log("load", "package %s requires %s to be loaded first", self.id, requirement.id)
if not requirement.loaded and not requirement.lazy then
logger:log("error", "failed to load %s; requirement: %s isn't loaded",
self.id, requirement.id)
return false
end
end
end
-- if the package isn't loaded and isn't lazy then it should probably be
-- loaded
if not self.loaded then
local ok, err = self:ensureadded(force)
if not ok then
@ -464,8 +489,9 @@ function package:loadtree(force)
end
end
package.subtree_loaded = true
self.subtree_loaded = true
-- make sure the dependants are loaded
for _, dependant in pairs(self.dependents) do
self.subtree_loaded = dependant:loadtree(force) and self.subtree_loaded
end
@ -490,4 +516,68 @@ function package:unconfiguretree()
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

View File

@ -1,12 +1,18 @@
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)
local buffer = {}
local function cb_output(_, data, _)
table.insert(buffer, table.concat(data))
end
local function cb_exit(job_id, exit_code, _)
local function cb_exit(_, exit_code, _)
local output = table.concat(buffer)
cb(exit_code ~= 0, output)
end
@ -62,54 +68,56 @@ function proc.git_checkout(dir, branch, commit, cb)
end
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)
return
end
local buffer = {}
local buffer = {}
local function cb_output(_, data, _)
if data[1] ~= "" then
buffer = data
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,
env = { GIT_TERMINAL_PROMPT = 0 },
env = git_env,
stdin = nil,
on_stdout = cb_output,
on_stderr = cb_output,
on_exit = function(_, exit_code, _)
if exit_code == 0 then
-- get a list of all versions
local versions = {}
for _, v in pairs(buffer) do
local s, e = string.find(v, "refs/tags/.+")
if not s or not e then
goto continue
end
if exit_code ~= 0 then
return
end
local tag = string.sub(v, s, e)
tag = string.gsub(tag, "refs/tags/", "")
tag = string.gsub(tag, "%^{}", "")
table.insert(versions, tag)
::continue::
-- get a list of all versions
local versions = {}
for _, v in pairs(buffer) do
local s, e = string.find(v, "refs/tags/.+")
if not s or not e then
goto continue
end
-- match the chosen version against all versions
for i = #versions, 1, -1 do
if branch == "*" then
cb(false, versions[i])
local tag = string.sub(v, s, e)
tag = tag:gsub("refs/tags/", ""):gsub("%^{}", "")
table.insert(versions, tag)
::continue::
end
-- match the chosen version against all versions
for i = #versions, 1, -1 do
if branch == "*" then
cb(false, versions[i])
return
else
local r = string.match(versions[i], branch)
if r then
cb(false, r)
return
else
local r = string.match(versions[i], branch)
if r then
cb(false, r)
return
end
end
end
end