tree_entry_interesting(): support wildcard matching
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Wed, 15 Dec 2010 15:02:46 +0000 (22:02 +0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 3 Feb 2011 22:08:30 +0000 (14:08 -0800)
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 <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
cache.h
dir.c
t/t4010-diff-pathspec.sh
tree-walk.c
tree-walk.h

diff --git a/cache.h b/cache.h
index 0cf0bac8935029aa93bd10f41c4c07b07eb5f4cf..800efa2328117cf49f482856c49f62ca7b1ebcdd 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -503,11 +503,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 5b4e2b1cb32c9a00d001d4202d8ebb09e30e7103..b6ccaf3703a262416e8c16ae2e72348e170a8d63 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -1197,6 +1197,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,
index 94df7ae53a0ef47c0ef10ca6b3215ffdf38fa399..4b120f8e23f92cd51f64d5a2ed8c3f37d31ec421 100755 (executable)
@@ -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
index be8182c72f90764c77807f6e872a0f333efa3edc..ae7ac1a9f29a074bbd4a03d335510188e1f72452 100644 (file)
@@ -553,12 +553,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)
@@ -578,7 +578,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;
@@ -596,6 +596,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 */
 }
index f81c232b5ad9cbe8cb2489e3c221c32cf06283b1..6589ee27e4047d5c8d1636de72250a864cf42b6b 100644 (file)
@@ -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