Commit 0e0108f7 by Edward Thomson Committed by Edward Thomson

introduce git_conflict_iterator

parent 5b3d52ce
...@@ -463,9 +463,9 @@ GIT_EXTERN(int) git_index_conflict_add( ...@@ -463,9 +463,9 @@ GIT_EXTERN(int) git_index_conflict_add(
/** /**
* Get the index entries that represent a conflict of a single file. * Get the index entries that represent a conflict of a single file.
* *
* The values of this entry can be modified (except the paths) * The entries are not modifiable and should not be freed. Because the
* and the changes will be written back to disk on the next * `git_index_entry` struct is a publicly defined struct, you should
* write() call. * be able to make your own permanent copy of the data if necessary.
* *
* @param ancestor_out Pointer to store the ancestor entry * @param ancestor_out Pointer to store the ancestor entry
* @param our_out Pointer to store the our entry * @param our_out Pointer to store the our entry
...@@ -474,9 +474,9 @@ GIT_EXTERN(int) git_index_conflict_add( ...@@ -474,9 +474,9 @@ GIT_EXTERN(int) git_index_conflict_add(
* @param path path to search * @param path path to search
*/ */
GIT_EXTERN(int) git_index_conflict_get( GIT_EXTERN(int) git_index_conflict_get(
git_index_entry **ancestor_out, const git_index_entry **ancestor_out,
git_index_entry **our_out, const git_index_entry **our_out,
git_index_entry **their_out, const git_index_entry **their_out,
git_index *index, git_index *index,
const char *path); const char *path);
...@@ -502,6 +502,40 @@ GIT_EXTERN(void) git_index_conflict_cleanup(git_index *index); ...@@ -502,6 +502,40 @@ GIT_EXTERN(void) git_index_conflict_cleanup(git_index *index);
*/ */
GIT_EXTERN(int) git_index_has_conflicts(const git_index *index); GIT_EXTERN(int) git_index_has_conflicts(const git_index *index);
/**
* Create an iterator for the conflicts in the index. You may not modify the
* index while iterating, the results are undefined.
*
* @return 0 or an error code
*/
GIT_EXTERN(int) git_index_conflict_iterator_new(
git_index_conflict_iterator **iterator_out,
git_index *index);
/**
* Returns the current conflict (ancestor, ours and theirs entry) and
* advance the iterator internally to the next value.
*
* @param ancestor_out Pointer to store the ancestor side of the conflict
* @param our_out Pointer to store our side of the conflict
* @param their_out Pointer to store their side of the conflict
* @return 0 (no error), GIT_ITEROVER (iteration is done) or an error code
* (negative value)
*/
GIT_EXTERN(int) git_index_conflict_next(
const git_index_entry **ancestor_out,
const git_index_entry **our_out,
const git_index_entry **their_out,
git_index_conflict_iterator *iterator);
/**
* Frees a `git_index_conflict_iterator`.
*
* @param it pointer to the iterator
*/
GIT_EXTERN(void) git_index_conflict_iterator_free(
git_index_conflict_iterator *iterator);
/**@}*/ /**@}*/
/** @} */ /** @} */
......
...@@ -131,6 +131,9 @@ typedef struct git_treebuilder git_treebuilder; ...@@ -131,6 +131,9 @@ typedef struct git_treebuilder git_treebuilder;
/** Memory representation of an index file. */ /** Memory representation of an index file. */
typedef struct git_index git_index; typedef struct git_index git_index;
/** An interator for conflicts in the index. */
typedef struct git_index_conflict_iterator git_index_conflict_iterator;
/** Memory representation of a set of config files */ /** Memory representation of a set of config files */
typedef struct git_config git_config; typedef struct git_config git_config;
......
...@@ -739,7 +739,7 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace) ...@@ -739,7 +739,7 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace)
static int index_conflict_to_reuc(git_index *index, const char *path) static int index_conflict_to_reuc(git_index *index, const char *path)
{ {
git_index_entry *conflict_entries[3]; const git_index_entry *conflict_entries[3];
int ancestor_mode, our_mode, their_mode; int ancestor_mode, our_mode, their_mode;
git_oid const *ancestor_oid, *our_oid, *their_oid; git_oid const *ancestor_oid, *our_oid, *their_oid;
int ret; int ret;
...@@ -978,52 +978,80 @@ on_error: ...@@ -978,52 +978,80 @@ on_error:
return ret; return ret;
} }
int git_index_conflict_get(git_index_entry **ancestor_out, static int index_conflict__get_byindex(
git_index_entry **our_out, const git_index_entry **ancestor_out,
git_index_entry **their_out, const git_index_entry **our_out,
git_index *index, const char *path) const git_index_entry **their_out,
git_index *index,
size_t n)
{ {
size_t pos, posmax; const git_index_entry *conflict_entry;
int stage; const char *path = NULL;
git_index_entry *conflict_entry; size_t count;
int error = GIT_ENOTFOUND; int stage, len = 0;
assert(ancestor_out && our_out && their_out && index && path); assert(ancestor_out && our_out && their_out && index);
*ancestor_out = NULL; *ancestor_out = NULL;
*our_out = NULL; *our_out = NULL;
*their_out = NULL; *their_out = NULL;
if (git_index_find(&pos, index, path) < 0) for (count = git_index_entrycount(index); n < count; ++n) {
return GIT_ENOTFOUND; conflict_entry = git_vector_get(&index->entries, n);
for (posmax = git_index_entrycount(index); pos < posmax; ++pos) { if (path && index->entries_cmp_path(conflict_entry->path, path) != 0)
conflict_entry = git_vector_get(&index->entries, pos);
if (index->entries_cmp_path(conflict_entry->path, path) != 0)
break; break;
stage = GIT_IDXENTRY_STAGE(conflict_entry); stage = GIT_IDXENTRY_STAGE(conflict_entry);
path = conflict_entry->path;
switch (stage) { switch (stage) {
case 3: case 3:
*their_out = conflict_entry; *their_out = conflict_entry;
error = 0; len++;
break; break;
case 2: case 2:
*our_out = conflict_entry; *our_out = conflict_entry;
error = 0; len++;
break; break;
case 1: case 1:
*ancestor_out = conflict_entry; *ancestor_out = conflict_entry;
error = 0; len++;
break; break;
default: default:
break; break;
}; };
} }
return error; return len;
}
int git_index_conflict_get(
const git_index_entry **ancestor_out,
const git_index_entry **our_out,
const git_index_entry **their_out,
git_index *index,
const char *path)
{
size_t pos;
int len = 0;
assert(ancestor_out && our_out && their_out && index && path);
*ancestor_out = NULL;
*our_out = NULL;
*their_out = NULL;
if (git_index_find(&pos, index, path) < 0)
return GIT_ENOTFOUND;
if ((len = index_conflict__get_byindex(
ancestor_out, our_out, their_out, index, pos)) < 0)
return len;
else if (len == 0)
return GIT_ENOTFOUND;
return 0;
} }
int git_index_conflict_remove(git_index *index, const char *path) int git_index_conflict_remove(git_index *index, const char *path)
...@@ -1093,6 +1121,68 @@ int git_index_has_conflicts(const git_index *index) ...@@ -1093,6 +1121,68 @@ int git_index_has_conflicts(const git_index *index)
return 0; return 0;
} }
int git_index_conflict_iterator_new(
git_index_conflict_iterator **iterator_out,
git_index *index)
{
git_index_conflict_iterator *it = NULL;
assert(iterator_out && index);
it = git__calloc(1, sizeof(git_index_conflict_iterator));
GITERR_CHECK_ALLOC(it);
it->index = index;
*iterator_out = it;
return 0;
}
int git_index_conflict_next(
const git_index_entry **ancestor_out,
const git_index_entry **our_out,
const git_index_entry **their_out,
git_index_conflict_iterator *iterator)
{
const git_index_entry *entry;
int len;
assert(ancestor_out && our_out && their_out && iterator);
*ancestor_out = NULL;
*our_out = NULL;
*their_out = NULL;
while (iterator->cur < iterator->index->entries.length) {
entry = git_index_get_byindex(iterator->index, iterator->cur);
if (git_index_entry_stage(entry) > 0) {
if ((len = index_conflict__get_byindex(
ancestor_out,
our_out,
their_out,
iterator->index,
iterator->cur)) < 0)
return len;
iterator->cur += len;
return 0;
}
iterator->cur++;
}
return GIT_ITEROVER;
}
void git_index_conflict_iterator_free(git_index_conflict_iterator *iterator)
{
if (iterator == NULL)
return;
git__free(iterator);
}
unsigned int git_index_name_entrycount(git_index *index) unsigned int git_index_name_entrycount(git_index *index)
{ {
assert(index); assert(index);
...@@ -1283,9 +1373,8 @@ static int read_reuc(git_index *index, const char *buffer, size_t size) ...@@ -1283,9 +1373,8 @@ static int read_reuc(git_index *index, const char *buffer, size_t size)
size_t len; size_t len;
int i; int i;
/* If called multiple times, the vector might already be initialized */ /* This gets called multiple times, the vector might already be initialized */
if (index->reuc._alloc_size == 0 && if (index->reuc._alloc_size == 0 && git_vector_init(&index->reuc, 16, reuc_cmp) < 0)
git_vector_init(&index->reuc, 16, reuc_cmp) < 0)
return -1; return -1;
while (size) { while (size) {
...@@ -1295,9 +1384,12 @@ static int read_reuc(git_index *index, const char *buffer, size_t size) ...@@ -1295,9 +1384,12 @@ static int read_reuc(git_index *index, const char *buffer, size_t size)
if (size <= len) if (size <= len)
return index_error_invalid("reading reuc entries"); return index_error_invalid("reading reuc entries");
lost = git__calloc(1, sizeof(git_index_reuc_entry)); lost = git__malloc(sizeof(git_index_reuc_entry));
GITERR_CHECK_ALLOC(lost); GITERR_CHECK_ALLOC(lost);
if (git_vector_insert(&index->reuc, lost) < 0)
return -1;
/* read NUL-terminated pathname for entry */ /* read NUL-terminated pathname for entry */
lost->path = git__strdup(buffer); lost->path = git__strdup(buffer);
GITERR_CHECK_ALLOC(lost->path); GITERR_CHECK_ALLOC(lost->path);
...@@ -1335,10 +1427,6 @@ static int read_reuc(git_index *index, const char *buffer, size_t size) ...@@ -1335,10 +1427,6 @@ static int read_reuc(git_index *index, const char *buffer, size_t size)
size -= 20; size -= 20;
buffer += 20; buffer += 20;
} }
/* entry was read successfully - insert into reuc vector */
if (git_vector_insert(&index->reuc, lost) < 0)
return -1;
} }
/* entries are guaranteed to be sorted on-disk */ /* entries are guaranteed to be sorted on-disk */
......
...@@ -42,6 +42,11 @@ struct git_index { ...@@ -42,6 +42,11 @@ struct git_index {
git_vector_cmp reuc_search; git_vector_cmp reuc_search;
}; };
struct git_index_conflict_iterator {
git_index *index;
size_t cur;
};
extern void git_index_entry__init_from_stat(git_index_entry *entry, struct stat *st); extern void git_index_entry__init_from_stat(git_index_entry *entry, struct stat *st);
extern size_t git_index__prefix_position(git_index *index, const char *path); extern size_t git_index__prefix_position(git_index *index, const char *path);
......
...@@ -65,7 +65,7 @@ void test_index_conflicts__add(void) ...@@ -65,7 +65,7 @@ void test_index_conflicts__add(void)
void test_index_conflicts__add_fixes_incorrect_stage(void) void test_index_conflicts__add_fixes_incorrect_stage(void)
{ {
git_index_entry ancestor_entry, our_entry, their_entry; git_index_entry ancestor_entry, our_entry, their_entry;
git_index_entry *conflict_entry[3]; const git_index_entry *conflict_entry[3];
cl_assert(git_index_entrycount(repo_index) == 8); cl_assert(git_index_entrycount(repo_index) == 8);
...@@ -98,7 +98,7 @@ void test_index_conflicts__add_fixes_incorrect_stage(void) ...@@ -98,7 +98,7 @@ void test_index_conflicts__add_fixes_incorrect_stage(void)
void test_index_conflicts__get(void) void test_index_conflicts__get(void)
{ {
git_index_entry *conflict_entry[3]; const git_index_entry *conflict_entry[3];
git_oid oid; git_oid oid;
cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1],
...@@ -130,6 +130,51 @@ void test_index_conflicts__get(void) ...@@ -130,6 +130,51 @@ void test_index_conflicts__get(void)
cl_assert(git_oid_cmp(&conflict_entry[2]->oid, &oid) == 0); cl_assert(git_oid_cmp(&conflict_entry[2]->oid, &oid) == 0);
} }
void test_index_conflicts__iterate(void)
{
git_index_conflict_iterator *iterator;
const git_index_entry *conflict_entry[3];
git_oid oid;
cl_git_pass(git_index_conflict_iterator_new(&iterator, repo_index));
cl_git_pass(git_index_conflict_next(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], iterator));
git_oid_fromstr(&oid, CONFLICTS_ONE_ANCESTOR_OID);
cl_assert(git_oid_cmp(&conflict_entry[0]->oid, &oid) == 0);
cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0);
git_oid_fromstr(&oid, CONFLICTS_ONE_OUR_OID);
cl_assert(git_oid_cmp(&conflict_entry[1]->oid, &oid) == 0);
cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0);
git_oid_fromstr(&oid, CONFLICTS_ONE_THEIR_OID);
cl_assert(git_oid_cmp(&conflict_entry[2]->oid, &oid) == 0);
cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0);
cl_git_pass(git_index_conflict_next(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], iterator));
git_oid_fromstr(&oid, CONFLICTS_TWO_ANCESTOR_OID);
cl_assert(git_oid_cmp(&conflict_entry[0]->oid, &oid) == 0);
cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0);
git_oid_fromstr(&oid, CONFLICTS_TWO_OUR_OID);
cl_assert(git_oid_cmp(&conflict_entry[1]->oid, &oid) == 0);
cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0);
git_oid_fromstr(&oid, CONFLICTS_TWO_THEIR_OID);
cl_assert(git_oid_cmp(&conflict_entry[2]->oid, &oid) == 0);
cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0);
cl_assert(git_index_conflict_next(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], iterator) == GIT_ITEROVER);
cl_assert(conflict_entry[0] == NULL);
cl_assert(conflict_entry[2] == NULL);
cl_assert(conflict_entry[2] == NULL);
git_index_conflict_iterator_free(iterator);
}
void test_index_conflicts__remove(void) void test_index_conflicts__remove(void)
{ {
const git_index_entry *entry; const git_index_entry *entry;
...@@ -218,7 +263,7 @@ void test_index_conflicts__remove_all_conflicts(void) ...@@ -218,7 +263,7 @@ void test_index_conflicts__remove_all_conflicts(void)
void test_index_conflicts__partial(void) void test_index_conflicts__partial(void)
{ {
git_index_entry ancestor_entry, our_entry, their_entry; git_index_entry ancestor_entry, our_entry, their_entry;
git_index_entry *conflict_entry[3]; const git_index_entry *conflict_entry[3];
cl_assert(git_index_entrycount(repo_index) == 8); cl_assert(git_index_entrycount(repo_index) == 8);
......
...@@ -133,7 +133,7 @@ void test_reset_default__resetting_filepaths_replaces_their_corresponding_index_ ...@@ -133,7 +133,7 @@ void test_reset_default__resetting_filepaths_replaces_their_corresponding_index_
*/ */
void test_reset_default__resetting_filepaths_clears_previous_conflicts(void) void test_reset_default__resetting_filepaths_clears_previous_conflicts(void)
{ {
git_index_entry *conflict_entry[3]; const git_index_entry *conflict_entry[3];
git_strarray after; git_strarray after;
char *paths[] = { "conflicts-one.txt" }; char *paths[] = { "conflicts-one.txt" };
......
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