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>
This commit is contained in:

committed by
Junio C Hamano

parent
8b7cb51a9d
commit
ef79b1f870
@ -379,6 +379,11 @@ full pathname may have special meaning:
|
|||||||
- Other consecutive asterisks are considered invalid.
|
- Other consecutive asterisks are considered invalid.
|
||||||
+
|
+
|
||||||
Glob magic is incompatible with literal magic.
|
Glob magic is incompatible with literal magic.
|
||||||
|
|
||||||
|
exclude;;
|
||||||
|
After a path matches any non-exclude pathspec, it will be run
|
||||||
|
through all exclude pathspec (magic signature: `!`). If it
|
||||||
|
matches, the path is ignored.
|
||||||
--
|
--
|
||||||
|
|
||||||
[[def_parent]]parent::
|
[[def_parent]]parent::
|
||||||
|
@ -540,10 +540,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
|||||||
PATHSPEC_FROMTOP |
|
PATHSPEC_FROMTOP |
|
||||||
PATHSPEC_LITERAL |
|
PATHSPEC_LITERAL |
|
||||||
PATHSPEC_GLOB |
|
PATHSPEC_GLOB |
|
||||||
PATHSPEC_ICASE);
|
PATHSPEC_ICASE |
|
||||||
|
PATHSPEC_EXCLUDE);
|
||||||
|
|
||||||
for (i = 0; i < pathspec.nr; i++) {
|
for (i = 0; i < pathspec.nr; i++) {
|
||||||
const char *path = pathspec.items[i].match;
|
const char *path = pathspec.items[i].match;
|
||||||
|
if (pathspec.items[i].magic & PATHSPEC_EXCLUDE)
|
||||||
|
continue;
|
||||||
if (!seen[i] &&
|
if (!seen[i] &&
|
||||||
((pathspec.items[i].magic &
|
((pathspec.items[i].magic &
|
||||||
(PATHSPEC_GLOB | PATHSPEC_ICASE)) ||
|
(PATHSPEC_GLOB | PATHSPEC_ICASE)) ||
|
||||||
|
47
dir.c
47
dir.c
@ -126,10 +126,13 @@ static size_t common_prefix_len(const struct pathspec *pathspec)
|
|||||||
PATHSPEC_MAXDEPTH |
|
PATHSPEC_MAXDEPTH |
|
||||||
PATHSPEC_LITERAL |
|
PATHSPEC_LITERAL |
|
||||||
PATHSPEC_GLOB |
|
PATHSPEC_GLOB |
|
||||||
PATHSPEC_ICASE);
|
PATHSPEC_ICASE |
|
||||||
|
PATHSPEC_EXCLUDE);
|
||||||
|
|
||||||
for (n = 0; n < pathspec->nr; n++) {
|
for (n = 0; n < pathspec->nr; n++) {
|
||||||
size_t i = 0, len = 0, item_len;
|
size_t i = 0, len = 0, item_len;
|
||||||
|
if (pathspec->items[n].magic & PATHSPEC_EXCLUDE)
|
||||||
|
continue;
|
||||||
if (pathspec->items[n].magic & PATHSPEC_ICASE)
|
if (pathspec->items[n].magic & PATHSPEC_ICASE)
|
||||||
item_len = pathspec->items[n].prefix;
|
item_len = pathspec->items[n].prefix;
|
||||||
else
|
else
|
||||||
@ -279,9 +282,10 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,
|
|||||||
* pathspec did not match any names, which could indicate that the
|
* pathspec did not match any names, which could indicate that the
|
||||||
* user mistyped the nth pathspec.
|
* user mistyped the nth pathspec.
|
||||||
*/
|
*/
|
||||||
int match_pathspec_depth(const struct pathspec *ps,
|
static int match_pathspec_depth_1(const struct pathspec *ps,
|
||||||
const char *name, int namelen,
|
const char *name, int namelen,
|
||||||
int prefix, char *seen)
|
int prefix, char *seen,
|
||||||
|
int exclude)
|
||||||
{
|
{
|
||||||
int i, retval = 0;
|
int i, retval = 0;
|
||||||
|
|
||||||
@ -290,7 +294,8 @@ int match_pathspec_depth(const struct pathspec *ps,
|
|||||||
PATHSPEC_MAXDEPTH |
|
PATHSPEC_MAXDEPTH |
|
||||||
PATHSPEC_LITERAL |
|
PATHSPEC_LITERAL |
|
||||||
PATHSPEC_GLOB |
|
PATHSPEC_GLOB |
|
||||||
PATHSPEC_ICASE);
|
PATHSPEC_ICASE |
|
||||||
|
PATHSPEC_EXCLUDE);
|
||||||
|
|
||||||
if (!ps->nr) {
|
if (!ps->nr) {
|
||||||
if (!ps->recursive ||
|
if (!ps->recursive ||
|
||||||
@ -309,8 +314,19 @@ int match_pathspec_depth(const struct pathspec *ps,
|
|||||||
|
|
||||||
for (i = ps->nr - 1; i >= 0; i--) {
|
for (i = ps->nr - 1; i >= 0; i--) {
|
||||||
int how;
|
int how;
|
||||||
|
|
||||||
|
if ((!exclude && ps->items[i].magic & PATHSPEC_EXCLUDE) ||
|
||||||
|
( exclude && !(ps->items[i].magic & PATHSPEC_EXCLUDE)))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (seen && seen[i] == MATCHED_EXACTLY)
|
if (seen && seen[i] == MATCHED_EXACTLY)
|
||||||
continue;
|
continue;
|
||||||
|
/*
|
||||||
|
* Make exclude patterns optional and never report
|
||||||
|
* "pathspec ':(exclude)foo' matches no files"
|
||||||
|
*/
|
||||||
|
if (seen && ps->items[i].magic & PATHSPEC_EXCLUDE)
|
||||||
|
seen[i] = MATCHED_FNMATCH;
|
||||||
how = match_pathspec_item(ps->items+i, prefix, name, namelen);
|
how = match_pathspec_item(ps->items+i, prefix, name, namelen);
|
||||||
if (ps->recursive &&
|
if (ps->recursive &&
|
||||||
(ps->magic & PATHSPEC_MAXDEPTH) &&
|
(ps->magic & PATHSPEC_MAXDEPTH) &&
|
||||||
@ -334,6 +350,18 @@ int match_pathspec_depth(const struct pathspec *ps,
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int match_pathspec_depth(const struct pathspec *ps,
|
||||||
|
const char *name, int namelen,
|
||||||
|
int prefix, char *seen)
|
||||||
|
{
|
||||||
|
int positive, negative;
|
||||||
|
positive = match_pathspec_depth_1(ps, name, namelen, prefix, seen, 0);
|
||||||
|
if (!(ps->magic & PATHSPEC_EXCLUDE) || !positive)
|
||||||
|
return positive;
|
||||||
|
negative = match_pathspec_depth_1(ps, name, namelen, prefix, seen, 1);
|
||||||
|
return negative ? 0 : positive;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the length of the "simple" part of a path match limiter.
|
* Return the length of the "simple" part of a path match limiter.
|
||||||
*/
|
*/
|
||||||
@ -1375,11 +1403,18 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru
|
|||||||
PATHSPEC_MAXDEPTH |
|
PATHSPEC_MAXDEPTH |
|
||||||
PATHSPEC_LITERAL |
|
PATHSPEC_LITERAL |
|
||||||
PATHSPEC_GLOB |
|
PATHSPEC_GLOB |
|
||||||
PATHSPEC_ICASE);
|
PATHSPEC_ICASE |
|
||||||
|
PATHSPEC_EXCLUDE);
|
||||||
|
|
||||||
if (has_symlink_leading_path(path, len))
|
if (has_symlink_leading_path(path, len))
|
||||||
return dir->nr;
|
return dir->nr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* exclude patterns are treated like positive ones in
|
||||||
|
* create_simplify. Usually exclude patterns should be a
|
||||||
|
* subset of positive ones, which has no impacts on
|
||||||
|
* create_simplify().
|
||||||
|
*/
|
||||||
simplify = create_simplify(pathspec ? pathspec->_raw : NULL);
|
simplify = create_simplify(pathspec ? pathspec->_raw : NULL);
|
||||||
if (!len || treat_leading_path(dir, path, len, simplify))
|
if (!len || treat_leading_path(dir, path, len, simplify))
|
||||||
read_directory_recursive(dir, path, len, 0, simplify);
|
read_directory_recursive(dir, path, len, 0, simplify);
|
||||||
|
@ -71,6 +71,7 @@ static struct pathspec_magic {
|
|||||||
{ PATHSPEC_LITERAL, 0, "literal" },
|
{ PATHSPEC_LITERAL, 0, "literal" },
|
||||||
{ PATHSPEC_GLOB, '\0', "glob" },
|
{ PATHSPEC_GLOB, '\0', "glob" },
|
||||||
{ PATHSPEC_ICASE, '\0', "icase" },
|
{ PATHSPEC_ICASE, '\0', "icase" },
|
||||||
|
{ PATHSPEC_EXCLUDE, '!', "exclude" },
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -355,7 +356,7 @@ void parse_pathspec(struct pathspec *pathspec,
|
|||||||
{
|
{
|
||||||
struct pathspec_item *item;
|
struct pathspec_item *item;
|
||||||
const char *entry = argv ? *argv : NULL;
|
const char *entry = argv ? *argv : NULL;
|
||||||
int i, n, prefixlen;
|
int i, n, prefixlen, nr_exclude = 0;
|
||||||
|
|
||||||
memset(pathspec, 0, sizeof(*pathspec));
|
memset(pathspec, 0, sizeof(*pathspec));
|
||||||
|
|
||||||
@ -412,6 +413,8 @@ void parse_pathspec(struct pathspec *pathspec,
|
|||||||
if ((flags & PATHSPEC_LITERAL_PATH) &&
|
if ((flags & PATHSPEC_LITERAL_PATH) &&
|
||||||
!(magic_mask & PATHSPEC_LITERAL))
|
!(magic_mask & PATHSPEC_LITERAL))
|
||||||
item[i].magic |= PATHSPEC_LITERAL;
|
item[i].magic |= PATHSPEC_LITERAL;
|
||||||
|
if (item[i].magic & PATHSPEC_EXCLUDE)
|
||||||
|
nr_exclude++;
|
||||||
if (item[i].magic & magic_mask)
|
if (item[i].magic & magic_mask)
|
||||||
unsupported_magic(entry,
|
unsupported_magic(entry,
|
||||||
item[i].magic & magic_mask,
|
item[i].magic & magic_mask,
|
||||||
@ -427,6 +430,10 @@ void parse_pathspec(struct pathspec *pathspec,
|
|||||||
pathspec->magic |= item[i].magic;
|
pathspec->magic |= item[i].magic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nr_exclude == n)
|
||||||
|
die(_("There is nothing to exclude from by :(exclude) patterns.\n"
|
||||||
|
"Perhaps you forgot to add either ':/' or '.' ?"));
|
||||||
|
|
||||||
|
|
||||||
if (pathspec->magic & PATHSPEC_MAXDEPTH) {
|
if (pathspec->magic & PATHSPEC_MAXDEPTH) {
|
||||||
if (flags & PATHSPEC_KEEP_ORDER)
|
if (flags & PATHSPEC_KEEP_ORDER)
|
||||||
|
@ -7,12 +7,14 @@
|
|||||||
#define PATHSPEC_LITERAL (1<<2)
|
#define PATHSPEC_LITERAL (1<<2)
|
||||||
#define PATHSPEC_GLOB (1<<3)
|
#define PATHSPEC_GLOB (1<<3)
|
||||||
#define PATHSPEC_ICASE (1<<4)
|
#define PATHSPEC_ICASE (1<<4)
|
||||||
|
#define PATHSPEC_EXCLUDE (1<<5)
|
||||||
#define PATHSPEC_ALL_MAGIC \
|
#define PATHSPEC_ALL_MAGIC \
|
||||||
(PATHSPEC_FROMTOP | \
|
(PATHSPEC_FROMTOP | \
|
||||||
PATHSPEC_MAXDEPTH | \
|
PATHSPEC_MAXDEPTH | \
|
||||||
PATHSPEC_LITERAL | \
|
PATHSPEC_LITERAL | \
|
||||||
PATHSPEC_GLOB | \
|
PATHSPEC_GLOB | \
|
||||||
PATHSPEC_ICASE)
|
PATHSPEC_ICASE | \
|
||||||
|
PATHSPEC_EXCLUDE)
|
||||||
|
|
||||||
#define PATHSPEC_ONESTAR 1 /* the pathspec pattern satisfies GFNM_ONESTAR */
|
#define PATHSPEC_ONESTAR 1 /* the pathspec pattern satisfies GFNM_ONESTAR */
|
||||||
|
|
||||||
|
184
t/t6132-pathspec-exclude.sh
Executable file
184
t/t6132-pathspec-exclude.sh
Executable file
@ -0,0 +1,184 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='test case exclude pathspec'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
test_expect_success 'setup' '
|
||||||
|
for p in file sub/file sub/sub/file sub/file2 sub/sub/sub/file sub2/file; do
|
||||||
|
if echo $p | grep /; then
|
||||||
|
mkdir -p `dirname $p`
|
||||||
|
fi &&
|
||||||
|
: >$p &&
|
||||||
|
git add $p &&
|
||||||
|
git commit -m $p
|
||||||
|
done &&
|
||||||
|
git log --oneline --format=%s >actual &&
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
sub2/file
|
||||||
|
sub/sub/sub/file
|
||||||
|
sub/file2
|
||||||
|
sub/sub/file
|
||||||
|
sub/file
|
||||||
|
file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'exclude only should error out' '
|
||||||
|
test_must_fail git log --oneline --format=%s -- ":(exclude)sub"
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 't_e_i() exclude sub' '
|
||||||
|
git log --oneline --format=%s -- . ":(exclude)sub" >actual
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
sub2/file
|
||||||
|
file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 't_e_i() exclude sub/sub/file' '
|
||||||
|
git log --oneline --format=%s -- . ":(exclude)sub/sub/file" >actual
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
sub2/file
|
||||||
|
sub/sub/sub/file
|
||||||
|
sub/file2
|
||||||
|
sub/file
|
||||||
|
file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 't_e_i() exclude sub using mnemonic' '
|
||||||
|
git log --oneline --format=%s -- . ":!sub" >actual
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
sub2/file
|
||||||
|
file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 't_e_i() exclude :(icase)SUB' '
|
||||||
|
git log --oneline --format=%s -- . ":(exclude,icase)SUB" >actual
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
sub2/file
|
||||||
|
file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 't_e_i() exclude sub2 from sub' '
|
||||||
|
(
|
||||||
|
cd sub &&
|
||||||
|
git log --oneline --format=%s -- :/ ":/!sub2" >actual
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
sub/sub/sub/file
|
||||||
|
sub/file2
|
||||||
|
sub/sub/file
|
||||||
|
sub/file
|
||||||
|
file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 't_e_i() exclude sub/*file' '
|
||||||
|
git log --oneline --format=%s -- . ":(exclude)sub/*file" >actual
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
sub2/file
|
||||||
|
sub/file2
|
||||||
|
file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 't_e_i() exclude :(glob)sub/*/file' '
|
||||||
|
git log --oneline --format=%s -- . ":(exclude,glob)sub/*/file" >actual
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
sub2/file
|
||||||
|
sub/sub/sub/file
|
||||||
|
sub/file2
|
||||||
|
sub/file
|
||||||
|
file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'm_p_d() exclude sub' '
|
||||||
|
git ls-files -- . ":(exclude)sub" >actual
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
file
|
||||||
|
sub2/file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'm_p_d() exclude sub/sub/file' '
|
||||||
|
git ls-files -- . ":(exclude)sub/sub/file" >actual
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
file
|
||||||
|
sub/file
|
||||||
|
sub/file2
|
||||||
|
sub/sub/sub/file
|
||||||
|
sub2/file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'm_p_d() exclude sub using mnemonic' '
|
||||||
|
git ls-files -- . ":!sub" >actual
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
file
|
||||||
|
sub2/file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'm_p_d() exclude :(icase)SUB' '
|
||||||
|
git ls-files -- . ":(exclude,icase)SUB" >actual
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
file
|
||||||
|
sub2/file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'm_p_d() exclude sub2 from sub' '
|
||||||
|
(
|
||||||
|
cd sub &&
|
||||||
|
git ls-files -- :/ ":/!sub2" >actual
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
../file
|
||||||
|
file
|
||||||
|
file2
|
||||||
|
sub/file
|
||||||
|
sub/sub/file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'm_p_d() exclude sub/*file' '
|
||||||
|
git ls-files -- . ":(exclude)sub/*file" >actual
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
file
|
||||||
|
sub/file2
|
||||||
|
sub2/file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'm_p_d() exclude :(glob)sub/*/file' '
|
||||||
|
git ls-files -- . ":(exclude,glob)sub/*/file" >actual
|
||||||
|
cat <<EOF >expect &&
|
||||||
|
file
|
||||||
|
sub/file
|
||||||
|
sub/file2
|
||||||
|
sub/sub/sub/file
|
||||||
|
sub2/file
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
83
tree-walk.c
83
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)
|
* Pre-condition: either baselen == base_offset (i.e. empty path)
|
||||||
* or base[baselen-1] == '/' (i.e. with trailing slash).
|
* or base[baselen-1] == '/' (i.e. with trailing slash).
|
||||||
*/
|
*/
|
||||||
enum interesting tree_entry_interesting(const struct name_entry *entry,
|
static enum interesting do_match(const struct name_entry *entry,
|
||||||
struct strbuf *base, int base_offset,
|
struct strbuf *base, int base_offset,
|
||||||
const struct pathspec *ps)
|
const struct pathspec *ps,
|
||||||
|
int exclude)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int pathlen, baselen = base->len - base_offset;
|
int pathlen, baselen = base->len - base_offset;
|
||||||
@ -676,7 +677,8 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
|
|||||||
PATHSPEC_MAXDEPTH |
|
PATHSPEC_MAXDEPTH |
|
||||||
PATHSPEC_LITERAL |
|
PATHSPEC_LITERAL |
|
||||||
PATHSPEC_GLOB |
|
PATHSPEC_GLOB |
|
||||||
PATHSPEC_ICASE);
|
PATHSPEC_ICASE |
|
||||||
|
PATHSPEC_EXCLUDE);
|
||||||
|
|
||||||
if (!ps->nr) {
|
if (!ps->nr) {
|
||||||
if (!ps->recursive ||
|
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;
|
const char *base_str = base->buf + base_offset;
|
||||||
int matchlen = item->len, matched = 0;
|
int matchlen = item->len, matched = 0;
|
||||||
|
|
||||||
|
if ((!exclude && item->magic & PATHSPEC_EXCLUDE) ||
|
||||||
|
( exclude && !(item->magic & PATHSPEC_EXCLUDE)))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (baselen >= matchlen) {
|
if (baselen >= matchlen) {
|
||||||
/* If it doesn't match, move along... */
|
/* If it doesn't match, move along... */
|
||||||
if (!match_dir_prefix(item, base_str, match, matchlen))
|
if (!match_dir_prefix(item, base_str, match, matchlen))
|
||||||
@ -782,3 +788,72 @@ match_wildcards:
|
|||||||
}
|
}
|
||||||
return never_interesting; /* No matches */
|
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 */
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user