Commit 6c9352bf30e97af5d646d92ceab1c7b0f4c7a1c4

Edward Thomson 2015-08-28T18:30:39

iterator: sort subdirs properly with pathlist When given a pathlist, don't assume that directories sort before files. Walk through any list of entries sorting before us to make sure that we've exhausted all entries that *aren't* directories. Eg, if we're searching for 'foo/bar', and we have a 'foo.c', keep advancing the pathlist to keep looking for an entry prefixed with 'foo/'.

diff --git a/src/iterator.c b/src/iterator.c
index 28629c7..9fa7cab 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -1071,13 +1071,22 @@ static dirload_pathlist_match_t dirload_pathlist_match(
 			&idx, pathlist, pathlist->_cmp, path) != GIT_ENOTFOUND)
 		return DIRLOAD_PATHLIST_EXACT;
 
-	/* the explicit path we searched for was not found, but this may be
-	 * a directory and the pathlist contains a file in it.  check.
+	/* the explicit path that we've seen in the directory iterator was
+	 * not found - however, we may have hit a subdirectory in the directory
+	 * iterator.  examine the pathlist to see if it contains children of the
+	 * current path.  if so, indicate that we've found a subdirectory that
+	 * is worth examining.
 	 */
-	if ((matched = git_vector_get(pathlist, idx)) != NULL &&
-		prefixcomp(matched, path) == 0 &&
-		matched[path_len] == '/')
-		return DIRLOAD_PATHLIST_DIRECTORY;
+	while ((matched = git_vector_get(pathlist, idx)) != NULL &&
+		prefixcomp(matched, path) == 0) {
+
+		if (matched[path_len] == '/')
+			return DIRLOAD_PATHLIST_DIRECTORY;
+		else if (matched[path_len] > '/')
+			break;
+
+		idx++;
+	}
 
 	return DIRLOAD_PATHLIST_NONE;
 }
diff --git a/tests/repo/iterator.c b/tests/repo/iterator.c
index 8af7bc5..84dfbe1 100644
--- a/tests/repo/iterator.c
+++ b/tests/repo/iterator.c
@@ -26,7 +26,7 @@ static void expect_iterator_items(
 	const git_index_entry *entry;
 	int count, error;
 	int no_trees = !(git_iterator_flags(i) & GIT_ITERATOR_INCLUDE_TREES);
-	bool v = false;
+	bool v = true;
 
 	if (expected_flat < 0) { v = true; expected_flat = -expected_flat; }
 	if (expected_total < 0) { v = true; expected_total = -expected_total; }
@@ -1236,8 +1236,11 @@ void test_repo_iterator__workdirfilelist(void)
 	cl_git_pass(git_vector_insert(&filelist, "c"));
 	cl_git_pass(git_vector_insert(&filelist, "D"));
 	cl_git_pass(git_vector_insert(&filelist, "e"));
+	cl_git_pass(git_vector_insert(&filelist, "k.a"));
+	cl_git_pass(git_vector_insert(&filelist, "k.b"));
 	cl_git_pass(git_vector_insert(&filelist, "k/1"));
 	cl_git_pass(git_vector_insert(&filelist, "k/a"));
+	cl_git_pass(git_vector_insert(&filelist, "kZZZZZZZ"));
 	cl_git_pass(git_vector_insert(&filelist, "L/1"));
 
 	g_repo = cl_git_sandbox_init("icase");
@@ -1284,8 +1287,11 @@ void test_repo_iterator__workdirfilelist_icase(void)
 	cl_git_pass(git_vector_insert(&filelist, "c"));
 	cl_git_pass(git_vector_insert(&filelist, "D"));
 	cl_git_pass(git_vector_insert(&filelist, "e"));
+	cl_git_pass(git_vector_insert(&filelist, "k.a"));
+	cl_git_pass(git_vector_insert(&filelist, "k.b"));
 	cl_git_pass(git_vector_insert(&filelist, "k/1"));
 	cl_git_pass(git_vector_insert(&filelist, "k/a"));
+	cl_git_pass(git_vector_insert(&filelist, "kZZZZ"));
 	cl_git_pass(git_vector_insert(&filelist, "L/1"));
 
 	g_repo = cl_git_sandbox_init("icase");