From eb41775ecc031cd8e38aebbd26826d74922a0db9 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 1 Jun 2012 11:28:00 -0700 Subject: ls-files -i: pay attention to exclusion of leading paths "git ls-files --exclude=t/ -i" does not show paths in directory t/ that have been added to the index, but it should. The excluded() API was designed for callers who walk the tree from the top, checking each level of the directory hierarchy as it descends if it is excluded, and not even bothering to recurse into an excluded directory. This would allow us optimize for a common case by not having to check if the exclude pattern "foo/" matches when looking at "foo/bar", because the caller should have noticed that "foo" is excluded and did not even bother to read "foo/bar" out of opendir()/readdir() to call it. The code for "ls-files -i" however walks the index linearly, feeding paths without checking if the leading directory is already excluded. Introduce a helper function path_excluded() to let this caller properly call excluded() check for higher hierarchies as necessary. Signed-off-by: Junio C Hamano --- dir.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'dir.h') diff --git a/dir.h b/dir.h index dd6947e1d4..7378e69c17 100644 --- a/dir.h +++ b/dir.h @@ -1,6 +1,8 @@ #ifndef DIR_H #define DIR_H +#include "strbuf.h" + struct dir_entry { unsigned int len; char name[FLEX_ARRAY]; /* more */ @@ -78,6 +80,20 @@ extern int excluded_from_list(const char *pathname, int pathlen, const char *bas int *dtype, struct exclude_list *el); extern int excluded(struct dir_struct *, const char *, int *); struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len); + +/* + * The excluded() API is meant for callers that check each level of leading + * directory hierarchies with excluded() to avoid recursing into excluded + * directories. Callers that do not do so should use this API instead. + */ +struct path_exclude_check { + struct dir_struct *dir; + struct strbuf path; +}; +extern void path_exclude_check_init(struct path_exclude_check *, struct dir_struct *); +extern void path_exclude_check_clear(struct path_exclude_check *); +extern int path_excluded(struct path_exclude_check *, struct cache_entry *); + extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen, char **buf_p, struct exclude_list *which, int check_index); extern void add_excludes_from_file(struct dir_struct *, const char *fname); -- cgit v1.3-5-g9baa From 782cd4c0f6e0fef5147cb738009dde6e778f4932 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 5 Jun 2012 21:17:52 -0700 Subject: path_excluded(): update API to less cache-entry centric It was stupid of me to make the API too much cache-entry specific; the caller may want to check arbitrary pathname without having a corresponding cache-entry to see if a path is ignored. Signed-off-by: Junio C Hamano --- builtin/ls-files.c | 10 ++++++++-- dir.c | 32 ++++++++++++++++++++------------ dir.h | 3 ++- 3 files changed, 30 insertions(+), 15 deletions(-) (limited to 'dir.h') diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 90dc3601a8..31b3f2d900 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -200,6 +200,12 @@ static void show_ru_info(void) } } +static int ce_excluded(struct path_exclude_check *check, struct cache_entry *ce) +{ + int dtype = ce_to_dtype(ce); + return path_excluded(check, ce->name, ce_namelen(ce), &dtype); +} + static void show_files(struct dir_struct *dir) { int i; @@ -220,7 +226,7 @@ static void show_files(struct dir_struct *dir) for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if ((dir->flags & DIR_SHOW_IGNORED) && - !path_excluded(&check, ce)) + !ce_excluded(&check, ce)) continue; if (show_unmerged && !ce_stage(ce)) continue; @@ -236,7 +242,7 @@ static void show_files(struct dir_struct *dir) struct stat st; int err; if ((dir->flags & DIR_SHOW_IGNORED) && - !path_excluded(&check, ce)) + !ce_excluded(&check, ce)) continue; if (ce->ce_flags & CE_UPDATE) continue; diff --git a/dir.c b/dir.c index 839bc9f61c..7ab7fc5c22 100644 --- a/dir.c +++ b/dir.c @@ -593,31 +593,40 @@ void path_exclude_check_clear(struct path_exclude_check *check) } /* - * Is the ce->name excluded? This is for a caller like show_files() that + * Is this name excluded? This is for a caller like show_files() that * do not honor directory hierarchy and iterate through paths that are * possibly in an ignored directory. * * A path to a directory known to be excluded is left in check->path to * optimize for repeated checks for files in the same excluded directory. */ -int path_excluded(struct path_exclude_check *check, struct cache_entry *ce) +int path_excluded(struct path_exclude_check *check, + const char *name, int namelen, int *dtype) { - int i, dtype; + int i; struct strbuf *path = &check->path; + /* + * we allow the caller to pass namelen as an optimization; it + * must match the length of the name, as we eventually call + * excluded() on the whole name string. + */ + if (namelen < 0) + namelen = strlen(name); + if (path->len && - path->len <= ce_namelen(ce) && - !memcmp(ce->name, path->buf, path->len) && - (!ce->name[path->len] || ce->name[path->len] == '/')) + path->len <= namelen && + !memcmp(name, path->buf, path->len) && + (!name[path->len] || name[path->len] == '/')) return 1; strbuf_setlen(path, 0); - for (i = 0; ce->name[i]; i++) { - int ch = ce->name[i]; + for (i = 0; name[i]; i++) { + int ch = name[i]; if (ch == '/') { - dtype = DT_DIR; - if (excluded(check->dir, path->buf, &dtype)) + int dt = DT_DIR; + if (excluded(check->dir, path->buf, &dt)) return 1; } strbuf_addch(path, ch); @@ -626,8 +635,7 @@ int path_excluded(struct path_exclude_check *check, struct cache_entry *ce) /* An entry in the index; cannot be a directory with subentries */ strbuf_setlen(path, 0); - dtype = ce_to_dtype(ce); - return excluded(check->dir, ce->name, &dtype); + return excluded(check->dir, name, dtype); } static struct dir_entry *dir_entry_new(const char *pathname, int len) diff --git a/dir.h b/dir.h index 7378e69c17..36a82b3bd1 100644 --- a/dir.h +++ b/dir.h @@ -92,7 +92,8 @@ struct path_exclude_check { }; extern void path_exclude_check_init(struct path_exclude_check *, struct dir_struct *); extern void path_exclude_check_clear(struct path_exclude_check *); -extern int path_excluded(struct path_exclude_check *, struct cache_entry *); +extern int path_excluded(struct path_exclude_check *, const char *, int namelen, int *dtype); + extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen, char **buf_p, struct exclude_list *which, int check_index); -- cgit v1.3-5-g9baa From 0d316f0ceff1c416c25327f40bc5fbdded98a01a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 5 Jun 2012 22:26:12 -0700 Subject: dir.c: make excluded() file scope static Now there no longer is external callers of this interface, so we can make it static. Signed-off-by: Junio C Hamano --- dir.c | 2 +- dir.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'dir.h') diff --git a/dir.c b/dir.c index 7ab7fc5c22..79e43377ad 100644 --- a/dir.c +++ b/dir.c @@ -560,7 +560,7 @@ int excluded_from_list(const char *pathname, return -1; /* undecided */ } -int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p) +static int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p) { int pathlen = strlen(pathname); int st; diff --git a/dir.h b/dir.h index 36a82b3bd1..1a88a7564d 100644 --- a/dir.h +++ b/dir.h @@ -78,7 +78,6 @@ extern int read_directory(struct dir_struct *, const char *path, int len, const extern int excluded_from_list(const char *pathname, int pathlen, const char *basename, int *dtype, struct exclude_list *el); -extern int excluded(struct dir_struct *, const char *, int *); struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len); /* -- cgit v1.3-5-g9baa