Subject: [PATCH 11/21] tree_entry_interesting(): support wildcard matching

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Wed, 15 Dec 2010 22:02:46 +0700

never_interesting optimization is disabled if there is any wildcard
pathspec, even if it only matches exactly on trees.

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 cache.h                  |    2 ++
 dir.c                    |    3 +++
 t/t4010-diff-pathspec.sh |   14 ++++++++++++++
 tree-walk.c              |   30 +++++++++++++++++++++++++++---
 tree-walk.h              |    2 +-
 5 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/cache.h b/cache.h
index b110775..dc0bfb4 100644
--- a/cache.h
+++ b/cache.h
@@ -496,11 +496,13 @@ extern int ie_modified(const struct index_state *, struct cache_entry *, struct
 struct pathspec {
 	const char **raw; /* get_pathspec() result, not freed by free_pathspec() */
 	int nr;
+	int has_wildcard:1;
 	int recursive:1;
 	int max_depth;
 	struct pathspec_item {
 		const char *match;
 		int len;
+		int has_wildcard:1;
 	} *items;
 };
 
diff --git a/dir.c b/dir.c
index aa0522d..66c163f 100644
--- a/dir.c
+++ b/dir.c
@@ -1117,6 +1117,9 @@ int init_pathspec(struct pathspec *pathspec, const char **paths)
 
 		item->match = path;
 		item->len = strlen(path);
+		item->has_wildcard = !no_wildcard(path);
+		if (item->has_wildcard)
+			pathspec->has_wildcard = 1;
 	}
 
 	qsort(pathspec->items, pathspec->nr,
diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh
index 94df7ae..4b120f8 100755
--- a/t/t4010-diff-pathspec.sh
+++ b/t/t4010-diff-pathspec.sh
@@ -70,4 +70,18 @@ test_expect_success 'diff-tree pathspec' '
 	test_cmp expected current
 '
 
+EMPTY_TREE=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+
+test_expect_success 'diff-tree with wildcard shows dir also matches' '
+	git diff-tree --name-only $EMPTY_TREE $tree -- "f*" >result &&
+	echo file0 >expected &&
+	test_cmp expected result
+'
+
+test_expect_success 'diff-tree -r with wildcard' '
+	git diff-tree -r --name-only $EMPTY_TREE $tree -- "*file1" >result &&
+	echo path1/file1 >expected &&
+	test_cmp expected result
+'
+
 test_done
diff --git a/tree-walk.c b/tree-walk.c
index 93b05a7..cc5a4e1 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -551,12 +551,12 @@ static int match_dir_prefix(const char *base, int baselen,
  *  - negative for "no, and no subsequent entries will be either"
  */
 int tree_entry_interesting(const struct name_entry *entry,
-			   const struct strbuf *base,
+			   struct strbuf *base,
 			   const struct pathspec *ps)
 {
 	int i;
 	int pathlen, baselen = base->len;
-	int never_interesting = -1;
+	int never_interesting = ps->has_wildcard ? 0 : -1;
 
 	if (!ps->nr) {
 		if (!ps->recursive || ps->max_depth == -1)
@@ -576,7 +576,7 @@ int tree_entry_interesting(const struct name_entry *entry,
 		if (baselen >= matchlen) {
 			/* If it doesn't match, move along... */
 			if (!match_dir_prefix(base->buf, baselen, match, matchlen))
-				continue;
+				goto match_wildcards;
 
 			if (!ps->recursive || ps->max_depth == -1)
 				return 2;
@@ -594,6 +594,30 @@ int tree_entry_interesting(const struct name_entry *entry,
 					&never_interesting))
 				return 1;
 		}
+
+match_wildcards:
+		if (!ps->items[i].has_wildcard)
+			continue;
+
+		/*
+		 * Concatenate base and entry->path into one and do
+		 * fnmatch() on it.
+		 */
+
+		strbuf_add(base, entry->path, pathlen);
+
+		if (!fnmatch(match, base->buf, 0)) {
+			strbuf_setlen(base, baselen);
+			return 1;
+		}
+		strbuf_setlen(base, baselen);
+
+		/*
+		 * Match all directories. We'll try to match files
+		 * later on.
+		 */
+		if (ps->recursive && S_ISDIR(entry->mode))
+			return 1;
 	}
 	return never_interesting; /* No matches */
 }
diff --git a/tree-walk.h b/tree-walk.h
index f81c232..6589ee2 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -60,6 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru
 	return info->pathlen + tree_entry_len(n->path, n->sha1);
 }
 
-extern int tree_entry_interesting(const struct name_entry *, const struct strbuf *, const struct pathspec *ps);
+extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, const struct pathspec *ps);
 
 #endif
-- 
1.7.3.3.476.g10a82