Commit c097f7173daced0f86fd816a72ad5fc0f636484a

Leo Yang 2015-08-17T15:02:02

New API: git_index_find_prefix Find the first index entry matching a prefix.

diff --git a/include/git2/index.h b/include/git2/index.h
index 7caf3ed..176ba30 100644
--- a/include/git2/index.h
+++ b/include/git2/index.h
@@ -643,6 +643,17 @@ GIT_EXTERN(int) git_index_update_all(
  */
 GIT_EXTERN(int) git_index_find(size_t *at_pos, git_index *index, const char *path);
 
+/**
+ * Find the first position of any entries matching a prefix. To find the first position
+ * of a path inside a given folder, suffix the prefix with a '/'.
+ *
+ * @param at_pos the address to which the position of the index entry is written (optional)
+ * @param index an existing index object
+ * @param prefix the prefix to search for
+ * @return 0 with valid value in at_pos; an error code otherwise
+ */
+GIT_EXTERN(int) git_index_find_prefix(size_t *at_pos, git_index *index, const char *prefix);
+
 /**@}*/
 
 /** @name Conflict Index Entry Functions
diff --git a/src/index.c b/src/index.c
index 53120e4..e32320f 100644
--- a/src/index.c
+++ b/src/index.c
@@ -1420,6 +1420,30 @@ int git_index_remove_directory(git_index *index, const char *dir, int stage)
 	return error;
 }
 
+int git_index_find_prefix(size_t *at_pos, git_index *index, const char *prefix)
+{
+	int error = 0;
+	size_t pos;
+	const git_index_entry *entry;
+
+	if (git_mutex_lock(&index->lock) < 0) {
+		giterr_set(GITERR_OS, "Failed to lock index");
+		return -1;
+	}
+
+	index_find(&pos, index, prefix, strlen(prefix), GIT_INDEX_STAGE_ANY, false);
+	entry = git_vector_get(&index->entries, pos);
+	if (!entry || git__prefixcmp(entry->path, prefix) != 0)
+		error = GIT_ENOTFOUND;
+
+	if (!error && at_pos)
+		*at_pos = pos;
+
+	git_mutex_unlock(&index->lock);
+
+	return error;
+}
+
 int git_index__find_pos(
 	size_t *out, git_index *index, const char *path, size_t path_len, int stage)
 {
diff --git a/tests/index/tests.c b/tests/index/tests.c
index e1ff12a..60c2126 100644
--- a/tests/index/tests.c
+++ b/tests/index/tests.c
@@ -155,6 +155,27 @@ void test_index_tests__find_in_empty(void)
    git_index_free(index);
 }
 
+void test_index_tests__find_prefix(void)
+{
+   git_index *index;
+   const git_index_entry *entry;
+   size_t pos;
+
+   cl_git_pass(git_index_open(&index, TEST_INDEX_PATH));
+
+   cl_git_pass(git_index_find_prefix(&pos, index, "src"));
+   entry = git_index_get_byindex(index, pos);
+   cl_assert(git__strcmp(entry->path, "src/block-sha1/sha1.c") == 0);
+
+   cl_git_pass(git_index_find_prefix(&pos, index, "src/co"));
+   entry = git_index_get_byindex(index, pos);
+   cl_assert(git__strcmp(entry->path, "src/commit.c") == 0);
+
+   cl_assert(GIT_ENOTFOUND == git_index_find_prefix(NULL, index, "blah"));
+
+   git_index_free(index);
+}
+
 void test_index_tests__write(void)
 {
    git_index *index;