From: Albert Yale Date: Sat, 28 Jan 2012 02:40:55 GMT Subject: Re: [PATCH/RFC] grep: Add the option '--exclude' Message-ID: In-Reply-To: I think you're correct. That would be a better way to implement this. I'll look into it this weekend. Albert Yale On Fri, Jan 27, 2012 at 9:19 PM, Junio C Hamano wrote: > I'd prefer to see this done not by introducing a separate pathspec, but > instead by adding exclusion-related fields to struct pathspec. That way, the > existing callsites to  match_pathspec() do not have to change, and only the > program start-up needs to learn to stuff these negative pathspecs, no? > > On Jan 27, 2012 6:06 PM, "Albert Yale" wrote: >> >> grep: Add the option '--exclude' >> >> Signed-off-by: Albert Yale >> --- >> This is a work-in-progress. It's functional, >> but it hasn't been thoroughly tested. >> >> I'd like some feedback. Particularly for >> init_pathspec_string_list() in dir.c. >> >> Thank you, >> >> Albert Yale >> >>  Documentation/git-grep.txt |    7 ++++++ >>  builtin/grep.c             |   50 >> ++++++++++++++++++++++++++++++++++++------- >>  cache.h                    |    1 + >>  dir.c                      |   32 ++++++++++++++++++++++++++++ >>  4 files changed, 82 insertions(+), 8 deletions(-) >> >> diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt >> index 6a8b1e3..8cbb161 100644 >> --- a/Documentation/git-grep.txt >> +++ b/Documentation/git-grep.txt >> @@ -22,6 +22,7 @@ SYNOPSIS >>           [--color[=] | --no-color] >>           [-A ] [-B ] [-C ] >>           [-f ] [-e] >> +          [-x |--exclude=] >>           [--and|--or|--not|(|)|-e ...] >>           [ [--exclude-standard] [--cached | --no-index | --untracked] | >> ...] >>           [--] [...] >> @@ -124,6 +125,12 @@ OPTIONS >>        Use fixed strings for patterns (don't interpret pattern >>        as a regex). >> >> +-x :: >> +--exclude=:: >> +       In addition to those found in .gitignore (per directory) and >> +       $GIT_DIR/info/exclude, also consider these patterns to be in the >> +       set of the ignore rules in effect. >> + >>  -n:: >>  --line-number:: >>        Prefix the line number to matching lines. >> diff --git a/builtin/grep.c b/builtin/grep.c >> index 9ce064a..106810f 100644 >> --- a/builtin/grep.c >> +++ b/builtin/grep.c >> @@ -518,7 +518,8 @@ static void run_pager(struct grep_opt *opt, const char >> *prefix) >>        free(argv); >>  } >> >> -static int grep_cache(struct grep_opt *opt, const struct pathspec >> *pathspec, int cached) >> +static int grep_cache(struct grep_opt *opt, const struct pathspec >> *pathspec, >> +                         int cached, const struct pathspec >> *exclude_pathspec) >>  { >>        int hit = 0; >>        int nr; >> @@ -530,6 +531,9 @@ static int grep_cache(struct grep_opt *opt, const >> struct pathspec *pathspec, int >>                        continue; >>                if (!match_pathspec_depth(pathspec, ce->name, >> ce_namelen(ce), 0, NULL)) >>                        continue; >> +               if (exclude_pathspec->nr && >> +                       match_pathspec_depth(exclude_pathspec, ce->name, >> ce_namelen(ce), 0, NULL)) >> +                       continue; >>                /* >>                 * If CE_VALID is on, we assume worktree file and its cache >> entry >>                 * are identical, even if worktree file has been modified, >> so use >> @@ -639,16 +643,23 @@ static int grep_object(struct grep_opt *opt, const >> struct pathspec *pathspec, >>  } >> >>  static int grep_objects(struct grep_opt *opt, const struct pathspec >> *pathspec, >> -                       const struct object_array *list) >> +                       const struct object_array *list, const struct >> pathspec *exclude_pathspec) >>  { >>        unsigned int i; >>        int hit = 0; >>        const unsigned int nr = list->nr; >> >>        for (i = 0; i < nr; i++) { >> +               const char *name = list->objects[i].name; >> +               int namelen = strlen(name); >>                struct object *real_obj; >>                real_obj = deref_tag(list->objects[i].item, NULL, 0); >> -               if (grep_object(opt, pathspec, real_obj, >> list->objects[i].name)) { >> + >> +               if (exclude_pathspec->nr && >> +                       match_pathspec_depth(exclude_pathspec, name, >> namelen, 0, NULL)) >> +                       continue; >> + >> +               if (grep_object(opt, pathspec, real_obj, name)) { >>                        hit = 1; >>                        if (opt->status_only) >>                                break; >> @@ -658,7 +669,7 @@ static int grep_objects(struct grep_opt *opt, const >> struct pathspec *pathspec, >>  } >> >>  static int grep_directory(struct grep_opt *opt, const struct pathspec >> *pathspec, >> -                         int exc_std) >> +                         int exc_std, struct string_list *exclude_list) >>  { >>        struct dir_struct dir; >>        int i, hit = 0; >> @@ -667,6 +678,10 @@ static int grep_directory(struct grep_opt *opt, const >> struct pathspec *pathspec, >>        if (exc_std) >>                setup_standard_excludes(&dir); >> >> +       for (i = 0; i < exclude_list->nr; i++) >> +               add_exclude(exclude_list->items[i].string, "", 0, >> +                           &dir.exclude_list[EXC_CMDL]); >> + >>        fill_directory(&dir, pathspec->raw); >>        for (i = 0; i < dir.nr; i++) { >>                const char *name = dir.entries[i]->name; >> @@ -764,6 +779,14 @@ static int pattern_callback(const struct option *opt, >> const char *arg, >>        return 0; >>  } >> >> +static int exclude_cb(const struct option *opt, const char *arg, >> +                           int unset) >> +{ >> +       struct string_list *exclude_list = opt->value; >> +       string_list_append(exclude_list, arg); >> +       return 0; >> +} >> + >>  static int help_callback(const struct option *opt, const char *arg, int >> unset) >>  { >>        return -1; >> @@ -780,6 +803,7 @@ int cmd_grep(int argc, const char **argv, const char >> *prefix) >>        struct object_array list = OBJECT_ARRAY_INIT; >>        const char **paths = NULL; >>        struct pathspec pathspec; >> +       struct pathspec exclude_pathspec; >>        struct string_list path_list = STRING_LIST_INIT_NODUP; >>        int i; >>        int dummy; >> @@ -792,7 +816,7 @@ int cmd_grep(int argc, const char **argv, const char >> *prefix) >>                pattern_type_pcre, >>        }; >>        int pattern_type = pattern_type_unspecified; >> - >> +       struct string_list exclude_list = STRING_LIST_INIT_NODUP; >>        struct option options[] = { >>                OPT_BOOLEAN(0, "cached", &cached, >>                        "search in index instead of in the work tree"), >> @@ -872,6 +896,8 @@ int cmd_grep(int argc, const char **argv, const char >> *prefix) >>                        "read patterns from file", file_callback), >>                { OPTION_CALLBACK, 'e', NULL, &opt, "pattern", >>                        "match ", PARSE_OPT_NONEG, >> pattern_callback }, >> +               { OPTION_CALLBACK, 'x', "exclude", &exclude_list, >> "pattern", >> +                 "add to ignore rules", PARSE_OPT_NONEG, >> exclude_cb }, >>                { OPTION_CALLBACK, 0, "and", &opt, NULL, >>                  "combine patterns specified with -e", >>                  PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback }, >> @@ -1053,6 +1079,10 @@ int cmd_grep(int argc, const char **argv, const >> char *prefix) >>        pathspec.max_depth = opt.max_depth; >>        pathspec.recursive = 1; >> >> +       init_pathspec_string_list(&exclude_pathspec, &exclude_list); >> +       exclude_pathspec.max_depth = opt.max_depth; >> +       exclude_pathspec.recursive = 1; >> + >>        if (show_in_pager && (cached || list.nr)) >>                die(_("--open-files-in-pager only works on the worktree")); >> >> @@ -1083,18 +1113,19 @@ int cmd_grep(int argc, const char **argv, const >> char *prefix) >>                int use_exclude = (opt_exclude < 0) ? use_index : >> !!opt_exclude; >>                if (list.nr) >>                        die(_("--no-index or --untracked cannot be used >> with revs.")); >> -               hit = grep_directory(&opt, &pathspec, use_exclude); >> +               hit = grep_directory(&opt, &pathspec, use_exclude, >> &exclude_list); >>        } else if (0 <= opt_exclude) { >>                die(_("--[no-]exclude-standard cannot be used for tracked >> contents.")); >>        } else if (!list.nr) { >>                if (!cached) >>                        setup_work_tree(); >> >> -               hit = grep_cache(&opt, &pathspec, cached); >> +               hit = grep_cache(&opt, &pathspec, cached, >> &exclude_pathspec); >>        } else { >>                if (cached) >>                        die(_("both --cached and trees are given.")); >> -               hit = grep_objects(&opt, &pathspec, &list); >> + >> +               hit = grep_objects(&opt, &pathspec, &list, >> &exclude_pathspec); >>        } >> >>        if (use_threads) >> @@ -1102,5 +1133,8 @@ int cmd_grep(int argc, const char **argv, const char >> *prefix) >>        if (hit && show_in_pager) >>                run_pager(&opt, prefix); >>        free_grep_patterns(&opt); >> +       free_pathspec(&pathspec); >> +       free_pathspec(&exclude_pathspec); >> +       string_list_clear(&exclude_list, 0); >>        return !hit; >>  } >> diff --git a/cache.h b/cache.h >> index 10afd71..5c34ccb 100644 >> --- a/cache.h >> +++ b/cache.h >> @@ -536,6 +536,7 @@ struct pathspec { >>  }; >> >>  extern int init_pathspec(struct pathspec *, const char **); >> +extern int init_pathspec_string_list(struct pathspec *, struct >> string_list *); >>  extern void free_pathspec(struct pathspec *); >>  extern int ce_path_match(const struct cache_entry *ce, const struct >> pathspec *pathspec); >> >> diff --git a/dir.c b/dir.c >> index 0a78d00..65749cc 100644 >> --- a/dir.c >> +++ b/dir.c >> @@ -9,6 +9,8 @@ >>  #include "dir.h" >>  #include "refs.h" >> >> +#include "string-list.h" >> + >>  struct path_simplify { >>        int len; >>        const char *path; >> @@ -1259,6 +1261,36 @@ static int pathspec_item_cmp(const void *a_, const >> void *b_) >>        return strcmp(a->match, b->match); >>  } >> >> +int init_pathspec_string_list(struct pathspec *pathspec, struct >> string_list *path_list) >> +{ >> +       int i; >> + >> +       memset(pathspec, 0, sizeof(*pathspec)); >> +       if (!path_list) >> +               return 0; >> +       pathspec->raw = 0; /* THIS IS PROBABLY BAD!!! */ >> +       pathspec->nr = path_list->nr; >> +       if (!pathspec->nr) >> +               return 0; >> + >> +       pathspec->items = xmalloc(sizeof(struct >> pathspec_item)*pathspec->nr); >> +       for (i = 0; i < pathspec->nr; i++) { >> +               struct pathspec_item *item = pathspec->items+i; >> +               const char *path = path_list->items[i].string; >> + >> +               item->match = path; >> +               item->len = strlen(path); >> +               item->use_wildcard = !no_wildcard(path); >> +               if (item->use_wildcard) >> +                       pathspec->has_wildcard = 1; >> +       } >> + >> +       qsort(pathspec->items, pathspec->nr, >> +             sizeof(struct pathspec_item), pathspec_item_cmp); >> + >> +       return 0; >> +} >> + >>  int init_pathspec(struct pathspec *pathspec, const char **paths) >>  { >>        const char **p = paths; >> -- >> 1.7.8.3 >> >> -- >> To unsubscribe from this list: send the line "unsubscribe git" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at  http://vger.kernel.org/majordomo-info.html