Save the lockfile through a temp file and a rename
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/lint Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful

An interrupted save could leave a truncated lock.json.
This commit is contained in:
2026-09-08 23:32:04 +10:00
parent 3190b30e97
commit 11ce1fed9d
2 changed files with 22 additions and 1 deletions
+9 -1
View File
@@ -33,15 +33,23 @@ function M:load()
return self
end
-- Write then rename, so an interrupted save cannot truncate the live lockfile.
function M:save()
vim.fn.mkdir(dirname(self.path), 'p')
local payload = { version = 1, plugins = self.entries }
local fd, err = io.open(self.path, 'w')
local tmp = string.format('%s.%d.tmp', self.path, vim.uv and vim.uv.os_getpid() or vim.loop.os_getpid())
local fd, err = io.open(tmp, 'w')
if not fd then
return false, err
end
fd:write(vim.json.encode(payload))
fd:close()
local ok, rename_err = os.rename(tmp, self.path)
if not ok then
os.remove(tmp)
return false, rename_err
end
return true
end
+13
View File
@@ -42,6 +42,19 @@ t.describe('lock', function()
t.eq({}, Lock.new(path):load():names())
end)
t.it('leaves no temporary file beside the state file', function()
local dir = tmpdir()
local lock = Lock.new(dir .. '/lock.json')
lock:set('plenary.nvim', { tag = 'v0.1.4' })
t.truthy(lock:save())
local names = {}
for _, entry in ipairs(vim.fn.readdir(dir)) do
table.insert(names, entry)
end
t.eq({ 'lock.json' }, names)
end)
t.it('lists names in sorted order', function()
local lock = Lock.new(tmpdir() .. '/lock.json')
lock:set('zebra', { tag = 'v1' })