2006-05-01 14:28:15 +08:00
|
|
|
/*
|
|
|
|
* Builtin "git grep"
|
|
|
|
*
|
|
|
|
* Copyright (c) 2006 Junio C Hamano
|
|
|
|
*/
|
|
|
|
#include "cache.h"
|
|
|
|
#include "blob.h"
|
|
|
|
#include "tree.h"
|
|
|
|
#include "commit.h"
|
|
|
|
#include "tag.h"
|
2006-05-02 06:58:29 +08:00
|
|
|
#include "tree-walk.h"
|
2006-05-01 14:28:15 +08:00
|
|
|
#include "builtin.h"
|
2009-05-08 03:46:48 +08:00
|
|
|
#include "parse-options.h"
|
2010-06-13 00:36:51 +08:00
|
|
|
#include "string-list.h"
|
|
|
|
#include "run-command.h"
|
2009-07-02 06:07:24 +08:00
|
|
|
#include "userdiff.h"
|
2006-09-18 07:02:52 +08:00
|
|
|
#include "grep.h"
|
2009-09-05 20:31:17 +08:00
|
|
|
#include "quote.h"
|
2010-02-07 02:40:08 +08:00
|
|
|
#include "dir.h"
|
2013-07-14 16:35:25 +08:00
|
|
|
#include "pathspec.h"
|
2016-12-17 03:03:20 +08:00
|
|
|
#include "submodule.h"
|
2016-12-17 03:03:21 +08:00
|
|
|
#include "submodule-config.h"
|
2010-01-26 06:51:39 +08:00
|
|
|
|
2009-05-08 03:46:48 +08:00
|
|
|
static char const * const grep_usage[] = {
|
2015-01-13 15:44:47 +08:00
|
|
|
N_("git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"),
|
2009-05-08 03:46:48 +08:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2016-12-17 03:03:20 +08:00
|
|
|
static const char *super_prefix;
|
|
|
|
static int recurse_submodules;
|
|
|
|
static struct argv_array submodule_options = ARGV_ARRAY_INIT;
|
2016-12-17 03:03:21 +08:00
|
|
|
static const char *parent_basename;
|
2016-12-17 03:03:20 +08:00
|
|
|
|
|
|
|
static int grep_submodule_launch(struct grep_opt *opt,
|
|
|
|
const struct grep_source *gs);
|
|
|
|
|
2015-12-15 23:31:39 +08:00
|
|
|
#define GREP_NUM_THREADS_DEFAULT 8
|
|
|
|
static int num_threads;
|
2010-01-26 06:51:39 +08:00
|
|
|
|
|
|
|
#ifndef NO_PTHREADS
|
2015-12-15 23:31:39 +08:00
|
|
|
static pthread_t *threads;
|
2010-01-26 06:51:39 +08:00
|
|
|
|
|
|
|
/* We use one producer thread and THREADS consumer
|
|
|
|
* threads. The producer adds struct work_items to 'todo' and the
|
|
|
|
* consumers pick work items from the same array.
|
|
|
|
*/
|
2011-03-16 15:08:34 +08:00
|
|
|
struct work_item {
|
2012-02-02 16:19:37 +08:00
|
|
|
struct grep_source source;
|
2010-01-26 06:51:39 +08:00
|
|
|
char done;
|
|
|
|
struct strbuf out;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* In the range [todo_done, todo_start) in 'todo' we have work_items
|
|
|
|
* that have been or are processed by a consumer thread. We haven't
|
|
|
|
* written the result for these to stdout yet.
|
|
|
|
*
|
|
|
|
* The work_items in [todo_start, todo_end) are waiting to be picked
|
|
|
|
* up by a consumer thread.
|
|
|
|
*
|
|
|
|
* The ranges are modulo TODO_SIZE.
|
|
|
|
*/
|
|
|
|
#define TODO_SIZE 128
|
|
|
|
static struct work_item todo[TODO_SIZE];
|
|
|
|
static int todo_start;
|
|
|
|
static int todo_end;
|
|
|
|
static int todo_done;
|
|
|
|
|
|
|
|
/* Has all work items been added? */
|
|
|
|
static int all_work_added;
|
|
|
|
|
|
|
|
/* This lock protects all the variables above. */
|
|
|
|
static pthread_mutex_t grep_mutex;
|
|
|
|
|
2011-10-27 02:45:15 +08:00
|
|
|
static inline void grep_lock(void)
|
|
|
|
{
|
2015-12-15 23:31:39 +08:00
|
|
|
if (num_threads)
|
2011-10-27 02:45:15 +08:00
|
|
|
pthread_mutex_lock(&grep_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void grep_unlock(void)
|
|
|
|
{
|
2015-12-15 23:31:39 +08:00
|
|
|
if (num_threads)
|
2011-10-27 02:45:15 +08:00
|
|
|
pthread_mutex_unlock(&grep_mutex);
|
|
|
|
}
|
|
|
|
|
2010-01-26 06:51:39 +08:00
|
|
|
/* Signalled when a new work_item is added to todo. */
|
|
|
|
static pthread_cond_t cond_add;
|
|
|
|
|
|
|
|
/* Signalled when the result from one work_item is written to
|
|
|
|
* stdout.
|
|
|
|
*/
|
|
|
|
static pthread_cond_t cond_write;
|
|
|
|
|
|
|
|
/* Signalled when we are finished with everything. */
|
|
|
|
static pthread_cond_t cond_result;
|
|
|
|
|
2011-06-05 23:24:15 +08:00
|
|
|
static int skip_first_line;
|
2010-03-16 00:21:10 +08:00
|
|
|
|
2012-02-02 16:24:28 +08:00
|
|
|
static void add_work(struct grep_opt *opt, enum grep_source_type type,
|
2012-10-12 18:49:38 +08:00
|
|
|
const char *name, const char *path, const void *id)
|
2010-01-26 06:51:39 +08:00
|
|
|
{
|
|
|
|
grep_lock();
|
|
|
|
|
|
|
|
while ((todo_end+1) % ARRAY_SIZE(todo) == todo_done) {
|
|
|
|
pthread_cond_wait(&cond_write, &grep_mutex);
|
|
|
|
}
|
|
|
|
|
2012-10-12 18:49:38 +08:00
|
|
|
grep_source_init(&todo[todo_end].source, type, name, path, id);
|
2012-02-02 16:24:28 +08:00
|
|
|
if (opt->binary != GREP_BINARY_TEXT)
|
|
|
|
grep_source_load_driver(&todo[todo_end].source);
|
2010-01-26 06:51:39 +08:00
|
|
|
todo[todo_end].done = 0;
|
|
|
|
strbuf_reset(&todo[todo_end].out);
|
|
|
|
todo_end = (todo_end + 1) % ARRAY_SIZE(todo);
|
|
|
|
|
|
|
|
pthread_cond_signal(&cond_add);
|
|
|
|
grep_unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct work_item *get_work(void)
|
|
|
|
{
|
|
|
|
struct work_item *ret;
|
|
|
|
|
|
|
|
grep_lock();
|
|
|
|
while (todo_start == todo_end && !all_work_added) {
|
|
|
|
pthread_cond_wait(&cond_add, &grep_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (todo_start == todo_end && all_work_added) {
|
|
|
|
ret = NULL;
|
|
|
|
} else {
|
|
|
|
ret = &todo[todo_start];
|
|
|
|
todo_start = (todo_start + 1) % ARRAY_SIZE(todo);
|
|
|
|
}
|
|
|
|
grep_unlock();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void work_done(struct work_item *w)
|
|
|
|
{
|
|
|
|
int old_done;
|
|
|
|
|
|
|
|
grep_lock();
|
|
|
|
w->done = 1;
|
|
|
|
old_done = todo_done;
|
|
|
|
for(; todo[todo_done].done && todo_done != todo_start;
|
|
|
|
todo_done = (todo_done+1) % ARRAY_SIZE(todo)) {
|
|
|
|
w = &todo[todo_done];
|
2010-03-16 00:21:10 +08:00
|
|
|
if (w->out.len) {
|
2011-06-05 23:24:15 +08:00
|
|
|
const char *p = w->out.buf;
|
|
|
|
size_t len = w->out.len;
|
|
|
|
|
|
|
|
/* Skip the leading hunk mark of the first file. */
|
|
|
|
if (skip_first_line) {
|
|
|
|
while (len) {
|
|
|
|
len--;
|
|
|
|
if (*p++ == '\n')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
skip_first_line = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
write_or_die(1, p, len);
|
2010-03-16 00:21:10 +08:00
|
|
|
}
|
2012-02-02 16:19:37 +08:00
|
|
|
grep_source_clear(&w->source);
|
2010-01-26 06:51:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (old_done != todo_done)
|
|
|
|
pthread_cond_signal(&cond_write);
|
|
|
|
|
|
|
|
if (all_work_added && todo_done == todo_end)
|
|
|
|
pthread_cond_signal(&cond_result);
|
|
|
|
|
|
|
|
grep_unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *run(void *arg)
|
|
|
|
{
|
|
|
|
int hit = 0;
|
|
|
|
struct grep_opt *opt = arg;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct work_item *w = get_work();
|
|
|
|
if (!w)
|
|
|
|
break;
|
|
|
|
|
|
|
|
opt->output_priv = w;
|
2016-12-17 03:03:20 +08:00
|
|
|
if (w->source.type == GREP_SOURCE_SUBMODULE)
|
|
|
|
hit |= grep_submodule_launch(opt, &w->source);
|
|
|
|
else
|
|
|
|
hit |= grep_source(opt, &w->source);
|
2012-02-02 16:19:37 +08:00
|
|
|
grep_source_clear_data(&w->source);
|
2010-01-26 06:51:39 +08:00
|
|
|
work_done(w);
|
|
|
|
}
|
2010-01-30 23:42:58 +08:00
|
|
|
free_grep_patterns(arg);
|
|
|
|
free(arg);
|
2010-01-26 06:51:39 +08:00
|
|
|
|
|
|
|
return (void*) (intptr_t) hit;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void strbuf_out(struct grep_opt *opt, const void *buf, size_t size)
|
|
|
|
{
|
|
|
|
struct work_item *w = opt->output_priv;
|
|
|
|
strbuf_add(&w->out, buf, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void start_threads(struct grep_opt *opt)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
pthread_mutex_init(&grep_mutex, NULL);
|
2012-02-02 16:18:41 +08:00
|
|
|
pthread_mutex_init(&grep_read_mutex, NULL);
|
2011-12-13 05:16:07 +08:00
|
|
|
pthread_mutex_init(&grep_attr_mutex, NULL);
|
2010-01-26 06:51:39 +08:00
|
|
|
pthread_cond_init(&cond_add, NULL);
|
|
|
|
pthread_cond_init(&cond_write, NULL);
|
|
|
|
pthread_cond_init(&cond_result, NULL);
|
grep: make locking flag global
The low-level grep code traditionally didn't care about
threading, as it doesn't do any threading itself and didn't
call out to other non-thread-safe code. That changed with
0579f91 (grep: enable threading with -p and -W using lazy
attribute lookup, 2011-12-12), which pushed the lookup of
funcname attributes (which is not thread-safe) into the
low-level grep code.
As a result, the low-level code learned about a new global
"grep_attr_mutex" to serialize access to the attribute code.
A multi-threaded caller (e.g., builtin/grep.c) is expected
to initialize the mutex and set "use_threads" in the
grep_opt structure. The low-level code only uses the lock if
use_threads is set.
However, putting the use_threads flag into the grep_opt
struct is not the most logical place. Whether threading is
in use is not something that matters for each call to
grep_buffer, but is instead global to the whole program
(i.e., if any thread is doing multi-threaded grep, every
other thread, even if it thinks it is doing its own
single-threaded grep, would need to use the locking). In
practice, this distinction isn't a problem for us, because
the only user of multi-threaded grep is "git-grep", which
does nothing except call grep.
This patch turns the opt->use_threads flag into a global
flag. More important than the nit-picking semantic argument
above is that this means that the locking functions don't
need to actually have access to a grep_opt to know whether
to lock. Which in turn can make adding new locks simpler, as
we don't need to pass around a grep_opt.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-02 16:18:29 +08:00
|
|
|
grep_use_locks = 1;
|
2010-01-26 06:51:39 +08:00
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(todo); i++) {
|
|
|
|
strbuf_init(&todo[i].out, 0);
|
|
|
|
}
|
|
|
|
|
2015-12-15 23:31:39 +08:00
|
|
|
threads = xcalloc(num_threads, sizeof(*threads));
|
|
|
|
for (i = 0; i < num_threads; i++) {
|
2010-01-26 06:51:39 +08:00
|
|
|
int err;
|
|
|
|
struct grep_opt *o = grep_opt_dup(opt);
|
|
|
|
o->output = strbuf_out;
|
2012-09-14 17:46:35 +08:00
|
|
|
o->debug = 0;
|
2010-01-26 06:51:39 +08:00
|
|
|
compile_grep_patterns(o);
|
|
|
|
err = pthread_create(&threads[i], NULL, run, o);
|
|
|
|
|
|
|
|
if (err)
|
2011-02-23 07:41:55 +08:00
|
|
|
die(_("grep: failed to create thread: %s"),
|
2010-01-26 06:51:39 +08:00
|
|
|
strerror(err));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wait_all(void)
|
|
|
|
{
|
|
|
|
int hit = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
grep_lock();
|
|
|
|
all_work_added = 1;
|
|
|
|
|
|
|
|
/* Wait until all work is done. */
|
|
|
|
while (todo_done != todo_end)
|
|
|
|
pthread_cond_wait(&cond_result, &grep_mutex);
|
|
|
|
|
|
|
|
/* Wake up all the consumer threads so they can see that there
|
|
|
|
* is no more work to do.
|
|
|
|
*/
|
|
|
|
pthread_cond_broadcast(&cond_add);
|
|
|
|
grep_unlock();
|
|
|
|
|
2015-12-15 23:31:39 +08:00
|
|
|
for (i = 0; i < num_threads; i++) {
|
2010-01-26 06:51:39 +08:00
|
|
|
void *h;
|
|
|
|
pthread_join(threads[i], &h);
|
|
|
|
hit |= (int) (intptr_t) h;
|
|
|
|
}
|
|
|
|
|
2015-12-15 23:31:39 +08:00
|
|
|
free(threads);
|
|
|
|
|
2010-01-26 06:51:39 +08:00
|
|
|
pthread_mutex_destroy(&grep_mutex);
|
2012-02-02 16:18:41 +08:00
|
|
|
pthread_mutex_destroy(&grep_read_mutex);
|
2011-12-13 05:16:07 +08:00
|
|
|
pthread_mutex_destroy(&grep_attr_mutex);
|
2010-01-26 06:51:39 +08:00
|
|
|
pthread_cond_destroy(&cond_add);
|
|
|
|
pthread_cond_destroy(&cond_write);
|
|
|
|
pthread_cond_destroy(&cond_result);
|
grep: make locking flag global
The low-level grep code traditionally didn't care about
threading, as it doesn't do any threading itself and didn't
call out to other non-thread-safe code. That changed with
0579f91 (grep: enable threading with -p and -W using lazy
attribute lookup, 2011-12-12), which pushed the lookup of
funcname attributes (which is not thread-safe) into the
low-level grep code.
As a result, the low-level code learned about a new global
"grep_attr_mutex" to serialize access to the attribute code.
A multi-threaded caller (e.g., builtin/grep.c) is expected
to initialize the mutex and set "use_threads" in the
grep_opt structure. The low-level code only uses the lock if
use_threads is set.
However, putting the use_threads flag into the grep_opt
struct is not the most logical place. Whether threading is
in use is not something that matters for each call to
grep_buffer, but is instead global to the whole program
(i.e., if any thread is doing multi-threaded grep, every
other thread, even if it thinks it is doing its own
single-threaded grep, would need to use the locking). In
practice, this distinction isn't a problem for us, because
the only user of multi-threaded grep is "git-grep", which
does nothing except call grep.
This patch turns the opt->use_threads flag into a global
flag. More important than the nit-picking semantic argument
above is that this means that the locking functions don't
need to actually have access to a grep_opt to know whether
to lock. Which in turn can make adding new locks simpler, as
we don't need to pass around a grep_opt.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-02 16:18:29 +08:00
|
|
|
grep_use_locks = 0;
|
2010-01-26 06:51:39 +08:00
|
|
|
|
|
|
|
return hit;
|
|
|
|
}
|
|
|
|
#else /* !NO_PTHREADS */
|
|
|
|
|
|
|
|
static int wait_all(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-10-10 07:04:12 +08:00
|
|
|
static int grep_cmd_config(const char *var, const char *value, void *cb)
|
|
|
|
{
|
|
|
|
int st = grep_config(var, value, cb);
|
|
|
|
if (git_color_default_config(var, value, cb) < 0)
|
|
|
|
st = -1;
|
2015-12-15 23:31:39 +08:00
|
|
|
|
|
|
|
if (!strcmp(var, "grep.threads")) {
|
|
|
|
num_threads = git_config_int(var, value);
|
|
|
|
if (num_threads < 0)
|
|
|
|
die(_("invalid number of threads specified (%d) for %s"),
|
|
|
|
num_threads, var);
|
|
|
|
}
|
|
|
|
|
2012-10-10 07:04:12 +08:00
|
|
|
return st;
|
|
|
|
}
|
|
|
|
|
2010-02-16 10:34:28 +08:00
|
|
|
static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
|
|
|
|
{
|
|
|
|
void *data;
|
|
|
|
|
2012-02-02 16:18:41 +08:00
|
|
|
grep_read_lock();
|
2011-10-27 03:15:51 +08:00
|
|
|
data = read_sha1_file(sha1, type, size);
|
2012-02-02 16:18:41 +08:00
|
|
|
grep_read_unlock();
|
2010-01-26 06:51:39 +08:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
|
2012-10-12 18:49:38 +08:00
|
|
|
const char *filename, int tree_name_len,
|
|
|
|
const char *path)
|
2010-01-26 06:51:39 +08:00
|
|
|
{
|
|
|
|
struct strbuf pathbuf = STRBUF_INIT;
|
|
|
|
|
2006-08-11 15:44:42 +08:00
|
|
|
if (opt->relative && opt->prefix_length) {
|
2013-06-25 23:53:45 +08:00
|
|
|
quote_path_relative(filename + tree_name_len, opt->prefix, &pathbuf);
|
2010-01-26 06:51:39 +08:00
|
|
|
strbuf_insert(&pathbuf, 0, filename, tree_name_len);
|
2016-12-17 03:03:20 +08:00
|
|
|
} else if (super_prefix) {
|
|
|
|
strbuf_add(&pathbuf, filename, tree_name_len);
|
|
|
|
strbuf_addstr(&pathbuf, super_prefix);
|
|
|
|
strbuf_addstr(&pathbuf, filename + tree_name_len);
|
2010-01-26 06:51:39 +08:00
|
|
|
} else {
|
|
|
|
strbuf_addstr(&pathbuf, filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NO_PTHREADS
|
2015-12-15 23:31:39 +08:00
|
|
|
if (num_threads) {
|
2012-10-12 18:49:38 +08:00
|
|
|
add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1);
|
2012-02-02 16:19:37 +08:00
|
|
|
strbuf_release(&pathbuf);
|
2010-01-26 06:51:39 +08:00
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
2012-02-02 16:19:37 +08:00
|
|
|
struct grep_source gs;
|
2010-01-26 06:51:39 +08:00
|
|
|
int hit;
|
2006-05-01 14:28:15 +08:00
|
|
|
|
2012-10-12 18:49:38 +08:00
|
|
|
grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1);
|
2012-02-02 16:19:37 +08:00
|
|
|
strbuf_release(&pathbuf);
|
|
|
|
hit = grep_source(opt, &gs);
|
2007-03-07 09:44:37 +08:00
|
|
|
|
2012-02-02 16:19:37 +08:00
|
|
|
grep_source_clear(&gs);
|
|
|
|
return hit;
|
2006-05-01 14:28:15 +08:00
|
|
|
}
|
2010-01-26 06:51:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int grep_file(struct grep_opt *opt, const char *filename)
|
|
|
|
{
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
|
2016-12-17 03:03:20 +08:00
|
|
|
if (opt->relative && opt->prefix_length) {
|
2013-06-25 23:53:45 +08:00
|
|
|
quote_path_relative(filename, opt->prefix, &buf);
|
2016-12-17 03:03:20 +08:00
|
|
|
} else {
|
|
|
|
if (super_prefix)
|
|
|
|
strbuf_addstr(&buf, super_prefix);
|
2010-01-26 06:51:39 +08:00
|
|
|
strbuf_addstr(&buf, filename);
|
2016-12-17 03:03:20 +08:00
|
|
|
}
|
2010-01-26 06:51:39 +08:00
|
|
|
|
|
|
|
#ifndef NO_PTHREADS
|
2015-12-15 23:31:39 +08:00
|
|
|
if (num_threads) {
|
2012-10-12 18:49:38 +08:00
|
|
|
add_work(opt, GREP_SOURCE_FILE, buf.buf, filename, filename);
|
2012-02-02 16:19:37 +08:00
|
|
|
strbuf_release(&buf);
|
2010-01-26 06:51:39 +08:00
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
2012-02-02 16:19:37 +08:00
|
|
|
struct grep_source gs;
|
2010-01-26 06:51:39 +08:00
|
|
|
int hit;
|
|
|
|
|
2012-10-12 18:49:38 +08:00
|
|
|
grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename);
|
2012-02-02 16:19:37 +08:00
|
|
|
strbuf_release(&buf);
|
|
|
|
hit = grep_source(opt, &gs);
|
|
|
|
|
|
|
|
grep_source_clear(&gs);
|
2010-01-26 06:51:39 +08:00
|
|
|
return hit;
|
|
|
|
}
|
2006-05-01 14:28:15 +08:00
|
|
|
}
|
|
|
|
|
2010-06-13 00:36:51 +08:00
|
|
|
static void append_path(struct grep_opt *opt, const void *data, size_t len)
|
|
|
|
{
|
|
|
|
struct string_list *path_list = opt->output_priv;
|
|
|
|
|
|
|
|
if (len == 1 && *(const char *)data == '\0')
|
|
|
|
return;
|
2010-06-26 07:41:39 +08:00
|
|
|
string_list_append(path_list, xstrndup(data, len));
|
2010-06-13 00:36:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void run_pager(struct grep_opt *opt, const char *prefix)
|
|
|
|
{
|
|
|
|
struct string_list *path_list = opt->output_priv;
|
2016-02-23 06:44:21 +08:00
|
|
|
struct child_process child = CHILD_PROCESS_INIT;
|
2010-06-13 00:36:51 +08:00
|
|
|
int i, status;
|
|
|
|
|
|
|
|
for (i = 0; i < path_list->nr; i++)
|
2016-02-23 06:44:21 +08:00
|
|
|
argv_array_push(&child.args, path_list->items[i].string);
|
|
|
|
child.dir = prefix;
|
|
|
|
child.use_shell = 1;
|
2010-06-13 00:36:51 +08:00
|
|
|
|
2016-02-23 06:44:21 +08:00
|
|
|
status = run_command(&child);
|
2010-06-13 00:36:51 +08:00
|
|
|
if (status)
|
|
|
|
exit(status);
|
|
|
|
}
|
|
|
|
|
2016-12-17 03:03:20 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Launch child process to grep contents of a submodule
|
|
|
|
*/
|
|
|
|
static int grep_submodule_launch(struct grep_opt *opt,
|
|
|
|
const struct grep_source *gs)
|
|
|
|
{
|
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
|
|
|
int status, i;
|
2016-12-17 03:03:21 +08:00
|
|
|
const char *end_of_base;
|
|
|
|
const char *name;
|
2016-12-17 03:03:20 +08:00
|
|
|
struct work_item *w = opt->output_priv;
|
|
|
|
|
2016-12-17 03:03:21 +08:00
|
|
|
end_of_base = strchr(gs->name, ':');
|
|
|
|
if (gs->identifier && end_of_base)
|
|
|
|
name = end_of_base + 1;
|
|
|
|
else
|
|
|
|
name = gs->name;
|
|
|
|
|
2016-12-17 03:03:20 +08:00
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
2016-12-17 03:03:22 +08:00
|
|
|
argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);
|
2016-12-17 03:03:20 +08:00
|
|
|
|
|
|
|
/* Add super prefix */
|
|
|
|
argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
|
|
|
|
super_prefix ? super_prefix : "",
|
2016-12-17 03:03:21 +08:00
|
|
|
name);
|
2016-12-17 03:03:20 +08:00
|
|
|
argv_array_push(&cp.args, "grep");
|
|
|
|
|
2016-12-17 03:03:21 +08:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
if (gs->identifier && end_of_base)
|
|
|
|
argv_array_pushf(&cp.args, "--parent-basename=%.*s",
|
|
|
|
(int) (end_of_base - gs->name),
|
|
|
|
gs->name);
|
|
|
|
|
2016-12-17 03:03:20 +08:00
|
|
|
/* Add options */
|
2016-12-17 03:03:21 +08:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2016-12-17 03:03:20 +08:00
|
|
|
argv_array_push(&cp.args, submodule_options.argv[i]);
|
2016-12-17 03:03:21 +08:00
|
|
|
}
|
2016-12-17 03:03:20 +08:00
|
|
|
|
|
|
|
cp.git_cmd = 1;
|
|
|
|
cp.dir = gs->path;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* invert the return code to make a hit equal to 1 */
|
|
|
|
return !status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
2016-12-17 03:03:22 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2016-12-17 03:03:20 +08:00
|
|
|
|
|
|
|
#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;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
write_or_die(1, w.out.buf, w.out.len);
|
|
|
|
|
|
|
|
grep_source_clear(&w.source);
|
|
|
|
strbuf_release(&w.out);
|
|
|
|
return hit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec,
|
|
|
|
int cached)
|
2006-05-01 14:28:15 +08:00
|
|
|
{
|
|
|
|
int hit = 0;
|
|
|
|
int nr;
|
2016-12-17 03:03:20 +08:00
|
|
|
struct strbuf name = STRBUF_INIT;
|
|
|
|
int name_base_len = 0;
|
|
|
|
if (super_prefix) {
|
|
|
|
name_base_len = strlen(super_prefix);
|
|
|
|
strbuf_addstr(&name, super_prefix);
|
|
|
|
}
|
|
|
|
|
2006-05-01 14:28:15 +08:00
|
|
|
read_cache();
|
|
|
|
|
|
|
|
for (nr = 0; nr < active_nr; nr++) {
|
Convert "struct cache_entry *" to "const ..." wherever possible
I attempted to make index_state->cache[] a "const struct cache_entry **"
to find out how existing entries in index are modified and where. The
question I have is what do we do if we really need to keep track of on-disk
changes in the index. The result is
- diff-lib.c: setting CE_UPTODATE
- name-hash.c: setting CE_HASHED
- preload-index.c, read-cache.c, unpack-trees.c and
builtin/update-index: obvious
- entry.c: write_entry() may refresh the checked out entry via
fill_stat_cache_info(). This causes "non-const struct cache_entry
*" in builtin/apply.c, builtin/checkout-index.c and
builtin/checkout.c
- builtin/ls-files.c: --with-tree changes stagemask and may set
CE_UPDATE
Of these, write_entry() and its call sites are probably most
interesting because it modifies on-disk info. But this is stat info
and can be retrieved via refresh, at least for porcelain
commands. Other just uses ce_flags for local purposes.
So, keeping track of "dirty" entries is just a matter of setting a
flag in index modification functions exposed by read-cache.c. Except
unpack-trees, the rest of the code base does not do anything funny
behind read-cache's back.
The actual patch is less valueable than the summary above. But if
anyone wants to re-identify the above sites. Applying this patch, then
this:
diff --git a/cache.h b/cache.h
index 430d021..1692891 100644
--- a/cache.h
+++ b/cache.h
@@ -267,7 +267,7 @@ static inline unsigned int canon_mode(unsigned int mode)
#define cache_entry_size(len) (offsetof(struct cache_entry,name) + (len) + 1)
struct index_state {
- struct cache_entry **cache;
+ const struct cache_entry **cache;
unsigned int version;
unsigned int cache_nr, cache_alloc, cache_changed;
struct string_list *resolve_undo;
will help quickly identify them without bogus warnings.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-07-09 23:29:00 +08:00
|
|
|
const struct cache_entry *ce = active_cache[nr];
|
2016-12-17 03:03:20 +08:00
|
|
|
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,
|
|
|
|
S_ISDIR(ce->ce_mode) ||
|
|
|
|
S_ISGITLINK(ce->ce_mode))) {
|
|
|
|
/*
|
|
|
|
* If CE_VALID is on, we assume worktree file and its
|
|
|
|
* cache entry are identical, even if worktree file has
|
|
|
|
* been modified, so use cache version instead
|
|
|
|
*/
|
|
|
|
if (cached || (ce->ce_flags & CE_VALID) ||
|
|
|
|
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);
|
|
|
|
} else {
|
|
|
|
hit |= grep_file(opt, ce->name);
|
|
|
|
}
|
|
|
|
} 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);
|
|
|
|
} else {
|
2006-05-01 14:28:15 +08:00
|
|
|
continue;
|
2006-11-27 04:47:52 +08:00
|
|
|
}
|
2016-12-17 03:03:20 +08:00
|
|
|
|
2006-11-27 04:47:52 +08:00
|
|
|
if (ce_stage(ce)) {
|
|
|
|
do {
|
|
|
|
nr++;
|
|
|
|
} while (nr < active_nr &&
|
|
|
|
!strcmp(ce->name, active_cache[nr]->name));
|
|
|
|
nr--; /* compensate for loop control */
|
|
|
|
}
|
2010-01-26 07:37:23 +08:00
|
|
|
if (hit && opt->status_only)
|
|
|
|
break;
|
2006-05-01 14:28:15 +08:00
|
|
|
}
|
2016-12-17 03:03:20 +08:00
|
|
|
|
|
|
|
strbuf_release(&name);
|
2006-05-01 14:28:15 +08:00
|
|
|
return hit;
|
|
|
|
}
|
|
|
|
|
2010-12-15 23:02:51 +08:00
|
|
|
static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
|
2012-10-12 18:49:38 +08:00
|
|
|
struct tree_desc *tree, struct strbuf *base, int tn_len,
|
|
|
|
int check_attr)
|
2006-05-01 14:28:15 +08:00
|
|
|
{
|
2011-10-24 14:36:10 +08:00
|
|
|
int hit = 0;
|
|
|
|
enum interesting match = entry_not_interesting;
|
tree_entry(): new tree-walking helper function
This adds a "tree_entry()" function that combines the common operation of
doing a "tree_entry_extract()" + "update_tree_entry()".
It also has a simplified calling convention, designed for simple loops
that traverse over a whole tree: the arguments are pointers to the tree
descriptor and a name_entry structure to fill in, and it returns a boolean
"true" if there was an entry left to be gotten in the tree.
This allows tree traversal with
struct tree_desc desc;
struct name_entry entry;
desc.buf = tree->buffer;
desc.size = tree->size;
while (tree_entry(&desc, &entry) {
... use "entry.{path, sha1, mode, pathlen}" ...
}
which is not only shorter than writing it out in full, it's hopefully less
error prone too.
[ It's actually a tad faster too - we don't need to recalculate the entry
pathlength in both extract and update, but need to do it only once.
Also, some callers can avoid doing a "strlen()" on the result, since
it's returned as part of the name_entry structure.
However, by now we're talking just 1% speedup on "git-rev-list --objects
--all", and we're definitely at the point where tree walking is no
longer the issue any more. ]
NOTE! Not everybody wants to use this new helper function, since some of
the tree walkers very much on purpose do the descriptor update separately
from the entry extraction. So the "extract + update" sequence still
remains as the core sequence, this is just a simplified interface.
We should probably add a silly two-line inline helper function for
initializing the descriptor from the "struct tree" too, just to cut down
on the noise from that common "desc" initializer.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-05-31 00:45:45 +08:00
|
|
|
struct name_entry entry;
|
2010-12-17 20:44:25 +08:00
|
|
|
int old_baselen = base->len;
|
2016-12-17 03:03:21 +08:00
|
|
|
struct strbuf name = STRBUF_INIT;
|
|
|
|
int name_base_len = 0;
|
|
|
|
if (super_prefix) {
|
|
|
|
strbuf_addstr(&name, super_prefix);
|
|
|
|
name_base_len = name.len;
|
|
|
|
}
|
2006-05-01 14:28:15 +08:00
|
|
|
|
tree_entry(): new tree-walking helper function
This adds a "tree_entry()" function that combines the common operation of
doing a "tree_entry_extract()" + "update_tree_entry()".
It also has a simplified calling convention, designed for simple loops
that traverse over a whole tree: the arguments are pointers to the tree
descriptor and a name_entry structure to fill in, and it returns a boolean
"true" if there was an entry left to be gotten in the tree.
This allows tree traversal with
struct tree_desc desc;
struct name_entry entry;
desc.buf = tree->buffer;
desc.size = tree->size;
while (tree_entry(&desc, &entry) {
... use "entry.{path, sha1, mode, pathlen}" ...
}
which is not only shorter than writing it out in full, it's hopefully less
error prone too.
[ It's actually a tad faster too - we don't need to recalculate the entry
pathlength in both extract and update, but need to do it only once.
Also, some callers can avoid doing a "strlen()" on the result, since
it's returned as part of the name_entry structure.
However, by now we're talking just 1% speedup on "git-rev-list --objects
--all", and we're definitely at the point where tree walking is no
longer the issue any more. ]
NOTE! Not everybody wants to use this new helper function, since some of
the tree walkers very much on purpose do the descriptor update separately
from the entry extraction. So the "extract + update" sequence still
remains as the core sequence, this is just a simplified interface.
We should probably add a silly two-line inline helper function for
initializing the descriptor from the "struct tree" too, just to cut down
on the noise from that common "desc" initializer.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-05-31 00:45:45 +08:00
|
|
|
while (tree_entry(tree, &entry)) {
|
2011-10-24 14:36:09 +08:00
|
|
|
int te_len = tree_entry_len(&entry);
|
2010-12-17 20:44:25 +08:00
|
|
|
|
2011-10-24 14:36:10 +08:00
|
|
|
if (match != all_entries_interesting) {
|
2016-12-17 03:03:21 +08:00
|
|
|
strbuf_addstr(&name, base->buf + tn_len);
|
|
|
|
match = tree_entry_interesting(&entry, &name,
|
|
|
|
0, pathspec);
|
|
|
|
strbuf_setlen(&name, name_base_len);
|
|
|
|
|
2011-10-24 14:36:10 +08:00
|
|
|
if (match == all_entries_not_interesting)
|
2011-03-25 17:34:20 +08:00
|
|
|
break;
|
2011-10-24 14:36:10 +08:00
|
|
|
if (match == entry_not_interesting)
|
2010-12-17 20:45:33 +08:00
|
|
|
continue;
|
|
|
|
}
|
2006-05-01 14:28:15 +08:00
|
|
|
|
2010-12-17 20:45:33 +08:00
|
|
|
strbuf_add(base, entry.path, te_len);
|
2006-05-02 03:27:56 +08:00
|
|
|
|
2010-12-17 20:45:33 +08:00
|
|
|
if (S_ISREG(entry.mode)) {
|
2016-04-18 07:10:39 +08:00
|
|
|
hit |= grep_sha1(opt, entry.oid->hash, base->buf, tn_len,
|
2012-10-12 18:49:38 +08:00
|
|
|
check_attr ? base->buf + tn_len : NULL);
|
2016-12-17 03:03:21 +08:00
|
|
|
} else if (S_ISDIR(entry.mode)) {
|
2007-02-27 03:55:59 +08:00
|
|
|
enum object_type type;
|
2006-05-01 14:28:15 +08:00
|
|
|
struct tree_desc sub;
|
|
|
|
void *data;
|
2007-03-22 01:08:25 +08:00
|
|
|
unsigned long size;
|
|
|
|
|
2016-04-18 07:10:39 +08:00
|
|
|
data = lock_and_read_sha1_file(entry.oid->hash, &type, &size);
|
2006-05-01 14:28:15 +08:00
|
|
|
if (!data)
|
2011-02-23 07:41:55 +08:00
|
|
|
die(_("unable to read tree (%s)"),
|
2016-04-18 07:10:39 +08:00
|
|
|
oid_to_hex(entry.oid));
|
2010-12-17 20:45:33 +08:00
|
|
|
|
|
|
|
strbuf_addch(base, '/');
|
2007-03-22 01:08:25 +08:00
|
|
|
init_tree_desc(&sub, data, size);
|
2012-10-12 18:49:38 +08:00
|
|
|
hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
|
|
|
|
check_attr);
|
2006-05-01 14:28:15 +08:00
|
|
|
free(data);
|
2016-12-17 03:03:21 +08:00
|
|
|
} else if (recurse_submodules && S_ISGITLINK(entry.mode)) {
|
|
|
|
hit |= grep_submodule(opt, entry.oid->hash, base->buf,
|
|
|
|
base->buf + tn_len);
|
2006-05-01 14:28:15 +08:00
|
|
|
}
|
2016-12-17 03:03:21 +08:00
|
|
|
|
2010-12-17 20:44:25 +08:00
|
|
|
strbuf_setlen(base, old_baselen);
|
|
|
|
|
2010-01-26 07:37:23 +08:00
|
|
|
if (hit && opt->status_only)
|
|
|
|
break;
|
2006-05-01 14:28:15 +08:00
|
|
|
}
|
2016-12-17 03:03:21 +08:00
|
|
|
|
|
|
|
strbuf_release(&name);
|
2006-05-01 14:28:15 +08:00
|
|
|
return hit;
|
|
|
|
}
|
|
|
|
|
2010-12-15 23:02:51 +08:00
|
|
|
static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
|
2014-10-16 06:42:57 +08:00
|
|
|
struct object *obj, const char *name, const char *path)
|
2006-05-01 14:28:15 +08:00
|
|
|
{
|
2006-07-12 11:45:31 +08:00
|
|
|
if (obj->type == OBJ_BLOB)
|
2015-11-10 10:22:29 +08:00
|
|
|
return grep_sha1(opt, obj->oid.hash, name, 0, path);
|
2006-07-12 11:45:31 +08:00
|
|
|
if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
|
2006-05-01 14:28:15 +08:00
|
|
|
struct tree_desc tree;
|
|
|
|
void *data;
|
2007-03-22 01:08:25 +08:00
|
|
|
unsigned long size;
|
2010-12-17 20:44:25 +08:00
|
|
|
struct strbuf base;
|
|
|
|
int hit, len;
|
|
|
|
|
2012-02-02 16:18:41 +08:00
|
|
|
grep_read_lock();
|
2015-11-10 10:22:28 +08:00
|
|
|
data = read_object_with_reference(obj->oid.hash, tree_type,
|
2007-03-22 01:08:25 +08:00
|
|
|
&size, NULL);
|
2012-02-02 16:18:41 +08:00
|
|
|
grep_read_unlock();
|
2011-08-30 21:45:38 +08:00
|
|
|
|
2006-05-01 14:28:15 +08:00
|
|
|
if (!data)
|
2015-11-10 10:22:28 +08:00
|
|
|
die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid));
|
2010-12-17 20:44:25 +08:00
|
|
|
|
2016-12-17 03:03:21 +08:00
|
|
|
/* Use parent's name as base when recursing submodules */
|
|
|
|
if (recurse_submodules && parent_basename)
|
|
|
|
name = parent_basename;
|
|
|
|
|
2010-12-17 20:44:25 +08:00
|
|
|
len = name ? strlen(name) : 0;
|
|
|
|
strbuf_init(&base, PATH_MAX + len + 1);
|
|
|
|
if (len) {
|
|
|
|
strbuf_add(&base, name, len);
|
|
|
|
strbuf_addch(&base, ':');
|
|
|
|
}
|
2007-03-22 01:08:25 +08:00
|
|
|
init_tree_desc(&tree, data, size);
|
2012-10-12 18:49:38 +08:00
|
|
|
hit = grep_tree(opt, pathspec, &tree, &base, base.len,
|
|
|
|
obj->type == OBJ_COMMIT);
|
2010-12-17 20:44:25 +08:00
|
|
|
strbuf_release(&base);
|
2006-05-01 14:28:15 +08:00
|
|
|
free(data);
|
|
|
|
return hit;
|
|
|
|
}
|
2011-02-23 07:41:55 +08:00
|
|
|
die(_("unable to grep from object of type %s"), typename(obj->type));
|
2006-05-01 14:28:15 +08:00
|
|
|
}
|
|
|
|
|
2010-12-15 23:02:51 +08:00
|
|
|
static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
|
2010-06-13 00:31:18 +08:00
|
|
|
const struct object_array *list)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
int hit = 0;
|
|
|
|
const unsigned int nr = list->nr;
|
|
|
|
|
|
|
|
for (i = 0; i < nr; i++) {
|
|
|
|
struct object *real_obj;
|
|
|
|
real_obj = deref_tag(list->objects[i].item, NULL, 0);
|
2016-12-17 03:03:21 +08:00
|
|
|
|
|
|
|
/* load the gitmodules file for this rev */
|
|
|
|
if (recurse_submodules) {
|
|
|
|
submodule_free();
|
|
|
|
gitmodules_config_sha1(real_obj->oid.hash);
|
|
|
|
}
|
2014-10-16 06:42:57 +08:00
|
|
|
if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path)) {
|
2010-06-13 00:31:18 +08:00
|
|
|
hit = 1;
|
|
|
|
if (opt->status_only)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return hit;
|
|
|
|
}
|
|
|
|
|
2011-10-05 09:40:41 +08:00
|
|
|
static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
|
grep: turn off gitlink detection for --no-index
If we are running "git grep --no-index" outside of a git
repository, we behave roughly like "grep -r", examining all
files in the current directory and its subdirectories.
However, because we use fill_directory() to do the
recursion, it will skip over any directories which look like
sub-repositories.
For a normal git operation (like "git grep" in a repository)
this makes sense; we do not want to cross the boundary out
of our current repository into a submodule. But for
"--no-index" without a repository, we should look at all
files, including embedded repositories.
There is one exception, though: we probably should _not_
descend into ".git" directories. Doing so is inefficient and
unlikely to turn up useful hits.
This patch drops our use of dir.c's gitlink-detection, but
we do still avoid ".git". That makes us more like tools such
as "ack" or "ag", which also know to avoid cruft in .git.
As a bonus, this also drops our usage of the ref code
when we are outside of a repository, making the transition
to pluggable ref backends cleaner.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-07 23:51:21 +08:00
|
|
|
int exc_std, int use_index)
|
2010-02-07 02:40:08 +08:00
|
|
|
{
|
|
|
|
struct dir_struct dir;
|
|
|
|
int i, hit = 0;
|
|
|
|
|
|
|
|
memset(&dir, 0, sizeof(dir));
|
grep: turn off gitlink detection for --no-index
If we are running "git grep --no-index" outside of a git
repository, we behave roughly like "grep -r", examining all
files in the current directory and its subdirectories.
However, because we use fill_directory() to do the
recursion, it will skip over any directories which look like
sub-repositories.
For a normal git operation (like "git grep" in a repository)
this makes sense; we do not want to cross the boundary out
of our current repository into a submodule. But for
"--no-index" without a repository, we should look at all
files, including embedded repositories.
There is one exception, though: we probably should _not_
descend into ".git" directories. Doing so is inefficient and
unlikely to turn up useful hits.
This patch drops our use of dir.c's gitlink-detection, but
we do still avoid ".git". That makes us more like tools such
as "ack" or "ag", which also know to avoid cruft in .git.
As a bonus, this also drops our usage of the ref code
when we are outside of a repository, making the transition
to pluggable ref backends cleaner.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-07 23:51:21 +08:00
|
|
|
if (!use_index)
|
|
|
|
dir.flags |= DIR_NO_GITLINKS;
|
2011-09-28 04:43:12 +08:00
|
|
|
if (exc_std)
|
|
|
|
setup_standard_excludes(&dir);
|
2010-02-07 02:40:08 +08:00
|
|
|
|
2013-07-14 16:35:55 +08:00
|
|
|
fill_directory(&dir, pathspec);
|
2010-02-07 02:40:08 +08:00
|
|
|
for (i = 0; i < dir.nr; i++) {
|
2014-01-24 21:40:29 +08:00
|
|
|
if (!dir_path_match(dir.entries[i], pathspec, 0, NULL))
|
2011-02-17 06:39:00 +08:00
|
|
|
continue;
|
2010-02-07 02:40:08 +08:00
|
|
|
hit |= grep_file(opt, dir.entries[i]->name);
|
|
|
|
if (hit && opt->status_only)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return hit;
|
|
|
|
}
|
|
|
|
|
2009-05-21 06:05:22 +08:00
|
|
|
static int context_callback(const struct option *opt, const char *arg,
|
|
|
|
int unset)
|
2009-05-08 03:46:48 +08:00
|
|
|
{
|
|
|
|
struct grep_opt *grep_opt = opt->value;
|
|
|
|
int value;
|
|
|
|
const char *endp;
|
|
|
|
|
|
|
|
if (unset) {
|
|
|
|
grep_opt->pre_context = grep_opt->post_context = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
value = strtol(arg, (char **)&endp, 10);
|
|
|
|
if (*endp) {
|
2011-02-23 07:41:55 +08:00
|
|
|
return error(_("switch `%c' expects a numerical value"),
|
2009-05-08 03:46:48 +08:00
|
|
|
opt->short_name);
|
|
|
|
}
|
|
|
|
grep_opt->pre_context = grep_opt->post_context = value;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-21 06:05:22 +08:00
|
|
|
static int file_callback(const struct option *opt, const char *arg, int unset)
|
2009-05-08 03:46:48 +08:00
|
|
|
{
|
|
|
|
struct grep_opt *grep_opt = opt->value;
|
2011-03-20 02:33:15 +08:00
|
|
|
int from_stdin = !strcmp(arg, "-");
|
2009-05-08 03:46:48 +08:00
|
|
|
FILE *patterns;
|
|
|
|
int lno = 0;
|
2009-10-16 22:13:25 +08:00
|
|
|
struct strbuf sb = STRBUF_INIT;
|
2009-05-08 03:46:48 +08:00
|
|
|
|
2011-03-20 02:33:15 +08:00
|
|
|
patterns = from_stdin ? stdin : fopen(arg, "r");
|
2009-05-08 03:46:48 +08:00
|
|
|
if (!patterns)
|
2011-02-23 07:41:55 +08:00
|
|
|
die_errno(_("cannot open '%s'"), arg);
|
2015-10-29 04:53:47 +08:00
|
|
|
while (strbuf_getline(&sb, patterns) == 0) {
|
2009-05-08 03:46:48 +08:00
|
|
|
/* ignore empty line like grep does */
|
|
|
|
if (sb.len == 0)
|
|
|
|
continue;
|
2010-05-23 05:43:43 +08:00
|
|
|
|
2012-05-22 00:10:09 +08:00
|
|
|
append_grep_pat(grep_opt, sb.buf, sb.len, arg, ++lno,
|
|
|
|
GREP_PATTERN);
|
2009-05-08 03:46:48 +08:00
|
|
|
}
|
2011-03-20 02:33:15 +08:00
|
|
|
if (!from_stdin)
|
|
|
|
fclose(patterns);
|
2009-05-08 03:46:48 +08:00
|
|
|
strbuf_release(&sb);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-21 06:05:22 +08:00
|
|
|
static int not_callback(const struct option *opt, const char *arg, int unset)
|
2009-05-08 03:46:48 +08:00
|
|
|
{
|
|
|
|
struct grep_opt *grep_opt = opt->value;
|
|
|
|
append_grep_pattern(grep_opt, "--not", "command line", 0, GREP_NOT);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-21 06:05:22 +08:00
|
|
|
static int and_callback(const struct option *opt, const char *arg, int unset)
|
2009-05-08 03:46:48 +08:00
|
|
|
{
|
|
|
|
struct grep_opt *grep_opt = opt->value;
|
|
|
|
append_grep_pattern(grep_opt, "--and", "command line", 0, GREP_AND);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-21 06:05:22 +08:00
|
|
|
static int open_callback(const struct option *opt, const char *arg, int unset)
|
2009-05-08 03:46:48 +08:00
|
|
|
{
|
|
|
|
struct grep_opt *grep_opt = opt->value;
|
|
|
|
append_grep_pattern(grep_opt, "(", "command line", 0, GREP_OPEN_PAREN);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-21 06:05:22 +08:00
|
|
|
static int close_callback(const struct option *opt, const char *arg, int unset)
|
2009-05-08 03:46:48 +08:00
|
|
|
{
|
|
|
|
struct grep_opt *grep_opt = opt->value;
|
|
|
|
append_grep_pattern(grep_opt, ")", "command line", 0, GREP_CLOSE_PAREN);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-21 06:05:22 +08:00
|
|
|
static int pattern_callback(const struct option *opt, const char *arg,
|
|
|
|
int unset)
|
2009-05-08 03:46:48 +08:00
|
|
|
{
|
|
|
|
struct grep_opt *grep_opt = opt->value;
|
|
|
|
append_grep_pattern(grep_opt, arg, "-e option", 0, GREP_PATTERN);
|
|
|
|
return 0;
|
|
|
|
}
|
2006-05-01 14:28:15 +08:00
|
|
|
|
2006-07-29 13:44:25 +08:00
|
|
|
int cmd_grep(int argc, const char **argv, const char *prefix)
|
2006-05-01 14:28:15 +08:00
|
|
|
{
|
|
|
|
int hit = 0;
|
2011-09-28 04:43:12 +08:00
|
|
|
int cached = 0, untracked = 0, opt_exclude = -1;
|
2006-05-09 14:55:47 +08:00
|
|
|
int seen_dashdash = 0;
|
2010-01-13 11:06:41 +08:00
|
|
|
int external_grep_allowed__ignored;
|
2010-06-13 00:39:46 +08:00
|
|
|
const char *show_in_pager = NULL, *default_pager = "dummy";
|
2006-05-01 14:28:15 +08:00
|
|
|
struct grep_opt opt;
|
2010-08-29 10:04:17 +08:00
|
|
|
struct object_array list = OBJECT_ARRAY_INIT;
|
2010-12-15 23:02:51 +08:00
|
|
|
struct pathspec pathspec;
|
2010-07-05 03:46:19 +08:00
|
|
|
struct string_list path_list = STRING_LIST_INIT_NODUP;
|
2006-05-09 14:55:47 +08:00
|
|
|
int i;
|
2009-05-08 03:46:48 +08:00
|
|
|
int dummy;
|
2010-08-06 11:06:39 +08:00
|
|
|
int use_index = 1;
|
grep: add a grep.patternType configuration setting
The grep.extendedRegexp configuration setting enables the -E flag on grep
by default but there are no equivalents for the -G, -F and -P flags.
Rather than adding an additional setting for grep.fooRegexp for current
and future pattern matching options, add a grep.patternType setting that
can accept appropriate values for modifying the default grep pattern
matching behavior. The current values are "basic", "extended", "fixed",
"perl" and "default" for setting -G, -E, -F, -P and the default behavior
respectively.
When grep.patternType is set to a value other than "default", the
grep.extendedRegexp setting is ignored. The value of "default" restores
the current default behavior, including the grep.extendedRegexp
behavior.
Signed-off-by: J Smith <dark.panda@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-08-03 22:53:50 +08:00
|
|
|
int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;
|
2011-05-10 09:48:36 +08:00
|
|
|
|
2009-05-08 03:46:48 +08:00
|
|
|
struct option options[] = {
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL(0, "cached", &cached,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("search in index instead of in the work tree")),
|
2012-02-29 03:06:09 +08:00
|
|
|
OPT_NEGBIT(0, "no-index", &use_index,
|
2012-08-20 20:32:55 +08:00
|
|
|
N_("find in contents not managed by git"), 1),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL(0, "untracked", &untracked,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("search in both tracked and untracked files")),
|
2011-09-28 04:43:12 +08:00
|
|
|
OPT_SET_INT(0, "exclude-standard", &opt_exclude,
|
2015-02-27 22:01:58 +08:00
|
|
|
N_("ignore files specified via '.gitignore'"), 1),
|
2016-12-17 03:03:20 +08:00
|
|
|
OPT_BOOL(0, "recurse-submodules", &recurse_submodules,
|
|
|
|
N_("recursivley search in each submodule")),
|
2016-12-17 03:03:21 +08:00
|
|
|
OPT_STRING(0, "parent-basename", &parent_basename,
|
|
|
|
N_("basename"),
|
|
|
|
N_("prepend parent project's basename to output")),
|
2009-05-08 03:46:48 +08:00
|
|
|
OPT_GROUP(""),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL('v', "invert-match", &opt.invert,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("show non-matching lines")),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL('i', "ignore-case", &opt.ignore_case,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("case insensitive matching")),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL('w', "word-regexp", &opt.word_regexp,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("match patterns only at word boundaries")),
|
2009-05-08 03:46:48 +08:00
|
|
|
OPT_SET_INT('a', "text", &opt.binary,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("process binary files as text"), GREP_BINARY_TEXT),
|
2009-05-08 03:46:48 +08:00
|
|
|
OPT_SET_INT('I', NULL, &opt.binary,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("don't match patterns in binary files"),
|
2009-05-08 03:46:48 +08:00
|
|
|
GREP_BINARY_NOMATCH),
|
2013-05-10 23:10:15 +08:00
|
|
|
OPT_BOOL(0, "textconv", &opt.allow_textconv,
|
|
|
|
N_("process binary files with textconv filters")),
|
2012-08-20 20:32:15 +08:00
|
|
|
{ OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"),
|
|
|
|
N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
|
grep: Add --max-depth option.
It is useful to grep directories non-recursively, e.g. when one wants to
look for all files in the toplevel directory, but not in any subdirectory,
or in Documentation/, but not in Documentation/technical/.
This patch adds support for --max-depth <depth> option to git-grep. If it is
given, git-grep descends at most <depth> levels of directories below paths
specified on the command line.
Note that if path specified on command line contains wildcards, this option
makes no sense, e.g.
$ git grep -l --max-depth 0 GNU -- 'contrib/*'
(note the quotes) will search all files in contrib/, even in
subdirectories, because '*' matches all files.
Documentation updates, bash-completion and simple test cases are also
provided.
Signed-off-by: Michał Kiedrowicz <michal.kiedrowicz@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-07-23 01:52:15 +08:00
|
|
|
NULL, 1 },
|
2009-05-08 03:46:48 +08:00
|
|
|
OPT_GROUP(""),
|
grep: add a grep.patternType configuration setting
The grep.extendedRegexp configuration setting enables the -E flag on grep
by default but there are no equivalents for the -G, -F and -P flags.
Rather than adding an additional setting for grep.fooRegexp for current
and future pattern matching options, add a grep.patternType setting that
can accept appropriate values for modifying the default grep pattern
matching behavior. The current values are "basic", "extended", "fixed",
"perl" and "default" for setting -G, -E, -F, -P and the default behavior
respectively.
When grep.patternType is set to a value other than "default", the
grep.extendedRegexp setting is ignored. The value of "default" restores
the current default behavior, including the grep.extendedRegexp
behavior.
Signed-off-by: J Smith <dark.panda@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-08-03 22:53:50 +08:00
|
|
|
OPT_SET_INT('E', "extended-regexp", &pattern_type_arg,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("use extended POSIX regular expressions"),
|
grep: add a grep.patternType configuration setting
The grep.extendedRegexp configuration setting enables the -E flag on grep
by default but there are no equivalents for the -G, -F and -P flags.
Rather than adding an additional setting for grep.fooRegexp for current
and future pattern matching options, add a grep.patternType setting that
can accept appropriate values for modifying the default grep pattern
matching behavior. The current values are "basic", "extended", "fixed",
"perl" and "default" for setting -G, -E, -F, -P and the default behavior
respectively.
When grep.patternType is set to a value other than "default", the
grep.extendedRegexp setting is ignored. The value of "default" restores
the current default behavior, including the grep.extendedRegexp
behavior.
Signed-off-by: J Smith <dark.panda@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-08-03 22:53:50 +08:00
|
|
|
GREP_PATTERN_TYPE_ERE),
|
|
|
|
OPT_SET_INT('G', "basic-regexp", &pattern_type_arg,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("use basic POSIX regular expressions (default)"),
|
grep: add a grep.patternType configuration setting
The grep.extendedRegexp configuration setting enables the -E flag on grep
by default but there are no equivalents for the -G, -F and -P flags.
Rather than adding an additional setting for grep.fooRegexp for current
and future pattern matching options, add a grep.patternType setting that
can accept appropriate values for modifying the default grep pattern
matching behavior. The current values are "basic", "extended", "fixed",
"perl" and "default" for setting -G, -E, -F, -P and the default behavior
respectively.
When grep.patternType is set to a value other than "default", the
grep.extendedRegexp setting is ignored. The value of "default" restores
the current default behavior, including the grep.extendedRegexp
behavior.
Signed-off-by: J Smith <dark.panda@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-08-03 22:53:50 +08:00
|
|
|
GREP_PATTERN_TYPE_BRE),
|
|
|
|
OPT_SET_INT('F', "fixed-strings", &pattern_type_arg,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("interpret patterns as fixed strings"),
|
grep: add a grep.patternType configuration setting
The grep.extendedRegexp configuration setting enables the -E flag on grep
by default but there are no equivalents for the -G, -F and -P flags.
Rather than adding an additional setting for grep.fooRegexp for current
and future pattern matching options, add a grep.patternType setting that
can accept appropriate values for modifying the default grep pattern
matching behavior. The current values are "basic", "extended", "fixed",
"perl" and "default" for setting -G, -E, -F, -P and the default behavior
respectively.
When grep.patternType is set to a value other than "default", the
grep.extendedRegexp setting is ignored. The value of "default" restores
the current default behavior, including the grep.extendedRegexp
behavior.
Signed-off-by: J Smith <dark.panda@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-08-03 22:53:50 +08:00
|
|
|
GREP_PATTERN_TYPE_FIXED),
|
|
|
|
OPT_SET_INT('P', "perl-regexp", &pattern_type_arg,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("use Perl-compatible regular expressions"),
|
grep: add a grep.patternType configuration setting
The grep.extendedRegexp configuration setting enables the -E flag on grep
by default but there are no equivalents for the -G, -F and -P flags.
Rather than adding an additional setting for grep.fooRegexp for current
and future pattern matching options, add a grep.patternType setting that
can accept appropriate values for modifying the default grep pattern
matching behavior. The current values are "basic", "extended", "fixed",
"perl" and "default" for setting -G, -E, -F, -P and the default behavior
respectively.
When grep.patternType is set to a value other than "default", the
grep.extendedRegexp setting is ignored. The value of "default" restores
the current default behavior, including the grep.extendedRegexp
behavior.
Signed-off-by: J Smith <dark.panda@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-08-03 22:53:50 +08:00
|
|
|
GREP_PATTERN_TYPE_PCRE),
|
2009-05-08 03:46:48 +08:00
|
|
|
OPT_GROUP(""),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL('n', "line-number", &opt.linenum, N_("show line numbers")),
|
2012-08-20 20:32:15 +08:00
|
|
|
OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1),
|
|
|
|
OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1),
|
2009-05-08 03:46:48 +08:00
|
|
|
OPT_NEGBIT(0, "full-name", &opt.relative,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("show filenames relative to top directory"), 1),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL('l', "files-with-matches", &opt.name_only,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("show only filenames instead of matching lines")),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL(0, "name-only", &opt.name_only,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("synonym for --files-with-matches")),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL('L', "files-without-match",
|
2009-05-08 03:46:48 +08:00
|
|
|
&opt.unmatch_name_only,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("show only the names of files without match")),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL('z', "null", &opt.null_following_name,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("print NUL after filenames")),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL('c', "count", &opt.count,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("show the number of matches instead of matching lines")),
|
|
|
|
OPT__COLOR(&opt.color, N_("highlight matches")),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL(0, "break", &opt.file_break,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("print empty line between matches from different files")),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL(0, "heading", &opt.heading,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("show filename only once above matches from same file")),
|
2009-05-08 03:46:48 +08:00
|
|
|
OPT_GROUP(""),
|
2012-08-20 20:32:15 +08:00
|
|
|
OPT_CALLBACK('C', "context", &opt, N_("n"),
|
|
|
|
N_("show <n> context lines before and after matches"),
|
2009-05-08 03:46:48 +08:00
|
|
|
context_callback),
|
2011-08-02 01:22:52 +08:00
|
|
|
OPT_INTEGER('B', "before-context", &opt.pre_context,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("show <n> context lines before matches")),
|
2011-08-02 01:22:52 +08:00
|
|
|
OPT_INTEGER('A', "after-context", &opt.post_context,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("show <n> context lines after matches")),
|
2015-12-15 23:31:39 +08:00
|
|
|
OPT_INTEGER(0, "threads", &num_threads,
|
|
|
|
N_("use <n> worker threads")),
|
2012-08-20 20:32:15 +08:00
|
|
|
OPT_NUMBER_CALLBACK(&opt, N_("shortcut for -C NUM"),
|
2009-05-08 03:46:48 +08:00
|
|
|
context_callback),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL('p', "show-function", &opt.funcname,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("show a line with the function name before matches")),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL('W', "function-context", &opt.funcbody,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("show the surrounding function")),
|
2009-05-08 03:46:48 +08:00
|
|
|
OPT_GROUP(""),
|
2012-08-20 20:32:15 +08:00
|
|
|
OPT_CALLBACK('f', NULL, &opt, N_("file"),
|
|
|
|
N_("read patterns from file"), file_callback),
|
|
|
|
{ OPTION_CALLBACK, 'e', NULL, &opt, N_("pattern"),
|
|
|
|
N_("match <pattern>"), PARSE_OPT_NONEG, pattern_callback },
|
2009-05-08 03:46:48 +08:00
|
|
|
{ OPTION_CALLBACK, 0, "and", &opt, NULL,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("combine patterns specified with -e"),
|
2009-05-08 03:46:48 +08:00
|
|
|
PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback },
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL(0, "or", &dummy, ""),
|
2009-05-08 03:46:48 +08:00
|
|
|
{ OPTION_CALLBACK, 0, "not", &opt, NULL, "",
|
|
|
|
PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback },
|
|
|
|
{ OPTION_CALLBACK, '(', NULL, &opt, NULL, "",
|
|
|
|
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
|
|
|
|
open_callback },
|
|
|
|
{ OPTION_CALLBACK, ')', NULL, &opt, NULL, "",
|
|
|
|
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
|
|
|
|
close_callback },
|
2010-11-09 02:06:54 +08:00
|
|
|
OPT__QUIET(&opt.status_only,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("indicate hit with exit status without output")),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL(0, "all-match", &opt.all_match,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("show only matches from files that match all patterns")),
|
2012-09-14 05:21:44 +08:00
|
|
|
{ OPTION_SET_INT, 0, "debug", &opt.debug, NULL,
|
2012-09-19 05:37:53 +08:00
|
|
|
N_("show parse tree for grep expression"),
|
2012-09-14 05:21:44 +08:00
|
|
|
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1 },
|
2009-05-08 03:46:48 +08:00
|
|
|
OPT_GROUP(""),
|
2010-06-13 00:39:46 +08:00
|
|
|
{ OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager,
|
2012-08-20 20:32:15 +08:00
|
|
|
N_("pager"), N_("show matching files in the pager"),
|
2010-06-13 00:39:46 +08:00
|
|
|
PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager },
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL(0, "ext-grep", &external_grep_allowed__ignored,
|
|
|
|
N_("allow calling of grep(1) (ignored by this build)")),
|
2009-05-08 03:46:48 +08:00
|
|
|
OPT_END()
|
|
|
|
};
|
2006-05-01 14:28:15 +08:00
|
|
|
|
2012-10-10 07:04:12 +08:00
|
|
|
init_grep_defaults();
|
|
|
|
git_config(grep_cmd_config, NULL);
|
|
|
|
grep_init(&opt, prefix);
|
2016-12-17 03:03:20 +08:00
|
|
|
super_prefix = get_super_prefix();
|
2009-03-07 20:32:32 +08:00
|
|
|
|
2006-05-01 14:28:15 +08:00
|
|
|
/*
|
2006-05-09 14:55:47 +08:00
|
|
|
* If there is no -- then the paths must exist in the working
|
|
|
|
* tree. If there is no explicit pattern specified with -e or
|
|
|
|
* -f, we take the first unrecognized non option to be the
|
|
|
|
* pattern, but then what follows it must be zero or more
|
|
|
|
* valid refs up to the -- (if exists), and then existing
|
|
|
|
* paths. If there is an explicit pattern, then the first
|
2006-07-10 13:50:18 +08:00
|
|
|
* unrecognized non option is the beginning of the refs list
|
2006-05-09 14:55:47 +08:00
|
|
|
* that continues up to the -- (if exists), and then paths.
|
2006-05-01 14:28:15 +08:00
|
|
|
*/
|
2009-05-24 02:53:12 +08:00
|
|
|
argc = parse_options(argc, argv, prefix, options, grep_usage,
|
2009-05-08 03:46:48 +08:00
|
|
|
PARSE_OPT_KEEP_DASHDASH |
|
2015-11-17 18:25:53 +08:00
|
|
|
PARSE_OPT_STOP_AT_NON_OPTION);
|
2012-10-04 05:47:48 +08:00
|
|
|
grep_commit_pattern_type(pattern_type_arg, &opt);
|
2009-05-08 03:46:48 +08:00
|
|
|
|
2016-01-12 18:40:26 +08:00
|
|
|
if (use_index && !startup_info->have_repository) {
|
|
|
|
int fallback = 0;
|
|
|
|
git_config_get_bool("grep.fallbacktonoindex", &fallback);
|
|
|
|
if (fallback)
|
|
|
|
use_index = 0;
|
|
|
|
else
|
|
|
|
/* die the same way as if we did it at the beginning */
|
|
|
|
setup_git_directory();
|
|
|
|
}
|
2010-02-07 02:40:08 +08:00
|
|
|
|
2010-02-07 12:44:15 +08:00
|
|
|
/*
|
|
|
|
* skip a -- separator; we know it cannot be
|
|
|
|
* separating revisions from pathnames if
|
|
|
|
* we haven't even had any patterns yet
|
|
|
|
*/
|
|
|
|
if (argc > 0 && !opt.pattern_list && !strcmp(argv[0], "--")) {
|
|
|
|
argv++;
|
|
|
|
argc--;
|
|
|
|
}
|
|
|
|
|
2009-05-08 03:46:48 +08:00
|
|
|
/* First unrecognized non-option token */
|
|
|
|
if (argc > 0 && !opt.pattern_list) {
|
|
|
|
append_grep_pattern(&opt, argv[0], "command line", 0,
|
|
|
|
GREP_PATTERN);
|
|
|
|
argv++;
|
|
|
|
argc--;
|
2006-05-01 14:28:15 +08:00
|
|
|
}
|
2006-05-09 14:55:47 +08:00
|
|
|
|
2010-06-13 00:39:46 +08:00
|
|
|
if (show_in_pager == default_pager)
|
|
|
|
show_in_pager = git_pager(1);
|
2010-06-13 00:36:51 +08:00
|
|
|
if (show_in_pager) {
|
2010-07-03 10:55:06 +08:00
|
|
|
opt.color = 0;
|
2010-06-13 00:39:46 +08:00
|
|
|
opt.name_only = 1;
|
|
|
|
opt.null_following_name = 1;
|
|
|
|
opt.output_priv = &path_list;
|
|
|
|
opt.output = append_path;
|
2010-06-26 07:41:39 +08:00
|
|
|
string_list_append(&path_list, show_in_pager);
|
2010-06-13 00:36:51 +08:00
|
|
|
}
|
|
|
|
|
2006-05-03 06:40:49 +08:00
|
|
|
if (!opt.pattern_list)
|
2011-02-23 07:41:55 +08:00
|
|
|
die(_("no pattern given."));
|
2009-11-06 17:22:35 +08:00
|
|
|
if (!opt.fixed && opt.ignore_case)
|
|
|
|
opt.regflags |= REG_ICASE;
|
2010-01-26 06:51:39 +08:00
|
|
|
|
2006-09-18 07:02:52 +08:00
|
|
|
compile_grep_patterns(&opt);
|
2006-05-09 14:55:47 +08:00
|
|
|
|
|
|
|
/* Check revs and then paths */
|
2009-05-08 03:46:48 +08:00
|
|
|
for (i = 0; i < argc; i++) {
|
2006-05-09 14:55:47 +08:00
|
|
|
const char *arg = argv[i];
|
2006-05-02 06:58:29 +08:00
|
|
|
unsigned char sha1[20];
|
2013-05-10 23:10:16 +08:00
|
|
|
struct object_context oc;
|
2017-02-14 14:04:17 +08:00
|
|
|
struct object *object;
|
|
|
|
|
2017-02-14 14:03:03 +08:00
|
|
|
if (!strcmp(arg, "--")) {
|
|
|
|
i++;
|
|
|
|
seen_dashdash = 1;
|
|
|
|
break;
|
|
|
|
}
|
2017-02-14 14:04:17 +08:00
|
|
|
|
|
|
|
/* Stop at the first non-rev */
|
|
|
|
if (get_sha1_with_context(arg, 0, sha1, &oc))
|
|
|
|
break;
|
|
|
|
|
|
|
|
object = parse_object_or_die(sha1, arg);
|
|
|
|
if (!seen_dashdash)
|
|
|
|
verify_non_filename(prefix, arg);
|
|
|
|
add_object_array_with_path(object, arg, &list, oc.mode, oc.path);
|
2006-05-02 06:58:29 +08:00
|
|
|
}
|
2006-05-09 14:55:47 +08:00
|
|
|
|
2017-02-14 14:02:38 +08:00
|
|
|
/* The rest are paths */
|
|
|
|
if (!seen_dashdash) {
|
|
|
|
int j;
|
|
|
|
for (j = i; j < argc; j++)
|
|
|
|
verify_filename(prefix, argv[j], j == i);
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_pathspec(&pathspec, 0,
|
|
|
|
PATHSPEC_PREFER_CWD |
|
|
|
|
(opt.max_depth != -1 ? PATHSPEC_MAXDEPTH_VALID : 0),
|
|
|
|
prefix, argv + i);
|
|
|
|
pathspec.max_depth = opt.max_depth;
|
|
|
|
pathspec.recursive = 1;
|
|
|
|
|
2011-12-13 05:16:08 +08:00
|
|
|
#ifndef NO_PTHREADS
|
2015-12-15 23:31:39 +08:00
|
|
|
if (list.nr || cached || show_in_pager)
|
2015-12-15 23:31:39 +08:00
|
|
|
num_threads = 0;
|
|
|
|
else if (num_threads == 0)
|
|
|
|
num_threads = GREP_NUM_THREADS_DEFAULT;
|
|
|
|
else if (num_threads < 0)
|
|
|
|
die(_("invalid number of threads specified (%d)"), num_threads);
|
2011-12-13 05:16:08 +08:00
|
|
|
#else
|
2015-12-15 23:31:39 +08:00
|
|
|
num_threads = 0;
|
2011-12-13 05:16:08 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef NO_PTHREADS
|
2015-12-15 23:31:39 +08:00
|
|
|
if (num_threads) {
|
2012-01-24 01:52:44 +08:00
|
|
|
if (!(opt.name_only || opt.unmatch_name_only || opt.count)
|
|
|
|
&& (opt.pre_context || opt.post_context ||
|
|
|
|
opt.file_break || opt.funcbody))
|
2011-12-13 05:16:08 +08:00
|
|
|
skip_first_line = 1;
|
|
|
|
start_threads(&opt);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-12-17 03:03:20 +08:00
|
|
|
if (recurse_submodules) {
|
|
|
|
gitmodules_config();
|
|
|
|
compile_submodule_options(&opt, &pathspec, cached, untracked,
|
|
|
|
opt_exclude, use_index,
|
|
|
|
pattern_type_arg);
|
|
|
|
}
|
|
|
|
|
2010-06-13 00:36:51 +08:00
|
|
|
if (show_in_pager && (cached || list.nr))
|
2011-02-23 07:41:56 +08:00
|
|
|
die(_("--open-files-in-pager only works on the worktree"));
|
2010-06-13 00:36:51 +08:00
|
|
|
|
|
|
|
if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) {
|
|
|
|
const char *pager = path_list.items[0].string;
|
|
|
|
int len = strlen(pager);
|
|
|
|
|
|
|
|
if (len > 4 && is_dir_sep(pager[len - 5]))
|
|
|
|
pager += len - 4;
|
|
|
|
|
2011-02-08 14:17:24 +08:00
|
|
|
if (opt.ignore_case && !strcmp("less", pager))
|
|
|
|
string_list_append(&path_list, "-I");
|
|
|
|
|
2010-06-13 00:36:51 +08:00
|
|
|
if (!strcmp("less", pager) || !strcmp("vi", pager)) {
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
strbuf_addf(&buf, "+/%s%s",
|
|
|
|
strcmp("less", pager) ? "" : "*",
|
|
|
|
opt.pattern_list->pattern);
|
2010-06-26 07:41:39 +08:00
|
|
|
string_list_append(&path_list, buf.buf);
|
2010-06-13 00:36:51 +08:00
|
|
|
strbuf_detach(&buf, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-17 03:03:21 +08:00
|
|
|
if (recurse_submodules && (!use_index || untracked))
|
2016-12-17 03:03:20 +08:00
|
|
|
die(_("option not supported with --recurse-submodules."));
|
|
|
|
|
2015-03-19 02:00:13 +08:00
|
|
|
if (!show_in_pager && !opt.status_only)
|
2010-06-13 00:36:51 +08:00
|
|
|
setup_pager();
|
|
|
|
|
2011-09-28 04:43:12 +08:00
|
|
|
if (!use_index && (untracked || cached))
|
2011-10-05 09:40:41 +08:00
|
|
|
die(_("--cached or --untracked cannot be used with --no-index."));
|
2010-06-13 00:36:51 +08:00
|
|
|
|
2011-09-28 04:43:12 +08:00
|
|
|
if (!use_index || untracked) {
|
|
|
|
int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;
|
2010-02-07 02:40:08 +08:00
|
|
|
if (list.nr)
|
2011-10-05 09:40:41 +08:00
|
|
|
die(_("--no-index or --untracked cannot be used with revs."));
|
grep: turn off gitlink detection for --no-index
If we are running "git grep --no-index" outside of a git
repository, we behave roughly like "grep -r", examining all
files in the current directory and its subdirectories.
However, because we use fill_directory() to do the
recursion, it will skip over any directories which look like
sub-repositories.
For a normal git operation (like "git grep" in a repository)
this makes sense; we do not want to cross the boundary out
of our current repository into a submodule. But for
"--no-index" without a repository, we should look at all
files, including embedded repositories.
There is one exception, though: we probably should _not_
descend into ".git" directories. Doing so is inefficient and
unlikely to turn up useful hits.
This patch drops our use of dir.c's gitlink-detection, but
we do still avoid ".git". That makes us more like tools such
as "ack" or "ag", which also know to avoid cruft in .git.
As a bonus, this also drops our usage of the ref code
when we are outside of a repository, making the transition
to pluggable ref backends cleaner.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-07 23:51:21 +08:00
|
|
|
hit = grep_directory(&opt, &pathspec, use_exclude, use_index);
|
2011-10-05 09:40:41 +08:00
|
|
|
} else if (0 <= opt_exclude) {
|
2011-10-16 11:26:52 +08:00
|
|
|
die(_("--[no-]exclude-standard cannot be used for tracked contents."));
|
2010-06-13 00:32:11 +08:00
|
|
|
} else if (!list.nr) {
|
2008-08-28 21:04:30 +08:00
|
|
|
if (!cached)
|
|
|
|
setup_work_tree();
|
2010-01-26 06:51:39 +08:00
|
|
|
|
2010-12-15 23:02:51 +08:00
|
|
|
hit = grep_cache(&opt, &pathspec, cached);
|
2010-06-13 00:32:11 +08:00
|
|
|
} else {
|
|
|
|
if (cached)
|
2011-02-23 07:41:55 +08:00
|
|
|
die(_("both --cached and trees are given."));
|
2010-12-15 23:02:51 +08:00
|
|
|
hit = grep_objects(&opt, &pathspec, &list);
|
2006-05-01 14:28:15 +08:00
|
|
|
}
|
2010-01-26 06:51:39 +08:00
|
|
|
|
2015-12-15 23:31:39 +08:00
|
|
|
if (num_threads)
|
2010-01-26 06:51:39 +08:00
|
|
|
hit |= wait_all();
|
2010-06-13 00:36:51 +08:00
|
|
|
if (hit && show_in_pager)
|
|
|
|
run_pager(&opt, prefix);
|
2006-09-28 07:27:10 +08:00
|
|
|
free_grep_patterns(&opt);
|
2006-05-01 14:28:15 +08:00
|
|
|
return !hit;
|
|
|
|
}
|