mirror of
https://github.com/kristoferssolo/telescope-frecency.nvim.git
synced 2025-10-21 20:10:38 +00:00
fix: get file lock forcibly (#153)
* fix: get file lock forcibly When Neovim ends without removing file locks, it will fail to open frecency ever because file locks remain. This fix makes it remove file locks when all attempts fail forcibly. * test: avoid error in Windows In Windows, unclosed file cannot be removed, so close it before unlinking. * feat: retry to unlink when it fails
This commit is contained in:
parent
ca5fa5326f
commit
de41070181
@ -9,13 +9,14 @@ local FileLock = {}
|
|||||||
|
|
||||||
---@class FrecencyFileLockConfig
|
---@class FrecencyFileLockConfig
|
||||||
---@field retry integer default: 5
|
---@field retry integer default: 5
|
||||||
|
---@field unlink_retry integer default: 5
|
||||||
---@field interval integer default: 500
|
---@field interval integer default: 500
|
||||||
|
|
||||||
---@param path string
|
---@param path string
|
||||||
---@param opts FrecencyFileLockConfig?
|
---@param opts FrecencyFileLockConfig?
|
||||||
---@return FrecencyFileLock
|
---@return FrecencyFileLock
|
||||||
FileLock.new = function(path, opts)
|
FileLock.new = function(path, opts)
|
||||||
local config = vim.tbl_extend("force", { retry = 5, interval = 500 }, opts or {})
|
local config = vim.tbl_extend("force", { retry = 5, unlink_retry = 5, interval = 500 }, opts or {})
|
||||||
local self = setmetatable({ config = config }, { __index = FileLock })
|
local self = setmetatable({ config = config }, { __index = FileLock })
|
||||||
self.filename = path .. ".lock"
|
self.filename = path .. ".lock"
|
||||||
return self
|
return self
|
||||||
@ -25,6 +26,7 @@ end
|
|||||||
---@return string? err
|
---@return string? err
|
||||||
function FileLock:get()
|
function FileLock:get()
|
||||||
local count = 0
|
local count = 0
|
||||||
|
local unlink_count = 0
|
||||||
local err, fd
|
local err, fd
|
||||||
while true do
|
while true do
|
||||||
count = count + 1
|
count = count + 1
|
||||||
@ -33,10 +35,18 @@ function FileLock:get()
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
async.util.sleep(self.config.interval)
|
async.util.sleep(self.config.interval)
|
||||||
if count == self.config.retry then
|
if count >= self.config.retry then
|
||||||
log.debug(("file_lock get() failed: retry count reached: %d"):format(count))
|
log.debug(("file_lock get(): retry count reached. try to delete the lock file: %d"):format(count))
|
||||||
|
err = async.uv.fs_unlink(self.filename)
|
||||||
|
if err then
|
||||||
|
log.debug("file_lock get() failed: " .. err)
|
||||||
|
unlink_count = unlink_count + 1
|
||||||
|
if unlink_count >= self.config.unlink_retry then
|
||||||
|
log.error("file_lock get(): failed to unlink the lock file: " .. err)
|
||||||
return "failed to get lock"
|
return "failed to get lock"
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
log.debug(("file_lock get() retry: %d"):format(count))
|
log.debug(("file_lock get() retry: %d"):format(count))
|
||||||
end
|
end
|
||||||
err = async.uv.fs_close(fd)
|
err = async.uv.fs_close(fd)
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
---@diagnostic disable: undefined-field
|
||||||
local FileLock = require "frecency.file_lock"
|
local FileLock = require "frecency.file_lock"
|
||||||
local util = require "frecency.tests.util"
|
local util = require "frecency.tests.util"
|
||||||
local async = require "plenary.async" --[[@as PlenaryAsync]]
|
local async = require "plenary.async" --[[@as PlenaryAsync]]
|
||||||
@ -10,6 +11,18 @@ local function with_dir(f)
|
|||||||
close()
|
close()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function with_unlink_fails(f)
|
||||||
|
return function()
|
||||||
|
local original = async.uv.fs_unlink
|
||||||
|
---@diagnostic disable-next-line: duplicate-set-field
|
||||||
|
async.uv.fs_unlink = function()
|
||||||
|
return "overwritten"
|
||||||
|
end
|
||||||
|
f()
|
||||||
|
async.uv.fs_unlink = original
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
a.describe("file_lock", function()
|
a.describe("file_lock", function()
|
||||||
a.describe("get()", function()
|
a.describe("get()", function()
|
||||||
a.describe("when no lock file", function()
|
a.describe("when no lock file", function()
|
||||||
@ -24,9 +37,11 @@ a.describe("file_lock", function()
|
|||||||
a.describe("when with a lock file", function()
|
a.describe("when with a lock file", function()
|
||||||
with_dir(function(filename)
|
with_dir(function(filename)
|
||||||
local fl = FileLock.new(filename, { retry = 1, interval = 10 })
|
local fl = FileLock.new(filename, { retry = 1, interval = 10 })
|
||||||
a.it("fails to get", function()
|
a.it("gets successfully", function()
|
||||||
assert.is.Nil(async.uv.fs_open(fl.filename, "wx", tonumber("600", 8)))
|
local err, fd = async.uv.fs_open(fl.filename, "wx", tonumber("600", 8))
|
||||||
assert.are.same("failed to get lock", fl:get())
|
assert.is.Nil(err)
|
||||||
|
assert.is.Nil(async.uv.fs_close(fd))
|
||||||
|
assert.is.Nil(fl:get())
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
@ -34,10 +49,23 @@ a.describe("file_lock", function()
|
|||||||
a.describe("when getting twice", function()
|
a.describe("when getting twice", function()
|
||||||
with_dir(function(filename)
|
with_dir(function(filename)
|
||||||
local fl = FileLock.new(filename, { retry = 1, interval = 10 })
|
local fl = FileLock.new(filename, { retry = 1, interval = 10 })
|
||||||
a.it("fails to get", function()
|
a.it("gets successfully", function()
|
||||||
|
assert.is.Nil(fl:get())
|
||||||
|
assert.is.Nil(fl:get())
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
a.describe("when getting twice but unlink fails", function()
|
||||||
|
with_dir(function(filename)
|
||||||
|
local fl = FileLock.new(filename, { retry = 1, interval = 10 })
|
||||||
|
a.it(
|
||||||
|
"fails to get",
|
||||||
|
with_unlink_fails(function()
|
||||||
assert.is.Nil(fl:get())
|
assert.is.Nil(fl:get())
|
||||||
assert.are.same("failed to get lock", fl:get())
|
assert.are.same("failed to get lock", fl:get())
|
||||||
end)
|
end)
|
||||||
|
)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
@ -78,7 +106,9 @@ a.describe("file_lock", function()
|
|||||||
a.describe("when get() fails", function()
|
a.describe("when get() fails", function()
|
||||||
with_dir(function(filename)
|
with_dir(function(filename)
|
||||||
local fl = FileLock.new(filename, { retry = 1, interval = 10 })
|
local fl = FileLock.new(filename, { retry = 1, interval = 10 })
|
||||||
a.it("fails with a valid err", function()
|
a.it(
|
||||||
|
"fails with a valid err",
|
||||||
|
with_unlink_fails(function()
|
||||||
assert.is.Nil(fl:get())
|
assert.is.Nil(fl:get())
|
||||||
assert.are.same(
|
assert.are.same(
|
||||||
"failed to get lock",
|
"failed to get lock",
|
||||||
@ -87,6 +117,7 @@ a.describe("file_lock", function()
|
|||||||
end)
|
end)
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|
)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user