feat(git): per-key cache invalidation and optional submodule tracking
This commit is contained in:
@@ -134,6 +134,156 @@ t.test("resolve_sha caches by prefix", function()
|
||||
t.truthy(r._cache["resolve:" .. short], "result should be cached")
|
||||
end)
|
||||
|
||||
---@param r ow.Git.Repo
|
||||
local function wait_initial(r)
|
||||
t.wait_for(function()
|
||||
return r.status.branch.head ~= nil
|
||||
end, "initial fetch to complete", 2000)
|
||||
end
|
||||
|
||||
t.test("_invalidate clears only matching keys for HEAD", function()
|
||||
local dir = h.make_repo({ a = "x" })
|
||||
local r = assert(require("git.core.repo").resolve(dir))
|
||||
r._cache.head = "h"
|
||||
r._cache.refs = { "main" }
|
||||
r._cache.pseudo_refs = { "HEAD" }
|
||||
r._cache.stash_refs = {}
|
||||
r._cache["resolve:abc"] = { "deadbeef", "ok" }
|
||||
r:_invalidate("HEAD")
|
||||
t.eq(r._cache.head, nil)
|
||||
t.eq(r._cache.pseudo_refs, nil)
|
||||
t.eq(r._cache["resolve:abc"], nil)
|
||||
t.truthy(r._cache.refs)
|
||||
t.truthy(r._cache.stash_refs)
|
||||
end)
|
||||
|
||||
t.test("_invalidate clears refs/head/resolve for refs/heads/*", function()
|
||||
local dir = h.make_repo({ a = "x" })
|
||||
local r = assert(require("git.core.repo").resolve(dir))
|
||||
r._cache.head = "h"
|
||||
r._cache.refs = { "main" }
|
||||
r._cache.pseudo_refs = { "HEAD" }
|
||||
r._cache.stash_refs = {}
|
||||
r._cache["resolve:abc"] = { "deadbeef", "ok" }
|
||||
r:_invalidate("refs/heads/feature")
|
||||
t.eq(r._cache.head, nil)
|
||||
t.eq(r._cache.refs, nil)
|
||||
t.eq(r._cache["resolve:abc"], nil)
|
||||
t.truthy(r._cache.pseudo_refs)
|
||||
t.truthy(r._cache.stash_refs)
|
||||
end)
|
||||
|
||||
t.test("_invalidate matches stash_refs on refs/stash and logs/refs/stash", function()
|
||||
local dir = h.make_repo({ a = "x" })
|
||||
local r = assert(require("git.core.repo").resolve(dir))
|
||||
r._cache.stash_refs = {}
|
||||
r:_invalidate("refs/stash")
|
||||
t.eq(r._cache.stash_refs, nil)
|
||||
r._cache.stash_refs = {}
|
||||
r:_invalidate("logs/refs/stash")
|
||||
t.eq(r._cache.stash_refs, nil)
|
||||
end)
|
||||
|
||||
t.test("refresh with invalidate=true wipes cache on next fetch", function()
|
||||
local dir = h.make_repo({ a = "x" })
|
||||
local r = assert(require("git.core.repo").resolve(dir))
|
||||
wait_initial(r)
|
||||
r._cache.head = "stale"
|
||||
r._cache["resolve:abc"] = { "x", "ok" }
|
||||
r:refresh({ invalidate = true })
|
||||
t.wait_for(function()
|
||||
return r._cache.head == nil
|
||||
end, "cache wiped after invalidating refresh completes", 2000)
|
||||
t.eq(r._cache.head, nil)
|
||||
t.eq(r._cache["resolve:abc"], nil)
|
||||
end)
|
||||
|
||||
t.test("refresh emits change.paths listing structurally-changed paths", function()
|
||||
local dir = h.make_repo({ a = "1", b = "1" })
|
||||
local r = assert(require("git.core.repo").resolve(dir))
|
||||
wait_initial(r)
|
||||
t.write(dir, "a", "2")
|
||||
---@type ow.Git.Repo.Change?
|
||||
local change_seen
|
||||
local unsub = r:on("refresh", function(change)
|
||||
change_seen = change
|
||||
end)
|
||||
r:refresh()
|
||||
t.wait_for(function()
|
||||
return change_seen ~= nil
|
||||
end, "refresh emit", 2000)
|
||||
unsub()
|
||||
local change = assert(change_seen)
|
||||
t.truthy(change.paths["a"])
|
||||
t.falsy(change.paths["b"], "b is unchanged structurally")
|
||||
end)
|
||||
|
||||
t.test("submodule: parent enumerates initialized submodules with flag on", function()
|
||||
vim.g.git_submodule_recursion = true
|
||||
t.defer(function()
|
||||
vim.g.git_submodule_recursion = nil
|
||||
end)
|
||||
local outer_path = h.make_submodule_repo()
|
||||
local outer = assert(require("git.core.repo").resolve(outer_path))
|
||||
t.truthy(outer._submodules["sub"], "sub recorded as submodule")
|
||||
end)
|
||||
|
||||
t.test("submodule: recursion flag eagerly creates child Repos and subscribes", function()
|
||||
vim.g.git_submodule_recursion = true
|
||||
t.defer(function()
|
||||
vim.g.git_submodule_recursion = nil
|
||||
end)
|
||||
local outer_path = h.make_submodule_repo()
|
||||
local outer = assert(require("git.core.repo").resolve(outer_path))
|
||||
wait_initial(outer)
|
||||
local inner = require("git.core.repo").all()[outer_path .. "/sub"]
|
||||
t.truthy(inner, "inner Repo eagerly created")
|
||||
t.truthy(outer._submodules["sub"] and outer._submodules["sub"].unsub, "inner subscribed by outer")
|
||||
|
||||
t.write(outer_path .. "/sub", "a", "modified\n")
|
||||
---@type ow.Git.Repo.Change?
|
||||
local outer_change
|
||||
local unsub = outer:on("refresh", function(change)
|
||||
outer_change = change
|
||||
end)
|
||||
inner:refresh()
|
||||
t.wait_for(function()
|
||||
return outer_change ~= nil
|
||||
end, "outer notified by inner refresh", 2000)
|
||||
unsub()
|
||||
|
||||
local entry = outer.status.entries["sub"]
|
||||
t.truthy(entry, "outer sub entry now present")
|
||||
t.eq(entry.kind, "changed")
|
||||
end)
|
||||
|
||||
t.test("submodule: no eager creation when flag is off", function()
|
||||
local outer_path = h.make_submodule_repo()
|
||||
local outer = assert(require("git.core.repo").resolve(outer_path))
|
||||
wait_initial(outer)
|
||||
t.eq(
|
||||
require("git.core.repo").all()[outer_path .. "/sub"],
|
||||
nil,
|
||||
"inner Repo not created when flag off"
|
||||
)
|
||||
t.eq(next(outer._submodules), nil)
|
||||
end)
|
||||
|
||||
t.test("submodule: outer created after inner picks up existing child", function()
|
||||
vim.g.git_submodule_recursion = true
|
||||
t.defer(function()
|
||||
vim.g.git_submodule_recursion = nil
|
||||
end)
|
||||
local outer_path = h.make_submodule_repo()
|
||||
local inner = assert(
|
||||
require("git.core.repo").resolve(outer_path .. "/sub")
|
||||
)
|
||||
wait_initial(inner)
|
||||
local outer = assert(require("git.core.repo").resolve(outer_path))
|
||||
wait_initial(outer)
|
||||
t.truthy(outer._submodules["sub"] and outer._submodules["sub"].unsub, "outer subscribed to pre-existing inner")
|
||||
end)
|
||||
|
||||
t.test("watcher cleans up after a slash-branch dir is removed", function()
|
||||
local dir = h.make_repo({ a = "x" })
|
||||
local r = assert(require("git.core.repo").resolve(dir))
|
||||
|
||||
Reference in New Issue
Block a user