X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=builtin%2Fgrep.c;h=ae2d5bbafcae263e91cd7f9ea7a97dc7a874d4aa;hb=37901a2202e2b806539080bf8cf129d36e4bd003;hp=9304c33e75051baa65ee02d1daa03c361e25339e;hpb=70a006ac4b494ddb1c3157a3c33bbae9e5856188;p=platform%2Fupstream%2Fgit.git diff --git a/builtin/grep.c b/builtin/grep.c index 9304c33..ae2d5bb 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -3,7 +3,10 @@ * * Copyright (c) 2006 Junio C Hamano */ +#define USE_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" +#include "repository.h" +#include "config.h" #include "blob.h" #include "tree.h" #include "commit.h" @@ -20,24 +23,18 @@ #include "pathspec.h" #include "submodule.h" #include "submodule-config.h" +#include "object-store.h" static char const * const grep_usage[] = { N_("git grep [] [-e] [...] [[--] ...]"), NULL }; -static const char *super_prefix; static int recurse_submodules; -static struct argv_array submodule_options = ARGV_ARRAY_INIT; -static const char *parent_basename; - -static int grep_submodule_launch(struct grep_opt *opt, - const struct grep_source *gs); #define GREP_NUM_THREADS_DEFAULT 8 static int num_threads; -#ifndef NO_PTHREADS static pthread_t *threads; /* We use one producer thread and THREADS consumer @@ -73,14 +70,12 @@ static pthread_mutex_t grep_mutex; static inline void grep_lock(void) { - if (num_threads) - pthread_mutex_lock(&grep_mutex); + pthread_mutex_lock(&grep_mutex); } static inline void grep_unlock(void) { - if (num_threads) - pthread_mutex_unlock(&grep_mutex); + pthread_mutex_unlock(&grep_mutex); } /* Signalled when a new work_item is added to todo. */ @@ -96,8 +91,7 @@ static pthread_cond_t cond_result; static int skip_first_line; -static void add_work(struct grep_opt *opt, enum grep_source_type type, - const char *name, const char *path, const void *id) +static void add_work(struct grep_opt *opt, const struct grep_source *gs) { grep_lock(); @@ -105,9 +99,10 @@ static void add_work(struct grep_opt *opt, enum grep_source_type type, pthread_cond_wait(&cond_write, &grep_mutex); } - grep_source_init(&todo[todo_end].source, type, name, path, id); + todo[todo_end].source = *gs; if (opt->binary != GREP_BINARY_TEXT) - grep_source_load_driver(&todo[todo_end].source); + grep_source_load_driver(&todo[todo_end].source, + opt->repo->index); todo[todo_end].done = 0; strbuf_reset(&todo[todo_end].out); todo_end = (todo_end + 1) % ARRAY_SIZE(todo); @@ -184,10 +179,7 @@ static void *run(void *arg) break; opt->output_priv = w; - if (w->source.type == GREP_SOURCE_SUBMODULE) - hit |= grep_submodule_launch(opt, &w->source); - else - hit |= grep_source(opt, &w->source); + hit |= grep_source(opt, &w->source); grep_source_clear_data(&w->source); work_done(w); } @@ -224,7 +216,8 @@ static void start_threads(struct grep_opt *opt) int err; struct grep_opt *o = grep_opt_dup(opt); o->output = strbuf_out; - o->debug = 0; + if (i) + o->debug = 0; compile_grep_patterns(o); err = pthread_create(&threads[i], NULL, run, o); @@ -239,6 +232,9 @@ static int wait_all(void) int hit = 0; int i; + if (!HAVE_THREADS) + BUG("Never call this function unless you have started threads"); + grep_lock(); all_work_added = 1; @@ -270,13 +266,6 @@ static int wait_all(void) return hit; } -#else /* !NO_PTHREADS */ - -static int wait_all(void) -{ - return 0; -} -#endif static int grep_cmd_config(const char *var, const char *value, void *cb) { @@ -289,51 +278,60 @@ static int grep_cmd_config(const char *var, const char *value, void *cb) if (num_threads < 0) die(_("invalid number of threads specified (%d) for %s"), num_threads, var); + else if (!HAVE_THREADS && num_threads > 1) { + /* + * TRANSLATORS: %s is the configuration + * variable for tweaking threads, currently + * grep.threads + */ + warning(_("no threads support, ignoring %s"), var); + num_threads = 1; + } } + if (!strcmp(var, "submodule.recurse")) + recurse_submodules = git_config_bool(var, value); + return st; } -static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size) +static void *lock_and_read_oid_file(const struct object_id *oid, enum object_type *type, unsigned long *size) { void *data; grep_read_lock(); - data = read_sha1_file(sha1, type, size); + data = read_object_file(oid, type, size); grep_read_unlock(); return data; } -static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, +static int grep_oid(struct grep_opt *opt, const struct object_id *oid, const char *filename, int tree_name_len, const char *path) { struct strbuf pathbuf = STRBUF_INIT; + struct grep_source gs; if (opt->relative && opt->prefix_length) { quote_path_relative(filename + tree_name_len, opt->prefix, &pathbuf); strbuf_insert(&pathbuf, 0, filename, tree_name_len); - } else if (super_prefix) { - strbuf_add(&pathbuf, filename, tree_name_len); - strbuf_addstr(&pathbuf, super_prefix); - strbuf_addstr(&pathbuf, filename + tree_name_len); } else { strbuf_addstr(&pathbuf, filename); } -#ifndef NO_PTHREADS - if (num_threads) { - add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1); - strbuf_release(&pathbuf); + grep_source_init(&gs, GREP_SOURCE_OID, pathbuf.buf, path, oid); + strbuf_release(&pathbuf); + + if (num_threads > 1) { + /* + * add_work() copies gs and thus assumes ownership of + * its fields, so do not call grep_source_clear() + */ + add_work(opt, &gs); return 0; - } else -#endif - { - struct grep_source gs; + } else { int hit; - grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1); - strbuf_release(&pathbuf); hit = grep_source(opt, &gs); grep_source_clear(&gs); @@ -344,28 +342,26 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, static int grep_file(struct grep_opt *opt, const char *filename) { struct strbuf buf = STRBUF_INIT; + struct grep_source gs; - if (opt->relative && opt->prefix_length) { + if (opt->relative && opt->prefix_length) quote_path_relative(filename, opt->prefix, &buf); - } else { - if (super_prefix) - strbuf_addstr(&buf, super_prefix); + else strbuf_addstr(&buf, filename); - } -#ifndef NO_PTHREADS - if (num_threads) { - add_work(opt, GREP_SOURCE_FILE, buf.buf, filename, filename); - strbuf_release(&buf); + grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename); + strbuf_release(&buf); + + if (num_threads > 1) { + /* + * add_work() copies gs and thus assumes ownership of + * its fields, so do not call grep_source_clear() + */ + add_work(opt, &gs); return 0; - } else -#endif - { - struct grep_source gs; + } else { int hit; - grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename); - strbuf_release(&buf); hit = grep_source(opt, &gs); grep_source_clear(&gs); @@ -398,287 +394,117 @@ static void run_pager(struct grep_opt *opt, const char *prefix) exit(status); } -static void compile_submodule_options(const struct grep_opt *opt, - const struct pathspec *pathspec, - int cached, int untracked, - int opt_exclude, int use_index, - int pattern_type_arg) -{ - struct grep_pat *pattern; - int i; - - if (recurse_submodules) - argv_array_push(&submodule_options, "--recurse-submodules"); - - if (cached) - argv_array_push(&submodule_options, "--cached"); - if (!use_index) - argv_array_push(&submodule_options, "--no-index"); - if (untracked) - argv_array_push(&submodule_options, "--untracked"); - if (opt_exclude > 0) - argv_array_push(&submodule_options, "--exclude-standard"); - - if (opt->invert) - argv_array_push(&submodule_options, "-v"); - if (opt->ignore_case) - argv_array_push(&submodule_options, "-i"); - if (opt->word_regexp) - argv_array_push(&submodule_options, "-w"); - switch (opt->binary) { - case GREP_BINARY_NOMATCH: - argv_array_push(&submodule_options, "-I"); - break; - case GREP_BINARY_TEXT: - argv_array_push(&submodule_options, "-a"); - break; - default: - break; - } - if (opt->allow_textconv) - argv_array_push(&submodule_options, "--textconv"); - if (opt->max_depth != -1) - argv_array_pushf(&submodule_options, "--max-depth=%d", - opt->max_depth); - if (opt->linenum) - argv_array_push(&submodule_options, "-n"); - if (!opt->pathname) - argv_array_push(&submodule_options, "-h"); - if (!opt->relative) - argv_array_push(&submodule_options, "--full-name"); - if (opt->name_only) - argv_array_push(&submodule_options, "-l"); - if (opt->unmatch_name_only) - argv_array_push(&submodule_options, "-L"); - if (opt->null_following_name) - argv_array_push(&submodule_options, "-z"); - if (opt->count) - argv_array_push(&submodule_options, "-c"); - if (opt->file_break) - argv_array_push(&submodule_options, "--break"); - if (opt->heading) - argv_array_push(&submodule_options, "--heading"); - if (opt->pre_context) - argv_array_pushf(&submodule_options, "--before-context=%d", - opt->pre_context); - if (opt->post_context) - argv_array_pushf(&submodule_options, "--after-context=%d", - opt->post_context); - if (opt->funcname) - argv_array_push(&submodule_options, "-p"); - if (opt->funcbody) - argv_array_push(&submodule_options, "-W"); - if (opt->all_match) - argv_array_push(&submodule_options, "--all-match"); - if (opt->debug) - argv_array_push(&submodule_options, "--debug"); - if (opt->status_only) - argv_array_push(&submodule_options, "-q"); - - switch (pattern_type_arg) { - case GREP_PATTERN_TYPE_BRE: - argv_array_push(&submodule_options, "-G"); - break; - case GREP_PATTERN_TYPE_ERE: - argv_array_push(&submodule_options, "-E"); - break; - case GREP_PATTERN_TYPE_FIXED: - argv_array_push(&submodule_options, "-F"); - break; - case GREP_PATTERN_TYPE_PCRE: - argv_array_push(&submodule_options, "-P"); - break; - case GREP_PATTERN_TYPE_UNSPECIFIED: - break; - } - - for (pattern = opt->pattern_list; pattern != NULL; - pattern = pattern->next) { - switch (pattern->token) { - case GREP_PATTERN: - argv_array_pushf(&submodule_options, "-e%s", - pattern->pattern); - break; - case GREP_AND: - case GREP_OPEN_PAREN: - case GREP_CLOSE_PAREN: - case GREP_NOT: - case GREP_OR: - argv_array_push(&submodule_options, pattern->pattern); - break; - /* BODY and HEAD are not used by git-grep */ - case GREP_PATTERN_BODY: - case GREP_PATTERN_HEAD: - break; - } - } - - /* - * Limit number of threads for child process to use. - * This is to prevent potential fork-bomb behavior of git-grep as each - * submodule process has its own thread pool. - */ - argv_array_pushf(&submodule_options, "--threads=%d", - (num_threads + 1) / 2); - - /* Add Pathspecs */ - argv_array_push(&submodule_options, "--"); - for (i = 0; i < pathspec->nr; i++) - argv_array_push(&submodule_options, - pathspec->items[i].original); -} +static int grep_cache(struct grep_opt *opt, + const struct pathspec *pathspec, int cached); +static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, + struct tree_desc *tree, struct strbuf *base, int tn_len, + int check_attr); -/* - * Launch child process to grep contents of a submodule - */ -static int grep_submodule_launch(struct grep_opt *opt, - const struct grep_source *gs) +static int grep_submodule(struct grep_opt *opt, + const struct pathspec *pathspec, + const struct object_id *oid, + const char *filename, const char *path, int cached) { - struct child_process cp = CHILD_PROCESS_INIT; - int status, i; - const char *end_of_base; - const char *name; - struct work_item *w = opt->output_priv; - - end_of_base = strchr(gs->name, ':'); - if (gs->identifier && end_of_base) - name = end_of_base + 1; - else - name = gs->name; - - prepare_submodule_repo_env(&cp.env_array); - argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT); - - /* Add super prefix */ - argv_array_pushf(&cp.args, "--super-prefix=%s%s/", - super_prefix ? super_prefix : "", - name); - argv_array_push(&cp.args, "grep"); + struct repository subrepo; + struct repository *superproject = opt->repo; + const struct submodule *sub = submodule_from_path(superproject, + &null_oid, path); + struct grep_opt subopt; + int hit; /* - * Add basename of parent project - * When performing grep on a tree object the filename is prefixed - * with the object's name: 'tree-name:filename'. In order to - * provide uniformity of output we want to pass the name of the - * parent project's object name to the submodule so the submodule can - * prefix its output with the parent's name and not its own SHA1. + * NEEDSWORK: submodules functions need to be protected because they + * access the object store via config_from_gitmodules(): the latter + * uses get_oid() which, for now, relies on the global the_repository + * object. */ - if (gs->identifier && end_of_base) - argv_array_pushf(&cp.args, "--parent-basename=%.*s", - (int) (end_of_base - gs->name), - gs->name); + grep_read_lock(); - /* Add options */ - for (i = 0; i < submodule_options.argc; i++) { - /* - * If there is a tree identifier for the submodule, add the - * rev after adding the submodule options but before the - * pathspecs. To do this we listen for the '--' and insert the - * sha1 before pushing the '--' onto the child process argv - * array. - */ - if (gs->identifier && - !strcmp("--", submodule_options.argv[i])) { - argv_array_push(&cp.args, sha1_to_hex(gs->identifier)); - } + if (!is_submodule_active(superproject, path)) { + grep_read_unlock(); + return 0; + } - argv_array_push(&cp.args, submodule_options.argv[i]); + if (repo_submodule_init(&subrepo, superproject, sub)) { + grep_read_unlock(); + return 0; } - cp.git_cmd = 1; - cp.dir = gs->path; + repo_read_gitmodules(&subrepo); /* - * Capture output to output buffer and check the return code from the - * child process. A '0' indicates a hit, a '1' indicates no hit and - * anything else is an error. + * NEEDSWORK: This adds the submodule's object directory to the list of + * alternates for the single in-memory object store. This has some bad + * consequences for memory (processed objects will never be freed) and + * performance (this increases the number of pack files git has to pay + * attention to, to the sum of the number of pack files in all the + * repositories processed so far). This can be removed once the object + * store is no longer global and instead is a member of the repository + * object. */ - status = capture_command(&cp, &w->out, 0); - if (status && (status != 1)) { - /* flush the buffer */ - write_or_die(1, w->out.buf, w->out.len); - die("process for submodule '%s' failed with exit code: %d", - gs->name, status); - } + add_to_alternates_memory(subrepo.objects->odb->path); + grep_read_unlock(); - /* invert the return code to make a hit equal to 1 */ - return !status; -} + memcpy(&subopt, opt, sizeof(subopt)); + subopt.repo = &subrepo; -/* - * Prep grep structures for a submodule grep - * sha1: the sha1 of the submodule or NULL if using the working tree - * filename: name of the submodule including tree name of parent - * path: location of the submodule - */ -static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1, - const char *filename, const char *path) -{ - if (!is_submodule_initialized(path)) - return 0; - if (!is_submodule_populated(path)) { - /* - * If searching history, check for the presense of the - * submodule's gitdir before skipping the submodule. - */ - if (sha1) { - const struct submodule *sub = - submodule_from_path(null_sha1, path); - if (sub) - path = git_path("modules/%s", sub->name); - - if (!(is_directory(path) && is_git_directory(path))) - return 0; - } else { - return 0; - } - } + if (oid) { + struct object *object; + struct tree_desc tree; + void *data; + unsigned long size; + struct strbuf base = STRBUF_INIT; -#ifndef NO_PTHREADS - if (num_threads) { - add_work(opt, GREP_SOURCE_SUBMODULE, filename, path, sha1); - return 0; - } else -#endif - { - struct work_item w; - int hit; + object = parse_object_or_die(oid, oid_to_hex(oid)); - grep_source_init(&w.source, GREP_SOURCE_SUBMODULE, - filename, path, sha1); - strbuf_init(&w.out, 0); - opt->output_priv = &w; - hit = grep_submodule_launch(opt, &w.source); + grep_read_lock(); + data = read_object_with_reference(&subrepo, + &object->oid, tree_type, + &size, NULL); + grep_read_unlock(); - write_or_die(1, w.out.buf, w.out.len); + if (!data) + die(_("unable to read tree (%s)"), oid_to_hex(&object->oid)); - grep_source_clear(&w.source); - strbuf_release(&w.out); - return hit; + strbuf_addstr(&base, filename); + strbuf_addch(&base, '/'); + + init_tree_desc(&tree, data, size); + hit = grep_tree(&subopt, pathspec, &tree, &base, base.len, + object->type == OBJ_COMMIT); + strbuf_release(&base); + free(data); + } else { + hit = grep_cache(&subopt, pathspec, cached); } + + repo_clear(&subrepo); + return hit; } -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) { + struct repository *repo = opt->repo; int hit = 0; int nr; struct strbuf name = STRBUF_INIT; int name_base_len = 0; - if (super_prefix) { - name_base_len = strlen(super_prefix); - strbuf_addstr(&name, super_prefix); + if (repo->submodule_prefix) { + name_base_len = strlen(repo->submodule_prefix); + strbuf_addstr(&name, repo->submodule_prefix); } - read_cache(); + if (repo_read_index(repo) < 0) + die(_("index file corrupt")); - for (nr = 0; nr < active_nr; nr++) { - const struct cache_entry *ce = active_cache[nr]; + for (nr = 0; nr < repo->index->cache_nr; nr++) { + const struct cache_entry *ce = repo->index->cache[nr]; strbuf_setlen(&name, name_base_len); strbuf_addstr(&name, ce->name); if (S_ISREG(ce->ce_mode) && - match_pathspec(pathspec, name.buf, name.len, 0, NULL, + match_pathspec(repo->index, pathspec, name.buf, name.len, 0, NULL, S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode))) { /* @@ -690,14 +516,15 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, ce_skip_worktree(ce)) { if (ce_stage(ce) || ce_intent_to_add(ce)) continue; - hit |= grep_sha1(opt, ce->oid.hash, ce->name, - 0, ce->name); + hit |= grep_oid(opt, &ce->oid, name.buf, + 0, name.buf); } else { - hit |= grep_file(opt, ce->name); + hit |= grep_file(opt, name.buf); } } else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) && - submodule_path_match(pathspec, name.buf, NULL)) { - hit |= grep_submodule(opt, NULL, ce->name, ce->name); + submodule_path_match(repo->index, pathspec, name.buf, NULL)) { + hit |= grep_submodule(opt, pathspec, NULL, ce->name, + ce->name, cached); } else { continue; } @@ -705,8 +532,8 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, if (ce_stage(ce)) { do { nr++; - } while (nr < active_nr && - !strcmp(ce->name, active_cache[nr]->name)); + } while (nr < repo->index->cache_nr && + !strcmp(ce->name, repo->index->cache[nr]->name)); nr--; /* compensate for loop control */ } if (hit && opt->status_only) @@ -721,14 +548,15 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, struct tree_desc *tree, struct strbuf *base, int tn_len, int check_attr) { + struct repository *repo = opt->repo; int hit = 0; enum interesting match = entry_not_interesting; struct name_entry entry; int old_baselen = base->len; struct strbuf name = STRBUF_INIT; int name_base_len = 0; - if (super_prefix) { - strbuf_addstr(&name, super_prefix); + if (repo->submodule_prefix) { + strbuf_addstr(&name, repo->submodule_prefix); name_base_len = name.len; } @@ -737,7 +565,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, if (match != all_entries_interesting) { strbuf_addstr(&name, base->buf + tn_len); - match = tree_entry_interesting(&entry, &name, + match = tree_entry_interesting(repo->index, + &entry, &name, 0, pathspec); strbuf_setlen(&name, name_base_len); @@ -750,7 +579,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, strbuf_add(base, entry.path, te_len); if (S_ISREG(entry.mode)) { - hit |= grep_sha1(opt, entry.oid->hash, base->buf, tn_len, + hit |= grep_oid(opt, &entry.oid, base->buf, tn_len, check_attr ? base->buf + tn_len : NULL); } else if (S_ISDIR(entry.mode)) { enum object_type type; @@ -758,10 +587,10 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, void *data; unsigned long size; - data = lock_and_read_sha1_file(entry.oid->hash, &type, &size); + data = lock_and_read_oid_file(&entry.oid, &type, &size); if (!data) die(_("unable to read tree (%s)"), - oid_to_hex(entry.oid)); + oid_to_hex(&entry.oid)); strbuf_addch(base, '/'); init_tree_desc(&sub, data, size); @@ -769,8 +598,9 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, check_attr); free(data); } else if (recurse_submodules && S_ISGITLINK(entry.mode)) { - hit |= grep_submodule(opt, entry.oid->hash, base->buf, - base->buf + tn_len); + hit |= grep_submodule(opt, pathspec, &entry.oid, + base->buf, base->buf + tn_len, + 1); /* ignored */ } strbuf_setlen(base, old_baselen); @@ -787,7 +617,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, struct object *obj, const char *name, const char *path) { if (obj->type == OBJ_BLOB) - return grep_sha1(opt, obj->oid.hash, name, 0, path); + return grep_oid(opt, &obj->oid, name, 0, path); if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) { struct tree_desc tree; void *data; @@ -796,17 +626,14 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, int hit, len; grep_read_lock(); - data = read_object_with_reference(obj->oid.hash, tree_type, + data = read_object_with_reference(opt->repo, + &obj->oid, tree_type, &size, NULL); grep_read_unlock(); if (!data) die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid)); - /* Use parent's name as base when recursing submodules */ - if (recurse_submodules && parent_basename) - name = parent_basename; - len = name ? strlen(name) : 0; strbuf_init(&base, PATH_MAX + len + 1); if (len) { @@ -820,7 +647,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, free(data); return hit; } - die(_("unable to grep from object of type %s"), typename(obj->type)); + die(_("unable to grep from object of type %s"), type_name(obj->type)); } static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, @@ -832,14 +659,16 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, for (i = 0; i < nr; i++) { struct object *real_obj; - real_obj = deref_tag(list->objects[i].item, NULL, 0); + real_obj = deref_tag(opt->repo, list->objects[i].item, + NULL, 0); /* load the gitmodules file for this rev */ if (recurse_submodules) { - submodule_free(); - gitmodules_config_sha1(real_obj->oid.hash); + submodule_free(opt->repo); + gitmodules_config_oid(&real_obj->oid); } - if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path)) { + if (grep_object(opt, pathspec, real_obj, list->objects[i].name, + list->objects[i].path)) { hit = 1; if (opt->status_only) break; @@ -860,9 +689,9 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec, if (exc_std) setup_standard_excludes(&dir); - fill_directory(&dir, pathspec); + fill_directory(&dir, opt->repo->index, pathspec); for (i = 0; i < dir.nr; i++) { - if (!dir_path_match(dir.entries[i], pathspec, 0, NULL)) + if (!dir_path_match(opt->repo->index, dir.entries[i], pathspec, 0, NULL)) continue; hit |= grep_file(opt, dir.entries[i]->name); if (hit && opt->status_only) @@ -894,11 +723,14 @@ static int context_callback(const struct option *opt, const char *arg, static int file_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; - int from_stdin = !strcmp(arg, "-"); + int from_stdin; FILE *patterns; int lno = 0; struct strbuf sb = STRBUF_INIT; + BUG_ON_OPT_NEG(unset); + + from_stdin = !strcmp(arg, "-"); patterns = from_stdin ? stdin : fopen(arg, "r"); if (!patterns) die_errno(_("cannot open '%s'"), arg); @@ -919,6 +751,8 @@ static int file_callback(const struct option *opt, const char *arg, int unset) static int not_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); append_grep_pattern(grep_opt, "--not", "command line", 0, GREP_NOT); return 0; } @@ -926,6 +760,8 @@ static int not_callback(const struct option *opt, const char *arg, int unset) static int and_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); append_grep_pattern(grep_opt, "--and", "command line", 0, GREP_AND); return 0; } @@ -933,6 +769,8 @@ static int and_callback(const struct option *opt, const char *arg, int unset) static int open_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); append_grep_pattern(grep_opt, "(", "command line", 0, GREP_OPEN_PAREN); return 0; } @@ -940,6 +778,8 @@ static int open_callback(const struct option *opt, const char *arg, int unset) static int close_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); append_grep_pattern(grep_opt, ")", "command line", 0, GREP_CLOSE_PAREN); return 0; } @@ -948,6 +788,7 @@ static int pattern_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; + BUG_ON_OPT_NEG(unset); append_grep_pattern(grep_opt, arg, "-e option", 0, GREP_PATTERN); return 0; } @@ -979,10 +820,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_SET_INT(0, "exclude-standard", &opt_exclude, N_("ignore files specified via '.gitignore'"), 1), OPT_BOOL(0, "recurse-submodules", &recurse_submodules, - N_("recursivley search in each submodule")), - OPT_STRING(0, "parent-basename", &parent_basename, - N_("basename"), - N_("prepend parent project's basename to output")), + N_("recursively search in each submodule")), OPT_GROUP(""), OPT_BOOL('v', "invert-match", &opt.invert, N_("show non-matching lines")), @@ -997,6 +835,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) GREP_BINARY_NOMATCH), OPT_BOOL(0, "textconv", &opt.allow_textconv, N_("process binary files with textconv filters")), + OPT_SET_INT('r', "recursive", &opt.max_depth, + N_("search in subdirectories (default)"), -1), { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"), N_("descend at most levels"), PARSE_OPT_NONEG, NULL, 1 }, @@ -1015,6 +855,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) GREP_PATTERN_TYPE_PCRE), OPT_GROUP(""), OPT_BOOL('n', "line-number", &opt.linenum, N_("show line numbers")), + OPT_BOOL(0, "column", &opt.columnnum, N_("show column number of first match")), OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1), OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1), OPT_NEGBIT(0, "full-name", &opt.relative, @@ -1026,8 +867,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOL('L', "files-without-match", &opt.unmatch_name_only, N_("show only the names of files without match")), - OPT_BOOL('z', "null", &opt.null_following_name, - N_("print NUL after filenames")), + OPT_BOOL_F('z', "null", &opt.null_following_name, + N_("print NUL after filenames"), + PARSE_OPT_NOCOMPLETE), + OPT_BOOL('o', "only-matching", &opt.only_matching, + N_("show only matching parts of a line")), OPT_BOOL('c', "count", &opt.count, N_("show the number of matches instead of matching lines")), OPT__COLOR(&opt.color, N_("highlight matches")), @@ -1072,22 +916,23 @@ int cmd_grep(int argc, const char **argv, const char *prefix) N_("indicate hit with exit status without output")), OPT_BOOL(0, "all-match", &opt.all_match, N_("show only matches from files that match all patterns")), - { OPTION_SET_INT, 0, "debug", &opt.debug, NULL, - N_("show parse tree for grep expression"), - PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1 }, + OPT_SET_INT_F(0, "debug", &opt.debug, + N_("show parse tree for grep expression"), + 1, PARSE_OPT_HIDDEN), OPT_GROUP(""), { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, N_("pager"), N_("show matching files in the pager"), - PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, - OPT_BOOL(0, "ext-grep", &external_grep_allowed__ignored, - N_("allow calling of grep(1) (ignored by this build)")), + PARSE_OPT_OPTARG | PARSE_OPT_NOCOMPLETE, + NULL, (intptr_t)default_pager }, + OPT_BOOL_F(0, "ext-grep", &external_grep_allowed__ignored, + N_("allow calling of grep(1) (ignored by this build)"), + PARSE_OPT_NOCOMPLETE), OPT_END() }; - init_grep_defaults(); + init_grep_defaults(the_repository); git_config(grep_cmd_config, NULL); - grep_init(&opt, prefix); - super_prefix = get_super_prefix(); + grep_init(&opt, the_repository, prefix); /* * If there is no -- then the paths must exist in the working @@ -1113,6 +958,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) /* die the same way as if we did it at the beginning */ setup_git_directory(); } + /* Ignore --recurse-submodules if --no-index is given or implied */ + if (!use_index) + recurse_submodules = 0; /* * skip a -- separator; we know it cannot be @@ -1144,11 +992,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (!opt.pattern_list) - die(_("no pattern given.")); - if (!opt.fixed && opt.ignore_case) - opt.regflags |= REG_ICASE; + die(_("no pattern given")); - compile_grep_patterns(&opt); + /* --only-matching has no effect with --invert. */ + if (opt.invert) + opt.only_matching = 0; /* * We have to find "--" in a separate pass, because its presence @@ -1169,7 +1017,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) allow_revs = use_index && !untracked; for (i = 0; i < argc; i++) { const char *arg = argv[i]; - unsigned char sha1[20]; + struct object_id oid; struct object_context oc; struct object *object; @@ -1184,16 +1032,19 @@ int cmd_grep(int argc, const char **argv, const char *prefix) break; } - if (get_sha1_with_context(arg, 0, sha1, &oc)) { + if (get_oid_with_context(the_repository, arg, + GET_OID_RECORD_PATH, + &oid, &oc)) { if (seen_dashdash) die(_("unable to resolve revision: %s"), arg); break; } - object = parse_object_or_die(sha1, arg); + object = parse_object_or_die(&oid, arg); if (!seen_dashdash) verify_non_filename(prefix, arg); add_object_array_with_path(object, arg, &list, oc.mode, oc.path); + free(oc.path); } /* @@ -1212,33 +1063,36 @@ int cmd_grep(int argc, const char **argv, const char *prefix) prefix, argv + i); pathspec.max_depth = opt.max_depth; pathspec.recursive = 1; - -#ifndef NO_PTHREADS - if (list.nr || cached || show_in_pager) - num_threads = 0; - else if (num_threads == 0) - num_threads = GREP_NUM_THREADS_DEFAULT; - else if (num_threads < 0) + pathspec.recurse_submodules = !!recurse_submodules; + + if (list.nr || cached || show_in_pager) { + if (num_threads > 1) + warning(_("invalid option combination, ignoring --threads")); + num_threads = 1; + } else if (!HAVE_THREADS && num_threads > 1) { + warning(_("no threads support, ignoring --threads")); + num_threads = 1; + } else if (num_threads < 0) die(_("invalid number of threads specified (%d)"), num_threads); -#else - num_threads = 0; -#endif + else if (num_threads == 0) + num_threads = HAVE_THREADS ? GREP_NUM_THREADS_DEFAULT : 1; -#ifndef NO_PTHREADS - if (num_threads) { + if (num_threads > 1) { + if (!HAVE_THREADS) + BUG("Somebody got num_threads calculation wrong!"); if (!(opt.name_only || opt.unmatch_name_only || opt.count) && (opt.pre_context || opt.post_context || opt.file_break || opt.funcbody)) skip_first_line = 1; start_threads(&opt); - } -#endif - - if (recurse_submodules) { - gitmodules_config(); - compile_submodule_options(&opt, &pathspec, cached, untracked, - opt_exclude, use_index, - pattern_type_arg); + } else { + /* + * The compiled patterns on the main path are only + * used when not using threading. Otherwise + * start_threads() above calls compile_grep_patterns() + * for each thread. + */ + compile_grep_patterns(&opt); } if (show_in_pager && (cached || list.nr)) @@ -1259,25 +1113,25 @@ int cmd_grep(int argc, const char **argv, const char *prefix) strbuf_addf(&buf, "+/%s%s", strcmp("less", pager) ? "" : "*", opt.pattern_list->pattern); - string_list_append(&path_list, buf.buf); - strbuf_detach(&buf, NULL); + string_list_append(&path_list, + strbuf_detach(&buf, NULL)); } } - if (recurse_submodules && (!use_index || untracked)) - die(_("option not supported with --recurse-submodules.")); + if (recurse_submodules && untracked) + die(_("--untracked not supported with --recurse-submodules")); if (!show_in_pager && !opt.status_only) setup_pager(); if (!use_index && (untracked || cached)) - die(_("--cached or --untracked cannot be used with --no-index.")); + die(_("--cached or --untracked cannot be used with --no-index")); if (!use_index || untracked) { int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude; hit = grep_directory(&opt, &pathspec, use_exclude, use_index); } else if (0 <= opt_exclude) { - die(_("--[no-]exclude-standard cannot be used for tracked contents.")); + die(_("--[no-]exclude-standard cannot be used for tracked contents")); } else if (!list.nr) { if (!cached) setup_work_tree(); @@ -1285,14 +1139,17 @@ int cmd_grep(int argc, const char **argv, const char *prefix) hit = grep_cache(&opt, &pathspec, cached); } else { if (cached) - die(_("both --cached and trees are given.")); + die(_("both --cached and trees are given")); + hit = grep_objects(&opt, &pathspec, &list); } - if (num_threads) + if (num_threads > 1) hit |= wait_all(); if (hit && show_in_pager) run_pager(&opt, prefix); + clear_pathspec(&pathspec); free_grep_patterns(&opt); + grep_destroy(); return !hit; }