Commit 5f4a61ae by Russell Belfer

Working implementation of git_submodule_status

This is a big redesign of the git_submodule_status API and the
implementation of the redesigned API.  It also fixes a number of
bugs that I found in other parts of the submodule API while
writing the tests for the status part.

This also fixes a couple of bugs in the iterators that had not
been noticed before - one with iterating when there is a gitlink
(i.e. separate-work-dir) and one where I was treating anything
even vaguely submodule-like as a submodule, more aggressively
than core git does.
parent 0c8858de
......@@ -391,6 +391,21 @@ GIT_EXTERN(int) git_diff_print_patch(
void *cb_data,
git_diff_data_fn print_cb);
/**
* Query how many diff records are there in a diff list.
*
* You can optionally pass in a `git_delta_t` value if you want a count
* of just entries that match that delta type, or pass -1 for all delta
* records.
*
* @param diff A git_diff_list generated by one of the above functions
* @param delta_t A git_delta_t value to filter the count, or -1 for all records
* @return Count of number of deltas matching delta_t type
*/
GIT_EXTERN(int) git_diff_entrycount(
git_diff_list *diff,
int delta_t);
/**@}*/
......
......@@ -185,6 +185,8 @@ GIT_EXTERN(int) git_oid_streq(const git_oid *a, const char *str);
/**
* Check is an oid is all zeros.
*
* @return 1 if all zeros, 0 otherwise.
*/
GIT_EXTERN(int) git_oid_iszero(const git_oid *a);
......
......@@ -718,6 +718,25 @@ int git_diff_print_patch(
return error;
}
int git_diff_entrycount(git_diff_list *diff, int delta_t)
{
int count = 0;
unsigned int i;
git_diff_delta *delta;
assert(diff);
if (delta_t < 0)
return diff->deltas.length;
git_vector_foreach(&diff->deltas, i, delta) {
if (delta->status == (git_delta_t)delta_t)
count++;
}
return count;
}
int git_diff_blobs(
git_blob *old_blob,
git_blob *new_blob,
......
......@@ -525,7 +525,9 @@ static int workdir_iterator__advance(
while ((wf = wi->stack) != NULL) {
next = git_vector_get(&wf->entries, ++wf->index);
if (next != NULL) {
if (strcmp(next->path, DOT_GIT "/") == 0)
/* match git's behavior of ignoring anything named ".git" */
if (strcmp(next->path, DOT_GIT "/") == 0 ||
strcmp(next->path, DOT_GIT) == 0)
continue;
/* else found a good entry */
break;
......@@ -607,8 +609,8 @@ static int workdir_iterator__update_entry(workdir_iterator *wi)
wi->entry.path = ps->path;
/* skip over .git directory */
if (strcmp(ps->path, DOT_GIT "/") == 0)
/* skip over .git entry */
if (strcmp(ps->path, DOT_GIT "/") == 0 || strcmp(ps->path, DOT_GIT) == 0)
return workdir_iterator__advance((git_iterator *)wi, NULL);
/* if there is an error processing the entry, treat as ignored */
......@@ -629,15 +631,10 @@ static int workdir_iterator__update_entry(workdir_iterator *wi)
/* detect submodules */
if (S_ISDIR(wi->entry.mode)) {
bool is_submodule = git_path_contains(&wi->path, DOT_GIT);
/* if there is no .git, still check submodules data */
if (!is_submodule) {
int res = git_submodule_lookup(NULL, wi->repo, wi->entry.path);
is_submodule = (res == 0);
if (res == GIT_ENOTFOUND)
giterr_clear();
}
int res = git_submodule_lookup(NULL, wi->repo, wi->entry.path);
bool is_submodule = (res == 0);
if (res == GIT_ENOTFOUND)
giterr_clear();
/* if submodule, mark as GITLINK and remove trailing slash */
if (is_submodule) {
......
......@@ -146,8 +146,13 @@ static int load_workdir(git_repository *repo, git_buf *parent_path)
return -1;
error = git_config_get_string(&worktree, config, "core.worktree");
if (!error && worktree != NULL)
repo->workdir = git__strdup(worktree);
if (!error && worktree != NULL) {
error = git_path_prettify_dir(
&worktree_buf, worktree, repo->path_repository);
if (error < 0)
return error;
repo->workdir = git_buf_detach(&worktree_buf);
}
else if (error != GIT_ENOTFOUND)
return error;
else {
......
......@@ -85,10 +85,18 @@ struct git_submodule {
};
/* Additional flags on top of public GIT_SUBMODULE_STATUS values */
#define GIT_SUBMODULE_STATUS__WD_SCANNED (1u << 15)
#define GIT_SUBMODULE_STATUS__HEAD_OID_VALID (1u << 16)
#define GIT_SUBMODULE_STATUS__INDEX_OID_VALID (1u << 17)
#define GIT_SUBMODULE_STATUS__WD_OID_VALID (1u << 18)
#define GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES (1u << 19)
enum {
GIT_SUBMODULE_STATUS__WD_SCANNED = (1u << 20),
GIT_SUBMODULE_STATUS__HEAD_OID_VALID = (1u << 21),
GIT_SUBMODULE_STATUS__INDEX_OID_VALID = (1u << 22),
GIT_SUBMODULE_STATUS__WD_OID_VALID = (1u << 23),
GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE = (1u << 24),
GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE = (1u << 25),
GIT_SUBMODULE_STATUS__WD_NOT_SUBMODULE = (1u << 26),
GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES = (1u << 27),
};
#define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \
((S) & ~(0xFFFFFFFFu << 20))
#endif
......@@ -50,7 +50,7 @@ void test_status_submodules__0(void)
git_status_foreach(g_repo, cb_status__count, &counts)
);
cl_assert(counts == 6);
cl_assert_equal_i(6, counts);
}
static const char *expected_files[] = {
......@@ -95,12 +95,12 @@ void test_status_submodules__1(void)
git_status_foreach(g_repo, cb_status__match, &index)
);
cl_assert(index == 6);
cl_assert_equal_i(6, index);
}
void test_status_submodules__single_file(void)
{
unsigned int status;
unsigned int status = 0;
cl_git_pass( git_status_file(&status, g_repo, "testrepo") );
cl_assert(status == 0);
cl_assert(!status);
}
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