diff options
| author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2013-12-06 14:30:48 +0700 | 
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2013-12-06 13:00:39 -0800 | 
| commit | ef79b1f8704668a6cdf4278f9255e03ca785bfb4 (patch) | |
| tree | f74ee3986aee50992cab9fcf16fcac3e55abe551 /tree-walk.c | |
| parent | 8b7cb51a9dda0debf48c62ae79b9d60a23507097 (diff) | |
| download | git-ef79b1f8704668a6cdf4278f9255e03ca785bfb4.tar.gz | |
Support pathspec magic :(exclude) and its short form :!
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'tree-walk.c')
| -rw-r--r-- | tree-walk.c | 83 | 
1 files changed, 79 insertions, 4 deletions
diff --git a/tree-walk.c b/tree-walk.c index 5ece8c3477..680afda060 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -662,9 +662,10 @@ static int match_wildcard_base(const struct pathspec_item *item,   * Pre-condition: either baselen == base_offset (i.e. empty path)   * or base[baselen-1] == '/' (i.e. with trailing slash).   */ -enum interesting tree_entry_interesting(const struct name_entry *entry, -					struct strbuf *base, int base_offset, -					const struct pathspec *ps) +static enum interesting do_match(const struct name_entry *entry, +				 struct strbuf *base, int base_offset, +				 const struct pathspec *ps, +				 int exclude)  {  	int i;  	int pathlen, baselen = base->len - base_offset; @@ -676,7 +677,8 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,  		       PATHSPEC_MAXDEPTH |  		       PATHSPEC_LITERAL |  		       PATHSPEC_GLOB | -		       PATHSPEC_ICASE); +		       PATHSPEC_ICASE | +		       PATHSPEC_EXCLUDE);  	if (!ps->nr) {  		if (!ps->recursive || @@ -697,6 +699,10 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,  		const char *base_str = base->buf + base_offset;  		int matchlen = item->len, matched = 0; +		if ((!exclude &&   item->magic & PATHSPEC_EXCLUDE) || +		    ( exclude && !(item->magic & PATHSPEC_EXCLUDE))) +			continue; +  		if (baselen >= matchlen) {  			/* If it doesn't match, move along... */  			if (!match_dir_prefix(item, base_str, match, matchlen)) @@ -782,3 +788,72 @@ match_wildcards:  	}  	return never_interesting; /* No matches */  } + +/* + * Is a tree entry interesting given the pathspec we have? + * + * Pre-condition: either baselen == base_offset (i.e. empty path) + * or base[baselen-1] == '/' (i.e. with trailing slash). + */ +enum interesting tree_entry_interesting(const struct name_entry *entry, +					struct strbuf *base, int base_offset, +					const struct pathspec *ps) +{ +	enum interesting positive, negative; +	positive = do_match(entry, base, base_offset, ps, 0); + +	/* +	 * case | entry | positive | negative | result +	 * -----+-------+----------+----------+------- +	 *   1  |  file |   -1     |  -1..2   |  -1 +	 *   2  |  file |    0     |  -1..2   |   0 +	 *   3  |  file |    1     |   -1     |   1 +	 *   4  |  file |    1     |    0     |   1 +	 *   5  |  file |    1     |    1     |   0 +	 *   6  |  file |    1     |    2     |   0 +	 *   7  |  file |    2     |   -1     |   2 +	 *   8  |  file |    2     |    0     |   2 +	 *   9  |  file |    2     |    1     |   0 +	 *  10  |  file |    2     |    2     |  -1 +	 * -----+-------+----------+----------+------- +	 *  11  |  dir  |   -1     |  -1..2   |  -1 +	 *  12  |  dir  |    0     |  -1..2   |   0 +	 *  13  |  dir  |    1     |   -1     |   1 +	 *  14  |  dir  |    1     |    0     |   1 +	 *  15  |  dir  |    1     |    1     |   1 (*) +	 *  16  |  dir  |    1     |    2     |   0 +	 *  17  |  dir  |    2     |   -1     |   2 +	 *  18  |  dir  |    2     |    0     |   2 +	 *  19  |  dir  |    2     |    1     |   1 (*) +	 *  20  |  dir  |    2     |    2     |  -1 +	 * +	 * (*) An exclude pattern interested in a directory does not +	 * necessarily mean it will exclude all of the directory. In +	 * wildcard case, it can't decide until looking at individual +	 * files inside. So don't write such directories off yet. +	 */ + +	if (!(ps->magic & PATHSPEC_EXCLUDE) || +	    positive <= entry_not_interesting) /* #1, #2, #11, #12 */ +		return positive; + +	negative = do_match(entry, base, base_offset, ps, 1); + +	/* #3, #4, #7, #8, #13, #14, #17, #18 */ +	if (negative <= entry_not_interesting) +		return positive; + +	/* #15, #19 */ +	if (S_ISDIR(entry->mode) && +	    positive >= entry_interesting && +	    negative == entry_interesting) +		return entry_interesting; + +	if ((positive == entry_interesting && +	     negative >= entry_interesting) || /* #5, #6, #16 */ +	    (positive == all_entries_interesting && +	     negative == entry_interesting)) /* #9 */ +		return entry_not_interesting; + +	return all_entries_not_interesting; /* #10, #20 */ +}  | 
