Skip to content

Commit

Permalink
Add submodule caching
Browse files Browse the repository at this point in the history
  • Loading branch information
jorio committed Nov 18, 2023
1 parent 82238f1 commit ce84a11
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 5 deletions.
11 changes: 6 additions & 5 deletions pygit2/_run.py
Expand Up @@ -91,14 +91,15 @@

C_HEADER_SRC = '\n'.join(h_source)

C_PREAMBLE = """\
#include <git2.h>
#include <git2/sys/repository.h>
"""

# ffi
_, libgit2_kw = get_libgit2_paths()
ffi = FFI()
ffi.set_source(
"pygit2._libgit2",
"#include <git2.h>", # preamble
**libgit2_kw
)
ffi.set_source("pygit2._libgit2", C_PREAMBLE, **libgit2_kw)
ffi.cdef(C_HEADER_SRC)


Expand Down
3 changes: 3 additions & 0 deletions pygit2/decl/repository.h
Expand Up @@ -87,3 +87,6 @@ int git_repository_ident(const char **name, const char **email, const git_reposi
int git_repository_set_ident(git_repository *repo, const char *name, const char *email);
int git_repository_index(git_index **out, git_repository *repo);
git_repository_state_t git_repository_state(git_repository *repo);

int git_repository_submodule_cache_all(git_repository *repo);
int git_repository_submodule_cache_clear(git_repository *repo);
25 changes: 25 additions & 0 deletions pygit2/repository.py
Expand Up @@ -252,6 +252,31 @@ def update_submodules(
for submodule in instances:
submodule.update(init, callbacks)

def submodule_cache_all(self):
"""
Load and cache all submodules in the repository.
Because the `.gitmodules` file is unstructured, loading submodules is an
O(N) operation. Any operation that requires accessing all submodules is O(N^2)
in the number of submodules, if it has to look each one up individually.
This function loads all submodules and caches them so that subsequent calls to
`lookup_submodule` are O(1).
"""
err = C.git_repository_submodule_cache_all(self._repo)
check_error(err)

def submodule_cache_clear(self):
"""
Clear the submodule cache populated by `submodule_cache_all`.
If there is no cache, do nothing.
The cache incorporates data from the repository's configuration, as well
as the state of the working tree, the index, and HEAD. So any time any
of these has changed, the cache might become invalid.
"""
err = C.git_repository_submodule_cache_clear(self._repo)
check_error(err)

#
# Mapping interface
#
Expand Down
14 changes: 14 additions & 0 deletions test/test_submodule.py
Expand Up @@ -132,3 +132,17 @@ def test_add_submodule(repo):
assert sm_repo_path == sm.path
assert SUBM_URL == sm.url
assert not sm_repo.is_empty

def test_submodule_cache(repo):
# When the cache is turned on, looking up the same submodule twice must return the same git_submodule object
repo.submodule_cache_all()
sm1 = repo.lookup_submodule(SUBM_NAME)
sm2 = repo.lookup_submodule(SUBM_NAME)
assert sm1._subm == sm2._subm

# After turning off the cache, each lookup must return a new git_submodule object
repo.submodule_cache_clear()
sm3 = repo.lookup_submodule(SUBM_NAME)
sm4 = repo.lookup_submodule(SUBM_NAME)
assert sm1._subm != sm3._subm
assert sm3._subm != sm4._subm

0 comments on commit ce84a11

Please sign in to comment.