summaryrefslogtreecommitdiff
path: root/src/diff_generate.c
diff options
context:
space:
mode:
authorlhchavez <lhchavez@lhchavez.com>2020-12-10 19:52:01 -0800
committerlhchavez <lhchavez@lhchavez.com>2020-12-10 20:23:12 -0800
commit41da4e16eb01a7bb19c52bbc4251963be192ba69 (patch)
treee5ec4485601b6a3303740c3787f72f0fd5941000 /src/diff_generate.c
parent03ea04bfacc601c9d573fabf4c1da3f9f85e148c (diff)
downloadlibgit2-41da4e16eb01a7bb19c52bbc4251963be192ba69.tar.gz
Cache the parsed submodule config when diffing
This change makes that anything that calls `git_diff__from_iterators` (any of the `git_diff_xxx` functions) only need to parse the `.gitmodules` file once. This can be avoided by calling `git_repository_submodule_cache_all(...)`, but we can do that safely for the user with no change in semantics. Fixes: #5725
Diffstat (limited to 'src/diff_generate.c')
-rw-r--r--src/diff_generate.c37
1 files changed, 34 insertions, 3 deletions
diff --git a/src/diff_generate.c b/src/diff_generate.c
index 745e5ae1b..bc7c26658 100644
--- a/src/diff_generate.c
+++ b/src/diff_generate.c
@@ -680,6 +680,8 @@ typedef struct {
git_iterator *new_iter;
const git_index_entry *oitem;
const git_index_entry *nitem;
+ git_strmap *submodule_cache;
+ bool submodule_cache_initialized;
} diff_in_progress;
#define MODE_BITS_MASK 0000777
@@ -694,6 +696,7 @@ static int maybe_modified_submodule(
git_submodule *sub;
unsigned int sm_status = 0;
git_submodule_ignore_t ign = diff->base.opts.ignore_submodules;
+ git_strmap *submodule_cache = NULL;
*status = GIT_DELTA_UNMODIFIED;
@@ -701,8 +704,29 @@ static int maybe_modified_submodule(
ign == GIT_SUBMODULE_IGNORE_ALL)
return 0;
- if ((error = git_submodule_lookup(
- &sub, diff->base.repo, info->nitem->path)) < 0) {
+ if (diff->base.repo->submodule_cache != NULL) {
+ submodule_cache = diff->base.repo->submodule_cache;
+ } else {
+ if (!info->submodule_cache_initialized) {
+ info->submodule_cache_initialized = true;
+ /* Cache the submodule information to avoid having to parse it for every submodule. */
+ if (git_strmap_new(&info->submodule_cache) == 0) {
+ if (git_submodule__map(diff->base.repo, info->submodule_cache) < 0) {
+ /* If the caching failed for whatever reason, bail out and clean up. */
+ git_submodule *sm = NULL;
+ git_strmap_foreach_value(info->submodule_cache, sm, {
+ git_submodule_free(sm);
+ });
+ git_strmap_free(info->submodule_cache);
+ info->submodule_cache = NULL;
+ }
+ }
+ }
+ submodule_cache = info->submodule_cache;
+ }
+
+ if ((error = git_submodule__lookup_with_cache(
+ &sub, diff->base.repo, info->nitem->path, submodule_cache)) < 0) {
/* GIT_EEXISTS means dir with .git in it was found - ignore it */
if (error == GIT_EEXISTS) {
@@ -1192,7 +1216,7 @@ int git_diff__from_iterators(
const git_diff_options *opts)
{
git_diff_generated *diff;
- diff_in_progress info;
+ diff_in_progress info = {0};
int error = 0;
*out = NULL;
@@ -1260,6 +1284,13 @@ cleanup:
*out = &diff->base;
else
git_diff_free(&diff->base);
+ if (info.submodule_cache) {
+ git_submodule *sm = NULL;
+ git_strmap_foreach_value(info.submodule_cache, sm, {
+ git_submodule_free(sm);
+ });
+ git_strmap_free(info.submodule_cache);
+ }
return error;
}