Commit dc7efa1a by Vicent Marti

Merge pull request #2204 from libgit2/rb/submodule-reference-counting

Make submodules externally refcounted
parents 77b699e0 591e8295
...@@ -363,18 +363,21 @@ static void print_short(git_repository *repo, git_status_list *status) ...@@ -363,18 +363,21 @@ static void print_short(git_repository *repo, git_status_list *status)
unsigned int smstatus = 0; unsigned int smstatus = 0;
if (!git_submodule_lookup( if (!git_submodule_lookup(
&sm, repo, s->index_to_workdir->new_file.path) && &sm, repo, s->index_to_workdir->new_file.path)) {
!git_submodule_status(&smstatus, sm))
{ if (!git_submodule_status(&smstatus, sm)) {
if (smstatus & GIT_SUBMODULE_STATUS_WD_MODIFIED) if (smstatus & GIT_SUBMODULE_STATUS_WD_MODIFIED)
extra = " (new commits)"; extra = " (new commits)";
else if (smstatus & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) else if (smstatus & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED)
extra = " (modified content)"; extra = " (modified content)";
else if (smstatus & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) else if (smstatus & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED)
extra = " (modified content)"; extra = " (modified content)";
else if (smstatus & GIT_SUBMODULE_STATUS_WD_UNTRACKED) else if (smstatus & GIT_SUBMODULE_STATUS_WD_UNTRACKED)
extra = " (untracked content)"; extra = " (untracked content)";
}
} }
git_submodule_free(sm);
} }
/** /**
......
...@@ -123,22 +123,28 @@ typedef enum { ...@@ -123,22 +123,28 @@ typedef enum {
* There may or may not be anything else at that path, but nothing that * There may or may not be anything else at that path, but nothing that
* looks like a submodule. In this case, this returns GIT_ENOTFOUND. * looks like a submodule. In this case, this returns GIT_ENOTFOUND.
* *
* The submodule object is owned by the containing repo and will be freed * You must call `git_submodule_free` when done with the submodule.
* when the repo is freed. The caller need not free the submodule.
* *
* @param submodule Pointer to submodule description object pointer.. * @param out Output ptr to submodule; pass NULL to just get return code
* @param repo The repository. * @param repo The parent repository
* @param name The name of the submodule. Trailing slashes will be ignored. * @param name The name of or path to the submodule; trailing slashes okay
* @return 0 on success, GIT_ENOTFOUND if submodule does not exist, * @return 0 on success, GIT_ENOTFOUND if submodule does not exist,
* GIT_EEXISTS if submodule exists in working directory only, -1 on * GIT_EEXISTS if submodule exists in working directory only,
* other errors. * -1 on other errors.
*/ */
GIT_EXTERN(int) git_submodule_lookup( GIT_EXTERN(int) git_submodule_lookup(
git_submodule **submodule, git_submodule **out,
git_repository *repo, git_repository *repo,
const char *name); const char *name);
/** /**
* Release a submodule
*
* @param submodule Submodule object
*/
GIT_EXTERN(void) git_submodule_free(git_submodule *submodule);
/**
* Iterate over all tracked submodules of a repository. * Iterate over all tracked submodules of a repository.
* *
* See the note on `git_submodule` above. This iterates over the tracked * See the note on `git_submodule` above. This iterates over the tracked
...@@ -175,9 +181,11 @@ GIT_EXTERN(int) git_submodule_foreach( ...@@ -175,9 +181,11 @@ GIT_EXTERN(int) git_submodule_foreach(
* `git_submodule_add_finalize()` to wrap up adding the new submodule and * `git_submodule_add_finalize()` to wrap up adding the new submodule and
* .gitmodules to the index to be ready to commit. * .gitmodules to the index to be ready to commit.
* *
* @param submodule The newly created submodule ready to open for clone * You must call `git_submodule_free` on the submodule object when done.
* @param repo Superproject repository to contain the new submodule *
* @param url URL for the submodules remote * @param out The newly created submodule ready to open for clone
* @param repo The repository in which you want to create the submodule
* @param url URL for the submodule's remote
* @param path Path at which the submodule should be created * @param path Path at which the submodule should be created
* @param use_gitlink Should workdir contain a gitlink to the repo in * @param use_gitlink Should workdir contain a gitlink to the repo in
* .git/modules vs. repo directly in workdir. * .git/modules vs. repo directly in workdir.
...@@ -185,7 +193,7 @@ GIT_EXTERN(int) git_submodule_foreach( ...@@ -185,7 +193,7 @@ GIT_EXTERN(int) git_submodule_foreach(
* -1 on other errors. * -1 on other errors.
*/ */
GIT_EXTERN(int) git_submodule_add_setup( GIT_EXTERN(int) git_submodule_add_setup(
git_submodule **submodule, git_submodule **out,
git_repository *repo, git_repository *repo,
const char *url, const char *url,
const char *path, const char *path,
...@@ -493,15 +501,23 @@ GIT_EXTERN(int) git_submodule_open( ...@@ -493,15 +501,23 @@ GIT_EXTERN(int) git_submodule_open(
* *
* Call this to reread cached submodule information for this submodule if * Call this to reread cached submodule information for this submodule if
* you have reason to believe that it has changed. * you have reason to believe that it has changed.
*
* @param submodule The submodule to reload
* @param force Force reload even if the data doesn't seem out of date
* @return 0 on success, <0 on error
*/ */
GIT_EXTERN(int) git_submodule_reload(git_submodule *submodule); GIT_EXTERN(int) git_submodule_reload(git_submodule *submodule, int force);
/** /**
* Reread all submodule info. * Reread all submodule info.
* *
* Call this to reload all cached submodule information for the repo. * Call this to reload all cached submodule information for the repo.
*
* @param repo The repository to reload submodule data for
* @param force Force full reload even if the data doesn't seem out of date
* @return 0 on success, <0 on error
*/ */
GIT_EXTERN(int) git_submodule_reload_all(git_repository *repo); GIT_EXTERN(int) git_submodule_reload_all(git_repository *repo, int force);
/** /**
* Get the status for a submodule. * Get the status for a submodule.
......
...@@ -147,19 +147,23 @@ static bool checkout_is_workdir_modified( ...@@ -147,19 +147,23 @@ static bool checkout_is_workdir_modified(
git_submodule *sm; git_submodule *sm;
unsigned int sm_status = 0; unsigned int sm_status = 0;
const git_oid *sm_oid = NULL; const git_oid *sm_oid = NULL;
bool rval = false;
if (git_submodule_lookup(&sm, data->repo, wditem->path) < 0 || if (git_submodule_lookup(&sm, data->repo, wditem->path) < 0) {
git_submodule_status(&sm_status, sm) < 0) giterr_clear();
return true;
if (GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status))
return true; return true;
}
sm_oid = git_submodule_wd_id(sm); if (git_submodule_status(&sm_status, sm) < 0 ||
if (!sm_oid) GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status))
return false; rval = true;
else if ((sm_oid = git_submodule_wd_id(sm)) == NULL)
rval = false;
else
rval = (git_oid__cmp(&baseitem->id, sm_oid) != 0);
return (git_oid__cmp(&baseitem->id, sm_oid) != 0); git_submodule_free(sm);
return rval;
} }
/* Look at the cache to decide if the workdir is modified. If not, /* Look at the cache to decide if the workdir is modified. If not,
...@@ -324,12 +328,17 @@ static bool submodule_is_config_only( ...@@ -324,12 +328,17 @@ static bool submodule_is_config_only(
{ {
git_submodule *sm = NULL; git_submodule *sm = NULL;
unsigned int sm_loc = 0; unsigned int sm_loc = 0;
bool rval = false;
if (git_submodule_lookup(&sm, data->repo, path) < 0 || if (git_submodule_lookup(&sm, data->repo, path) < 0)
git_submodule_location(&sm_loc, sm) < 0 ||
sm_loc == GIT_SUBMODULE_STATUS_IN_CONFIG)
return true; return true;
if (git_submodule_location(&sm_loc, sm) < 0 ||
sm_loc == GIT_SUBMODULE_STATUS_IN_CONFIG)
rval = true;
git_submodule_free(sm);
return false; return false;
} }
...@@ -1258,7 +1267,6 @@ static int checkout_submodule( ...@@ -1258,7 +1267,6 @@ static int checkout_submodule(
const git_diff_file *file) const git_diff_file *file)
{ {
int error = 0; int error = 0;
git_submodule *sm;
/* Until submodules are supported, UPDATE_ONLY means do nothing here */ /* Until submodules are supported, UPDATE_ONLY means do nothing here */
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
...@@ -1269,7 +1277,7 @@ static int checkout_submodule( ...@@ -1269,7 +1277,7 @@ static int checkout_submodule(
data->opts.dir_mode, GIT_MKDIR_PATH)) < 0) data->opts.dir_mode, GIT_MKDIR_PATH)) < 0)
return error; return error;
if ((error = git_submodule_lookup(&sm, data->repo, file->path)) < 0) { if ((error = git_submodule_lookup(NULL, data->repo, file->path)) < 0) {
/* I've observed repos with submodules in the tree that do not /* I've observed repos with submodules in the tree that do not
* have a .gitmodules - core Git just makes an empty directory * have a .gitmodules - core Git just makes an empty directory
*/ */
...@@ -1510,7 +1518,7 @@ static int checkout_create_submodules( ...@@ -1510,7 +1518,7 @@ static int checkout_create_submodules(
/* initial reload of submodules if .gitmodules was changed */ /* initial reload of submodules if .gitmodules was changed */
if (data->reload_submodules && if (data->reload_submodules &&
(error = git_submodule_reload_all(data->repo)) < 0) (error = git_submodule_reload_all(data->repo, 1)) < 0)
return error; return error;
git_vector_foreach(&data->diff->deltas, i, delta) { git_vector_foreach(&data->diff->deltas, i, delta) {
...@@ -1534,7 +1542,7 @@ static int checkout_create_submodules( ...@@ -1534,7 +1542,7 @@ static int checkout_create_submodules(
} }
/* final reload once submodules have been updated */ /* final reload once submodules have been updated */
return git_submodule_reload_all(data->repo); return git_submodule_reload_all(data->repo, 1);
} }
static int checkout_lookup_head_tree(git_tree **out, git_repository *repo) static int checkout_lookup_head_tree(git_tree **out, git_repository *repo)
......
...@@ -528,12 +528,15 @@ int git_diff__oid_for_file( ...@@ -528,12 +528,15 @@ int git_diff__oid_for_file(
/* calculate OID for file if possible */ /* calculate OID for file if possible */
if (S_ISGITLINK(mode)) { if (S_ISGITLINK(mode)) {
git_submodule *sm; git_submodule *sm;
const git_oid *sm_oid;
if (!git_submodule_lookup(&sm, repo, path) && memset(oid, 0, sizeof(*oid));
(sm_oid = git_submodule_wd_id(sm)) != NULL)
git_oid_cpy(oid, sm_oid); if (!git_submodule_lookup(&sm, repo, path)) {
else { const git_oid *sm_oid = git_submodule_wd_id(sm);
if (sm_oid)
git_oid_cpy(oid, sm_oid);
git_submodule_free(sm);
} else {
/* if submodule lookup failed probably just in an intermediate /* if submodule lookup failed probably just in an intermediate
* state where some init hasn't happened, so ignore the error * state where some init hasn't happened, so ignore the error
*/ */
...@@ -615,24 +618,24 @@ static int maybe_modified_submodule( ...@@ -615,24 +618,24 @@ static int maybe_modified_submodule(
} }
if (ign <= 0 && git_submodule_ignore(sub) == GIT_SUBMODULE_IGNORE_ALL) if (ign <= 0 && git_submodule_ignore(sub) == GIT_SUBMODULE_IGNORE_ALL)
return 0; /* ignore it */;
else if ((error = git_submodule__status(
if ((error = git_submodule__status(
&sm_status, NULL, NULL, found_oid, sub, ign)) < 0) &sm_status, NULL, NULL, found_oid, sub, ign)) < 0)
return error; /* return error below */;
/* check IS_WD_UNMODIFIED because this case is only used /* check IS_WD_UNMODIFIED because this case is only used
* when the new side of the diff is the working directory * when the new side of the diff is the working directory
*/ */
if (!GIT_SUBMODULE_STATUS_IS_WD_UNMODIFIED(sm_status)) else if (!GIT_SUBMODULE_STATUS_IS_WD_UNMODIFIED(sm_status))
*status = GIT_DELTA_MODIFIED; *status = GIT_DELTA_MODIFIED;
/* now that we have a HEAD OID, check if HEAD moved */ /* now that we have a HEAD OID, check if HEAD moved */
if ((sm_status & GIT_SUBMODULE_STATUS_IN_WD) != 0 && else if ((sm_status & GIT_SUBMODULE_STATUS_IN_WD) != 0 &&
!git_oid_equal(&info->oitem->id, found_oid)) !git_oid_equal(&info->oitem->id, found_oid))
*status = GIT_DELTA_MODIFIED; *status = GIT_DELTA_MODIFIED;
return 0; git_submodule_free(sub);
return error;
} }
static int maybe_modified( static int maybe_modified(
...@@ -960,10 +963,8 @@ static int handle_unmatched_new_item( ...@@ -960,10 +963,8 @@ static int handle_unmatched_new_item(
delta_type = GIT_DELTA_ADDED; delta_type = GIT_DELTA_ADDED;
else if (nitem->mode == GIT_FILEMODE_COMMIT) { else if (nitem->mode == GIT_FILEMODE_COMMIT) {
git_submodule *sm;
/* ignore things that are not actual submodules */ /* ignore things that are not actual submodules */
if (git_submodule_lookup(&sm, info->repo, nitem->path) != 0) { if (git_submodule_lookup(NULL, info->repo, nitem->path) != 0) {
giterr_clear(); giterr_clear();
delta_type = GIT_DELTA_IGNORED; delta_type = GIT_DELTA_IGNORED;
} }
......
...@@ -177,11 +177,17 @@ static int diff_file_content_commit_to_str( ...@@ -177,11 +177,17 @@ static int diff_file_content_commit_to_str(
unsigned int sm_status = 0; unsigned int sm_status = 0;
const git_oid *sm_head; const git_oid *sm_head;
if ((error = git_submodule_lookup(&sm, fc->repo, fc->file->path)) < 0 || if ((error = git_submodule_lookup(&sm, fc->repo, fc->file->path)) < 0) {
(error = git_submodule_status(&sm_status, sm)) < 0) {
/* GIT_EEXISTS means a "submodule" that has not been git added */ /* GIT_EEXISTS means a "submodule" that has not been git added */
if (error == GIT_EEXISTS) if (error == GIT_EEXISTS) {
giterr_clear();
error = 0; error = 0;
}
return error;
}
if ((error = git_submodule_status(&sm_status, sm)) < 0) {
git_submodule_free(sm);
return error; return error;
} }
...@@ -196,6 +202,8 @@ static int diff_file_content_commit_to_str( ...@@ -196,6 +202,8 @@ static int diff_file_content_commit_to_str(
if (GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status)) if (GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status))
status = "-dirty"; status = "-dirty";
git_submodule_free(sm);
} }
git_oid_tostr(oid, sizeof(oid), &fc->file->id); git_oid_tostr(oid, sizeof(oid), &fc->file->id);
...@@ -312,7 +320,8 @@ static int diff_file_content_load_workdir_file( ...@@ -312,7 +320,8 @@ static int diff_file_content_load_workdir_file(
error = git_filter_list_apply_to_data(&out, fl, &raw); error = git_filter_list_apply_to_data(&out, fl, &raw);
git_buf_free(&raw); if (out.ptr != raw.ptr)
git_buf_free(&raw);
if (!error) { if (!error) {
fc->map.len = out.size; fc->map.len = out.size;
......
...@@ -111,6 +111,11 @@ enum { ...@@ -111,6 +111,11 @@ enum {
GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES = (1u << 27), GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES = (1u << 27),
}; };
#define GIT_SUBMODULE_STATUS__ALL_WD_FLAGS \
(GIT_SUBMODULE_STATUS_IN_WD | \
GIT_SUBMODULE_STATUS__WD_OID_VALID | \
GIT_SUBMODULE_STATUS__WD_FLAGS)
#define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \ #define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \
((S) & ~(0xFFFFFFFFu << 20)) ((S) & ~(0xFFFFFFFFu << 20))
...@@ -128,9 +133,6 @@ extern int git_submodule_open_bare( ...@@ -128,9 +133,6 @@ extern int git_submodule_open_bare(
git_repository **repo, git_repository **repo,
git_submodule *submodule); git_submodule *submodule);
/* Release reference to submodule object - not currently for external use */
extern void git_submodule_free(git_submodule *sm);
extern int git_submodule_parse_ignore( extern int git_submodule_parse_ignore(
git_submodule_ignore_t *out, const char *value); git_submodule_ignore_t *out, const char *value);
extern int git_submodule_parse_update( extern int git_submodule_parse_update(
......
...@@ -131,7 +131,7 @@ void test_diff_submodules__dirty_submodule_2(void) ...@@ -131,7 +131,7 @@ void test_diff_submodules__dirty_submodule_2(void)
g_repo = setup_fixture_submodules(); g_repo = setup_fixture_submodules();
cl_git_pass(git_submodule_reload_all(g_repo)); cl_git_pass(git_submodule_reload_all(g_repo, 1));
opts.flags = GIT_DIFF_INCLUDE_UNTRACKED | opts.flags = GIT_DIFF_INCLUDE_UNTRACKED |
GIT_DIFF_SHOW_UNTRACKED_CONTENT | GIT_DIFF_SHOW_UNTRACKED_CONTENT |
...@@ -165,7 +165,7 @@ void test_diff_submodules__dirty_submodule_2(void) ...@@ -165,7 +165,7 @@ void test_diff_submodules__dirty_submodule_2(void)
git_diff_free(diff); git_diff_free(diff);
cl_git_pass(git_submodule_reload_all(g_repo)); cl_git_pass(git_submodule_reload_all(g_repo, 1));
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
check_diff_patches(diff, expected_dirty); check_diff_patches(diff, expected_dirty);
...@@ -291,7 +291,9 @@ void test_diff_submodules__invalid_cache(void) ...@@ -291,7 +291,9 @@ void test_diff_submodules__invalid_cache(void)
check_diff_patches(diff, expected_dirty); check_diff_patches(diff, expected_dirty);
git_diff_free(diff); git_diff_free(diff);
cl_git_pass(git_submodule_reload_all(g_repo)); git_submodule_free(sm);
cl_git_pass(git_submodule_reload_all(g_repo, 1));
cl_git_pass(git_submodule_lookup(&sm, g_repo, smpath)); cl_git_pass(git_submodule_lookup(&sm, g_repo, smpath));
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
...@@ -344,6 +346,8 @@ void test_diff_submodules__invalid_cache(void) ...@@ -344,6 +346,8 @@ void test_diff_submodules__invalid_cache(void)
p_unlink("submod2/sm_changed_head/new_around_here"); p_unlink("submod2/sm_changed_head/new_around_here");
git_submodule_free(sm);
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
check_diff_patches(diff, expected_moved); check_diff_patches(diff, expected_moved);
git_diff_free(diff); git_diff_free(diff);
......
...@@ -19,6 +19,9 @@ void test_stash_submodules__initialize(void) ...@@ -19,6 +19,9 @@ void test_stash_submodules__initialize(void)
void test_stash_submodules__cleanup(void) void test_stash_submodules__cleanup(void)
{ {
git_submodule_free(sm);
sm = NULL;
git_signature_free(signature); git_signature_free(signature);
signature = NULL; signature = NULL;
} }
......
...@@ -29,6 +29,7 @@ void test_status_submodules__api(void) ...@@ -29,6 +29,7 @@ void test_status_submodules__api(void)
cl_assert(sm != NULL); cl_assert(sm != NULL);
cl_assert_equal_s("testrepo", git_submodule_name(sm)); cl_assert_equal_s("testrepo", git_submodule_name(sm));
cl_assert_equal_s("testrepo", git_submodule_path(sm)); cl_assert_equal_s("testrepo", git_submodule_path(sm));
git_submodule_free(sm);
} }
void test_status_submodules__0(void) void test_status_submodules__0(void)
...@@ -136,6 +137,7 @@ void test_status_submodules__moved_head(void) ...@@ -136,6 +137,7 @@ void test_status_submodules__moved_head(void)
cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo")); cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo"));
cl_git_pass(git_submodule_open(&smrepo, sm)); cl_git_pass(git_submodule_open(&smrepo, sm));
git_submodule_free(sm);
/* move submodule HEAD to c47800c7266a2be04c571c04d5a6614691ea99bd */ /* move submodule HEAD to c47800c7266a2be04c571c04d5a6614691ea99bd */
cl_git_pass( cl_git_pass(
......
...@@ -12,31 +12,25 @@ void test_submodule_lookup__initialize(void) ...@@ -12,31 +12,25 @@ void test_submodule_lookup__initialize(void)
void test_submodule_lookup__simple_lookup(void) void test_submodule_lookup__simple_lookup(void)
{ {
git_submodule *sm; assert_submodule_exists(g_repo, "sm_unchanged");
/* lookup existing */
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
cl_assert(sm);
/* lookup pending change in .gitmodules that is not in HEAD */ /* lookup pending change in .gitmodules that is not in HEAD */
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited")); assert_submodule_exists(g_repo, "sm_added_and_uncommited");
cl_assert(sm);
/* lookup pending change in .gitmodules that is neither in HEAD nor index */ /* lookup pending change in .gitmodules that is not in HEAD nor index */
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_gitmodules_only")); assert_submodule_exists(g_repo, "sm_gitmodules_only");
cl_assert(sm);
/* lookup git repo subdir that is not added as submodule */ /* lookup git repo subdir that is not added as submodule */
cl_assert(git_submodule_lookup(&sm, g_repo, "not-submodule") == GIT_EEXISTS); refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
/* lookup existing directory that is not a submodule */ /* lookup existing directory that is not a submodule */
cl_assert(git_submodule_lookup(&sm, g_repo, "just_a_dir") == GIT_ENOTFOUND); refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
/* lookup existing file that is not a submodule */ /* lookup existing file that is not a submodule */
cl_assert(git_submodule_lookup(&sm, g_repo, "just_a_file") == GIT_ENOTFOUND); refute_submodule_exists(g_repo, "just_a_file", GIT_ENOTFOUND);
/* lookup non-existent item */ /* lookup non-existent item */
cl_assert(git_submodule_lookup(&sm, g_repo, "no_such_file") == GIT_ENOTFOUND); refute_submodule_exists(g_repo, "no_such_file", GIT_ENOTFOUND);
} }
void test_submodule_lookup__accessors(void) void test_submodule_lookup__accessors(void)
...@@ -57,6 +51,9 @@ void test_submodule_lookup__accessors(void) ...@@ -57,6 +51,9 @@ void test_submodule_lookup__accessors(void)
cl_assert(git_submodule_ignore(sm) == GIT_SUBMODULE_IGNORE_NONE); cl_assert(git_submodule_ignore(sm) == GIT_SUBMODULE_IGNORE_NONE);
cl_assert(git_submodule_update(sm) == GIT_SUBMODULE_UPDATE_CHECKOUT); cl_assert(git_submodule_update(sm) == GIT_SUBMODULE_UPDATE_CHECKOUT);
git_submodule_free(sm);
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head")); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
cl_assert_equal_s("sm_changed_head", git_submodule_name(sm)); cl_assert_equal_s("sm_changed_head", git_submodule_name(sm));
...@@ -65,6 +62,9 @@ void test_submodule_lookup__accessors(void) ...@@ -65,6 +62,9 @@ void test_submodule_lookup__accessors(void)
cl_assert(git_oid_streq(git_submodule_wd_id(sm), cl_assert(git_oid_streq(git_submodule_wd_id(sm),
"3d9386c507f6b093471a3e324085657a3c2b4247") == 0); "3d9386c507f6b093471a3e324085657a3c2b4247") == 0);
git_submodule_free(sm);
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited")); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited"));
cl_assert_equal_s("sm_added_and_uncommited", git_submodule_name(sm)); cl_assert_equal_s("sm_added_and_uncommited", git_submodule_name(sm));
...@@ -72,6 +72,9 @@ void test_submodule_lookup__accessors(void) ...@@ -72,6 +72,9 @@ void test_submodule_lookup__accessors(void)
cl_assert(git_submodule_head_id(sm) == NULL); cl_assert(git_submodule_head_id(sm) == NULL);
cl_assert(git_oid_streq(git_submodule_wd_id(sm), oid) == 0); cl_assert(git_oid_streq(git_submodule_wd_id(sm), oid) == 0);
git_submodule_free(sm);
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits")); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits"));
cl_assert_equal_s("sm_missing_commits", git_submodule_name(sm)); cl_assert_equal_s("sm_missing_commits", git_submodule_name(sm));
...@@ -79,6 +82,8 @@ void test_submodule_lookup__accessors(void) ...@@ -79,6 +82,8 @@ void test_submodule_lookup__accessors(void)
cl_assert(git_oid_streq(git_submodule_head_id(sm), oid) == 0); cl_assert(git_oid_streq(git_submodule_head_id(sm), oid) == 0);
cl_assert(git_oid_streq(git_submodule_wd_id(sm), cl_assert(git_oid_streq(git_submodule_wd_id(sm),
"5e4963595a9774b90524d35a807169049de8ccad") == 0); "5e4963595a9774b90524d35a807169049de8ccad") == 0);
git_submodule_free(sm);
} }
typedef struct { typedef struct {
...@@ -104,69 +109,35 @@ void test_submodule_lookup__foreach(void) ...@@ -104,69 +109,35 @@ void test_submodule_lookup__foreach(void)
void test_submodule_lookup__lookup_even_with_unborn_head(void) void test_submodule_lookup__lookup_even_with_unborn_head(void)
{ {
git_reference *head; git_reference *head;
git_submodule *sm;
/* put us on an unborn branch */ /* put us on an unborn branch */
cl_git_pass(git_reference_symbolic_create( cl_git_pass(git_reference_symbolic_create(
&head, g_repo, "HEAD", "refs/heads/garbage", 1, NULL, NULL)); &head, g_repo, "HEAD", "refs/heads/garbage", 1, NULL, NULL));
git_reference_free(head); git_reference_free(head);
/* lookup existing */ assert_submodule_exists(g_repo, "sm_unchanged");
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); assert_submodule_exists(g_repo, "sm_added_and_uncommited");
cl_assert(sm); assert_submodule_exists(g_repo, "sm_gitmodules_only");
refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
/* lookup pending change in .gitmodules that is not in HEAD */ refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited")); refute_submodule_exists(g_repo, "just_a_file", GIT_ENOTFOUND);
cl_assert(sm); refute_submodule_exists(g_repo, "no_such_file", GIT_ENOTFOUND);
/* lookup pending change in .gitmodules that is neither in HEAD nor index */
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_gitmodules_only"));
cl_assert(sm);
/* lookup git repo subdir that is not added as submodule */
cl_assert_equal_i(GIT_EEXISTS, git_submodule_lookup(&sm, g_repo, "not-submodule"));
/* lookup existing directory that is not a submodule */
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "just_a_dir"));
/* lookup existing file that is not a submodule */
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "just_a_file"));
/* lookup non-existent item */
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "no_such_file"));
} }
void test_submodule_lookup__lookup_even_with_missing_index(void) void test_submodule_lookup__lookup_even_with_missing_index(void)
{ {
git_index *idx; git_index *idx;
git_submodule *sm;
/* give the repo an empty index */ /* give the repo an empty index */
cl_git_pass(git_index_new(&idx)); cl_git_pass(git_index_new(&idx));
git_repository_set_index(g_repo, idx); git_repository_set_index(g_repo, idx);
git_index_free(idx); git_index_free(idx);
/* lookup existing */ assert_submodule_exists(g_repo, "sm_unchanged");
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); assert_submodule_exists(g_repo, "sm_added_and_uncommited");
cl_assert(sm); assert_submodule_exists(g_repo, "sm_gitmodules_only");
refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
/* lookup pending change in .gitmodules that is not in HEAD */ refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited")); refute_submodule_exists(g_repo, "just_a_file", GIT_ENOTFOUND);
cl_assert(sm); refute_submodule_exists(g_repo, "no_such_file", GIT_ENOTFOUND);
/* lookup pending change in .gitmodules that is neither in HEAD nor index */
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_gitmodules_only"));
cl_assert(sm);
/* lookup git repo subdir that is not added as submodule */
cl_assert_equal_i(GIT_EEXISTS, git_submodule_lookup(&sm, g_repo, "not-submodule"));
/* lookup existing directory that is not a submodule */
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "just_a_dir"));
/* lookup existing file that is not a submodule */
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "just_a_file"));
/* lookup non-existent item */
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "no_such_file"));
} }
...@@ -21,15 +21,16 @@ void test_submodule_modify__add(void) ...@@ -21,15 +21,16 @@ void test_submodule_modify__add(void)
const char *s; const char *s;
/* re-add existing submodule */ /* re-add existing submodule */
cl_assert( cl_assert_equal_i(
git_submodule_add_setup(NULL, g_repo, "whatever", "sm_unchanged", 1) == GIT_EEXISTS,
GIT_EEXISTS ); git_submodule_add_setup(NULL, g_repo, "whatever", "sm_unchanged", 1));
/* add a submodule using a gitlink */ /* add a submodule using a gitlink */
cl_git_pass( cl_git_pass(
git_submodule_add_setup(&sm, g_repo, SM_LIBGIT2_URL, SM_LIBGIT2, 1) git_submodule_add_setup(&sm, g_repo, SM_LIBGIT2_URL, SM_LIBGIT2, 1)
); );
git_submodule_free(sm);
cl_assert(git_path_isfile("submod2/" SM_LIBGIT2 "/.git")); cl_assert(git_path_isfile("submod2/" SM_LIBGIT2 "/.git"));
...@@ -48,6 +49,7 @@ void test_submodule_modify__add(void) ...@@ -48,6 +49,7 @@ void test_submodule_modify__add(void)
cl_git_pass( cl_git_pass(
git_submodule_add_setup(&sm, g_repo, SM_LIBGIT2_URL, SM_LIBGIT2B, 0) git_submodule_add_setup(&sm, g_repo, SM_LIBGIT2_URL, SM_LIBGIT2B, 0)
); );
git_submodule_free(sm);
cl_assert(git_path_isdir("submod2/" SM_LIBGIT2B "/.git")); cl_assert(git_path_isdir("submod2/" SM_LIBGIT2B "/.git"));
cl_assert(git_path_isfile("submod2/" SM_LIBGIT2B "/.git/HEAD")); cl_assert(git_path_isfile("submod2/" SM_LIBGIT2B "/.git/HEAD"));
...@@ -95,7 +97,7 @@ void test_submodule_modify__init(void) ...@@ -95,7 +97,7 @@ void test_submodule_modify__init(void)
/* call init and see that settings are copied */ /* call init and see that settings are copied */
cl_git_pass(git_submodule_foreach(g_repo, init_one_submodule, NULL)); cl_git_pass(git_submodule_foreach(g_repo, init_one_submodule, NULL));
git_submodule_reload_all(g_repo); git_submodule_reload_all(g_repo, 1);
/* confirm submodule data in config */ /* confirm submodule data in config */
cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_pass(git_repository_config(&cfg, g_repo));
...@@ -159,6 +161,10 @@ void test_submodule_modify__sync(void) ...@@ -159,6 +161,10 @@ void test_submodule_modify__sync(void)
cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM3".url")); cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM3".url"));
cl_assert_equal_s(git_submodule_url(sm3), str); cl_assert_equal_s(git_submodule_url(sm3), str);
git_config_free(cfg); git_config_free(cfg);
git_submodule_free(sm1);
git_submodule_free(sm2);
git_submodule_free(sm3);
} }
void test_submodule_modify__edit_and_save(void) void test_submodule_modify__edit_and_save(void)
...@@ -231,7 +237,7 @@ void test_submodule_modify__edit_and_save(void) ...@@ -231,7 +237,7 @@ void test_submodule_modify__edit_and_save(void)
cl_assert_equal_i(GIT_SUBMODULE_RECURSE_YES, 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 */ /* call reload and check that the new values are loaded */
cl_git_pass(git_submodule_reload(sm1)); cl_git_pass(git_submodule_reload(sm1, 0));
cl_assert_equal_s(SM_LIBGIT2_URL, git_submodule_url(sm1)); cl_assert_equal_s(SM_LIBGIT2_URL, git_submodule_url(sm1));
cl_assert_equal_i( cl_assert_equal_i(
...@@ -253,16 +259,18 @@ void test_submodule_modify__edit_and_save(void) ...@@ -253,16 +259,18 @@ void test_submodule_modify__edit_and_save(void)
GIT_SUBMODULE_RECURSE_NO, git_submodule_fetch_recurse_submodules(sm2)); GIT_SUBMODULE_RECURSE_NO, git_submodule_fetch_recurse_submodules(sm2));
/* set fetchRecurseSubmodules on-demand */ /* set fetchRecurseSubmodules on-demand */
cl_git_pass(git_submodule_reload(sm1)); cl_git_pass(git_submodule_reload(sm1, 0));
git_submodule_set_fetch_recurse_submodules(sm1, GIT_SUBMODULE_RECURSE_ONDEMAND); git_submodule_set_fetch_recurse_submodules(sm1, GIT_SUBMODULE_RECURSE_ONDEMAND);
cl_assert_equal_i( cl_assert_equal_i(
GIT_SUBMODULE_RECURSE_ONDEMAND, git_submodule_fetch_recurse_submodules(sm1)); GIT_SUBMODULE_RECURSE_ONDEMAND, git_submodule_fetch_recurse_submodules(sm1));
/* call save */ /* call save */
cl_git_pass(git_submodule_save(sm1)); cl_git_pass(git_submodule_save(sm1));
cl_git_pass(git_submodule_reload(sm1)); cl_git_pass(git_submodule_reload(sm1, 0));
cl_assert_equal_i( cl_assert_equal_i(
GIT_SUBMODULE_RECURSE_ONDEMAND, git_submodule_fetch_recurse_submodules(sm1)); GIT_SUBMODULE_RECURSE_ONDEMAND, git_submodule_fetch_recurse_submodules(sm1));
git_submodule_free(sm1);
git_submodule_free(sm2);
git_repository_free(r2); git_repository_free(r2);
git__free(old_url); git__free(old_url);
} }
...@@ -125,3 +125,32 @@ git_repository *setup_fixture_submod2(void) ...@@ -125,3 +125,32 @@ git_repository *setup_fixture_submod2(void)
return repo; return repo;
} }
void assert_submodule_exists(git_repository *repo, const char *name)
{
git_submodule *sm;
cl_git_pass(git_submodule_lookup(&sm, repo, name));
cl_assert(sm);
git_submodule_free(sm);
}
void refute_submodule_exists(
git_repository *repo, const char *name, int expected_error)
{
git_submodule *sm;
cl_assert_equal_i(
expected_error, git_submodule_lookup(&sm, repo, name));
}
unsigned int get_submodule_status(git_repository *repo, const char *name)
{
git_submodule *sm = NULL;
unsigned int status = 0;
cl_git_pass(git_submodule_lookup(&sm, repo, name));
cl_assert(sm);
cl_git_pass(git_submodule_status(&status, sm));
git_submodule_free(sm);
return status;
}
...@@ -3,3 +3,8 @@ extern void rewrite_gitmodules(const char *workdir); ...@@ -3,3 +3,8 @@ extern void rewrite_gitmodules(const char *workdir);
/* these will automatically set a cleanup callback */ /* these will automatically set a cleanup callback */
extern git_repository *setup_fixture_submodules(void); extern git_repository *setup_fixture_submodules(void);
extern git_repository *setup_fixture_submod2(void); extern git_repository *setup_fixture_submod2(void);
extern unsigned int get_submodule_status(git_repository *, const char *);
extern void assert_submodule_exists(git_repository *, const char *);
extern void refute_submodule_exists(git_repository *, const char *, int err);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment