diff --git a/src/submodule.c b/src/submodule.c index 5588a4f69..7b06c25c2 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -49,6 +49,16 @@ static git_cvar_map _sm_recurse_map[] = { {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_RECURSE_YES}, }; +enum { + CACHE_OK = 0, + CACHE_REFRESH = 1, + CACHE_FLUSH = 2 +}; +enum { + GITMODULES_EXISTING = 0, + GITMODULES_CREATE = 1, +}; + static kh_inline khint_t str_hash_no_trailing_slash(const char *s) { khint_t h; @@ -77,10 +87,10 @@ __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, bool refresh); +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 *, bool); +static git_config_backend *open_gitmodules(git_submodule_cache *, int gitmod); static int lookup_head_remote_key(git_buf *key, git_repository *repo); static int lookup_head_remote(git_buf *url, git_repository *repo); static int submodule_get(git_submodule **, git_submodule_cache *, const char *, const char *); @@ -153,7 +163,7 @@ bool git_submodule__is_submodule(git_repository *repo, const char *name) { git_strmap *map; - if (submodule_cache_init(repo, false) < 0) { + if (submodule_cache_init(repo, CACHE_OK) < 0) { giterr_clear(); return false; } @@ -183,7 +193,7 @@ int git_submodule__lookup( assert(repo && name); - if ((error = submodule_cache_init(repo, false)) < 0) + if ((error = submodule_cache_init(repo, CACHE_OK)) < 0) return error; if ((error = submodule_lookup(out, repo->_submodules, name, NULL)) < 0) @@ -201,7 +211,7 @@ int git_submodule_lookup( assert(repo && name); - if ((error = submodule_cache_init(repo, true)) < 0) + if ((error = submodule_cache_init(repo, CACHE_REFRESH)) < 0) return error; if ((error = submodule_lookup(out, repo->_submodules, name, NULL)) < 0) { @@ -238,7 +248,7 @@ int git_submodule_foreach( assert(repo && callback); - if ((error = submodule_cache_init(repo, true)) < 0) + if ((error = submodule_cache_init(repo, CACHE_REFRESH)) < 0) return error; git_strmap_foreach_value(repo->_submodules->submodules, sm, { @@ -317,9 +327,9 @@ int git_submodule_add_setup( /* update .gitmodules */ - if ((mods = open_gitmodules(repo->_submodules, true)) == NULL) { + if (!(mods = open_gitmodules(repo->_submodules, GITMODULES_CREATE))) { giterr_set(GITERR_SUBMODULE, - "Adding submodules to a bare repository is not supported (for now)"); + "Adding submodules to a bare repository is not supported"); return -1; } @@ -517,10 +527,10 @@ int git_submodule_save(git_submodule *submodule) assert(submodule); - mods = open_gitmodules(submodule->repo->_submodules, true); + mods = open_gitmodules(submodule->repo->_submodules, GITMODULES_CREATE); if (!mods) { giterr_set(GITERR_SUBMODULE, - "Adding submodules to a bare repository is not supported (for now)"); + "Adding submodules to a bare repository is not supported"); return -1; } @@ -929,7 +939,7 @@ int git_submodule_reload_all(git_repository *repo, int force) if (repo->_submodules) submodule_cache_clear_flags(repo->_submodules, 0xFFFFFFFFu); - if ((error = submodule_cache_init(repo, true)) < 0) + if ((error = submodule_cache_init(repo, CACHE_FLUSH)) < 0) return error; if (!repo->_submodules || !(map = repo->_submodules->submodules)) @@ -1049,7 +1059,7 @@ int git_submodule_reload(git_submodule *sm, int force) return error; /* refresh config data */ - mods = open_gitmodules(cache, false); + mods = open_gitmodules(cache, GITMODULES_EXISTING); if (mods != NULL) { git_buf path = GIT_BUF_INIT; @@ -1537,7 +1547,7 @@ static int submodule_cache_refresh_from_head( static git_config_backend *open_gitmodules( git_submodule_cache *cache, - bool okay_to_create) + int okay_to_create) { const char *workdir = git_repository_workdir(cache->repo); git_buf path = GIT_BUF_INIT; @@ -1607,15 +1617,19 @@ static int submodule_cache_alloc( return 0; } -static int submodule_cache_refresh(git_submodule_cache *cache, bool force) +static int submodule_cache_refresh(git_submodule_cache *cache, int refresh) { - int error = 0, updates = 0, changed; + int error = 0, updates = 0, flush, changed; git_config_backend *mods = NULL; const char *wd; git_index *idx = NULL; git_tree *head = NULL; git_buf path = GIT_BUF_INIT; + if (!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; @@ -1626,7 +1640,7 @@ static int submodule_cache_refresh(git_submodule_cache *cache, bool force) /* add submodule information from index */ if (!git_repository_index(&idx, cache->repo)) { - if (force || git_index__changed_relative_to(idx, &cache->index_stamp)) { + if (flush || git_index__changed_relative_to(idx, &cache->index_stamp)) { if ((error = submodule_cache_refresh_from_index(cache, idx)) < 0) goto cleanup; @@ -1646,7 +1660,7 @@ static int submodule_cache_refresh(git_submodule_cache *cache, bool force) /* add submodule information from HEAD */ if (!git_repository_head_tree(&head, cache->repo)) { - if (force || !git_oid_equal(&cache->head_id, git_tree_id(head))) { + if (flush || !git_oid_equal(&cache->head_id, git_tree_id(head))) { if ((error = submodule_cache_refresh_from_head(cache, head)) < 0) goto cleanup; @@ -1669,6 +1683,9 @@ static int submodule_cache_refresh(git_submodule_cache *cache, bool force) goto cleanup; changed = git_futils_filestamp_check(&cache->gitmodules_stamp, path.ptr); + if (flush && !changed) + changed = 1; + if (changed < 0) { giterr_clear(); submodule_cache_clear_flags(cache, GIT_SUBMODULE_STATUS_IN_CONFIG); @@ -1709,18 +1726,18 @@ cleanup: return error; } -static int submodule_cache_init(git_repository *repo, bool refresh) +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 refresh ? submodule_cache_refresh(repo->_submodules, false) : 0; + 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, true))) + !(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 */