Merge branch 'ds/include-exclude'

The internal code originally invented for ".gitignore" processing
got reshuffled and renamed to make it less tied to "excluding" and
stress more that it is about "matching", as it has been reused for
things like sparse checkout specification that want to check if a
path is "included".

* ds/include-exclude:
  unpack-trees: rename 'is_excluded_from_list()'
  treewide: rename 'exclude' methods to 'pattern'
  treewide: rename 'EXCL_FLAG_' to 'PATTERN_FLAG_'
  treewide: rename 'struct exclude_list' to 'struct pattern_list'
  treewide: rename 'struct exclude' to 'struct path_pattern'
This commit is contained in:
Junio C Hamano 2019-09-30 13:19:31 +09:00
commit 9755f70fe6
12 changed files with 284 additions and 251 deletions

View file

@ -10,7 +10,7 @@ Fixes since v2.7
setting GIT_WORK_TREE environment themselves. setting GIT_WORK_TREE environment themselves.
* The "exclude_list" structure has the usual "alloc, nr" pair of * The "exclude_list" structure has the usual "alloc, nr" pair of
fields to be used by ALLOC_GROW(), but clear_exclude_list() forgot fields to be used by ALLOC_GROW(), but clear_pattern_list() forgot
to reset 'alloc' to 0 when it cleared 'nr' to discard the managed to reset 'alloc' to 0 when it cleared 'nr' to discard the managed
array. array.

View file

@ -270,7 +270,7 @@ notes for details).
setting GIT_WORK_TREE environment themselves. setting GIT_WORK_TREE environment themselves.
* The "exclude_list" structure has the usual "alloc, nr" pair of * The "exclude_list" structure has the usual "alloc, nr" pair of
fields to be used by ALLOC_GROW(), but clear_exclude_list() forgot fields to be used by ALLOC_GROW(), but clear_pattern_list() forgot
to reset 'alloc' to 0 when it cleared 'nr' to discard the managed to reset 'alloc' to 0 when it cleared 'nr' to discard the managed
array. array.

View file

@ -111,11 +111,11 @@ marked. If you to exclude files, make sure you have loaded index first.
* Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0, * Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,
sizeof(dir))`. sizeof(dir))`.
* To add single exclude pattern, call `add_exclude_list()` and then * To add single exclude pattern, call `add_pattern_list()` and then
`add_exclude()`. `add_pattern()`.
* To add patterns from a file (e.g. `.git/info/exclude`), call * To add patterns from a file (e.g. `.git/info/exclude`), call
`add_excludes_from_file()` , and/or set `dir.exclude_per_dir`. A `add_patterns_from_file()` , and/or set `dir.exclude_per_dir`. A
short-hand function `setup_standard_excludes()` can be used to set short-hand function `setup_standard_excludes()` can be used to set
up the standard set of exclude settings. up the standard set of exclude settings.

10
attr.c
View file

@ -259,7 +259,7 @@ struct pattern {
const char *pattern; const char *pattern;
int patternlen; int patternlen;
int nowildcardlen; int nowildcardlen;
unsigned flags; /* EXC_FLAG_* */ unsigned flags; /* PATTERN_FLAG_* */
}; };
/* /*
@ -400,11 +400,11 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
char *p = (char *)&(res->state[num_attr]); char *p = (char *)&(res->state[num_attr]);
memcpy(p, name, namelen); memcpy(p, name, namelen);
res->u.pat.pattern = p; res->u.pat.pattern = p;
parse_exclude_pattern(&res->u.pat.pattern, parse_path_pattern(&res->u.pat.pattern,
&res->u.pat.patternlen, &res->u.pat.patternlen,
&res->u.pat.flags, &res->u.pat.flags,
&res->u.pat.nowildcardlen); &res->u.pat.nowildcardlen);
if (res->u.pat.flags & EXC_FLAG_NEGATIVE) { if (res->u.pat.flags & PATTERN_FLAG_NEGATIVE) {
warning(_("Negative patterns are ignored in git attributes\n" warning(_("Negative patterns are ignored in git attributes\n"
"Use '\\!' for literal leading exclamation.")); "Use '\\!' for literal leading exclamation."));
goto fail_return; goto fail_return;
@ -991,10 +991,10 @@ static int path_matches(const char *pathname, int pathlen,
int prefix = pat->nowildcardlen; int prefix = pat->nowildcardlen;
int isdir = (pathlen && pathname[pathlen - 1] == '/'); int isdir = (pathlen && pathname[pathlen - 1] == '/');
if ((pat->flags & EXC_FLAG_MUSTBEDIR) && !isdir) if ((pat->flags & PATTERN_FLAG_MUSTBEDIR) && !isdir)
return 0; return 0;
if (pat->flags & EXC_FLAG_NODIR) { if (pat->flags & PATTERN_FLAG_NODIR) {
return match_basename(pathname + basename_offset, return match_basename(pathname + basename_offset,
pathlen - basename_offset - isdir, pathlen - basename_offset - isdir,
pattern, prefix, pattern, prefix,

View file

@ -32,19 +32,19 @@ static const struct option check_ignore_options[] = {
OPT_END() OPT_END()
}; };
static void output_exclude(const char *path, struct exclude *exclude) static void output_pattern(const char *path, struct path_pattern *pattern)
{ {
char *bang = (exclude && exclude->flags & EXC_FLAG_NEGATIVE) ? "!" : ""; char *bang = (pattern && pattern->flags & PATTERN_FLAG_NEGATIVE) ? "!" : "";
char *slash = (exclude && exclude->flags & EXC_FLAG_MUSTBEDIR) ? "/" : ""; char *slash = (pattern && pattern->flags & PATTERN_FLAG_MUSTBEDIR) ? "/" : "";
if (!nul_term_line) { if (!nul_term_line) {
if (!verbose) { if (!verbose) {
write_name_quoted(path, stdout, '\n'); write_name_quoted(path, stdout, '\n');
} else { } else {
if (exclude) { if (pattern) {
quote_c_style(exclude->el->src, NULL, stdout, 0); quote_c_style(pattern->pl->src, NULL, stdout, 0);
printf(":%d:%s%s%s\t", printf(":%d:%s%s%s\t",
exclude->srcpos, pattern->srcpos,
bang, exclude->pattern, slash); bang, pattern->pattern, slash);
} }
else { else {
printf("::\t"); printf("::\t");
@ -56,11 +56,11 @@ static void output_exclude(const char *path, struct exclude *exclude)
if (!verbose) { if (!verbose) {
printf("%s%c", path, '\0'); printf("%s%c", path, '\0');
} else { } else {
if (exclude) if (pattern)
printf("%s%c%d%c%s%s%s%c%s%c", printf("%s%c%d%c%s%s%s%c%s%c",
exclude->el->src, '\0', pattern->pl->src, '\0',
exclude->srcpos, '\0', pattern->srcpos, '\0',
bang, exclude->pattern, slash, '\0', bang, pattern->pattern, slash, '\0',
path, '\0'); path, '\0');
else else
printf("%c%c%c%s%c", '\0', '\0', '\0', path, '\0'); printf("%c%c%c%s%c", '\0', '\0', '\0', path, '\0');
@ -74,7 +74,7 @@ static int check_ignore(struct dir_struct *dir,
const char *full_path; const char *full_path;
char *seen; char *seen;
int num_ignored = 0, i; int num_ignored = 0, i;
struct exclude *exclude; struct path_pattern *pattern;
struct pathspec pathspec; struct pathspec pathspec;
if (!argc) { if (!argc) {
@ -103,15 +103,15 @@ static int check_ignore(struct dir_struct *dir,
seen = find_pathspecs_matching_against_index(&pathspec, &the_index); seen = find_pathspecs_matching_against_index(&pathspec, &the_index);
for (i = 0; i < pathspec.nr; i++) { for (i = 0; i < pathspec.nr; i++) {
full_path = pathspec.items[i].match; full_path = pathspec.items[i].match;
exclude = NULL; pattern = NULL;
if (!seen[i]) { if (!seen[i]) {
int dtype = DT_UNKNOWN; int dtype = DT_UNKNOWN;
exclude = last_exclude_matching(dir, &the_index, pattern = last_matching_pattern(dir, &the_index,
full_path, &dtype); full_path, &dtype);
} }
if (!quiet && (exclude || show_non_matching)) if (!quiet && (pattern || show_non_matching))
output_exclude(pathspec.items[i].original, exclude); output_pattern(pathspec.items[i].original, pattern);
if (exclude) if (pattern)
num_ignored++; num_ignored++;
} }
free(seen); free(seen);

View file

@ -648,7 +648,7 @@ static int filter_by_patterns_cmd(void)
struct strbuf confirm = STRBUF_INIT; struct strbuf confirm = STRBUF_INIT;
struct strbuf **ignore_list; struct strbuf **ignore_list;
struct string_list_item *item; struct string_list_item *item;
struct exclude_list *el; struct pattern_list *pl;
int changed = -1, i; int changed = -1, i;
for (;;) { for (;;) {
@ -671,7 +671,7 @@ static int filter_by_patterns_cmd(void)
break; break;
memset(&dir, 0, sizeof(dir)); memset(&dir, 0, sizeof(dir));
el = add_exclude_list(&dir, EXC_CMDL, "manual exclude"); pl = add_pattern_list(&dir, EXC_CMDL, "manual exclude");
ignore_list = strbuf_split_max(&confirm, ' ', 0); ignore_list = strbuf_split_max(&confirm, ' ', 0);
for (i = 0; ignore_list[i]; i++) { for (i = 0; ignore_list[i]; i++) {
@ -679,7 +679,7 @@ static int filter_by_patterns_cmd(void)
if (!ignore_list[i]->len) if (!ignore_list[i]->len)
continue; continue;
add_exclude(ignore_list[i]->buf, "", 0, el, -(i+1)); add_pattern(ignore_list[i]->buf, "", 0, pl, -(i+1));
} }
changed = 0; changed = 0;
@ -901,7 +901,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
struct pathspec pathspec; struct pathspec pathspec;
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
struct string_list exclude_list = STRING_LIST_INIT_NODUP; struct string_list exclude_list = STRING_LIST_INIT_NODUP;
struct exclude_list *el; struct pattern_list *pl;
struct string_list_item *item; struct string_list_item *item;
const char *qname; const char *qname;
struct option options[] = { struct option options[] = {
@ -958,9 +958,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (!ignored) if (!ignored)
setup_standard_excludes(&dir); setup_standard_excludes(&dir);
el = add_exclude_list(&dir, EXC_CMDL, "--exclude option"); pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
for (i = 0; i < exclude_list.nr; i++) for (i = 0; i < exclude_list.nr; i++)
add_exclude(exclude_list.items[i].string, "", 0, el, -(i+1)); add_pattern(exclude_list.items[i].string, "", 0, pl, -(i+1));
parse_pathspec(&pathspec, 0, parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_CWD, PATHSPEC_PREFER_CWD,

View file

@ -492,7 +492,7 @@ static int option_parse_exclude_from(const struct option *opt,
BUG_ON_OPT_NEG(unset); BUG_ON_OPT_NEG(unset);
exc_given = 1; exc_given = 1;
add_excludes_from_file(dir, arg); add_patterns_from_file(dir, arg);
return 0; return 0;
} }
@ -516,7 +516,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
int require_work_tree = 0, show_tag = 0, i; int require_work_tree = 0, show_tag = 0, i;
const char *max_prefix; const char *max_prefix;
struct dir_struct dir; struct dir_struct dir;
struct exclude_list *el; struct pattern_list *pl;
struct string_list exclude_list = STRING_LIST_INIT_NODUP; struct string_list exclude_list = STRING_LIST_INIT_NODUP;
struct option builtin_ls_files_options[] = { struct option builtin_ls_files_options[] = {
/* Think twice before adding "--nul" synonym to this */ /* Think twice before adding "--nul" synonym to this */
@ -594,9 +594,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
argc = parse_options(argc, argv, prefix, builtin_ls_files_options, argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
ls_files_usage, 0); ls_files_usage, 0);
el = add_exclude_list(&dir, EXC_CMDL, "--exclude option"); pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
for (i = 0; i < exclude_list.nr; i++) { for (i = 0; i < exclude_list.nr; i++) {
add_exclude(exclude_list.items[i].string, "", 0, el, --exclude_args); add_pattern(exclude_list.items[i].string, "", 0, pl, --exclude_args);
} }
if (show_tag || show_valid_bit || show_fsmonitor_bit) { if (show_tag || show_valid_bit || show_fsmonitor_bit) {
tag_cached = "H "; tag_cached = "H ";

282
dir.c
View file

@ -561,7 +561,7 @@ int no_wildcard(const char *string)
return string[simple_length(string)] == '\0'; return string[simple_length(string)] == '\0';
} }
void parse_exclude_pattern(const char **pattern, void parse_path_pattern(const char **pattern,
int *patternlen, int *patternlen,
unsigned *flags, unsigned *flags,
int *nowildcardlen) int *nowildcardlen)
@ -571,20 +571,20 @@ void parse_exclude_pattern(const char **pattern,
*flags = 0; *flags = 0;
if (*p == '!') { if (*p == '!') {
*flags |= EXC_FLAG_NEGATIVE; *flags |= PATTERN_FLAG_NEGATIVE;
p++; p++;
} }
len = strlen(p); len = strlen(p);
if (len && p[len - 1] == '/') { if (len && p[len - 1] == '/') {
len--; len--;
*flags |= EXC_FLAG_MUSTBEDIR; *flags |= PATTERN_FLAG_MUSTBEDIR;
} }
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (p[i] == '/') if (p[i] == '/')
break; break;
} }
if (i == len) if (i == len)
*flags |= EXC_FLAG_NODIR; *flags |= PATTERN_FLAG_NODIR;
*nowildcardlen = simple_length(p); *nowildcardlen = simple_length(p);
/* /*
* we should have excluded the trailing slash from 'p' too, * we should have excluded the trailing slash from 'p' too,
@ -594,35 +594,35 @@ void parse_exclude_pattern(const char **pattern,
if (*nowildcardlen > len) if (*nowildcardlen > len)
*nowildcardlen = len; *nowildcardlen = len;
if (*p == '*' && no_wildcard(p + 1)) if (*p == '*' && no_wildcard(p + 1))
*flags |= EXC_FLAG_ENDSWITH; *flags |= PATTERN_FLAG_ENDSWITH;
*pattern = p; *pattern = p;
*patternlen = len; *patternlen = len;
} }
void add_exclude(const char *string, const char *base, void add_pattern(const char *string, const char *base,
int baselen, struct exclude_list *el, int srcpos) int baselen, struct pattern_list *pl, int srcpos)
{ {
struct exclude *x; struct path_pattern *pattern;
int patternlen; int patternlen;
unsigned flags; unsigned flags;
int nowildcardlen; int nowildcardlen;
parse_exclude_pattern(&string, &patternlen, &flags, &nowildcardlen); parse_path_pattern(&string, &patternlen, &flags, &nowildcardlen);
if (flags & EXC_FLAG_MUSTBEDIR) { if (flags & PATTERN_FLAG_MUSTBEDIR) {
FLEXPTR_ALLOC_MEM(x, pattern, string, patternlen); FLEXPTR_ALLOC_MEM(pattern, pattern, string, patternlen);
} else { } else {
x = xmalloc(sizeof(*x)); pattern = xmalloc(sizeof(*pattern));
x->pattern = string; pattern->pattern = string;
} }
x->patternlen = patternlen; pattern->patternlen = patternlen;
x->nowildcardlen = nowildcardlen; pattern->nowildcardlen = nowildcardlen;
x->base = base; pattern->base = base;
x->baselen = baselen; pattern->baselen = baselen;
x->flags = flags; pattern->flags = flags;
x->srcpos = srcpos; pattern->srcpos = srcpos;
ALLOC_GROW(el->excludes, el->nr + 1, el->alloc); ALLOC_GROW(pl->patterns, pl->nr + 1, pl->alloc);
el->excludes[el->nr++] = x; pl->patterns[pl->nr++] = pattern;
x->el = el; pattern->pl = pl;
} }
static int read_skip_worktree_file_from_index(const struct index_state *istate, static int read_skip_worktree_file_from_index(const struct index_state *istate,
@ -643,19 +643,19 @@ static int read_skip_worktree_file_from_index(const struct index_state *istate,
} }
/* /*
* Frees memory within el which was allocated for exclude patterns and * Frees memory within pl which was allocated for exclude patterns and
* the file buffer. Does not free el itself. * the file buffer. Does not free pl itself.
*/ */
void clear_exclude_list(struct exclude_list *el) void clear_pattern_list(struct pattern_list *pl)
{ {
int i; int i;
for (i = 0; i < el->nr; i++) for (i = 0; i < pl->nr; i++)
free(el->excludes[i]); free(pl->patterns[i]);
free(el->excludes); free(pl->patterns);
free(el->filebuf); free(pl->filebuf);
memset(el, 0, sizeof(*el)); memset(pl, 0, sizeof(*pl));
} }
static void trim_trailing_spaces(char *buf) static void trim_trailing_spaces(char *buf)
@ -762,21 +762,21 @@ static void invalidate_directory(struct untracked_cache *uc,
dir->dirs[i]->recurse = 0; dir->dirs[i]->recurse = 0;
} }
static int add_excludes_from_buffer(char *buf, size_t size, static int add_patterns_from_buffer(char *buf, size_t size,
const char *base, int baselen, const char *base, int baselen,
struct exclude_list *el); struct pattern_list *pl);
/* /*
* Given a file with name "fname", read it (either from disk, or from * Given a file with name "fname", read it (either from disk, or from
* an index if 'istate' is non-null), parse it and store the * an index if 'istate' is non-null), parse it and store the
* exclude rules in "el". * exclude rules in "pl".
* *
* If "ss" is not NULL, compute SHA-1 of the exclude file and fill * If "ss" is not NULL, compute SHA-1 of the exclude file and fill
* stat data from disk (only valid if add_excludes returns zero). If * stat data from disk (only valid if add_patterns returns zero). If
* ss_valid is non-zero, "ss" must contain good value as input. * ss_valid is non-zero, "ss" must contain good value as input.
*/ */
static int add_excludes(const char *fname, const char *base, int baselen, static int add_patterns(const char *fname, const char *base, int baselen,
struct exclude_list *el, struct index_state *istate, struct pattern_list *pl, struct index_state *istate,
struct oid_stat *oid_stat) struct oid_stat *oid_stat)
{ {
struct stat st; struct stat st;
@ -837,21 +837,21 @@ static int add_excludes(const char *fname, const char *base, int baselen,
} }
} }
add_excludes_from_buffer(buf, size, base, baselen, el); add_patterns_from_buffer(buf, size, base, baselen, pl);
return 0; return 0;
} }
static int add_excludes_from_buffer(char *buf, size_t size, static int add_patterns_from_buffer(char *buf, size_t size,
const char *base, int baselen, const char *base, int baselen,
struct exclude_list *el) struct pattern_list *pl)
{ {
int i, lineno = 1; int i, lineno = 1;
char *entry; char *entry;
el->filebuf = buf; pl->filebuf = buf;
if (skip_utf8_bom(&buf, size)) if (skip_utf8_bom(&buf, size))
size -= buf - el->filebuf; size -= buf - pl->filebuf;
entry = buf; entry = buf;
@ -860,7 +860,7 @@ static int add_excludes_from_buffer(char *buf, size_t size,
if (entry != buf + i && entry[0] != '#') { if (entry != buf + i && entry[0] != '#') {
buf[i - (i && buf[i-1] == '\r')] = 0; buf[i - (i && buf[i-1] == '\r')] = 0;
trim_trailing_spaces(entry); trim_trailing_spaces(entry);
add_exclude(entry, base, baselen, el, lineno); add_pattern(entry, base, baselen, pl, lineno);
} }
lineno++; lineno++;
entry = buf + i + 1; entry = buf + i + 1;
@ -869,17 +869,17 @@ static int add_excludes_from_buffer(char *buf, size_t size,
return 0; return 0;
} }
int add_excludes_from_file_to_list(const char *fname, const char *base, int add_patterns_from_file_to_list(const char *fname, const char *base,
int baselen, struct exclude_list *el, int baselen, struct pattern_list *pl,
struct index_state *istate) struct index_state *istate)
{ {
return add_excludes(fname, base, baselen, el, istate, NULL); return add_patterns(fname, base, baselen, pl, istate, NULL);
} }
int add_excludes_from_blob_to_list( int add_patterns_from_blob_to_list(
struct object_id *oid, struct object_id *oid,
const char *base, int baselen, const char *base, int baselen,
struct exclude_list *el) struct pattern_list *pl)
{ {
char *buf; char *buf;
size_t size; size_t size;
@ -889,31 +889,31 @@ int add_excludes_from_blob_to_list(
if (r != 1) if (r != 1)
return r; return r;
add_excludes_from_buffer(buf, size, base, baselen, el); add_patterns_from_buffer(buf, size, base, baselen, pl);
return 0; return 0;
} }
struct exclude_list *add_exclude_list(struct dir_struct *dir, struct pattern_list *add_pattern_list(struct dir_struct *dir,
int group_type, const char *src) int group_type, const char *src)
{ {
struct exclude_list *el; struct pattern_list *pl;
struct exclude_list_group *group; struct exclude_list_group *group;
group = &dir->exclude_list_group[group_type]; group = &dir->exclude_list_group[group_type];
ALLOC_GROW(group->el, group->nr + 1, group->alloc); ALLOC_GROW(group->pl, group->nr + 1, group->alloc);
el = &group->el[group->nr++]; pl = &group->pl[group->nr++];
memset(el, 0, sizeof(*el)); memset(pl, 0, sizeof(*pl));
el->src = src; pl->src = src;
return el; return pl;
} }
/* /*
* Used to set up core.excludesfile and .git/info/exclude lists. * Used to set up core.excludesfile and .git/info/exclude lists.
*/ */
static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname, static void add_patterns_from_file_1(struct dir_struct *dir, const char *fname,
struct oid_stat *oid_stat) struct oid_stat *oid_stat)
{ {
struct exclude_list *el; struct pattern_list *pl;
/* /*
* catch setup_standard_excludes() that's called before * catch setup_standard_excludes() that's called before
* dir->untracked is assigned. That function behaves * dir->untracked is assigned. That function behaves
@ -921,15 +921,15 @@ static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname,
*/ */
if (!dir->untracked) if (!dir->untracked)
dir->unmanaged_exclude_files++; dir->unmanaged_exclude_files++;
el = add_exclude_list(dir, EXC_FILE, fname); pl = add_pattern_list(dir, EXC_FILE, fname);
if (add_excludes(fname, "", 0, el, NULL, oid_stat) < 0) if (add_patterns(fname, "", 0, pl, NULL, oid_stat) < 0)
die(_("cannot use %s as an exclude file"), fname); die(_("cannot use %s as an exclude file"), fname);
} }
void add_excludes_from_file(struct dir_struct *dir, const char *fname) void add_patterns_from_file(struct dir_struct *dir, const char *fname)
{ {
dir->unmanaged_exclude_files++; /* see validate_untracked_cache() */ dir->unmanaged_exclude_files++; /* see validate_untracked_cache() */
add_excludes_from_file_1(dir, fname, NULL); add_patterns_from_file_1(dir, fname, NULL);
} }
int match_basename(const char *basename, int basenamelen, int match_basename(const char *basename, int basenamelen,
@ -940,7 +940,7 @@ int match_basename(const char *basename, int basenamelen,
if (patternlen == basenamelen && if (patternlen == basenamelen &&
!fspathncmp(pattern, basename, basenamelen)) !fspathncmp(pattern, basename, basenamelen))
return 1; return 1;
} else if (flags & EXC_FLAG_ENDSWITH) { } else if (flags & PATTERN_FLAG_ENDSWITH) {
/* "*literal" matching against "fooliteral" */ /* "*literal" matching against "fooliteral" */
if (patternlen - 1 <= basenamelen && if (patternlen - 1 <= basenamelen &&
!fspathncmp(pattern + 1, !fspathncmp(pattern + 1,
@ -1021,85 +1021,97 @@ int match_pathname(const char *pathname, int pathlen,
* any, determines the fate. Returns the exclude_list element which * any, determines the fate. Returns the exclude_list element which
* matched, or NULL for undecided. * matched, or NULL for undecided.
*/ */
static struct exclude *last_exclude_matching_from_list(const char *pathname, static struct path_pattern *last_matching_pattern_from_list(const char *pathname,
int pathlen, int pathlen,
const char *basename, const char *basename,
int *dtype, int *dtype,
struct exclude_list *el, struct pattern_list *pl,
struct index_state *istate) struct index_state *istate)
{ {
struct exclude *exc = NULL; /* undecided */ struct path_pattern *res = NULL; /* undecided */
int i; int i;
if (!el->nr) if (!pl->nr)
return NULL; /* undefined */ return NULL; /* undefined */
for (i = el->nr - 1; 0 <= i; i--) { for (i = pl->nr - 1; 0 <= i; i--) {
struct exclude *x = el->excludes[i]; struct path_pattern *pattern = pl->patterns[i];
const char *exclude = x->pattern; const char *exclude = pattern->pattern;
int prefix = x->nowildcardlen; int prefix = pattern->nowildcardlen;
if (x->flags & EXC_FLAG_MUSTBEDIR) { if (pattern->flags & PATTERN_FLAG_MUSTBEDIR) {
if (*dtype == DT_UNKNOWN) if (*dtype == DT_UNKNOWN)
*dtype = get_dtype(NULL, istate, pathname, pathlen); *dtype = get_dtype(NULL, istate, pathname, pathlen);
if (*dtype != DT_DIR) if (*dtype != DT_DIR)
continue; continue;
} }
if (x->flags & EXC_FLAG_NODIR) { if (pattern->flags & PATTERN_FLAG_NODIR) {
if (match_basename(basename, if (match_basename(basename,
pathlen - (basename - pathname), pathlen - (basename - pathname),
exclude, prefix, x->patternlen, exclude, prefix, pattern->patternlen,
x->flags)) { pattern->flags)) {
exc = x; res = pattern;
break; break;
} }
continue; continue;
} }
assert(x->baselen == 0 || x->base[x->baselen - 1] == '/'); assert(pattern->baselen == 0 ||
pattern->base[pattern->baselen - 1] == '/');
if (match_pathname(pathname, pathlen, if (match_pathname(pathname, pathlen,
x->base, x->baselen ? x->baselen - 1 : 0, pattern->base,
exclude, prefix, x->patternlen, x->flags)) { pattern->baselen ? pattern->baselen - 1 : 0,
exc = x; exclude, prefix, pattern->patternlen,
pattern->flags)) {
res = pattern;
break; break;
} }
} }
return exc; return res;
} }
/* /*
* Scan the list and let the last match determine the fate. * Scan the list of patterns to determine if the ordered list
* Return 1 for exclude, 0 for include and -1 for undecided. * of patterns matches on 'pathname'.
*
* Return 1 for a match, 0 for not matched and -1 for undecided.
*/ */
int is_excluded_from_list(const char *pathname, enum pattern_match_result path_matches_pattern_list(
int pathlen, const char *basename, int *dtype, const char *pathname, int pathlen,
struct exclude_list *el, struct index_state *istate) const char *basename, int *dtype,
struct pattern_list *pl,
struct index_state *istate)
{ {
struct exclude *exclude; struct path_pattern *pattern;
exclude = last_exclude_matching_from_list(pathname, pathlen, basename, pattern = last_matching_pattern_from_list(pathname, pathlen, basename,
dtype, el, istate); dtype, pl, istate);
if (exclude) if (pattern) {
return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1; if (pattern->flags & PATTERN_FLAG_NEGATIVE)
return -1; /* undecided */ return NOT_MATCHED;
else
return MATCHED;
}
return UNDECIDED;
} }
static struct exclude *last_exclude_matching_from_lists(struct dir_struct *dir, static struct path_pattern *last_matching_pattern_from_lists(
struct index_state *istate, struct dir_struct *dir, struct index_state *istate,
const char *pathname, int pathlen, const char *basename, const char *pathname, int pathlen,
int *dtype_p) const char *basename, int *dtype_p)
{ {
int i, j; int i, j;
struct exclude_list_group *group; struct exclude_list_group *group;
struct exclude *exclude; struct path_pattern *pattern;
for (i = EXC_CMDL; i <= EXC_FILE; i++) { for (i = EXC_CMDL; i <= EXC_FILE; i++) {
group = &dir->exclude_list_group[i]; group = &dir->exclude_list_group[i];
for (j = group->nr - 1; j >= 0; j--) { for (j = group->nr - 1; j >= 0; j--) {
exclude = last_exclude_matching_from_list( pattern = last_matching_pattern_from_list(
pathname, pathlen, basename, dtype_p, pathname, pathlen, basename, dtype_p,
&group->el[j], istate); &group->pl[j], istate);
if (exclude) if (pattern)
return exclude; return pattern;
} }
} }
return NULL; return NULL;
@ -1114,7 +1126,7 @@ static void prep_exclude(struct dir_struct *dir,
const char *base, int baselen) const char *base, int baselen)
{ {
struct exclude_list_group *group; struct exclude_list_group *group;
struct exclude_list *el; struct pattern_list *pl;
struct exclude_stack *stk = NULL; struct exclude_stack *stk = NULL;
struct untracked_cache_dir *untracked; struct untracked_cache_dir *untracked;
int current; int current;
@ -1130,17 +1142,17 @@ static void prep_exclude(struct dir_struct *dir,
if (stk->baselen <= baselen && if (stk->baselen <= baselen &&
!strncmp(dir->basebuf.buf, base, stk->baselen)) !strncmp(dir->basebuf.buf, base, stk->baselen))
break; break;
el = &group->el[dir->exclude_stack->exclude_ix]; pl = &group->pl[dir->exclude_stack->exclude_ix];
dir->exclude_stack = stk->prev; dir->exclude_stack = stk->prev;
dir->exclude = NULL; dir->pattern = NULL;
free((char *)el->src); /* see strbuf_detach() below */ free((char *)pl->src); /* see strbuf_detach() below */
clear_exclude_list(el); clear_pattern_list(pl);
free(stk); free(stk);
group->nr--; group->nr--;
} }
/* Skip traversing into sub directories if the parent is excluded */ /* Skip traversing into sub directories if the parent is excluded */
if (dir->exclude) if (dir->pattern)
return; return;
/* /*
@ -1181,7 +1193,7 @@ static void prep_exclude(struct dir_struct *dir,
stk->baselen = cp - base; stk->baselen = cp - base;
stk->exclude_ix = group->nr; stk->exclude_ix = group->nr;
stk->ucd = untracked; stk->ucd = untracked;
el = add_exclude_list(dir, EXC_DIRS, NULL); pl = add_pattern_list(dir, EXC_DIRS, NULL);
strbuf_add(&dir->basebuf, base + current, stk->baselen - current); strbuf_add(&dir->basebuf, base + current, stk->baselen - current);
assert(stk->baselen == dir->basebuf.len); assert(stk->baselen == dir->basebuf.len);
@ -1189,15 +1201,15 @@ static void prep_exclude(struct dir_struct *dir,
if (stk->baselen) { if (stk->baselen) {
int dt = DT_DIR; int dt = DT_DIR;
dir->basebuf.buf[stk->baselen - 1] = 0; dir->basebuf.buf[stk->baselen - 1] = 0;
dir->exclude = last_exclude_matching_from_lists(dir, dir->pattern = last_matching_pattern_from_lists(dir,
istate, istate,
dir->basebuf.buf, stk->baselen - 1, dir->basebuf.buf, stk->baselen - 1,
dir->basebuf.buf + current, &dt); dir->basebuf.buf + current, &dt);
dir->basebuf.buf[stk->baselen - 1] = '/'; dir->basebuf.buf[stk->baselen - 1] = '/';
if (dir->exclude && if (dir->pattern &&
dir->exclude->flags & EXC_FLAG_NEGATIVE) dir->pattern->flags & PATTERN_FLAG_NEGATIVE)
dir->exclude = NULL; dir->pattern = NULL;
if (dir->exclude) { if (dir->pattern) {
dir->exclude_stack = stk; dir->exclude_stack = stk;
return; return;
} }
@ -1223,30 +1235,30 @@ static void prep_exclude(struct dir_struct *dir,
/* /*
* dir->basebuf gets reused by the traversal, but we * dir->basebuf gets reused by the traversal, but we
* need fname to remain unchanged to ensure the src * need fname to remain unchanged to ensure the src
* member of each struct exclude correctly * member of each struct path_pattern correctly
* back-references its source file. Other invocations * back-references its source file. Other invocations
* of add_exclude_list provide stable strings, so we * of add_pattern_list provide stable strings, so we
* strbuf_detach() and free() here in the caller. * strbuf_detach() and free() here in the caller.
*/ */
struct strbuf sb = STRBUF_INIT; struct strbuf sb = STRBUF_INIT;
strbuf_addbuf(&sb, &dir->basebuf); strbuf_addbuf(&sb, &dir->basebuf);
strbuf_addstr(&sb, dir->exclude_per_dir); strbuf_addstr(&sb, dir->exclude_per_dir);
el->src = strbuf_detach(&sb, NULL); pl->src = strbuf_detach(&sb, NULL);
add_excludes(el->src, el->src, stk->baselen, el, istate, add_patterns(pl->src, pl->src, stk->baselen, pl, istate,
untracked ? &oid_stat : NULL); untracked ? &oid_stat : NULL);
} }
/* /*
* NEEDSWORK: when untracked cache is enabled, prep_exclude() * NEEDSWORK: when untracked cache is enabled, prep_exclude()
* will first be called in valid_cached_dir() then maybe many * will first be called in valid_cached_dir() then maybe many
* times more in last_exclude_matching(). When the cache is * times more in last_matching_pattern(). When the cache is
* used, last_exclude_matching() will not be called and * used, last_matching_pattern() will not be called and
* reading .gitignore content will be a waste. * reading .gitignore content will be a waste.
* *
* So when it's called by valid_cached_dir() and we can get * So when it's called by valid_cached_dir() and we can get
* .gitignore SHA-1 from the index (i.e. .gitignore is not * .gitignore SHA-1 from the index (i.e. .gitignore is not
* modified on work tree), we could delay reading the * modified on work tree), we could delay reading the
* .gitignore content until we absolutely need it in * .gitignore content until we absolutely need it in
* last_exclude_matching(). Be careful about ignore rule * last_matching_pattern(). Be careful about ignore rule
* order, though, if you do that. * order, though, if you do that.
*/ */
if (untracked && if (untracked &&
@ -1266,7 +1278,7 @@ static void prep_exclude(struct dir_struct *dir,
* Returns the exclude_list element which matched, or NULL for * Returns the exclude_list element which matched, or NULL for
* undecided. * undecided.
*/ */
struct exclude *last_exclude_matching(struct dir_struct *dir, struct path_pattern *last_matching_pattern(struct dir_struct *dir,
struct index_state *istate, struct index_state *istate,
const char *pathname, const char *pathname,
int *dtype_p) int *dtype_p)
@ -1277,10 +1289,10 @@ struct exclude *last_exclude_matching(struct dir_struct *dir,
prep_exclude(dir, istate, pathname, basename-pathname); prep_exclude(dir, istate, pathname, basename-pathname);
if (dir->exclude) if (dir->pattern)
return dir->exclude; return dir->pattern;
return last_exclude_matching_from_lists(dir, istate, pathname, pathlen, return last_matching_pattern_from_lists(dir, istate, pathname, pathlen,
basename, dtype_p); basename, dtype_p);
} }
@ -1292,10 +1304,10 @@ struct exclude *last_exclude_matching(struct dir_struct *dir,
int is_excluded(struct dir_struct *dir, struct index_state *istate, int is_excluded(struct dir_struct *dir, struct index_state *istate,
const char *pathname, int *dtype_p) const char *pathname, int *dtype_p)
{ {
struct exclude *exclude = struct path_pattern *pattern =
last_exclude_matching(dir, istate, pathname, dtype_p); last_matching_pattern(dir, istate, pathname, dtype_p);
if (exclude) if (pattern)
return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1; return pattern->flags & PATTERN_FLAG_NEGATIVE ? 0 : 1;
return 0; return 0;
} }
@ -1808,7 +1820,7 @@ static int valid_cached_dir(struct dir_struct *dir,
/* /*
* prep_exclude will be called eventually on this directory, * prep_exclude will be called eventually on this directory,
* but it's called much later in last_exclude_matching(). We * but it's called much later in last_matching_pattern(). We
* need it now to determine the validity of the cache for this * need it now to determine the validity of the cache for this
* path. The next calls will be nearly no-op, the way * path. The next calls will be nearly no-op, the way
* prep_exclude() is designed. * prep_exclude() is designed.
@ -2488,14 +2500,14 @@ void setup_standard_excludes(struct dir_struct *dir)
if (!excludes_file) if (!excludes_file)
excludes_file = xdg_config_home("ignore"); excludes_file = xdg_config_home("ignore");
if (excludes_file && !access_or_warn(excludes_file, R_OK, 0)) if (excludes_file && !access_or_warn(excludes_file, R_OK, 0))
add_excludes_from_file_1(dir, excludes_file, add_patterns_from_file_1(dir, excludes_file,
dir->untracked ? &dir->ss_excludes_file : NULL); dir->untracked ? &dir->ss_excludes_file : NULL);
/* per repository user preference */ /* per repository user preference */
if (startup_info->have_repository) { if (startup_info->have_repository) {
const char *path = git_path_info_exclude(); const char *path = git_path_info_exclude();
if (!access_or_warn(path, R_OK, 0)) if (!access_or_warn(path, R_OK, 0))
add_excludes_from_file_1(dir, path, add_patterns_from_file_1(dir, path,
dir->untracked ? &dir->ss_info_exclude : NULL); dir->untracked ? &dir->ss_info_exclude : NULL);
} }
} }
@ -2527,18 +2539,18 @@ void clear_directory(struct dir_struct *dir)
{ {
int i, j; int i, j;
struct exclude_list_group *group; struct exclude_list_group *group;
struct exclude_list *el; struct pattern_list *pl;
struct exclude_stack *stk; struct exclude_stack *stk;
for (i = EXC_CMDL; i <= EXC_FILE; i++) { for (i = EXC_CMDL; i <= EXC_FILE; i++) {
group = &dir->exclude_list_group[i]; group = &dir->exclude_list_group[i];
for (j = 0; j < group->nr; j++) { for (j = 0; j < group->nr; j++) {
el = &group->el[j]; pl = &group->pl[j];
if (i == EXC_DIRS) if (i == EXC_DIRS)
free((char *)el->src); free((char *)pl->src);
clear_exclude_list(el); clear_pattern_list(pl);
} }
free(group->el); free(group->pl);
} }
stk = dir->exclude_stack; stk = dir->exclude_stack;

71
dir.h
View file

@ -11,24 +11,24 @@ struct dir_entry {
char name[FLEX_ARRAY]; /* more */ char name[FLEX_ARRAY]; /* more */
}; };
#define EXC_FLAG_NODIR 1 #define PATTERN_FLAG_NODIR 1
#define EXC_FLAG_ENDSWITH 4 #define PATTERN_FLAG_ENDSWITH 4
#define EXC_FLAG_MUSTBEDIR 8 #define PATTERN_FLAG_MUSTBEDIR 8
#define EXC_FLAG_NEGATIVE 16 #define PATTERN_FLAG_NEGATIVE 16
struct exclude { struct path_pattern {
/* /*
* This allows callers of last_exclude_matching() etc. * This allows callers of last_matching_pattern() etc.
* to determine the origin of the matching pattern. * to determine the origin of the matching pattern.
*/ */
struct exclude_list *el; struct pattern_list *pl;
const char *pattern; const char *pattern;
int patternlen; int patternlen;
int nowildcardlen; int nowildcardlen;
const char *base; const char *base;
int baselen; int baselen;
unsigned flags; /* EXC_FLAG_* */ unsigned flags; /* PATTERN_FLAG_* */
/* /*
* Counting starts from 1 for line numbers in ignore files, * Counting starts from 1 for line numbers in ignore files,
@ -44,7 +44,7 @@ struct exclude {
* can also be used to represent the list of --exclude values passed * can also be used to represent the list of --exclude values passed
* via CLI args. * via CLI args.
*/ */
struct exclude_list { struct pattern_list {
int nr; int nr;
int alloc; int alloc;
@ -54,7 +54,7 @@ struct exclude_list {
/* origin of list, e.g. path to filename, or descriptive string */ /* origin of list, e.g. path to filename, or descriptive string */
const char *src; const char *src;
struct exclude **excludes; struct path_pattern **patterns;
}; };
/* /*
@ -72,7 +72,7 @@ struct exclude_stack {
struct exclude_list_group { struct exclude_list_group {
int nr, alloc; int nr, alloc;
struct exclude_list *el; struct pattern_list *pl;
}; };
struct oid_stat { struct oid_stat {
@ -191,7 +191,7 @@ struct dir_struct {
* matching exclude struct if the directory is excluded. * matching exclude struct if the directory is excluded.
*/ */
struct exclude_stack *exclude_stack; struct exclude_stack *exclude_stack;
struct exclude *exclude; struct path_pattern *pattern;
struct strbuf basebuf; struct strbuf basebuf;
/* Enable untracked file cache if set */ /* Enable untracked file cache if set */
@ -230,10 +230,23 @@ int read_directory(struct dir_struct *, struct index_state *istate,
const char *path, int len, const char *path, int len,
const struct pathspec *pathspec); const struct pathspec *pathspec);
int is_excluded_from_list(const char *pathname, int pathlen, enum pattern_match_result {
const char *basename, int *dtype, UNDECIDED = -1,
struct exclude_list *el, NOT_MATCHED = 0,
struct index_state *istate); MATCHED = 1,
};
/*
* Scan the list of patterns to determine if the ordered list
* of patterns matches on 'pathname'.
*
* Return 1 for a match, 0 for not matched and -1 for undecided.
*/
enum pattern_match_result path_matches_pattern_list(const char *pathname,
int pathlen,
const char *basename, int *dtype,
struct pattern_list *pl,
struct index_state *istate);
struct dir_entry *dir_add_ignored(struct dir_struct *dir, struct dir_entry *dir_add_ignored(struct dir_struct *dir,
struct index_state *istate, struct index_state *istate,
const char *pathname, int len); const char *pathname, int len);
@ -248,26 +261,26 @@ int match_pathname(const char *, int,
const char *, int, const char *, int,
const char *, int, int, unsigned); const char *, int, int, unsigned);
struct exclude *last_exclude_matching(struct dir_struct *dir, struct path_pattern *last_matching_pattern(struct dir_struct *dir,
struct index_state *istate, struct index_state *istate,
const char *name, int *dtype); const char *name, int *dtype);
int is_excluded(struct dir_struct *dir, int is_excluded(struct dir_struct *dir,
struct index_state *istate, struct index_state *istate,
const char *name, int *dtype); const char *name, int *dtype);
struct exclude_list *add_exclude_list(struct dir_struct *dir, struct pattern_list *add_pattern_list(struct dir_struct *dir,
int group_type, const char *src); int group_type, const char *src);
int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen, int add_patterns_from_file_to_list(const char *fname, const char *base, int baselen,
struct exclude_list *el, struct index_state *istate); struct pattern_list *pl, struct index_state *istate);
void add_excludes_from_file(struct dir_struct *, const char *fname); void add_patterns_from_file(struct dir_struct *, const char *fname);
int add_excludes_from_blob_to_list(struct object_id *oid, int add_patterns_from_blob_to_list(struct object_id *oid,
const char *base, int baselen, const char *base, int baselen,
struct exclude_list *el); struct pattern_list *pl);
void parse_exclude_pattern(const char **string, int *patternlen, unsigned *flags, int *nowildcardlen); void parse_path_pattern(const char **string, int *patternlen, unsigned *flags, int *nowildcardlen);
void add_exclude(const char *string, const char *base, void add_pattern(const char *string, const char *base,
int baselen, struct exclude_list *el, int srcpos); int baselen, struct pattern_list *pl, int srcpos);
void clear_exclude_list(struct exclude_list *el); void clear_pattern_list(struct pattern_list *pl);
void clear_directory(struct dir_struct *dir); void clear_directory(struct dir_struct *dir);
int repo_file_exists(struct repository *repo, const char *path); int repo_file_exists(struct repository *repo, const char *path);

View file

@ -328,12 +328,12 @@ static void filter_blobs_limit__init(
*/ */
struct frame { struct frame {
/* /*
* defval is the usual default include/exclude value that * default_match is the usual default include/exclude value that
* should be inherited as we recurse into directories based * should be inherited as we recurse into directories based
* upon pattern matching of the directory itself or of a * upon pattern matching of the directory itself or of a
* containing directory. * containing directory.
*/ */
int defval; enum pattern_match_result default_match;
/* /*
* 1 if the directory (recursively) contains any provisionally * 1 if the directory (recursively) contains any provisionally
@ -347,7 +347,7 @@ struct frame {
}; };
struct filter_sparse_data { struct filter_sparse_data {
struct exclude_list el; struct pattern_list pl;
size_t nr, alloc; size_t nr, alloc;
struct frame *array_frame; struct frame *array_frame;
@ -363,8 +363,9 @@ static enum list_objects_filter_result filter_sparse(
void *filter_data_) void *filter_data_)
{ {
struct filter_sparse_data *filter_data = filter_data_; struct filter_sparse_data *filter_data = filter_data_;
int val, dtype; int dtype;
struct frame *frame; struct frame *frame;
enum pattern_match_result match;
switch (filter_situation) { switch (filter_situation) {
default: default:
@ -373,15 +374,15 @@ static enum list_objects_filter_result filter_sparse(
case LOFS_BEGIN_TREE: case LOFS_BEGIN_TREE:
assert(obj->type == OBJ_TREE); assert(obj->type == OBJ_TREE);
dtype = DT_DIR; dtype = DT_DIR;
val = is_excluded_from_list(pathname, strlen(pathname), match = path_matches_pattern_list(pathname, strlen(pathname),
filename, &dtype, &filter_data->el, filename, &dtype, &filter_data->pl,
r->index); r->index);
if (val < 0) if (match == UNDECIDED)
val = filter_data->array_frame[filter_data->nr - 1].defval; match = filter_data->array_frame[filter_data->nr - 1].default_match;
ALLOC_GROW(filter_data->array_frame, filter_data->nr + 1, ALLOC_GROW(filter_data->array_frame, filter_data->nr + 1,
filter_data->alloc); filter_data->alloc);
filter_data->array_frame[filter_data->nr].defval = val; filter_data->array_frame[filter_data->nr].default_match = match;
filter_data->array_frame[filter_data->nr].child_prov_omit = 0; filter_data->array_frame[filter_data->nr].child_prov_omit = 0;
filter_data->nr++; filter_data->nr++;
@ -435,12 +436,12 @@ static enum list_objects_filter_result filter_sparse(
frame = &filter_data->array_frame[filter_data->nr - 1]; frame = &filter_data->array_frame[filter_data->nr - 1];
dtype = DT_REG; dtype = DT_REG;
val = is_excluded_from_list(pathname, strlen(pathname), match = path_matches_pattern_list(pathname, strlen(pathname),
filename, &dtype, &filter_data->el, filename, &dtype, &filter_data->pl,
r->index); r->index);
if (val < 0) if (match == UNDECIDED)
val = frame->defval; match = frame->default_match;
if (val > 0) { if (match == MATCHED) {
if (omits) if (omits)
oidset_remove(omits, &obj->oid); oidset_remove(omits, &obj->oid);
return LOFR_MARK_SEEN | LOFR_DO_SHOW; return LOFR_MARK_SEEN | LOFR_DO_SHOW;
@ -482,12 +483,12 @@ static void filter_sparse_oid__init(
struct filter *filter) struct filter *filter)
{ {
struct filter_sparse_data *d = xcalloc(1, sizeof(*d)); struct filter_sparse_data *d = xcalloc(1, sizeof(*d));
if (add_excludes_from_blob_to_list(filter_options->sparse_oid_value, if (add_patterns_from_blob_to_list(filter_options->sparse_oid_value,
NULL, 0, &d->el) < 0) NULL, 0, &d->pl) < 0)
die("could not load filter specification"); die("could not load filter specification");
ALLOC_GROW(d->array_frame, d->nr + 1, d->alloc); ALLOC_GROW(d->array_frame, d->nr + 1, d->alloc);
d->array_frame[d->nr].defval = 0; /* default to include */ d->array_frame[d->nr].default_match = 0; /* default to include */
d->array_frame[d->nr].child_prov_omit = 0; d->array_frame[d->nr].child_prov_omit = 0;
d->nr++; d->nr++;

View file

@ -1269,7 +1269,8 @@ static int clear_ce_flags_1(struct index_state *istate,
struct cache_entry **cache, int nr, struct cache_entry **cache, int nr,
struct strbuf *prefix, struct strbuf *prefix,
int select_mask, int clear_mask, int select_mask, int clear_mask,
struct exclude_list *el, int defval); struct pattern_list *pl,
enum pattern_match_result default_match);
/* Whole directory matching */ /* Whole directory matching */
static int clear_ce_flags_dir(struct index_state *istate, static int clear_ce_flags_dir(struct index_state *istate,
@ -1277,19 +1278,21 @@ static int clear_ce_flags_dir(struct index_state *istate,
struct strbuf *prefix, struct strbuf *prefix,
char *basename, char *basename,
int select_mask, int clear_mask, int select_mask, int clear_mask,
struct exclude_list *el, int defval) struct pattern_list *pl,
enum pattern_match_result default_match)
{ {
struct cache_entry **cache_end; struct cache_entry **cache_end;
int dtype = DT_DIR; int dtype = DT_DIR;
int ret = is_excluded_from_list(prefix->buf, prefix->len,
basename, &dtype, el, istate);
int rc; int rc;
enum pattern_match_result ret;
ret = path_matches_pattern_list(prefix->buf, prefix->len,
basename, &dtype, pl, istate);
strbuf_addch(prefix, '/'); strbuf_addch(prefix, '/');
/* If undecided, use matching result of parent dir in defval */ /* If undecided, use matching result of parent dir in defval */
if (ret < 0) if (ret == UNDECIDED)
ret = defval; ret = default_match;
for (cache_end = cache; cache_end != cache + nr; cache_end++) { for (cache_end = cache; cache_end != cache + nr; cache_end++) {
struct cache_entry *ce = *cache_end; struct cache_entry *ce = *cache_end;
@ -1298,23 +1301,23 @@ static int clear_ce_flags_dir(struct index_state *istate,
} }
/* /*
* TODO: check el, if there are no patterns that may conflict * TODO: check pl, if there are no patterns that may conflict
* with ret (iow, we know in advance the incl/excl * with ret (iow, we know in advance the incl/excl
* decision for the entire directory), clear flag here without * decision for the entire directory), clear flag here without
* calling clear_ce_flags_1(). That function will call * calling clear_ce_flags_1(). That function will call
* the expensive is_excluded_from_list() on every entry. * the expensive path_matches_pattern_list() on every entry.
*/ */
rc = clear_ce_flags_1(istate, cache, cache_end - cache, rc = clear_ce_flags_1(istate, cache, cache_end - cache,
prefix, prefix,
select_mask, clear_mask, select_mask, clear_mask,
el, ret); pl, ret);
strbuf_setlen(prefix, prefix->len - 1); strbuf_setlen(prefix, prefix->len - 1);
return rc; return rc;
} }
/* /*
* Traverse the index, find every entry that matches according to * Traverse the index, find every entry that matches according to
* o->el. Do "ce_flags &= ~clear_mask" on those entries. Return the * o->pl. Do "ce_flags &= ~clear_mask" on those entries. Return the
* number of traversed entries. * number of traversed entries.
* *
* If select_mask is non-zero, only entries whose ce_flags has on of * If select_mask is non-zero, only entries whose ce_flags has on of
@ -1331,7 +1334,8 @@ static int clear_ce_flags_1(struct index_state *istate,
struct cache_entry **cache, int nr, struct cache_entry **cache, int nr,
struct strbuf *prefix, struct strbuf *prefix,
int select_mask, int clear_mask, int select_mask, int clear_mask,
struct exclude_list *el, int defval) struct pattern_list *pl,
enum pattern_match_result default_match)
{ {
struct cache_entry **cache_end = cache + nr; struct cache_entry **cache_end = cache + nr;
@ -1342,7 +1346,8 @@ static int clear_ce_flags_1(struct index_state *istate,
while(cache != cache_end) { while(cache != cache_end) {
struct cache_entry *ce = *cache; struct cache_entry *ce = *cache;
const char *name, *slash; const char *name, *slash;
int len, dtype, ret; int len, dtype;
enum pattern_match_result ret;
if (select_mask && !(ce->ce_flags & select_mask)) { if (select_mask && !(ce->ce_flags & select_mask)) {
cache++; cache++;
@ -1366,7 +1371,7 @@ static int clear_ce_flags_1(struct index_state *istate,
prefix, prefix,
prefix->buf + prefix->len - len, prefix->buf + prefix->len - len,
select_mask, clear_mask, select_mask, clear_mask,
el, defval); pl, default_match);
/* clear_c_f_dir eats a whole dir already? */ /* clear_c_f_dir eats a whole dir already? */
if (processed) { if (processed) {
@ -1378,18 +1383,20 @@ static int clear_ce_flags_1(struct index_state *istate,
strbuf_addch(prefix, '/'); strbuf_addch(prefix, '/');
cache += clear_ce_flags_1(istate, cache, cache_end - cache, cache += clear_ce_flags_1(istate, cache, cache_end - cache,
prefix, prefix,
select_mask, clear_mask, el, defval); select_mask, clear_mask, pl,
default_match);
strbuf_setlen(prefix, prefix->len - len - 1); strbuf_setlen(prefix, prefix->len - len - 1);
continue; continue;
} }
/* Non-directory */ /* Non-directory */
dtype = ce_to_dtype(ce); dtype = ce_to_dtype(ce);
ret = is_excluded_from_list(ce->name, ce_namelen(ce), ret = path_matches_pattern_list(ce->name,
name, &dtype, el, istate); ce_namelen(ce),
if (ret < 0) name, &dtype, pl, istate);
ret = defval; if (ret == UNDECIDED)
if (ret > 0) ret = default_match;
if (ret == MATCHED)
ce->ce_flags &= ~clear_mask; ce->ce_flags &= ~clear_mask;
cache++; cache++;
} }
@ -1398,7 +1405,7 @@ static int clear_ce_flags_1(struct index_state *istate,
static int clear_ce_flags(struct index_state *istate, static int clear_ce_flags(struct index_state *istate,
int select_mask, int clear_mask, int select_mask, int clear_mask,
struct exclude_list *el) struct pattern_list *pl)
{ {
static struct strbuf prefix = STRBUF_INIT; static struct strbuf prefix = STRBUF_INIT;
@ -1409,13 +1416,13 @@ static int clear_ce_flags(struct index_state *istate,
istate->cache_nr, istate->cache_nr,
&prefix, &prefix,
select_mask, clear_mask, select_mask, clear_mask,
el, 0); pl, 0);
} }
/* /*
* Set/Clear CE_NEW_SKIP_WORKTREE according to $GIT_DIR/info/sparse-checkout * Set/Clear CE_NEW_SKIP_WORKTREE according to $GIT_DIR/info/sparse-checkout
*/ */
static void mark_new_skip_worktree(struct exclude_list *el, static void mark_new_skip_worktree(struct pattern_list *pl,
struct index_state *istate, struct index_state *istate,
int select_flag, int skip_wt_flag) int select_flag, int skip_wt_flag)
{ {
@ -1441,7 +1448,7 @@ static void mark_new_skip_worktree(struct exclude_list *el,
* 2. Widen worktree according to sparse-checkout file. * 2. Widen worktree according to sparse-checkout file.
* Matched entries will have skip_wt_flag cleared (i.e. "in") * Matched entries will have skip_wt_flag cleared (i.e. "in")
*/ */
clear_ce_flags(istate, select_flag, skip_wt_flag, el); clear_ce_flags(istate, select_flag, skip_wt_flag, pl);
} }
static int verify_absent(const struct cache_entry *, static int verify_absent(const struct cache_entry *,
@ -1457,21 +1464,21 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
{ {
int i, ret; int i, ret;
static struct cache_entry *dfc; static struct cache_entry *dfc;
struct exclude_list el; struct pattern_list pl;
if (len > MAX_UNPACK_TREES) if (len > MAX_UNPACK_TREES)
die("unpack_trees takes at most %d trees", MAX_UNPACK_TREES); die("unpack_trees takes at most %d trees", MAX_UNPACK_TREES);
trace_performance_enter(); trace_performance_enter();
memset(&el, 0, sizeof(el)); memset(&pl, 0, sizeof(pl));
if (!core_apply_sparse_checkout || !o->update) if (!core_apply_sparse_checkout || !o->update)
o->skip_sparse_checkout = 1; o->skip_sparse_checkout = 1;
if (!o->skip_sparse_checkout) { if (!o->skip_sparse_checkout) {
char *sparse = git_pathdup("info/sparse-checkout"); char *sparse = git_pathdup("info/sparse-checkout");
if (add_excludes_from_file_to_list(sparse, "", 0, &el, NULL) < 0) if (add_patterns_from_file_to_list(sparse, "", 0, &pl, NULL) < 0)
o->skip_sparse_checkout = 1; o->skip_sparse_checkout = 1;
else else
o->el = &el; o->pl = &pl;
free(sparse); free(sparse);
} }
@ -1502,7 +1509,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
* Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries * Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries
*/ */
if (!o->skip_sparse_checkout) if (!o->skip_sparse_checkout)
mark_new_skip_worktree(o->el, o->src_index, 0, CE_NEW_SKIP_WORKTREE); mark_new_skip_worktree(o->pl, o->src_index, 0, CE_NEW_SKIP_WORKTREE);
if (!dfc) if (!dfc)
dfc = xcalloc(1, cache_entry_size(0)); dfc = xcalloc(1, cache_entry_size(0));
@ -1567,7 +1574,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
* If the will have NEW_SKIP_WORKTREE, also set CE_SKIP_WORKTREE * If the will have NEW_SKIP_WORKTREE, also set CE_SKIP_WORKTREE
* so apply_sparse_checkout() won't attempt to remove it from worktree * so apply_sparse_checkout() won't attempt to remove it from worktree
*/ */
mark_new_skip_worktree(o->el, &o->result, CE_ADDED, CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE); mark_new_skip_worktree(o->pl, &o->result, CE_ADDED, CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
ret = 0; ret = 0;
for (i = 0; i < o->result.cache_nr; i++) { for (i = 0; i < o->result.cache_nr; i++) {
@ -1635,7 +1642,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
done: done:
trace_performance_leave("unpack_trees"); trace_performance_leave("unpack_trees");
clear_exclude_list(&el); clear_pattern_list(&pl);
return ret; return ret;
return_failed: return_failed:

View file

@ -10,7 +10,7 @@
struct cache_entry; struct cache_entry;
struct unpack_trees_options; struct unpack_trees_options;
struct exclude_list; struct pattern_list;
typedef int (*merge_fn_t)(const struct cache_entry * const *src, typedef int (*merge_fn_t)(const struct cache_entry * const *src,
struct unpack_trees_options *options); struct unpack_trees_options *options);
@ -83,7 +83,7 @@ struct unpack_trees_options {
struct index_state *src_index; struct index_state *src_index;
struct index_state result; struct index_state result;
struct exclude_list *el; /* for internal use */ struct pattern_list *pl; /* for internal use */
}; };
int unpack_trees(unsigned n, struct tree_desc *t, int unpack_trees(unsigned n, struct tree_desc *t,