summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2014-03-30 15:35:56 -0700
committerRussell Belfer <rb@github.com>2014-04-01 09:49:58 -0700
commiteeeb9654f064e1047ef8f3cb5a38636133426cdd (patch)
tree84fbf49d866bf79f275396ccd81c5da640cb1b05
parenta4ccd2b00199306889585b23845368455ff348f4 (diff)
downloadlibgit2-eeeb9654f064e1047ef8f3cb5a38636133426cdd.tar.gz
Reinstate efficient submodule reloading
This makes it so that git_submodule_reload_all will actually only reload changed items unless the `force` flag is used.
-rw-r--r--src/submodule.c234
1 files changed, 111 insertions, 123 deletions
diff --git a/src/submodule.c b/src/submodule.c
index 7b06c25c2..96b445ace 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -898,66 +898,9 @@ int git_submodule_open(git_repository **subrepo, git_submodule *sm)
return git_submodule__open(subrepo, sm, false);
}
-static void submodule_cache_remove_item(
- git_strmap *map,
- const char *name,
- git_submodule *expected,
- bool free_after_remove)
-{
- khiter_t pos;
- git_submodule *found;
-
- if (!map)
- return;
-
- pos = git_strmap_lookup_index(map, name);
-
- if (!git_strmap_valid_index(map, pos))
- return;
-
- found = git_strmap_value_at(map, pos);
-
- if (expected && found != expected)
- return;
-
- git_strmap_set_value_at(map, pos, NULL);
- git_strmap_delete_at(map, pos);
-
- if (free_after_remove)
- git_submodule_free(found);
-}
-
int git_submodule_reload_all(git_repository *repo, int force)
{
- int error = 0;
- git_submodule *sm;
- git_strmap *map;
-
- GIT_UNUSED(force);
- assert(repo);
-
- if (repo->_submodules)
- submodule_cache_clear_flags(repo->_submodules, 0xFFFFFFFFu);
-
- if ((error = submodule_cache_init(repo, CACHE_FLUSH)) < 0)
- return error;
-
- if (!repo->_submodules || !(map = repo->_submodules->submodules))
- return error;
-
- git_strmap_foreach_value(map, sm, {
- if (sm && (sm->flags & GIT_SUBMODULE_STATUS__IN_FLAGS) == 0) {
- /* we must check path != name before first remove, in case
- * that call frees the submodule */
- bool free_as_path = (sm->path != sm->name);
-
- submodule_cache_remove_item(map, sm->name, sm, true);
- if (free_as_path)
- submodule_cache_remove_item(map, sm->path, sm, true);
- }
- });
-
- return error;
+ return submodule_cache_init(repo, force ? CACHE_FLUSH : CACHE_REFRESH);
}
static void submodule_update_from_index_entry(
@@ -1210,20 +1153,49 @@ static int submodule_alloc(
return 0;
}
+static void submodule_cache_remove_item(
+ git_submodule_cache *cache,
+ git_submodule *item,
+ bool free_after_remove)
+{
+ git_strmap *map;
+ const char *name, *alt;
+
+ if (!cache || !(map = cache->submodules) || !item)
+ return;
+
+ name = item->name;
+ alt = (item->path != item->name) ? item->path : NULL;
+
+ for (; name; name = alt, alt = NULL) {
+ khiter_t pos = git_strmap_lookup_index(map, name);
+ git_submodule *found;
+
+ if (!git_strmap_valid_index(map, pos))
+ continue;
+
+ found = git_strmap_value_at(map, pos);
+
+ if (found != item)
+ continue;
+
+ git_strmap_set_value_at(map, pos, NULL);
+ git_strmap_delete_at(map, pos);
+
+ if (free_after_remove)
+ git_submodule_free(found);
+ }
+}
+
static void submodule_release(git_submodule *sm)
{
if (!sm)
return;
- if (sm->repo && sm->repo->_submodules) {
- git_strmap *map = sm->repo->_submodules->submodules;
- bool free_as_path = (sm->path != sm->name);
-
+ if (sm->repo) {
+ git_submodule_cache *cache = sm->repo->_submodules;
sm->repo = NULL;
-
- submodule_cache_remove_item(map, sm->name, sm, false);
- if (free_as_path)
- submodule_cache_remove_item(map, sm->path, sm, false);
+ submodule_cache_remove_item(cache, sm, false);
}
if (sm->path != sm->name)
@@ -1619,99 +1591,115 @@ static int submodule_cache_alloc(
static int submodule_cache_refresh(git_submodule_cache *cache, int refresh)
{
- int error = 0, updates = 0, flush, changed;
- git_config_backend *mods = NULL;
- const char *wd;
+ int error = 0, update_index, update_head, update_gitmod;
git_index *idx = NULL;
git_tree *head = NULL;
+ const char *wd = NULL;
git_buf path = GIT_BUF_INIT;
+ git_submodule *sm;
+ git_config_backend *mods = NULL;
+ uint32_t mask;
- if (!refresh)
+ if (!cache || !cache->repo || !refresh)
return 0;
- flush = (refresh == CACHE_FLUSH);
if (git_mutex_lock(&cache->lock) < 0) {
giterr_set(GITERR_OS, "Unable to acquire lock on submodule cache");
return -1;
}
- /* TODO: only do the following if the sources appear modified */
+ /* get sources that we will need to check */
- /* add submodule information from index */
+ if (git_repository_index(&idx, cache->repo) < 0)
+ giterr_clear();
+ if (git_repository_head_tree(&head, cache->repo) < 0)
+ giterr_clear();
- if (!git_repository_index(&idx, cache->repo)) {
- if (flush || git_index__changed_relative_to(idx, &cache->index_stamp)) {
- if ((error = submodule_cache_refresh_from_index(cache, idx)) < 0)
- goto cleanup;
+ wd = git_repository_workdir(cache->repo);
+ if (wd && (error = git_buf_joinpath(&path, wd, GIT_MODULES_FILE)) < 0)
+ goto cleanup;
- updates += 1;
- git_futils_filestamp_set(
- &cache->index_stamp, git_index__filestamp(idx));
- }
- } else {
- giterr_clear();
+ /* check for invalidation */
- submodule_cache_clear_flags(
- cache, GIT_SUBMODULE_STATUS_IN_INDEX |
- GIT_SUBMODULE_STATUS__INDEX_FLAGS |
- GIT_SUBMODULE_STATUS__INDEX_OID_VALID);
+ if (refresh == CACHE_FLUSH)
+ update_index = update_head = update_gitmod = true;
+ else {
+ update_index =
+ !idx || git_index__changed_relative_to(idx, &cache->index_stamp);
+ update_head =
+ !head || !git_oid_equal(&cache->head_id, git_tree_id(head));
+
+ update_gitmod = (wd != NULL) ?
+ git_futils_filestamp_check(&cache->gitmodules_stamp, path.ptr) :
+ (cache->gitmodules_stamp.mtime != 0);
+ if (update_gitmod < 0)
+ giterr_clear();
}
- /* add submodule information from HEAD */
+ /* clear submodule flags that are to be refreshed */
- if (!git_repository_head_tree(&head, cache->repo)) {
- if (flush || !git_oid_equal(&cache->head_id, git_tree_id(head))) {
- if ((error = submodule_cache_refresh_from_head(cache, head)) < 0)
- goto cleanup;
+ mask = 0;
+ if (!idx || update_index)
+ mask |= GIT_SUBMODULE_STATUS_IN_INDEX |
+ GIT_SUBMODULE_STATUS__INDEX_FLAGS |
+ GIT_SUBMODULE_STATUS__INDEX_OID_VALID |
+ GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES;
+ if (!head || update_head)
+ mask |= GIT_SUBMODULE_STATUS_IN_HEAD |
+ GIT_SUBMODULE_STATUS__HEAD_OID_VALID;
+ if (update_gitmod)
+ mask |= GIT_SUBMODULE_STATUS_IN_CONFIG;
+ if (mask != 0)
+ mask |= GIT_SUBMODULE_STATUS_IN_WD |
+ GIT_SUBMODULE_STATUS__WD_SCANNED |
+ GIT_SUBMODULE_STATUS__WD_FLAGS |
+ GIT_SUBMODULE_STATUS__WD_OID_VALID;
- updates += 1;
- git_oid_cpy(&cache->head_id, git_tree_id(head));
- }
- } else {
- giterr_clear();
+ submodule_cache_clear_flags(cache, mask);
+
+ /* add back submodule information from index */
+
+ if (idx && update_index) {
+ if ((error = submodule_cache_refresh_from_index(cache, idx)) < 0)
+ goto cleanup;
- submodule_cache_clear_flags(
- cache, GIT_SUBMODULE_STATUS_IN_HEAD |
- GIT_SUBMODULE_STATUS__HEAD_OID_VALID);
+ git_futils_filestamp_set(
+ &cache->index_stamp, git_index__filestamp(idx));
}
- /* add submodule information from .gitmodules */
+ /* add submodule information from HEAD */
- wd = git_repository_workdir(cache->repo);
+ if (head && update_head) {
+ if ((error = submodule_cache_refresh_from_head(cache, head)) < 0)
+ goto cleanup;
- if (wd && (error = git_buf_joinpath(&path, wd, GIT_MODULES_FILE)) < 0)
- goto cleanup;
+ git_oid_cpy(&cache->head_id, git_tree_id(head));
+ }
- changed = git_futils_filestamp_check(&cache->gitmodules_stamp, path.ptr);
- if (flush && !changed)
- changed = 1;
+ /* add submodule information from .gitmodules */
- if (changed < 0) {
- giterr_clear();
- submodule_cache_clear_flags(cache, GIT_SUBMODULE_STATUS_IN_CONFIG);
- } else if (changed > 0 && (mods = open_gitmodules(cache, false)) != NULL) {
- if ((error = git_config_file_foreach(
+ if (wd && update_gitmod > 0) {
+ if ((mods = open_gitmodules(cache, false)) != NULL &&
+ (error = git_config_file_foreach(
mods, submodule_load_from_config, cache)) < 0)
goto cleanup;
- updates += 1;
}
- /* shallow scan submodules in work tree */
-
- if (wd && updates > 0) {
- git_submodule *sm;
-
- submodule_cache_clear_flags(
- cache, GIT_SUBMODULE_STATUS_IN_WD |
- GIT_SUBMODULE_STATUS__WD_SCANNED |
- GIT_SUBMODULE_STATUS__WD_FLAGS |
- GIT_SUBMODULE_STATUS__WD_OID_VALID);
+ /* shallow scan submodules in work tree as needed */
+ if (wd && mask != 0) {
git_strmap_foreach_value(cache->submodules, sm, {
submodule_load_from_wd_lite(sm);
});
}
+ /* remove submodules that no longer exist */
+
+ git_strmap_foreach_value(cache->submodules, sm, {
+ if (sm && (sm->flags & GIT_SUBMODULE_STATUS__IN_FLAGS) == 0)
+ submodule_cache_remove_item(cache, sm, true);
+ });
+
cleanup:
git_config_file_free(mods);