Commit a15c7802 by Russell Belfer

Make submodules externally refcounted

`git_submodule` objects were already refcounted internally in case
the submodule name was different from the path at which it was
stored.  This makes that refcounting externally used as well, so
`git_submodule_lookup` and `git_submodule_add_setup` return an
object that requires a `git_submodule_free` when done.
parent f210cb5b
...@@ -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,
...@@ -1510,7 +1514,7 @@ static int checkout_create_submodules( ...@@ -1510,7 +1514,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 +1538,7 @@ static int checkout_create_submodules( ...@@ -1534,7 +1538,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);
......
...@@ -99,27 +99,55 @@ static int submodule_config_key_trunc_puts(git_buf *key, const char *suffix) ...@@ -99,27 +99,55 @@ static int submodule_config_key_trunc_puts(git_buf *key, const char *suffix)
return git_buf_puts(key, 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_strmap *cache,
const char *name,
const char *alternate)
{
khiter_t pos;
/* lock cache */
pos = git_strmap_lookup_index(cache, name);
if (!git_strmap_valid_index(cache, pos) && alternate)
pos = git_strmap_lookup_index(cache, alternate);
if (!git_strmap_valid_index(cache, pos)) {
/* unlock cache */
return GIT_ENOTFOUND; /* don't set error - caller will cope */
}
if (out != NULL) {
git_submodule *sm = git_strmap_value_at(cache, pos);
GIT_REFCOUNT_INC(sm);
*out = sm;
}
/* unlock cache */
return 0;
}
/* /*
* PUBLIC APIS * PUBLIC APIS
*/ */
int git_submodule_lookup( int git_submodule_lookup(
git_submodule **sm_ptr, /* NULL if user only wants to test existence */ git_submodule **out, /* NULL if user only wants to test existence */
git_repository *repo, git_repository *repo,
const char *name) /* trailing slash is allowed */ const char *name) /* trailing slash is allowed */
{ {
int error; int error;
khiter_t pos;
assert(repo && name); assert(repo && name);
if ((error = load_submodule_config(repo)) < 0) if ((error = load_submodule_config(repo)) < 0)
return error; return error;
pos = git_strmap_lookup_index(repo->submodules, name); if ((error = submodule_lookup(out, repo->submodules, name, NULL)) < 0) {
if (!git_strmap_valid_index(repo->submodules, pos)) {
error = GIT_ENOTFOUND;
/* check if a plausible submodule exists at path */ /* check if a plausible submodule exists at path */
if (git_repository_workdir(repo)) { if (git_repository_workdir(repo)) {
...@@ -137,14 +165,9 @@ int git_submodule_lookup( ...@@ -137,14 +165,9 @@ int git_submodule_lookup(
giterr_set(GITERR_SUBMODULE, (error == GIT_ENOTFOUND) ? giterr_set(GITERR_SUBMODULE, (error == GIT_ENOTFOUND) ?
"No submodule named '%s'" : "No submodule named '%s'" :
"Submodule '%s' has not been added yet", name); "Submodule '%s' has not been added yet", name);
return error;
} }
if (sm_ptr) return error;
*sm_ptr = git_strmap_value_at(repo->submodules, pos);
return 0;
} }
int git_submodule_foreach( int git_submodule_foreach(
...@@ -203,7 +226,7 @@ void git_submodule_config_free(git_repository *repo) ...@@ -203,7 +226,7 @@ void git_submodule_config_free(git_repository *repo)
} }
int git_submodule_add_setup( 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,
...@@ -211,7 +234,7 @@ int git_submodule_add_setup( ...@@ -211,7 +234,7 @@ int git_submodule_add_setup(
{ {
int error = 0; int error = 0;
git_config_backend *mods = NULL; git_config_backend *mods = NULL;
git_submodule *sm; git_submodule *sm = NULL;
git_buf name = GIT_BUF_INIT, real_url = GIT_BUF_INIT; git_buf name = GIT_BUF_INIT, real_url = GIT_BUF_INIT;
git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT; git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
git_repository *subrepo = NULL; git_repository *subrepo = NULL;
...@@ -223,6 +246,7 @@ int git_submodule_add_setup( ...@@ -223,6 +246,7 @@ int git_submodule_add_setup(
if (git_submodule_lookup(&sm, repo, path) < 0) if (git_submodule_lookup(&sm, repo, path) < 0)
giterr_clear(); giterr_clear();
else { else {
git_submodule_free(sm);
giterr_set(GITERR_SUBMODULE, giterr_set(GITERR_SUBMODULE,
"Attempt to add a submodule that already exists"); "Attempt to add a submodule that already exists");
return GIT_EEXISTS; return GIT_EEXISTS;
...@@ -307,12 +331,16 @@ int git_submodule_add_setup( ...@@ -307,12 +331,16 @@ int git_submodule_add_setup(
/* add submodule to hash and "reload" it */ /* add submodule to hash and "reload" it */
if (!(error = submodule_get(&sm, repo, path, NULL)) && if (!(error = submodule_get(&sm, repo, path, NULL)) &&
!(error = git_submodule_reload(sm))) !(error = git_submodule_reload(sm, false)))
error = git_submodule_init(sm, false); error = git_submodule_init(sm, false);
cleanup: cleanup:
if (submodule != NULL) if (error && sm) {
*submodule = !error ? sm : NULL; git_submodule_free(sm);
sm = NULL;
}
if (out != NULL)
*out = sm;
if (mods != NULL) if (mods != NULL)
git_config_file_free(mods); git_config_file_free(mods);
...@@ -775,8 +803,9 @@ int git_submodule_open(git_repository **subrepo, git_submodule *sm) ...@@ -775,8 +803,9 @@ int git_submodule_open(git_repository **subrepo, git_submodule *sm)
return git_submodule__open(subrepo, sm, false); return git_submodule__open(subrepo, sm, false);
} }
int git_submodule_reload_all(git_repository *repo) int git_submodule_reload_all(git_repository *repo, int force)
{ {
GIT_UNUSED(force);
assert(repo); assert(repo);
git_submodule_config_free(repo); git_submodule_config_free(repo);
return load_submodule_config(repo); return load_submodule_config(repo);
...@@ -855,11 +884,13 @@ static int submodule_update_head(git_submodule *submodule) ...@@ -855,11 +884,13 @@ static int submodule_update_head(git_submodule *submodule)
return 0; return 0;
} }
int git_submodule_reload(git_submodule *submodule) int git_submodule_reload(git_submodule *submodule, int force)
{ {
int error = 0; int error = 0;
git_config_backend *mods; git_config_backend *mods;
GIT_UNUSED(force);
assert(submodule); assert(submodule);
/* refresh index data */ /* refresh index data */
...@@ -1042,17 +1073,15 @@ void git_submodule_free(git_submodule *sm) ...@@ -1042,17 +1073,15 @@ void git_submodule_free(git_submodule *sm)
} }
static int submodule_get( static int submodule_get(
git_submodule **sm_ptr, git_submodule **out,
git_repository *repo, git_repository *repo,
const char *name, const char *name,
const char *alternate) const char *alternate)
{ {
int error = 0;
git_strmap *smcfg = repo->submodules; git_strmap *smcfg = repo->submodules;
khiter_t pos; khiter_t pos;
git_submodule *sm; git_submodule *sm;
int error;
assert(repo && name);
pos = git_strmap_lookup_index(smcfg, name); pos = git_strmap_lookup_index(smcfg, name);
...@@ -1068,22 +1097,28 @@ static int submodule_get( ...@@ -1068,22 +1097,28 @@ static int submodule_get(
*/ */
pos = kh_put(str, smcfg, sm->name, &error); pos = kh_put(str, smcfg, sm->name, &error);
if (error < 0) { if (error < 0)
git_submodule_free(sm); goto done;
sm = NULL; else if (error == 0) {
} else if (error == 0) {
git_submodule_free(sm); git_submodule_free(sm);
sm = git_strmap_value_at(smcfg, pos); sm = git_strmap_value_at(smcfg, pos);
} else { } else {
error = 0;
git_strmap_set_value_at(smcfg, pos, sm); git_strmap_set_value_at(smcfg, pos, sm);
} }
} else { } else {
sm = git_strmap_value_at(smcfg, pos); sm = git_strmap_value_at(smcfg, pos);
} }
*sm_ptr = sm; done:
if (error < 0)
git_submodule_free(sm);
else if (out) {
GIT_REFCOUNT_INC(sm);
*out = sm;
}
return (sm != NULL) ? 0 : -1; return error;
} }
static int submodule_config_error(const char *property, const char *value) static int submodule_config_error(const char *property, const char *value)
...@@ -1143,7 +1178,7 @@ static int submodule_load_from_config( ...@@ -1143,7 +1178,7 @@ static int submodule_load_from_config(
const char *namestart, *property, *alternate = NULL; const char *namestart, *property, *alternate = NULL;
const char *key = entry->name, *value = entry->value, *path; const char *key = entry->name, *value = entry->value, *path;
git_buf name = GIT_BUF_INIT; git_buf name = GIT_BUF_INIT;
git_submodule *sm; git_submodule *sm = NULL;
int error = 0; int error = 0;
if (git__prefixcmp(key, "submodule.") != 0) if (git__prefixcmp(key, "submodule.") != 0)
...@@ -1242,6 +1277,7 @@ static int submodule_load_from_config( ...@@ -1242,6 +1277,7 @@ static int submodule_load_from_config(
/* ignore other unknown submodule properties */ /* ignore other unknown submodule properties */
done: done:
git_submodule_free(sm); /* offset refcount inc from submodule_get() */
git_buf_free(&name); git_buf_free(&name);
return error; return error;
} }
...@@ -1293,8 +1329,10 @@ static int load_submodule_config_from_index( ...@@ -1293,8 +1329,10 @@ static int load_submodule_config_from_index(
else else
sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE; sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
} else if (S_ISGITLINK(entry->mode)) { } else if (S_ISGITLINK(entry->mode)) {
if (!submodule_get(&sm, repo, entry->path, NULL)) if (!submodule_get(&sm, repo, entry->path, NULL)) {
submodule_update_from_index_entry(sm, entry); submodule_update_from_index_entry(sm, entry);
git_submodule_free(sm);
}
} else if (strcmp(entry->path, GIT_MODULES_FILE) == 0) } else if (strcmp(entry->path, GIT_MODULES_FILE) == 0)
git_oid_cpy(gitmodules_oid, &entry->id); git_oid_cpy(gitmodules_oid, &entry->id);
} }
...@@ -1339,9 +1377,11 @@ static int load_submodule_config_from_head( ...@@ -1339,9 +1377,11 @@ static int load_submodule_config_from_head(
else else
sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE; sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
} else if (S_ISGITLINK(entry->mode)) { } else if (S_ISGITLINK(entry->mode)) {
if (!submodule_get(&sm, repo, entry->path, NULL)) if (!submodule_get(&sm, repo, entry->path, NULL)) {
submodule_update_from_head_data( submodule_update_from_head_data(
sm, entry->mode, &entry->id); sm, entry->mode, &entry->id);
git_submodule_free(sm);
}
} else if (strcmp(entry->path, GIT_MODULES_FILE) == 0 && } else if (strcmp(entry->path, GIT_MODULES_FILE) == 0 &&
git_oid_iszero(gitmodules_oid)) { git_oid_iszero(gitmodules_oid)) {
git_oid_cpy(gitmodules_oid, &entry->id); git_oid_cpy(gitmodules_oid, &entry->id);
......
...@@ -128,9 +128,6 @@ extern int git_submodule_open_bare( ...@@ -128,9 +128,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(
......
...@@ -123,7 +123,7 @@ void test_diff_submodules__dirty_submodule_2(void) ...@@ -123,7 +123,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 |
...@@ -157,7 +157,7 @@ void test_diff_submodules__dirty_submodule_2(void) ...@@ -157,7 +157,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);
...@@ -281,7 +281,9 @@ void test_diff_submodules__invalid_cache(void) ...@@ -281,7 +281,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));
...@@ -334,6 +336,8 @@ void test_diff_submodules__invalid_cache(void) ...@@ -334,6 +336,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