dir.c: refactor is_path_excluded()

In a similar way to the previous commit, this extracts a new helper function last_exclude_matching_path() which return the last exclude_list element which matched, or NULL if no match was found. is_path_excluded() becomes a wrapper around this, and just returns 0 or 1 depending on whether any matching exclude_list element was found. This allows callers to find out _why_ a given path was excluded, rather than just whether it was or not, paving the way for a new git sub-command which allows users to test their exclude lists from the command line. Signed-off-by: Adam Spiers <git@adamspiers.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Adam Spiers committed Dec 27, 2012 at 02:32 UTC a35341a86ecf354d46cf326ed9e0ffbceb54309d
2 files changed +41 -9
dir.c
+38 -9
@@ -709,6 +709,7 @@ void path_exclude_check_init(struct path_exclude_check *check,
709 struct dir_struct *dir)
710 {
711 check->dir = dir;
712 + check->exclude = NULL;
713 strbuf_init(&check->path, 256);
714 }
715
@@ -718,18 +719,21 @@ void path_exclude_check_clear(struct path_exclude_check *check)
719 }
720
721 /*
721 - * Is this name excluded? This is for a caller like show_files() that
722 - * do not honor directory hierarchy and iterate through paths that are
723 - * possibly in an ignored directory.
722 + * For each subdirectory in name, starting with the top-most, checks
723 + * to see if that subdirectory is excluded, and if so, returns the
724 + * corresponding exclude structure. Otherwise, checks whether name
725 + * itself (which is presumably a file) is excluded.
726 *
727 * A path to a directory known to be excluded is left in check->path to
728 * optimize for repeated checks for files in the same excluded directory.
729 */
728 -int is_path_excluded(struct path_exclude_check *check,
729 - const char *name, int namelen, int *dtype)
730 +struct exclude *last_exclude_matching_path(struct path_exclude_check *check,
731 + const char *name, int namelen,
732 + int *dtype)
733 {
734 int i;
735 struct strbuf *path = &check->path;
736 + struct exclude *exclude;
737
738 /*
739 * we allow the caller to pass namelen as an optimization; it
@@ -739,11 +743,17 @@ int is_path_excluded(struct path_exclude_check *check,
743 if (namelen < 0)
744 namelen = strlen(name);
745
746 + /*
747 + * If path is non-empty, and name is equal to path or a
748 + * subdirectory of path, name should be excluded, because
749 + * it's inside a directory which is already known to be
750 + * excluded and was previously left in check->path.
751 + */
752 if (path->len &&
753 path->len <= namelen &&
754 !memcmp(name, path->buf, path->len) &&
755 (!name[path->len] || name[path->len] == '/'))
746 - return 1;
756 + return check->exclude;
757
758 strbuf_setlen(path, 0);
759 for (i = 0; name[i]; i++) {
@@ -751,8 +761,12 @@ int is_path_excluded(struct path_exclude_check *check,
761
762 if (ch == '/') {
763 int dt = DT_DIR;
754 - if (is_excluded(check->dir, path->buf, &dt))
755 - return 1;
764 + exclude = last_exclude_matching(check->dir,
765 + path->buf, &dt);
766 + if (exclude) {
767 + check->exclude = exclude;
768 + return exclude;
769 + }
770 }
771 strbuf_addch(path, ch);
772 }
@@ -760,7 +774,22 @@ int is_path_excluded(struct path_exclude_check *check,
774 /* An entry in the index; cannot be a directory with subentries */
775 strbuf_setlen(path, 0);
776
763 - return is_excluded(check->dir, name, dtype);
777 + return last_exclude_matching(check->dir, name, dtype);
778 +}
779 +
780 +/*
781 + * Is this name excluded? This is for a caller like show_files() that
782 + * do not honor directory hierarchy and iterate through paths that are
783 + * possibly in an ignored directory.
784 + */
785 +int is_path_excluded(struct path_exclude_check *check,
786 + const char *name, int namelen, int *dtype)
787 +{
788 + struct exclude *exclude =
789 + last_exclude_matching_path(check, name, namelen, dtype);
790 + if (exclude)
791 + return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
792 + return 0;
793 }
794
795 static struct dir_entry *dir_entry_new(const char *pathname, int len)
dir.h
+3
@@ -119,10 +119,13 @@ extern int match_pathname(const char *, int,
119 */
120 struct path_exclude_check {
121 struct dir_struct *dir;
122 + struct exclude *exclude;
123 struct strbuf path;
124 };
125 extern void path_exclude_check_init(struct path_exclude_check *, struct dir_struct *);
126 extern void path_exclude_check_clear(struct path_exclude_check *);
127 +extern struct exclude *last_exclude_matching_path(struct path_exclude_check *, const char *,
128 + int namelen, int *dtype);
129 extern int is_path_excluded(struct path_exclude_check *, const char *, int namelen, int *dtype);
130
131