summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/checkout.c8
-rw-r--r--src/repository.c1
-rw-r--r--src/repository.h1
-rw-r--r--src/submodule.c770
-rw-r--r--src/submodule.h20
-rw-r--r--tests/submodule/modify.c2
-rw-r--r--tests/submodule/nosubs.c44
7 files changed, 270 insertions, 576 deletions
diff --git a/src/checkout.c b/src/checkout.c
index 2893c63de..dab83c65a 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -1860,11 +1860,6 @@ static int checkout_create_submodules(
git_diff_delta *delta;
size_t i;
- /* initial reload of submodules if .gitmodules was changed */
- if (data->reload_submodules &&
- (error = git_submodule_reload_all(data->repo, 1)) < 0)
- return error;
-
git_vector_foreach(&data->diff->deltas, i, delta) {
if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) {
/* this has a blocker directory that should only be removed iff
@@ -1885,8 +1880,7 @@ static int checkout_create_submodules(
}
}
- /* final reload once submodules have been updated */
- return git_submodule_reload_all(data->repo, 1);
+ return 0;
}
static int checkout_lookup_head_tree(git_tree **out, git_repository *repo)
diff --git a/src/repository.c b/src/repository.c
index c608fa0b8..85c86716e 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -109,7 +109,6 @@ void git_repository__cleanup(git_repository *repo)
git_cache_clear(&repo->objects);
git_attr_cache_flush(repo);
- git_submodule_cache_free(repo);
set_config(repo, NULL);
set_index(repo, NULL);
diff --git a/src/repository.h b/src/repository.h
index 253287368..fd679b483 100644
--- a/src/repository.h
+++ b/src/repository.h
@@ -121,7 +121,6 @@ struct git_repository {
git_refdb *_refdb;
git_config *_config;
git_index *_index;
- git_submodule_cache *_submodules;
git_cache objects;
git_attr_cache *attrcache;
diff --git a/src/submodule.c b/src/submodule.c
index 246502e99..9a1485436 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -87,17 +87,16 @@ __KHASH_IMPL(
str, static kh_inline, const char *, void *, 1,
str_hash_no_trailing_slash, str_equal_no_trailing_slash)
-static int submodule_cache_init(git_repository *repo, int refresh);
-static void submodule_cache_free(git_submodule_cache *cache);
-
-static git_config_backend *open_gitmodules(git_submodule_cache *, int gitmod);
+static int submodule_alloc(git_submodule **out, git_repository *repo, const char *name);
+static git_config_backend *open_gitmodules(git_repository *repo, int gitmod);
static int get_url_base(git_buf *url, git_repository *repo);
static int lookup_head_remote_key(git_buf *remote_key, git_repository *repo);
-static int submodule_get(git_submodule **, git_submodule_cache *, const char *, const char *);
static int submodule_load_from_config(const git_config_entry *, void *);
static int submodule_load_from_wd_lite(git_submodule *);
static void submodule_get_index_status(unsigned int *, git_submodule *);
static void submodule_get_wd_status(unsigned int *, git_submodule *, git_repository *, git_submodule_ignore_t);
+static void submodule_update_from_index_entry(git_submodule *sm, const git_index_entry *ie);
+static void submodule_update_from_head_data(git_submodule *sm, mode_t mode, const git_oid *id);
static int submodule_cmp(const void *a, const void *b)
{
@@ -111,69 +110,10 @@ static int submodule_config_key_trunc_puts(git_buf *key, const char *suffix)
return git_buf_puts(key, suffix);
}
-/* lookup submodule or return ENOTFOUND if it doesn't exist */
-static int submodule_lookup(
- git_submodule **out,
- git_submodule_cache *cache,
- const char *name,
- const char *alternate)
-{
- khiter_t pos;
-
- /* lock cache */
-
- pos = git_strmap_lookup_index(cache->submodules, name);
-
- if (!git_strmap_valid_index(cache->submodules, pos) && alternate)
- pos = git_strmap_lookup_index(cache->submodules, alternate);
-
- if (!git_strmap_valid_index(cache->submodules, pos)) {
- /* unlock cache */
- return GIT_ENOTFOUND; /* don't set error - caller will cope */
- }
-
- if (out != NULL) {
- git_submodule *sm = git_strmap_value_at(cache->submodules, pos);
- GIT_REFCOUNT_INC(sm);
- *out = sm;
- }
-
- /* unlock cache */
-
- return 0;
-}
-
-/* clear a set of flags on all submodules */
-static void submodule_cache_clear_flags(
- git_submodule_cache *cache, uint32_t mask)
-{
- git_submodule *sm;
- uint32_t inverted_mask = ~mask;
-
- git_strmap_foreach_value(cache->submodules, sm, {
- sm->flags &= inverted_mask;
- });
-}
-
/*
* PUBLIC APIS
*/
-bool git_submodule__is_submodule(git_repository *repo, const char *name)
-{
- git_strmap *map;
-
- if (submodule_cache_init(repo, CACHE_OK) < 0) {
- giterr_clear();
- return false;
- }
-
- if (!repo->_submodules || !(map = repo->_submodules->submodules))
- return false;
-
- return git_strmap_valid_index(map, git_strmap_lookup_index(map, name));
-}
-
static void submodule_set_lookup_error(int error, const char *name)
{
if (!error)
@@ -184,44 +124,39 @@ static void submodule_set_lookup_error(int error, const char *name)
"Submodule '%s' has not been added yet", name);
}
-int git_submodule__lookup(
+int git_submodule_lookup(
git_submodule **out, /* NULL if user only wants to test existence */
git_repository *repo,
const char *name) /* trailing slash is allowed */
{
int error;
+ git_submodule *sm;
+ git_config_backend *mods;
assert(repo && name);
- if ((error = submodule_cache_init(repo, CACHE_OK)) < 0)
- return error;
-
- if ((error = submodule_lookup(out, repo->_submodules, name, NULL)) < 0)
- submodule_set_lookup_error(error, name);
-
- return error;
-}
-
-int git_submodule_lookup(
- git_submodule **out, /* NULL if user only wants to test existence */
- git_repository *repo,
- const char *name) /* trailing slash is allowed */
-{
- int error;
+ mods = open_gitmodules(repo, GITMODULES_EXISTING);
+ if (!mods)
+ return -1;
- assert(repo && name);
+ if ((error = submodule_alloc(&sm, repo, name)) < 0)
+ return error;
- if ((error = submodule_cache_init(repo, CACHE_REFRESH)) < 0)
+ if ((error = git_submodule_reload(sm, false)) < 0) {
+ git_submodule_free(sm);
return error;
+ }
- if ((error = submodule_lookup(out, repo->_submodules, name, NULL)) < 0) {
+ /* If we didn't find the url, consider it missing */
+ if (!sm->url) {
+ git_submodule_free(sm);
+ error = GIT_ENOTFOUND;
- /* check if a plausible submodule exists at path */
+ /* If it's not configured, we still check if there's a repo at the path */
if (git_repository_workdir(repo)) {
git_buf path = GIT_BUF_INIT;
-
if (git_buf_join3(&path,
- '/', git_repository_workdir(repo), name, DOT_GIT) < 0)
+ '/', git_repository_workdir(repo), name, DOT_GIT) < 0)
return -1;
if (git_path_exists(path.ptr))
@@ -231,9 +166,15 @@ int git_submodule_lookup(
}
submodule_set_lookup_error(error, name);
+ return error;
}
- return error;
+ if (out)
+ *out = sm;
+ else
+ git_submodule_free(sm);
+
+ return 0;
}
static void submodule_free_dup(void *sm)
@@ -241,41 +182,221 @@ static void submodule_free_dup(void *sm)
git_submodule_free(sm);
}
+static int submodule_get_or_create(git_submodule **out, git_repository *repo, git_strmap *map, const char *name)
+{
+ int error = 0;
+ khiter_t pos;
+ git_submodule *sm = NULL;
+
+ pos = git_strmap_lookup_index(map, name);
+ if (git_strmap_valid_index(map, pos)) {
+ sm = git_strmap_value_at(map, pos);
+ goto done;
+ }
+
+ /* if the submodule doesn't exist yet in the map, create it */
+ if ((error = submodule_alloc(&sm, repo, name)) < 0)
+ return error;
+
+ pos = kh_put(str, map, sm->name, &error);
+ /* nobody can beat us to adding it */
+ assert(error != 0);
+ if (error < 0) {
+ git_submodule_free(sm);
+ return error;
+ }
+
+ git_strmap_set_value_at(map, pos, sm);
+
+done:
+ GIT_REFCOUNT_INC(sm);
+ *out = sm;
+ return 0;
+}
+
+static int submodules_from_index(git_strmap *map, git_index *idx)
+{
+ int error;
+ git_iterator *i;
+ const git_index_entry *entry;
+
+ if ((error = git_iterator_for_index(&i, idx, 0, NULL, NULL)) < 0)
+ return error;
+
+ while (!(error = git_iterator_advance(&entry, i))) {
+ khiter_t pos = git_strmap_lookup_index(map, entry->path);
+ git_submodule *sm;
+
+ if (git_strmap_valid_index(map, pos)) {
+ sm = git_strmap_value_at(map, pos);
+
+ if (S_ISGITLINK(entry->mode))
+ submodule_update_from_index_entry(sm, entry);
+ else
+ sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
+ } else if (S_ISGITLINK(entry->mode)) {
+ if (!submodule_get_or_create(&sm, git_index_owner(idx), map, entry->path)) {
+ submodule_update_from_index_entry(sm, entry);
+ git_submodule_free(sm);
+ }
+ }
+ }
+
+ if (error == GIT_ITEROVER)
+ error = 0;
+
+ git_iterator_free(i);
+
+ return error;
+}
+
+static int submodules_from_head(git_strmap *map, git_tree *head)
+{
+ int error;
+ git_iterator *i;
+ const git_index_entry *entry;
+
+ if ((error = git_iterator_for_tree(&i, head, 0, NULL, NULL)) < 0)
+ return error;
+
+ while (!(error = git_iterator_advance(&entry, i))) {
+ khiter_t pos = git_strmap_lookup_index(map, entry->path);
+ git_submodule *sm;
+
+ if (git_strmap_valid_index(map, pos)) {
+ sm = git_strmap_value_at(map, pos);
+
+ if (S_ISGITLINK(entry->mode))
+ submodule_update_from_head_data(sm, entry->mode, &entry->id);
+ else
+ sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
+ } else if (S_ISGITLINK(entry->mode)) {
+ if (!submodule_get_or_create(&sm, git_tree_owner(head), map, entry->path)) {
+ submodule_update_from_head_data(
+ sm, entry->mode, &entry->id);
+ git_submodule_free(sm);
+ }
+ }
+ }
+
+ if (error == GIT_ITEROVER)
+ error = 0;
+
+ git_iterator_free(i);
+
+ return error;
+}
+
+/* If have_sm is true, sm is populated, otherwise map an repo are. */
+typedef struct {
+ int have_sm;
+ git_submodule *sm;
+ git_strmap *map;
+ git_repository *repo;
+} lfc_data;
+
+static int all_submodules(git_repository *repo, git_strmap *map)
+{
+ int error = 0;
+ 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;
+
+ assert(repo && map);
+
+ /* get sources that we will need to check */
+ if (git_repository_index(&idx, repo) < 0)
+ giterr_clear();
+ if (git_repository_head_tree(&head, repo) < 0)
+ giterr_clear();
+
+ wd = git_repository_workdir(repo);
+ if (wd && (error = git_buf_joinpath(&path, wd, GIT_MODULES_FILE)) < 0)
+ goto cleanup;
+
+ /* clear submodule flags that are to be refreshed */
+ mask = 0;
+ mask |= GIT_SUBMODULE_STATUS_IN_INDEX |
+ GIT_SUBMODULE_STATUS__INDEX_FLAGS |
+ GIT_SUBMODULE_STATUS__INDEX_OID_VALID |
+ GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES;
+
+ mask |= GIT_SUBMODULE_STATUS_IN_HEAD |
+ GIT_SUBMODULE_STATUS__HEAD_OID_VALID;
+ 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;
+
+ /* add back submodule information from index */
+ if (idx) {
+ if ((error = submodules_from_index(map, idx)) < 0)
+ goto cleanup;
+ }
+ /* add submodule information from HEAD */
+ if (head) {
+ if ((error = submodules_from_head(map, head)) < 0)
+ goto cleanup;
+ }
+ /* add submodule information from .gitmodules */
+ if (wd) {
+ lfc_data data = { 0 };
+ data.map = map;
+ data.repo = repo;
+ if ((mods = open_gitmodules(repo, false)) != NULL &&
+ (error = git_config_file_foreach(
+ mods, submodule_load_from_config, &data)) < 0)
+ goto cleanup;
+ }
+ /* shallow scan submodules in work tree as needed */
+ if (wd && mask != 0) {
+ git_strmap_foreach_value(map, sm, {
+ submodule_load_from_wd_lite(sm);
+ });
+ }
+
+cleanup:
+ git_config_file_free(mods);
+ /* TODO: if we got an error, mark submodule config as invalid? */
+ git_index_free(idx);
+ git_tree_free(head);
+ git_buf_free(&path);
+ return error;
+}
+
int git_submodule_foreach(
git_repository *repo,
int (*callback)(git_submodule *sm, const char *name, void *payload),
void *payload)
{
+ git_vector snapshot = GIT_VECTOR_INIT;
+ git_strmap *submodules;
+ git_submodule *sm;
int error;
size_t i;
- git_submodule *sm;
- git_submodule_cache *cache;
- git_vector snapshot = GIT_VECTOR_INIT;
- assert(repo && callback);
-
- if ((error = submodule_cache_init(repo, CACHE_REFRESH)) < 0)
+ if ((error = git_strmap_alloc(&submodules)) < 0)
return error;
- cache = repo->_submodules;
-
- if (git_mutex_lock(&cache->lock) < 0) {
- giterr_set(GITERR_OS, "Unable to acquire lock on submodule cache");
- return -1;
- }
+ if ((error = all_submodules(repo, submodules)) < 0)
+ goto done;
if (!(error = git_vector_init(
- &snapshot, kh_size(cache->submodules), submodule_cmp))) {
+ &snapshot, kh_size(submodules), submodule_cmp))) {
- git_strmap_foreach_value(cache->submodules, sm, {
+ git_strmap_foreach_value(submodules, sm, {
if ((error = git_vector_insert(&snapshot, sm)) < 0)
break;
GIT_REFCOUNT_INC(sm);
});
}
- git_mutex_unlock(&cache->lock);
-
if (error < 0)
goto done;
@@ -293,17 +414,12 @@ done:
git_submodule_free(sm);
git_vector_free(&snapshot);
- return error;
-}
-
-void git_submodule_cache_free(git_repository *repo)
-{
- git_submodule_cache *cache;
-
- assert(repo);
+ git_strmap_foreach_value(submodules, sm, {
+ git_submodule_free(sm);
+ });
+ git_strmap_free(submodules);
- if ((cache = git__swap(repo->_submodules, NULL)) != NULL)
- submodule_cache_free(cache);
+ return error;
}
static int submodule_repo_init(
@@ -394,7 +510,7 @@ int git_submodule_add_setup(
/* update .gitmodules */
- if (!(mods = open_gitmodules(repo->_submodules, GITMODULES_CREATE))) {
+ if (!(mods = open_gitmodules(repo, GITMODULES_CREATE))) {
giterr_set(GITERR_SUBMODULE,
"Adding submodules to a bare repository is not supported");
return -1;
@@ -430,19 +546,10 @@ int git_submodule_add_setup(
goto cleanup;
}
- /* add submodule to hash and "reload" it */
-
- if (git_mutex_lock(&repo->_submodules->lock) < 0) {
- giterr_set(GITERR_OS, "Unable to acquire lock on submodule cache");
- error = -1;
+ if ((error = git_submodule_lookup(&sm, repo, path)) < 0)
goto cleanup;
- }
-
- if (!(error = submodule_get(&sm, repo->_submodules, path, NULL)) &&
- !(error = git_submodule_reload(sm, false)))
- error = git_submodule_init(sm, false);
- git_mutex_unlock(&repo->_submodules->lock);
+ error = git_submodule_init(sm, false);
cleanup:
if (error && sm) {
@@ -608,7 +715,7 @@ int git_submodule_save(git_submodule *submodule)
assert(submodule);
- mods = open_gitmodules(submodule->repo->_submodules, GITMODULES_CREATE);
+ mods = open_gitmodules(submodule->repo, GITMODULES_CREATE);
if (!mods) {
giterr_set(GITERR_SUBMODULE,
"Adding submodules to a bare repository is not supported");
@@ -1197,11 +1304,6 @@ int git_submodule_open(git_repository **subrepo, git_submodule *sm)
return git_submodule__open(subrepo, sm, false);
}
-int git_submodule_reload_all(git_repository *repo, int force)
-{
- return submodule_cache_init(repo, force ? CACHE_FLUSH : CACHE_REFRESH);
-}
-
static void submodule_update_from_index_entry(
git_submodule *sm, const git_index_entry *ie)
{
@@ -1280,14 +1382,12 @@ int git_submodule_reload(git_submodule *sm, int force)
{
int error = 0;
git_config_backend *mods;
- git_submodule_cache *cache;
+ lfc_data data = { 0 };
GIT_UNUSED(force);
assert(sm);
- cache = sm->repo->_submodules;
-
/* refresh index data */
if ((error = submodule_update_index(sm)) < 0)
return error;
@@ -1301,7 +1401,7 @@ int git_submodule_reload(git_submodule *sm, int force)
return error;
/* refresh config data */
- mods = open_gitmodules(cache, GITMODULES_EXISTING);
+ mods = open_gitmodules(sm->repo, GITMODULES_EXISTING);
if (mods != NULL) {
git_buf path = GIT_BUF_INIT;
@@ -1309,11 +1409,14 @@ int git_submodule_reload(git_submodule *sm, int force)
git_buf_text_puts_escape_regex(&path, sm->name);
git_buf_puts(&path, ".*");
- if (git_buf_oom(&path))
+ if (git_buf_oom(&path)) {
error = -1;
- else
+ } else {
+ data.have_sm = 1;
+ data.sm = sm;
error = git_config_file_foreach_match(
- mods, path.ptr, submodule_load_from_config, cache);
+ mods, path.ptr, submodule_load_from_config, &data);
+ }
git_buf_free(&path);
git_config_file_free(mods);
@@ -1422,7 +1525,7 @@ int git_submodule_location(unsigned int *location, git_submodule *sm)
*/
static int submodule_alloc(
- git_submodule **out, git_submodule_cache *cache, const char *name)
+ git_submodule **out, git_repository *repo, const char *name)
{
size_t namelen;
git_submodule *sm;
@@ -1445,56 +1548,20 @@ static int submodule_alloc(
sm->ignore = sm->ignore_default = GIT_SUBMODULE_IGNORE_NONE;
sm->update = sm->update_default = GIT_SUBMODULE_UPDATE_CHECKOUT;
sm->fetch_recurse = sm->fetch_recurse_default = GIT_SUBMODULE_RECURSE_NO;
- sm->repo = cache->repo;
+ sm->repo = repo;
sm->branch = NULL;
*out = sm;
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) {
- git_submodule_cache *cache = sm->repo->_submodules;
sm->repo = NULL;
- submodule_cache_remove_item(cache, sm, false);
}
if (sm->path != sm->name)
@@ -1513,54 +1580,6 @@ void git_submodule_free(git_submodule *sm)
GIT_REFCOUNT_DEC(sm, submodule_release);
}
-static int submodule_get(
- git_submodule **out,
- git_submodule_cache *cache,
- const char *name,
- const char *alternate)
-{
- int error = 0;
- khiter_t pos;
- git_submodule *sm;
-
- pos = git_strmap_lookup_index(cache->submodules, name);
-
- if (!git_strmap_valid_index(cache->submodules, pos) && alternate)
- pos = git_strmap_lookup_index(cache->submodules, alternate);
-
- if (!git_strmap_valid_index(cache->submodules, pos)) {
- if ((error = submodule_alloc(&sm, cache, name)) < 0)
- return error;
-
- /* insert value at name - if another thread beats us to it, then use
- * their record and release our own.
- */
- pos = kh_put(str, cache->submodules, sm->name, &error);
-
- if (error < 0)
- goto done;
- else if (error == 0) {
- git_submodule_free(sm);
- sm = git_strmap_value_at(cache->submodules, pos);
- } else {
- error = 0;
- git_strmap_set_value_at(cache->submodules, pos, sm);
- }
- } else {
- sm = git_strmap_value_at(cache->submodules, pos);
- }
-
-done:
- if (error < 0)
- git_submodule_free(sm);
- else if (out) {
- GIT_REFCOUNT_INC(sm);
- *out = sm;
- }
-
- return error;
-}
-
static int submodule_config_error(const char *property, const char *value)
{
giterr_set(GITERR_INVALID,
@@ -1613,12 +1632,12 @@ int git_submodule_parse_recurse(git_submodule_recurse_t *out, const char *value)
static int submodule_load_from_config(
const git_config_entry *entry, void *payload)
{
- git_submodule_cache *cache = payload;
const char *namestart, *property;
const char *key = entry->name, *value = entry->value, *path;
char *alternate = NULL, *replaced = NULL;
git_buf name = GIT_BUF_INIT;
- git_submodule *sm = NULL;
+ lfc_data *data = payload;
+ git_submodule *sm;
int error = 0;
if (git__prefixcmp(key, "submodule.") != 0)
@@ -1633,10 +1652,29 @@ static int submodule_load_from_config(
property++;
path = !strcasecmp(property, "path") ? value : NULL;
- if ((error = git_buf_set(&name, namestart, property - namestart - 1)) < 0 ||
- (error = submodule_get(&sm, cache, name.ptr, path)) < 0)
+ if ((error = git_buf_set(&name, namestart, property - namestart -1)) < 0)
goto done;
+ if (data->have_sm) {
+ sm = data->sm;
+ } else {
+ khiter_t pos;
+ git_strmap *map = data->map;
+ pos = git_strmap_lookup_index(map, name.ptr);
+ if (git_strmap_valid_index(map, pos)) {
+ sm = git_strmap_value_at(map, pos);
+ } else {
+ if ((error = submodule_alloc(&sm, data->repo, name.ptr)) < 0)
+ goto done;
+
+ git_strmap_insert(map, sm->name, sm, error);
+ assert(error != 0);
+ if (error < 0)
+ goto done;
+ error = 0;
+ }
+ }
+
sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG;
/* Only from config might we get differing names & paths. If so, then
@@ -1648,7 +1686,7 @@ static int submodule_load_from_config(
*/
if (strcmp(sm->name, name.ptr) != 0) { /* name changed */
- if (!strcmp(sm->path, name.ptr)) { /* already set as path */
+ if (sm->path && !strcmp(sm->path, name.ptr)) { /* already set as path */
replaced = sm->name;
sm->name = sm->path;
} else {
@@ -1674,7 +1712,6 @@ static int submodule_load_from_config(
/* Deregister under name being replaced */
if (replaced) {
- git_strmap_delete(cache->submodules, replaced);
git_submodule_free(sm);
git__free(replaced);
}
@@ -1682,7 +1719,6 @@ static int submodule_load_from_config(
/* Insert under alternate key */
if (alternate) {
void *old_sm = NULL;
- git_strmap_insert2(cache->submodules, alternate, sm, old_sm, error);
if (error < 0)
goto done;
@@ -1742,7 +1778,6 @@ static int submodule_load_from_config(
/* ignore other unknown submodule properties */
done:
- git_submodule_free(sm); /* offset refcount inc from submodule_get() */
git_buf_free(&name);
return error;
}
@@ -1764,86 +1799,11 @@ static int submodule_load_from_wd_lite(git_submodule *sm)
return 0;
}
-static int submodule_cache_refresh_from_index(
- git_submodule_cache *cache, git_index *idx)
-{
- int error;
- git_iterator *i;
- const git_index_entry *entry;
-
- if ((error = git_iterator_for_index(&i, idx, 0, NULL, NULL)) < 0)
- return error;
-
- while (!(error = git_iterator_advance(&entry, i))) {
- khiter_t pos = git_strmap_lookup_index(cache->submodules, entry->path);
- git_submodule *sm;
-
- if (git_strmap_valid_index(cache->submodules, pos)) {
- sm = git_strmap_value_at(cache->submodules, pos);
-
- if (S_ISGITLINK(entry->mode))
- submodule_update_from_index_entry(sm, entry);
- else
- sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
- } else if (S_ISGITLINK(entry->mode)) {
- if (!submodule_get(&sm, cache, entry->path, NULL)) {
- submodule_update_from_index_entry(sm, entry);
- git_submodule_free(sm);
- }
- }
- }
-
- if (error == GIT_ITEROVER)
- error = 0;
-
- git_iterator_free(i);
-
- return error;
-}
-
-static int submodule_cache_refresh_from_head(
- git_submodule_cache *cache, git_tree *head)
-{
- int error;
- git_iterator *i;
- const git_index_entry *entry;
-
- if ((error = git_iterator_for_tree(&i, head, 0, NULL, NULL)) < 0)
- return error;
-
- while (!(error = git_iterator_advance(&entry, i))) {
- khiter_t pos = git_strmap_lookup_index(cache->submodules, entry->path);
- git_submodule *sm;
-
- if (git_strmap_valid_index(cache->submodules, pos)) {
- sm = git_strmap_value_at(cache->submodules, pos);
-
- if (S_ISGITLINK(entry->mode))
- submodule_update_from_head_data(sm, entry->mode, &entry->id);
- else
- sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
- } else if (S_ISGITLINK(entry->mode)) {
- if (!submodule_get(&sm, cache, entry->path, NULL)) {
- submodule_update_from_head_data(
- sm, entry->mode, &entry->id);
- git_submodule_free(sm);
- }
- }
- }
-
- if (error == GIT_ITEROVER)
- error = 0;
-
- git_iterator_free(i);
-
- return error;
-}
-
static git_config_backend *open_gitmodules(
- git_submodule_cache *cache,
+ git_repository *repo,
int okay_to_create)
{
- const char *workdir = git_repository_workdir(cache->repo);
+ const char *workdir = git_repository_workdir(repo);
git_buf path = GIT_BUF_INIT;
git_config_backend *mods = NULL;
@@ -1868,198 +1828,6 @@ static git_config_backend *open_gitmodules(
return mods;
}
-static void submodule_cache_free(git_submodule_cache *cache)
-{
- git_submodule *sm;
-
- if (!cache)
- return;
-
- git_strmap_foreach_value(cache->submodules, sm, {
- sm->repo = NULL; /* disconnect from repo */
- git_submodule_free(sm);
- });
- git_strmap_free(cache->submodules);
-
- git_buf_free(&cache->gitmodules_path);
- git_mutex_free(&cache->lock);
- git__free(cache);
-}
-
-static int submodule_cache_alloc(
- git_submodule_cache **out, git_repository *repo)
-{
- git_submodule_cache *cache = git__calloc(1, sizeof(git_submodule_cache));
- GITERR_CHECK_ALLOC(cache);
-
- if (git_mutex_init(&cache->lock) < 0) {
- giterr_set(GITERR_OS, "Unable to initialize submodule cache lock");
- git__free(cache);
- return -1;
- }
-
- if (git_strmap_alloc(&cache->submodules) < 0) {
- submodule_cache_free(cache);
- return -1;
- }
-
- cache->repo = repo;
- git_buf_init(&cache->gitmodules_path, 0);
-
- *out = cache;
- return 0;
-}
-
-static int submodule_cache_refresh(git_submodule_cache *cache, int refresh)
-{
- 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 (!cache || !cache->repo || !refresh)
- return 0;
-
- if (git_mutex_lock(&cache->lock) < 0) {
- giterr_set(GITERR_OS, "Unable to acquire lock on submodule cache");
- return -1;
- }
-
- /* get sources that we will need to check */
-
- if (git_repository_index(&idx, cache->repo) < 0)
- giterr_clear();
- if (git_repository_head_tree(&head, cache->repo) < 0)
- giterr_clear();
-
- wd = git_repository_workdir(cache->repo);
- if (wd && (error = git_buf_joinpath(&path, wd, GIT_MODULES_FILE)) < 0)
- goto cleanup;
-
- /* check for invalidation */
-
- if (refresh == CACHE_FLUSH)
- update_index = update_head = update_gitmod = true;
- else {
- update_index =
- !idx || git_index__changed_relative_to(idx, &cache->index_checksum);
- 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);
- }
-
- /* clear submodule flags that are to be refreshed */
-
- 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;
- else
- goto cleanup; /* nothing to do */
-
- 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;
-
- git_oid_cpy(&cache->index_checksum, git_index_checksum(idx));
- }
-
- /* add submodule information from HEAD */
-
- if (head && update_head) {
- if ((error = submodule_cache_refresh_from_head(cache, head)) < 0)
- goto cleanup;
-
- git_oid_cpy(&cache->head_id, git_tree_id(head));
- }
-
- /* add submodule information from .gitmodules */
-
- 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;
- }
-
- /* 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, {
- /* purge unless in HEAD, index, or .gitmodules; no sm for wd only */
- if (sm != NULL &&
- !(sm->flags &
- (GIT_SUBMODULE_STATUS_IN_HEAD |
- GIT_SUBMODULE_STATUS_IN_INDEX |
- GIT_SUBMODULE_STATUS_IN_CONFIG)))
- submodule_cache_remove_item(cache, sm, true);
- });
-
-cleanup:
- git_config_file_free(mods);
-
- /* TODO: if we got an error, mark submodule config as invalid? */
-
- git_mutex_unlock(&cache->lock);
-
- git_index_free(idx);
- git_tree_free(head);
- git_buf_free(&path);
-
- return error;
-}
-
-static int submodule_cache_init(git_repository *repo, int cache_refresh)
-{
- int error = 0;
- git_submodule_cache *cache = NULL;
-
- /* if submodules already exist, just refresh as requested */
- if (repo->_submodules)
- return submodule_cache_refresh(repo->_submodules, cache_refresh);
-
- /* otherwise create a new cache, load it, and atomically swap it in */
- if (!(error = submodule_cache_alloc(&cache, repo)) &&
- !(error = submodule_cache_refresh(cache, CACHE_FLUSH)))
- cache = git__compare_and_swap(&repo->_submodules, NULL, cache);
-
- /* might have raced with another thread to set cache, so free if needed */
- if (cache)
- submodule_cache_free(cache);
-
- return error;
-}
-
/* Lookup name of remote of the local tracking branch HEAD points to */
static int lookup_head_remote_key(git_buf *remote_name, git_repository *repo)
{
diff --git a/src/submodule.h b/src/submodule.h
index 7a9bf9c92..d67796193 100644
--- a/src/submodule.h
+++ b/src/submodule.h
@@ -99,23 +99,6 @@ struct git_submodule {
git_oid wd_oid;
};
-/**
- * The git_submodule_cache stores known submodules along with timestamps,
- * etc. about when they were loaded
- */
-typedef struct {
- git_repository *repo;
- git_strmap *submodules;
- git_mutex lock;
-
- /* cache invalidation data */
- git_oid head_id;
- git_oid index_checksum;
- git_buf gitmodules_path;
- git_futils_filestamp gitmodules_stamp;
- git_futils_filestamp config_stamp;
-} git_submodule_cache;
-
/* Force revalidation of submodule data cache (alloc as needed) */
extern int git_submodule_cache_refresh(git_repository *repo);
@@ -137,9 +120,6 @@ enum {
#define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \
((S) & ~(0xFFFFFFFFu << 20))
-/* Internal submodule check does not attempt to refresh cached data */
-extern bool git_submodule__is_submodule(git_repository *repo, const char *name);
-
/* Internal lookup does not attempt to refresh cached data */
extern int git_submodule__lookup(
git_submodule **out, git_repository *repo, const char *path);
diff --git a/tests/submodule/modify.c b/tests/submodule/modify.c
index bbbb2d56e..8f24d9bb5 100644
--- a/tests/submodule/modify.c
+++ b/tests/submodule/modify.c
@@ -50,8 +50,6 @@ void test_submodule_modify__init(void)
/* call init and see that settings are copied */
cl_git_pass(git_submodule_foreach(g_repo, init_one_submodule, NULL));
- git_submodule_reload_all(g_repo, 1);
-
/* confirm submodule data in config */
cl_git_pass(git_repository_config_snapshot(&cfg, g_repo));
cl_git_pass(git_config_get_string(&str, cfg, "submodule.sm_unchanged.url"));
diff --git a/tests/submodule/nosubs.c b/tests/submodule/nosubs.c
index e343c1620..538825c1c 100644
--- a/tests/submodule/nosubs.c
+++ b/tests/submodule/nosubs.c
@@ -21,19 +21,11 @@ void test_submodule_nosubs__lookup(void)
cl_assert_equal_i(GIT_EEXISTS, git_submodule_lookup(&sm, repo, "subrepo"));
- cl_git_pass(git_submodule_reload_all(repo, 0));
-
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, repo, "subdir"));
cl_assert_equal_i(GIT_EEXISTS, git_submodule_lookup(&sm, repo, "subrepo"));
}
-void test_submodule_nosubs__immediate_reload(void)
-{
- git_repository *repo = cl_git_sandbox_init("status");
- cl_git_pass(git_submodule_reload_all(repo, 0));
-}
-
static int fake_submod_cb(git_submodule *sm, const char *n, void *p)
{
GIT_UNUSED(sm); GIT_UNUSED(n); GIT_UNUSED(p);
@@ -57,41 +49,7 @@ void test_submodule_nosubs__add(void)
git_submodule_free(sm2);
cl_git_pass(git_submodule_foreach(repo, fake_submod_cb, NULL));
- cl_git_pass(git_submodule_reload_all(repo, 0));
-
- git_submodule_free(sm);
-}
-
-void test_submodule_nosubs__reload_add_reload(void)
-{
- git_repository *repo = cl_git_sandbox_init("status");
- git_submodule *sm;
-
- cl_git_pass(git_submodule_reload_all(repo, 0));
-
- /* try one add with a reload (to make sure no errors happen) */
-
- cl_git_pass(git_submodule_add_setup(&sm, repo,
- "https://github.com/libgit2/libgit2.git", "submodules/libgit2", 1));
-
- cl_git_pass(git_submodule_reload_all(repo, 0));
-
- cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm));
- git_submodule_free(sm);
-
- cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
- cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm));
- git_submodule_free(sm);
-
- /* try one add without a reload (to make sure cache inval works, too) */
-
- cl_git_pass(git_submodule_add_setup(&sm, repo,
- "https://github.com/libgit2/libgit2.git", "libgit2-again", 1));
- cl_assert_equal_s("libgit2-again", git_submodule_name(sm));
- git_submodule_free(sm);
- cl_git_pass(git_submodule_lookup(&sm, repo, "libgit2-again"));
- cl_assert_equal_s("libgit2-again", git_submodule_name(sm));
git_submodule_free(sm);
}
@@ -100,10 +58,8 @@ void test_submodule_nosubs__bad_gitmodules(void)
git_repository *repo = cl_git_sandbox_init("status");
cl_git_mkfile("status/.gitmodules", "[submodule \"foobar\"]\tpath=blargle\n\turl=\n\tbranch=\n\tupdate=flooble\n\n");
- cl_git_fail(git_submodule_reload_all(repo, 0));
cl_git_rewritefile("status/.gitmodules", "[submodule \"foobar\"]\tpath=blargle\n\turl=\n\tbranch=\n\tupdate=rebase\n\n");
- cl_git_pass(git_submodule_reload_all(repo, 0));
cl_git_pass(git_submodule_lookup(NULL, repo, "foobar"));
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(NULL, repo, "subdir"));