18
#include "quote.h"
19
#include "dir.h"
20
#include "pathspec.h"
21
+#include "submodule.h"
22
23
static char const * const grep_usage[] = {
24
N_("git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"),
25
NULL
26
};
27
28
+static const char *super_prefix;
29
+static int recurse_submodules;
30
+static struct argv_array submodule_options = ARGV_ARRAY_INIT;
31
+
32
+static int grep_submodule_launch(struct grep_opt *opt,
33
+ const struct grep_source *gs);
34
+
35
#define GREP_NUM_THREADS_DEFAULT 8
36
static int num_threads;
37
182
break;
183
184
opt->output_priv = w;
177
- hit |= grep_source(opt, &w->source);
185
+ if (w->source.type == GREP_SOURCE_SUBMODULE)
186
+ hit |= grep_submodule_launch(opt, &w->source);
187
+ else
188
+ hit |= grep_source(opt, &w->source);
189
grep_source_clear_data(&w->source);
190
work_done(w);
191
}
311
if (opt->relative && opt->prefix_length) {
312
quote_path_relative(filename + tree_name_len, opt->prefix, &pathbuf);
313
strbuf_insert(&pathbuf, 0, filename, tree_name_len);
314
+ } else if (super_prefix) {
315
+ strbuf_add(&pathbuf, filename, tree_name_len);
316
+ strbuf_addstr(&pathbuf, super_prefix);
317
+ strbuf_addstr(&pathbuf, filename + tree_name_len);
318
} else {
319
strbuf_addstr(&pathbuf, filename);
320
}
343
{
344
struct strbuf buf = STRBUF_INIT;
345
331
- if (opt->relative && opt->prefix_length)
346
+ if (opt->relative && opt->prefix_length) {
347
quote_path_relative(filename, opt->prefix, &buf);
333
- else
348
+ } else {
349
+ if (super_prefix)
350
+ strbuf_addstr(&buf, super_prefix);
351
strbuf_addstr(&buf, filename);
352
+ }
353
354
#ifndef NO_PTHREADS
355
if (num_threads) {
396
exit(status);
397
}
398
381
-static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached)
399
+static void compile_submodule_options(const struct grep_opt *opt,
400
+ const struct pathspec *pathspec,
401
+ int cached, int untracked,
402
+ int opt_exclude, int use_index,
403
+ int pattern_type_arg)
404
+{
405
+ struct grep_pat *pattern;
406
+ int i;
407
+
408
+ if (recurse_submodules)
409
+ argv_array_push(&submodule_options, "--recurse-submodules");
410
+
411
+ if (cached)
412
+ argv_array_push(&submodule_options, "--cached");
413
+ if (!use_index)
414
+ argv_array_push(&submodule_options, "--no-index");
415
+ if (untracked)
416
+ argv_array_push(&submodule_options, "--untracked");
417
+ if (opt_exclude > 0)
418
+ argv_array_push(&submodule_options, "--exclude-standard");
419
+
420
+ if (opt->invert)
421
+ argv_array_push(&submodule_options, "-v");
422
+ if (opt->ignore_case)
423
+ argv_array_push(&submodule_options, "-i");
424
+ if (opt->word_regexp)
425
+ argv_array_push(&submodule_options, "-w");
426
+ switch (opt->binary) {
427
+ case GREP_BINARY_NOMATCH:
428
+ argv_array_push(&submodule_options, "-I");
429
+ break;
430
+ case GREP_BINARY_TEXT:
431
+ argv_array_push(&submodule_options, "-a");
432
+ break;
433
+ default:
434
+ break;
435
+ }
436
+ if (opt->allow_textconv)
437
+ argv_array_push(&submodule_options, "--textconv");
438
+ if (opt->max_depth != -1)
439
+ argv_array_pushf(&submodule_options, "--max-depth=%d",
440
+ opt->max_depth);
441
+ if (opt->linenum)
442
+ argv_array_push(&submodule_options, "-n");
443
+ if (!opt->pathname)
444
+ argv_array_push(&submodule_options, "-h");
445
+ if (!opt->relative)
446
+ argv_array_push(&submodule_options, "--full-name");
447
+ if (opt->name_only)
448
+ argv_array_push(&submodule_options, "-l");
449
+ if (opt->unmatch_name_only)
450
+ argv_array_push(&submodule_options, "-L");
451
+ if (opt->null_following_name)
452
+ argv_array_push(&submodule_options, "-z");
453
+ if (opt->count)
454
+ argv_array_push(&submodule_options, "-c");
455
+ if (opt->file_break)
456
+ argv_array_push(&submodule_options, "--break");
457
+ if (opt->heading)
458
+ argv_array_push(&submodule_options, "--heading");
459
+ if (opt->pre_context)
460
+ argv_array_pushf(&submodule_options, "--before-context=%d",
461
+ opt->pre_context);
462
+ if (opt->post_context)
463
+ argv_array_pushf(&submodule_options, "--after-context=%d",
464
+ opt->post_context);
465
+ if (opt->funcname)
466
+ argv_array_push(&submodule_options, "-p");
467
+ if (opt->funcbody)
468
+ argv_array_push(&submodule_options, "-W");
469
+ if (opt->all_match)
470
+ argv_array_push(&submodule_options, "--all-match");
471
+ if (opt->debug)
472
+ argv_array_push(&submodule_options, "--debug");
473
+ if (opt->status_only)
474
+ argv_array_push(&submodule_options, "-q");
475
+
476
+ switch (pattern_type_arg) {
477
+ case GREP_PATTERN_TYPE_BRE:
478
+ argv_array_push(&submodule_options, "-G");
479
+ break;
480
+ case GREP_PATTERN_TYPE_ERE:
481
+ argv_array_push(&submodule_options, "-E");
482
+ break;
483
+ case GREP_PATTERN_TYPE_FIXED:
484
+ argv_array_push(&submodule_options, "-F");
485
+ break;
486
+ case GREP_PATTERN_TYPE_PCRE:
487
+ argv_array_push(&submodule_options, "-P");
488
+ break;
489
+ case GREP_PATTERN_TYPE_UNSPECIFIED:
490
+ break;
491
+ }
492
+
493
+ for (pattern = opt->pattern_list; pattern != NULL;
494
+ pattern = pattern->next) {
495
+ switch (pattern->token) {
496
+ case GREP_PATTERN:
497
+ argv_array_pushf(&submodule_options, "-e%s",
498
+ pattern->pattern);
499
+ break;
500
+ case GREP_AND:
501
+ case GREP_OPEN_PAREN:
502
+ case GREP_CLOSE_PAREN:
503
+ case GREP_NOT:
504
+ case GREP_OR:
505
+ argv_array_push(&submodule_options, pattern->pattern);
506
+ break;
507
+ /* BODY and HEAD are not used by git-grep */
508
+ case GREP_PATTERN_BODY:
509
+ case GREP_PATTERN_HEAD:
510
+ break;
511
+ }
512
+ }
513
+
514
+ /*
515
+ * Limit number of threads for child process to use.
516
+ * This is to prevent potential fork-bomb behavior of git-grep as each
517
+ * submodule process has its own thread pool.
518
+ */
519
+ argv_array_pushf(&submodule_options, "--threads=%d",
520
+ (num_threads + 1) / 2);
521
+
522
+ /* Add Pathspecs */
523
+ argv_array_push(&submodule_options, "--");
524
+ for (i = 0; i < pathspec->nr; i++)
525
+ argv_array_push(&submodule_options,
526
+ pathspec->items[i].original);
527
+}
528
+
529
+/*
530
+ * Launch child process to grep contents of a submodule
531
+ */
532
+static int grep_submodule_launch(struct grep_opt *opt,
533
+ const struct grep_source *gs)
534
+{
535
+ struct child_process cp = CHILD_PROCESS_INIT;
536
+ int status, i;
537
+ struct work_item *w = opt->output_priv;
538
+
539
+ prepare_submodule_repo_env(&cp.env_array);
540
+
541
+ /* Add super prefix */
542
+ argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
543
+ super_prefix ? super_prefix : "",
544
+ gs->name);
545
+ argv_array_push(&cp.args, "grep");
546
+
547
+ /* Add options */
548
+ for (i = 0; i < submodule_options.argc; i++)
549
+ argv_array_push(&cp.args, submodule_options.argv[i]);
550
+
551
+ cp.git_cmd = 1;
552
+ cp.dir = gs->path;
553
+
554
+ /*
555
+ * Capture output to output buffer and check the return code from the
556
+ * child process. A '0' indicates a hit, a '1' indicates no hit and
557
+ * anything else is an error.
558
+ */
559
+ status = capture_command(&cp, &w->out, 0);
560
+ if (status && (status != 1)) {
561
+ /* flush the buffer */
562
+ write_or_die(1, w->out.buf, w->out.len);
563
+ die("process for submodule '%s' failed with exit code: %d",
564
+ gs->name, status);
565
+ }
566
+
567
+ /* invert the return code to make a hit equal to 1 */
568
+ return !status;
569
+}
570
+
571
+/*
572
+ * Prep grep structures for a submodule grep
573
+ * sha1: the sha1 of the submodule or NULL if using the working tree
574
+ * filename: name of the submodule including tree name of parent
575
+ * path: location of the submodule
576
+ */
577
+static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1,
578
+ const char *filename, const char *path)
579
+{
580
+ if (!is_submodule_initialized(path))
581
+ return 0;
582
+ if (!is_submodule_populated(path))
583
+ return 0;
584
+
585
+#ifndef NO_PTHREADS
586
+ if (num_threads) {
587
+ add_work(opt, GREP_SOURCE_SUBMODULE, filename, path, sha1);
588
+ return 0;
589
+ } else
590
+#endif
591
+ {
592
+ struct work_item w;
593
+ int hit;
594
+
595
+ grep_source_init(&w.source, GREP_SOURCE_SUBMODULE,
596
+ filename, path, sha1);
597
+ strbuf_init(&w.out, 0);
598
+ opt->output_priv = &w;
599
+ hit = grep_submodule_launch(opt, &w.source);
600
+
601
+ write_or_die(1, w.out.buf, w.out.len);
602
+
603
+ grep_source_clear(&w.source);
604
+ strbuf_release(&w.out);
605
+ return hit;
606
+ }
607
+}
608
+
609
+static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec,
610
+ int cached)
611
{
612
int hit = 0;
613
int nr;
614
+ struct strbuf name = STRBUF_INIT;
615
+ int name_base_len = 0;
616
+ if (super_prefix) {
617
+ name_base_len = strlen(super_prefix);
618
+ strbuf_addstr(&name, super_prefix);
619
+ }
620
+
621
read_cache();
622
623
for (nr = 0; nr < active_nr; nr++) {
624
const struct cache_entry *ce = active_cache[nr];
389
- if (!S_ISREG(ce->ce_mode))
390
- continue;
391
- if (!ce_path_match(ce, pathspec, NULL))
625
+ strbuf_setlen(&name, name_base_len);
626
+ strbuf_addstr(&name, ce->name);
627
+
628
+ if (S_ISREG(ce->ce_mode) &&
629
+ match_pathspec(pathspec, name.buf, name.len, 0, NULL,
630
+ S_ISDIR(ce->ce_mode) ||
631
+ S_ISGITLINK(ce->ce_mode))) {
632
+ /*
633
+ * If CE_VALID is on, we assume worktree file and its
634
+ * cache entry are identical, even if worktree file has
635
+ * been modified, so use cache version instead
636
+ */
637
+ if (cached || (ce->ce_flags & CE_VALID) ||
638
+ ce_skip_worktree(ce)) {
639
+ if (ce_stage(ce) || ce_intent_to_add(ce))
640
+ continue;
641
+ hit |= grep_sha1(opt, ce->oid.hash, ce->name,
642
+ 0, ce->name);
643
+ } else {
644
+ hit |= grep_file(opt, ce->name);
645
+ }
646
+ } else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
647
+ submodule_path_match(pathspec, name.buf, NULL)) {
648
+ hit |= grep_submodule(opt, NULL, ce->name, ce->name);
649
+ } else {
650
continue;
393
- /*
394
- * If CE_VALID is on, we assume worktree file and its cache entry
395
- * are identical, even if worktree file has been modified, so use
396
- * cache version instead
397
- */
398
- if (cached || (ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) {
399
- if (ce_stage(ce) || ce_intent_to_add(ce))
400
- continue;
401
- hit |= grep_sha1(opt, ce->oid.hash, ce->name, 0,
402
- ce->name);
651
}
404
- else
405
- hit |= grep_file(opt, ce->name);
652
+
653
if (ce_stage(ce)) {
654
do {
655
nr++;
660
if (hit && opt->status_only)
661
break;
662
}
663
+
664
+ strbuf_release(&name);
665
return hit;
666
}
667
900
N_("search in both tracked and untracked files")),
901
OPT_SET_INT(0, "exclude-standard", &opt_exclude,
902
N_("ignore files specified via '.gitignore'"), 1),
903
+ OPT_BOOL(0, "recurse-submodules", &recurse_submodules,
904
+ N_("recursivley search in each submodule")),
905
OPT_GROUP(""),
906
OPT_BOOL('v', "invert-match", &opt.invert,
907
N_("show non-matching lines")),
1006
init_grep_defaults();
1007
git_config(grep_cmd_config, NULL);
1008
grep_init(&opt, prefix);
1009
+ super_prefix = get_super_prefix();
1010
1011
/*
1012
* If there is no -- then the paths must exist in the working
1124
pathspec.max_depth = opt.max_depth;
1125
pathspec.recursive = 1;
1126
1127
+ if (recurse_submodules) {
1128
+ gitmodules_config();
1129
+ compile_submodule_options(&opt, &pathspec, cached, untracked,
1130
+ opt_exclude, use_index,
1131
+ pattern_type_arg);
1132
+ }
1133
+
1134
if (show_in_pager && (cached || list.nr))
1135
die(_("--open-files-in-pager only works on the worktree"));
1136
1154
}
1155
}
1156
1157
+ if (recurse_submodules && (!use_index || untracked || list.nr))
1158
+ die(_("option not supported with --recurse-submodules."));
1159
+
1160
if (!show_in_pager && !opt.status_only)
1161
setup_pager();
1162