commit 3b860653ca0c698629d714f3af996822335debd1
parent 006101360d6fbcadfe7c8d030f1d66cfcaf34951
Author: Evgeni Chasnovski <evgeni.chasnovski@gmail.com>
Date: Tue, 7 Oct 2025 22:24:23 +0300
fix(pack): handle lockfile in case of install errors #36064
Problem: If plugin was intended to install but there were errors (like
if there is a typo in `src`), lockfile still includes its entry.
This leads to all source of problems (like not correct `get()` output,
not working `update()`, etc.).
Solution: Explicitly account for plugins that were not installed.
Alternative solution might be to write a safe
`lock_set(plug, field, value)` wrapper (which sets field for a correct
`plugins` entry in the lockfile Lua table) and use it after install
to detect the change in `version`. However, this always requires
an extra pass through plugins on every startup, which is suboptimal.
Optimizing for the "happy path" should be a priority in `add()`.
Diffstat:
2 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua
@@ -789,6 +789,11 @@ function M.add(specs, opts)
if #plugs_to_install > 0 then
git_ensure_exec()
install_list(plugs_to_install, opts.confirm)
+ for _, p in ipairs(plugs_to_install) do
+ if not p.info.installed then
+ plugin_lock.plugins[p.spec.name] = nil
+ end
+ end
end
if needs_lock_write then
diff --git a/test/functional/plugin/pack_spec.lua b/test/functional/plugin/pack_spec.lua
@@ -541,6 +541,29 @@ describe('vim.pack', function()
eq(ref_lockfile, get_lock_tbl())
end)
+ it('handles lockfile during install errors', function()
+ local repo_not_exist = 'file://' .. repo_get_path('does-not-exist')
+ pcall_err(exec_lua, function()
+ vim.pack.add({
+ repo_not_exist,
+ { src = repos_src.basic, version = 'not-exist' },
+ { src = repos_src.pluginerr, version = 'main' },
+ })
+ end)
+
+ local pluginerr_hash = git_get_hash('main', 'pluginerr')
+ local ref_lockfile = {
+ -- Should be no entry for `repo_not_exist`
+ plugins = {
+ -- No `rev` because there was no relevant checkout
+ basic = { src = repos_src.basic, version = "'not-exist'" },
+ -- Error during sourcing 'plugin/' should not affect lockfile
+ pluginerr = { rev = pluginerr_hash, src = repos_src.pluginerr, version = "'main'" },
+ },
+ }
+ eq(ref_lockfile, get_lock_tbl())
+ end)
+
it('installs at proper version', function()
local out = exec_lua(function()
vim.pack.add({