Commit 6edb427b7615207142e10a228164d6a019045126

Nico von Geyso 2013-03-06T16:43:21

basic note iterator implementation * git_note_iterator_new() - create a new note iterator * git_note_next() - retrieves the next item of the iterator

diff --git a/include/git2/notes.h b/include/git2/notes.h
index c51d373..466f0a8 100644
--- a/include/git2/notes.h
+++ b/include/git2/notes.h
@@ -30,6 +30,45 @@ typedef int (*git_note_foreach_cb)(
 	const git_oid *blob_id, const git_oid *annotated_object_id, void *payload);
 
 /**
+ * note iterator
+ */
+typedef struct git_iterator git_iterator;
+
+/**
+ * Creates a new iterator for notes
+ *
+ * The iterator must be freed manually by the user.
+ *
+ * @param out pointer to the iterator
+ * @param repo repository where to look up the note
+ * @param notes_ref canonical name of the reference to use (optional); defaults to
+ *                  "refs/notes/commits"
+ *
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_note_iterator_new(
+	git_iterator **out,
+	git_repository *repo,
+	const char *notes_ref);
+
+/**
+ * Next iteration step for note iteration
+ *
+ * The notes must not be freed manually by the user.
+ *
+ * @param it pointer to the iterator
+ * @param note_id id of blob containing the message
+ * @param annotated_id id of the git object being annotated
+ *
+ * @return 0, GIT_ITEROVER or an error code
+ */
+GIT_EXTERN(int) git_note_next(
+	git_oid* note_id,
+	git_oid* annotated_id,
+	git_iterator *it);
+
+
+/**
  * Read the note for an object
  *
  * The note must be freed manually by the user.
diff --git a/src/notes.c b/src/notes.c
index f5537db..d7462d0 100644
--- a/src/notes.c
+++ b/src/notes.c
@@ -531,14 +531,12 @@ void git_note_free(git_note *note)
 
 static int process_entry_path(
 	const char* entry_path,
-	const git_oid *note_oid,
-	git_note_foreach_cb note_cb,
-	void *payload)
+	git_oid *annotated_object_id
+)
 {
 	int error = -1;
 	size_t i = 0, j = 0, len;
 	git_buf buf = GIT_BUF_INIT;
-	git_oid annotated_object_id;
 
 	if ((error = git_buf_puts(&buf, entry_path)) < 0)
 		goto cleanup;
@@ -571,12 +569,9 @@ static int process_entry_path(
 		goto cleanup;
 	}
 
-	if ((error = git_oid_fromstr(&annotated_object_id, buf.ptr)) < 0)
+	if ((error = git_oid_fromstr(annotated_object_id, buf.ptr)) < 0)
 		goto cleanup;
 
-	if (note_cb(note_oid, &annotated_object_id, payload))
-		error = GIT_EUSER;
-
 cleanup:
 	git_buf_free(&buf);
 	return error;
@@ -592,6 +587,7 @@ int git_note_foreach(
 	git_iterator *iter = NULL;
 	git_tree *tree = NULL;
 	git_commit *commit = NULL;
+	git_oid annotated_object_id;
 	const git_index_entry *item;
 
 	if (!(error = retrieve_note_tree_and_commit(
@@ -600,7 +596,10 @@ int git_note_foreach(
 		error = git_iterator_current(iter, &item);
 
 	while (!error && item) {
-		error = process_entry_path(item->path, &item->oid, note_cb, payload);
+		error = process_entry_path(item->path, &annotated_object_id);
+
+		if (note_cb(&item->oid, &annotated_object_id, payload))
+			error = GIT_EUSER;
 
 		if (!error)
 			error = git_iterator_advance(iter, &item);
@@ -612,3 +611,54 @@ int git_note_foreach(
 
 	return error;
 }
+
+int git_note_iterator_new(
+	git_iterator **it,
+	git_repository *repo,
+	const char *notes_ref
+)
+{
+	int error;
+	git_commit *commit = NULL;
+	git_tree *tree = NULL;
+
+	error = retrieve_note_tree_and_commit(&tree, &commit, repo, &notes_ref);
+	if (!error) {
+		*it = (git_iterator *)git__malloc(sizeof(git_iterator));
+		GITERR_CHECK_ALLOC(*it);
+
+		error = git_iterator_for_tree(it, tree);
+		if (error)
+			git_iterator_free(*it);
+	}
+
+	git_tree_free(tree);
+	git_commit_free(commit);
+
+	return error;
+}
+
+int git_note_next(
+	git_oid* note_id,
+	git_oid* annotated_id,
+	git_iterator *it
+)
+{
+	int error;
+	const git_index_entry *item;
+
+	error = git_iterator_current(it, &item);
+	if (!error && item) {
+		git_oid_cpy(note_id, &item->oid);
+
+		error = process_entry_path(item->path, annotated_id);
+
+		if (!error)
+			error = git_iterator_advance(it, NULL);
+	}
+
+	if (!error && !item)
+		error = GIT_ITEROVER;
+
+	return error;
+}
diff --git a/src/notes.h b/src/notes.h
index 2f119e3..70d5e13 100644
--- a/src/notes.h
+++ b/src/notes.h
@@ -10,6 +10,9 @@
 #include "common.h"
 
 #include "git2/oid.h"
+#include "git2/types.h"
+
+#include "iterator.h"
 
 #define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
 
diff --git a/tests-clar/notes/notes.c b/tests-clar/notes/notes.c
index ee0b6c2..ea81067 100644
--- a/tests-clar/notes/notes.c
+++ b/tests-clar/notes/notes.c
@@ -40,7 +40,9 @@ static void create_note(git_oid *note_oid, const char *canonical_namespace, cons
 static struct {
 	const char *note_sha;
 	const char *annotated_object_sha;
-} list_expectations[] = {
+}
+
+list_expectations[] = {
 	{ "1c73b1f51762155d357bcd1fd4f2c409ef80065b", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045" },
 	{ "1c73b1f51762155d357bcd1fd4f2c409ef80065b", "9fd738e8f7967c078dceed8190330fc8648ee56a" },
 	{ "257b43746b6b46caa4aa788376c647cce0a33e2b", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750" },
@@ -317,3 +319,66 @@ void test_notes_notes__removing_a_note_which_doesnt_exists_returns_ENOTFOUND(voi
 	cl_git_fail(error);
 	cl_assert_equal_i(GIT_ENOTFOUND, error);
 }
+
+void test_notes_notes__can_iterate_default_namespace(void)
+{
+	git_iterator *iter;
+	git_note *note;
+	git_oid note_id, annotated_id;
+	git_oid note_created[2];
+	const char* note_message[] = {
+		"I decorate a65f\n",
+		"I decorate c478\n"
+	};
+	int i;
+
+	create_note(&note_created[0], "refs/notes/commits",
+		"a65fedf39aefe402d3bb6e24df4d4f5fe4547750", note_message[0]);
+	create_note(&note_created[1], "refs/notes/commits",
+		"c47800c7266a2be04c571c04d5a6614691ea99bd", note_message[1]);
+
+	cl_git_pass(git_note_iterator_new(&iter, _repo, NULL));
+
+	for (i = 0; git_note_next(&note_id, &annotated_id, iter) != GIT_ITEROVER; ++i)
+	{
+		cl_git_pass(git_note_read(&note, _repo, NULL, &annotated_id));
+		cl_assert_equal_s(git_note_message(note), note_message[i]);
+	}
+
+	cl_assert(i == 2);
+}
+
+void test_notes_notes__can_iterate_custom_namespace(void)
+{
+	git_iterator *iter;
+	git_note *note;
+	git_oid note_id, annotated_id;
+	git_oid note_created[2];
+	const char* note_message[] = {
+		"I decorate a65f\n",
+		"I decorate c478\n"
+	};
+	int i;
+
+	create_note(&note_created[0], "refs/notes/beer",
+		"a65fedf39aefe402d3bb6e24df4d4f5fe4547750", note_message[0]);
+	create_note(&note_created[1], "refs/notes/beer",
+		"c47800c7266a2be04c571c04d5a6614691ea99bd", note_message[1]);
+
+	cl_git_pass(git_note_iterator_new(&iter, _repo, "refs/notes/beer"));
+
+	for (i = 0; git_note_next(&note_id, &annotated_id, iter) != GIT_ITEROVER; ++i)
+	{
+		cl_git_pass(git_note_read(&note, _repo, "refs/notes/beer", &annotated_id));
+		cl_assert_equal_s(git_note_message(note), note_message[i]);
+	}
+
+	cl_assert(i == 2);
+}
+
+void test_notes_notes__empty_iterate(void)
+{
+	git_iterator *iter;
+
+	cl_git_fail(git_note_iterator_new(&iter, _repo, "refs/notes/commits"));
+}