Skip to content

Commit c62a917

Browse files
pcloudsgitster
authored andcommitted
dir.c: support marking some patterns already matched
Given path "a" and the pattern "a", it's matched. But if we throw path "a/b" to pattern "a", the code fails to realize that if "a" matches "a" then "a/b" should also be matched. When the pattern is matched the first time, we can mark it "sticky", so that all files and dirs inside the matched path also matches. This is a simpler solution than modify all match scenarios to fix that. Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent bac65a2 commit c62a917

File tree

2 files changed

+77
-3
lines changed

2 files changed

+77
-3
lines changed

dir.c

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ void add_exclude(const char *string, const char *base,
521521
x->baselen = baselen;
522522
x->flags = flags;
523523
x->srcpos = srcpos;
524+
string_list_init(&x->sticky_paths, 1);
524525
ALLOC_GROW(el->excludes, el->nr + 1, el->alloc);
525526
el->excludes[el->nr++] = x;
526527
x->el = el;
@@ -561,8 +562,10 @@ void clear_exclude_list(struct exclude_list *el)
561562
{
562563
int i;
563564

564-
for (i = 0; i < el->nr; i++)
565+
for (i = 0; i < el->nr; i++) {
566+
string_list_clear(&el->excludes[i]->sticky_paths, 0);
565567
free(el->excludes[i]);
568+
}
566569
free(el->excludes);
567570
free(el->filebuf);
568571

@@ -889,6 +892,44 @@ int match_pathname(const char *pathname, int pathlen,
889892
WM_PATHNAME) == 0;
890893
}
891894

895+
static void add_sticky(struct exclude *exc, const char *pathname, int pathlen)
896+
{
897+
struct strbuf sb = STRBUF_INIT;
898+
int i;
899+
900+
for (i = exc->sticky_paths.nr - 1; i >= 0; i--) {
901+
const char *sticky = exc->sticky_paths.items[i].string;
902+
int len = strlen(sticky);
903+
904+
if (pathlen < len && sticky[pathlen] == '/' &&
905+
!strncmp(pathname, sticky, pathlen))
906+
return;
907+
}
908+
909+
strbuf_add(&sb, pathname, pathlen);
910+
string_list_append_nodup(&exc->sticky_paths, strbuf_detach(&sb, NULL));
911+
}
912+
913+
static int match_sticky(struct exclude *exc, const char *pathname, int pathlen, int dtype)
914+
{
915+
int i;
916+
917+
for (i = exc->sticky_paths.nr - 1; i >= 0; i--) {
918+
const char *sticky = exc->sticky_paths.items[i].string;
919+
int len = strlen(sticky);
920+
921+
if (pathlen == len && dtype == DT_DIR &&
922+
!strncmp(pathname, sticky, len))
923+
return 1;
924+
925+
if (pathlen > len && pathname[len] == '/' &&
926+
!strncmp(pathname, sticky, len))
927+
return 1;
928+
}
929+
930+
return 0;
931+
}
932+
892933
/*
893934
* Scan the given exclude list in reverse to see whether pathname
894935
* should be ignored. The first match (i.e. the last on the list), if
@@ -914,6 +955,16 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
914955
const char *exclude = x->pattern;
915956
int prefix = x->nowildcardlen;
916957

958+
if (x->sticky_paths.nr) {
959+
if (*dtype == DT_UNKNOWN)
960+
*dtype = get_dtype(NULL, pathname, pathlen);
961+
if (match_sticky(x, pathname, pathlen, *dtype)) {
962+
exc = x;
963+
break;
964+
}
965+
continue;
966+
}
967+
917968
if (x->flags & EXC_FLAG_MUSTBEDIR) {
918969
if (*dtype == DT_UNKNOWN)
919970
*dtype = get_dtype(NULL, pathname, pathlen);
@@ -947,9 +998,10 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
947998
return NULL;
948999
}
9491000

950-
trace_printf_key(&trace_exclude, "exclude: %.*s vs %s at line %d => %s\n",
1001+
trace_printf_key(&trace_exclude, "exclude: %.*s vs %s at line %d => %s%s\n",
9511002
pathlen, pathname, exc->pattern, exc->srcpos,
952-
exc->flags & EXC_FLAG_NEGATIVE ? "no" : "yes");
1003+
exc->flags & EXC_FLAG_NEGATIVE ? "no" : "yes",
1004+
exc->sticky_paths.nr ? " (stuck)" : "");
9531005
return exc;
9541006
}
9551007

@@ -2005,6 +2057,25 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
20052057
return root;
20062058
}
20072059

2060+
static void clear_sticky(struct dir_struct *dir)
2061+
{
2062+
struct exclude_list_group *g;
2063+
struct exclude_list *el;
2064+
struct exclude *x;
2065+
int i, j, k;
2066+
2067+
for (i = EXC_CMDL; i <= EXC_FILE; i++) {
2068+
g = &dir->exclude_list_group[i];
2069+
for (j = g->nr - 1; j >= 0; j--) {
2070+
el = &g->el[j];
2071+
for (k = el->nr - 1; 0 <= k; k--) {
2072+
x = el->excludes[k];
2073+
string_list_clear(&x->sticky_paths, 0);
2074+
}
2075+
}
2076+
}
2077+
}
2078+
20082079
int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)
20092080
{
20102081
struct path_simplify *simplify;

dir.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
/* See Documentation/technical/api-directory-listing.txt */
55

66
#include "strbuf.h"
7+
#include "string-list.h"
78

89
struct dir_entry {
910
unsigned int len;
@@ -34,6 +35,8 @@ struct exclude {
3435
* and from -1 decrementing for patterns from CLI args.
3536
*/
3637
int srcpos;
38+
39+
struct string_list sticky_paths;
3740
};
3841

3942
/*

0 commit comments

Comments
 (0)