diff --git a/include/git2/submodule.h b/include/git2/submodule.h index 186f263f5..a1507593c 100644 --- a/include/git2/submodule.h +++ b/include/git2/submodule.h @@ -104,6 +104,19 @@ typedef enum { GIT_SUBMODULE_STATUS_WD_WD_MODIFIED | \ GIT_SUBMODULE_STATUS_WD_UNTRACKED)) != 0) +/** + * Options for submodule recurse. + * + * * GIT_SUBMODULE_RECURSE_NO - do no recurse into submodules + * * GIT_SUBMODULE_RECURSE_YES - recurse into submodules + * * GIT_SUBMODULE_RECURSE_ONDEMAND - recurse into submodules only when commit not already in local clone + */ +typedef enum { + GIT_SUBMODULE_RECURSE_NO = 0, + GIT_SUBMODULE_RECURSE_YES = 1, + GIT_SUBMODULE_RECURSE_ONDEMAND = 2, +} git_submodule_recurse_t; + /** * Lookup submodule information by name or path. * @@ -410,7 +423,7 @@ GIT_EXTERN(git_submodule_update_t) git_submodule_set_update( * * @return 0 if fetchRecurseSubmodules is false, 1 if true */ -GIT_EXTERN(int) git_submodule_fetch_recurse_submodules( +GIT_EXTERN(git_submodule_recurse_t) git_submodule_fetch_recurse_submodules( git_submodule *submodule); /** @@ -426,7 +439,7 @@ GIT_EXTERN(int) git_submodule_fetch_recurse_submodules( */ GIT_EXTERN(int) git_submodule_set_fetch_recurse_submodules( git_submodule *submodule, - int fetch_recurse_submodules); + git_submodule_recurse_t fetch_recurse_submodules); /** * Copy submodule info into ".git/config" file. diff --git a/src/submodule.c b/src/submodule.c index f6660a87e..5548e4553 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -43,6 +43,12 @@ static git_cvar_map _sm_ignore_map[] = { {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_IGNORE_ALL}, }; +static git_cvar_map _sm_recurse_map[] = { + {GIT_CVAR_STRING, "on-demand", GIT_SUBMODULE_RECURSE_ONDEMAND}, + {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_RECURSE_NO}, + {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_RECURSE_YES}, +}; + static kh_inline khint_t str_hash_no_trailing_slash(const char *s) { khint_t h; @@ -428,6 +434,15 @@ const char *git_submodule_update_to_str(git_submodule_update_t update) return NULL; } +const char *git_submodule_recurse_to_str(git_submodule_recurse_t recurse) +{ + int i; + for (i = 0; i < (int)ARRAY_SIZE(_sm_recurse_map); ++i) + if (_sm_recurse_map[i].map_value == recurse) + return _sm_recurse_map[i].str_match; + return NULL; +} + int git_submodule_save(git_submodule *submodule) { int error = 0; @@ -469,10 +484,10 @@ int git_submodule_save(git_submodule *submodule) if (error < 0) goto cleanup; - if ((error = submodule_config_key_trunc_puts( - &key, "fetchRecurseSubmodules")) < 0 || - (error = git_config_file_set_string( - mods, key.ptr, submodule->fetch_recurse ? "true" : "false")) < 0) + if (!(error = submodule_config_key_trunc_puts(&key, "fetchRecurseSubmodules")) && + (val = git_submodule_recurse_to_str(submodule->fetch_recurse)) != NULL) + error = git_config_file_set_string(mods, key.ptr, val); + if (error < 0) goto cleanup; /* update internal defaults */ @@ -610,7 +625,7 @@ git_submodule_update_t git_submodule_set_update( return old; } -int git_submodule_fetch_recurse_submodules( +git_submodule_recurse_t git_submodule_fetch_recurse_submodules( git_submodule *submodule) { assert(submodule); @@ -619,14 +634,14 @@ int git_submodule_fetch_recurse_submodules( int git_submodule_set_fetch_recurse_submodules( git_submodule *submodule, - int fetch_recurse_submodules) + git_submodule_recurse_t fetch_recurse_submodules) { int old; assert(submodule); old = submodule->fetch_recurse; - submodule->fetch_recurse = (fetch_recurse_submodules != 0); + submodule->fetch_recurse = fetch_recurse_submodules; return old; } @@ -975,6 +990,7 @@ static git_submodule *submodule_alloc(git_repository *repo, const char *name) GIT_REFCOUNT_INC(sm); sm->ignore = sm->ignore_default = GIT_SUBMODULE_IGNORE_NONE; sm->update = sm->update_default = GIT_SUBMODULE_UPDATE_CHECKOUT; + sm->fetch_recurse = sm->update_default = GIT_SUBMODULE_RECURSE_YES; sm->repo = repo; return sm; @@ -1080,6 +1096,20 @@ int git_submodule_parse_update(git_submodule_update_t *out, const char *value) return 0; } +int git_submodule_parse_recurse(git_submodule_recurse_t *out, const char *value) +{ + int val; + + if (git_config_lookup_map_value( + &val, _sm_recurse_map, ARRAY_SIZE(_sm_recurse_map), value) < 0) { + *out = GIT_SUBMODULE_RECURSE_YES; + return submodule_config_error("recurse", value); + } + + *out = (git_submodule_recurse_t)val; + return 0; +} + static int submodule_load_from_config( const git_config_entry *entry, void *payload) { @@ -1166,10 +1196,8 @@ static int submodule_load_from_config( sm->update_default = sm->update; } else if (strcasecmp(property, "fetchRecurseSubmodules") == 0) { - if (git__parse_bool(&sm->fetch_recurse, value) < 0) { - error = submodule_config_error("fetchRecurseSubmodules", value); - goto done; - } + if (git_submodule_parse_recurse(&sm->fetch_recurse, value) < 0) + return -1; } else if (strcasecmp(property, "ignore") == 0) { if ((error = git_submodule_parse_ignore(&sm->ignore, value)) < 0) diff --git a/src/submodule.h b/src/submodule.h index b05937503..2a610e112 100644 --- a/src/submodule.h +++ b/src/submodule.h @@ -85,7 +85,7 @@ struct git_submodule { git_submodule_update_t update_default; git_submodule_ignore_t ignore; git_submodule_ignore_t ignore_default; - int fetch_recurse; + git_submodule_recurse_t fetch_recurse; /* internal information */ git_repository *repo; diff --git a/tests/submodule/modify.c b/tests/submodule/modify.c index e326287a6..8ec9fceb0 100644 --- a/tests/submodule/modify.c +++ b/tests/submodule/modify.c @@ -168,7 +168,7 @@ void test_submodule_modify__edit_and_save(void) git_submodule_ignore_t old_ignore; git_submodule_update_t old_update; git_repository *r2; - int old_fetchrecurse; + git_submodule_recurse_t old_fetchrecurse; cl_git_pass(git_submodule_lookup(&sm1, g_repo, "sm_changed_head")); @@ -178,14 +178,14 @@ void test_submodule_modify__edit_and_save(void) cl_git_pass(git_submodule_set_url(sm1, SM_LIBGIT2_URL)); old_ignore = git_submodule_set_ignore(sm1, GIT_SUBMODULE_IGNORE_UNTRACKED); old_update = git_submodule_set_update(sm1, GIT_SUBMODULE_UPDATE_REBASE); - old_fetchrecurse = git_submodule_set_fetch_recurse_submodules(sm1, 1); + old_fetchrecurse = git_submodule_set_fetch_recurse_submodules(sm1, GIT_SUBMODULE_RECURSE_YES); cl_assert_equal_s(SM_LIBGIT2_URL, git_submodule_url(sm1)); cl_assert_equal_i( (int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm1)); cl_assert_equal_i( (int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update(sm1)); - cl_assert_equal_i(1, git_submodule_fetch_recurse_submodules(sm1)); + cl_assert_equal_i(GIT_SUBMODULE_RECURSE_YES, git_submodule_fetch_recurse_submodules(sm1)); /* revert without saving (and confirm setters return old value) */ cl_git_pass(git_submodule_set_url(sm1, old_url)); @@ -196,7 +196,7 @@ void test_submodule_modify__edit_and_save(void) (int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_set_update(sm1, GIT_SUBMODULE_UPDATE_RESET)); cl_assert_equal_i( - 1, git_submodule_set_fetch_recurse_submodules(sm1, old_fetchrecurse)); + GIT_SUBMODULE_RECURSE_YES, git_submodule_set_fetch_recurse_submodules(sm1, old_fetchrecurse)); /* check that revert was successful */ cl_assert_equal_s(old_url, git_submodule_url(sm1)); @@ -209,7 +209,7 @@ void test_submodule_modify__edit_and_save(void) cl_git_pass(git_submodule_set_url(sm1, SM_LIBGIT2_URL)); git_submodule_set_ignore(sm1, GIT_SUBMODULE_IGNORE_UNTRACKED); git_submodule_set_update(sm1, GIT_SUBMODULE_UPDATE_REBASE); - git_submodule_set_fetch_recurse_submodules(sm1, 1); + git_submodule_set_fetch_recurse_submodules(sm1, GIT_SUBMODULE_RECURSE_YES); /* call save */ cl_git_pass(git_submodule_save(sm1)); @@ -225,7 +225,7 @@ void test_submodule_modify__edit_and_save(void) (int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm1)); cl_assert_equal_i( (int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update(sm1)); - cl_assert_equal_i(1, git_submodule_fetch_recurse_submodules(sm1)); + cl_assert_equal_i(GIT_SUBMODULE_RECURSE_YES, git_submodule_fetch_recurse_submodules(sm1)); /* call reload and check that the new values are loaded */ cl_git_pass(git_submodule_reload(sm1)); @@ -235,7 +235,7 @@ void test_submodule_modify__edit_and_save(void) (int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm1)); cl_assert_equal_i( (int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update(sm1)); - cl_assert_equal_i(1, git_submodule_fetch_recurse_submodules(sm1)); + cl_assert_equal_i(GIT_SUBMODULE_RECURSE_YES, git_submodule_fetch_recurse_submodules(sm1)); /* open a second copy of the repo and compare submodule */ cl_git_pass(git_repository_open(&r2, "submod2")); @@ -246,7 +246,16 @@ void test_submodule_modify__edit_and_save(void) (int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm2)); cl_assert_equal_i( (int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update(sm2)); - cl_assert_equal_i(1, git_submodule_fetch_recurse_submodules(sm2)); + cl_assert_equal_i(GIT_SUBMODULE_RECURSE_YES, git_submodule_fetch_recurse_submodules(sm2)); + + /* set fetchRecurseSubmodules on-demand */ + cl_git_pass(git_submodule_reload(sm1)); + git_submodule_set_fetch_recurse_submodules(sm1, GIT_SUBMODULE_RECURSE_ONDEMAND); + cl_assert_equal_i(GIT_SUBMODULE_RECURSE_ONDEMAND, git_submodule_fetch_recurse_submodules(sm1)); + /* call save */ + cl_git_pass(git_submodule_save(sm1)); + cl_git_pass(git_submodule_reload(sm1)); + cl_assert_equal_i(GIT_SUBMODULE_RECURSE_ONDEMAND, git_submodule_fetch_recurse_submodules(sm1)); git_repository_free(r2); git__free(old_url);