git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Chris Packham <judge.packham@gmail.com>
To: git@vger.kernel.org
Cc: Jens.Lehmann@web.de, pclouds@gmail.com, gitster@pobox.com,
	Chris Packham <judge.packham@gmail.com>
Subject: [RFC/PATCHv2 5/5] grep: add support for grepping in submodules
Date: Fri, 15 Oct 2010 16:26:44 -0700	[thread overview]
Message-ID: <1287185204-843-6-git-send-email-judge.packham@gmail.com> (raw)
In-Reply-To: <1287185204-843-1-git-send-email-judge.packham@gmail.com>

When the --recurse-submodules option is given git grep will search in
submodules as they are encountered.

Signed-off-by: Chris Packham <judge.packham@gmail.com>
---
The refspec from the super project is passed as an environment variable
along with the GIT_DIR and GIT_WORK_TREE. We re-build a command line for
the sub-process grep which works for the basic cases but I need to add
some more complex tests to ensure everything gets passed through
correctly.
    
At the moment I don't alter the pathspec or max-depth option but I'll do
so in a future re-roll.

 builtin/grep.c |  103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 grep.h         |    1 +
 2 files changed, 102 insertions(+), 2 deletions(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 251c4e7..7bcdf05 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -587,6 +587,91 @@ static void run_pager(struct grep_opt *opt, const char *prefix)
 	free(argv);
 }
 
+static int pattern_list_to_argv(struct grep_opt *opt, const char **argv, int len)
+{
+	int i = 0;
+	struct grep_pat *p = opt->pattern_list;
+	while(p) {
+		if (i > len)
+			die("grep: not enough space for subprocess args");
+		if (p->token == GREP_PATTERN)
+			argv[i++] = "-e";
+		argv[i++] = p->pattern;
+		p = p->next;
+	}
+	return i;
+}
+
+static const char **create_sub_grep_argv(struct grep_opt *opt,
+		const char *path, const char *sha1, const char *tree_name)
+{
+	#define NUM_ARGS 10
+	struct strbuf buf = STRBUF_INIT;
+	const char **argv;
+	int i = 0;
+
+	argv = xcalloc(NUM_ARGS, sizeof(const char *));
+	argv[i++] = "grep";
+
+	if (opt->linenum)
+		argv[i++] = "-n";
+	if (opt->invert)
+		argv[i++] = "-v";
+	if (opt->ignore_case)
+		argv[i++] = "-i";
+	if (opt->count)
+		argv[i++] = "-c";
+	if (opt->name_only)
+		argv[i++] = "-l";
+	if (opt->recurse_submodules)
+		argv[i++] = "--recursive";
+
+	i += pattern_list_to_argv(opt, &argv[i], NUM_ARGS-(i+1));
+	if (sha1) {
+		argv[i++] = sha1;
+	}
+	argv[i++] = NULL;
+
+	strbuf_release(&buf);
+	return argv;
+}
+
+static int grep_submodule(struct grep_opt *opt, const char *path,
+			  const char *sha1, const char *tree_name)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct strbuf pre_buf = STRBUF_INIT;
+	struct child_process cp;
+	const char **argv = create_sub_grep_argv(opt, path, sha1, tree_name);
+	const char *git_dir;
+	int hit = 0;
+	memset(&cp, 0, sizeof(cp));
+
+	strbuf_addf(&buf, "%s/.git", path);
+	git_dir = read_gitfile_gently(buf.buf);
+	if (!git_dir)
+		git_dir = buf.buf;
+	if (!is_directory(git_dir))
+		goto out_free;
+
+	setenv("GIT_SUPER_REFNAME", tree_name, 1);
+	setenv(GIT_DIR_ENVIRONMENT, git_dir, 1);
+	setenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);
+	cp.argv = argv;
+	cp.git_cmd = 1;
+	cp.no_stdin = 1;
+	if (run_command(&cp) == 0)
+		hit = 1;
+out_free:
+	unsetenv("GIT_SUPER_REFNAME");
+	unsetenv(GIT_DIR_ENVIRONMENT);
+	unsetenv(GIT_WORK_TREE_ENVIRONMENT);
+	free(argv);
+	strbuf_release(&buf);
+	strbuf_release(&pre_buf);
+	return hit;
+}
+
 static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
 {
 	int hit = 0;
@@ -597,6 +682,10 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
 		struct cache_entry *ce = active_cache[nr];
 		if (!pathspec_matches(paths, ce->name, opt->max_depth))
 			continue;
+		if (S_ISGITLINK(ce->ce_mode) && opt->recurse_submodules) {
+			hit |= grep_submodule(opt, ce->name, NULL, NULL);
+			continue;
+		}
 		if (!S_ISREG(ce->ce_mode))
 			continue;
 		/*
@@ -634,11 +723,16 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
 	char *down;
 	int tn_len = strlen(tree_name);
 	struct strbuf pathbuf;
+	const char *refname = getenv("GIT_SUPER_REFNAME");
+	int rn_len = refname ? strlen(refname) : 0;
 
-	strbuf_init(&pathbuf, PATH_MAX + tn_len);
+	strbuf_init(&pathbuf, PATH_MAX + MAX(tn_len, rn_len));
 
 	if (tn_len) {
-		strbuf_add(&pathbuf, tree_name, tn_len);
+		if (refname)
+			strbuf_add(&pathbuf, refname, rn_len);
+		else
+			strbuf_add(&pathbuf, tree_name, tn_len);
 		strbuf_addch(&pathbuf, ':');
 		tn_len = pathbuf.len;
 	}
@@ -664,6 +758,9 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
 			;
 		else if (S_ISREG(entry.mode))
 			hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len);
+		else if (S_ISGITLINK(entry.mode) && opt->recurse_submodules)
+			hit |= grep_submodule(opt, entry.path,
+				sha1_to_hex(entry.sha1), tree_name);
 		else if (S_ISDIR(entry.mode)) {
 			enum object_type type;
 			struct tree_desc sub;
@@ -931,6 +1028,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 			    "allow calling of grep(1) (ignored by this build)"),
 		{ OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage",
 		  PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
+		OPT_BOOLEAN(0, "recursive", &opt.recurse_submodules,
+			"recurse into submodules"),
 		OPT_END()
 	};
 
diff --git a/grep.h b/grep.h
index 06621fe..d5e2e11 100644
--- a/grep.h
+++ b/grep.h
@@ -101,6 +101,7 @@ struct grep_opt {
 	unsigned post_context;
 	unsigned last_shown;
 	int show_hunk_mark;
+	int recurse_submodules;
 	void *priv;
 
 	void (*output)(struct grep_opt *opt, const void *data, size_t size);
-- 
1.7.3.1

  parent reply	other threads:[~2010-10-15 23:27 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-10-15 23:26 [RGC/PATCHv2] grep: submodule support Chris Packham
2010-10-15 23:26 ` [RFC/PATCHv2 1/5] worktree: provide better prefix to go back to original cwd Chris Packham
2010-10-16 18:42   ` Jonathan Nieder
2010-10-17  2:48     ` Chris Packham
2010-10-17 10:01       ` Nguyen Thai Ngoc Duy
2010-10-18  2:05         ` Chris Packham
2010-10-15 23:26 ` [RFC/PATCHv2 2/5] grep: output the path from cwd to worktree Chris Packham
2010-10-15 23:26 ` [RFC/PATCHv2 3/5] grep_cache: check pathspec first Chris Packham
2010-10-15 23:26 ` [RFC/PATCHv2 4/5] add test for git grep --recursive Chris Packham
2010-10-15 23:26 ` Chris Packham [this message]
2010-10-17 10:28   ` [RFC/PATCHv2 5/5] grep: add support for grepping in submodules Nguyen Thai Ngoc Duy
2010-10-18  2:01     ` Chris Packham
2010-10-18  3:37       ` Nguyen Thai Ngoc Duy
2010-10-16 15:54 ` [RGC/PATCHv2] grep: submodule support Jens Lehmann
2010-10-17  2:13   ` Chris Packham

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1287185204-843-6-git-send-email-judge.packham@gmail.com \
    --to=judge.packham@gmail.com \
    --cc=Jens.Lehmann@web.de \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=pclouds@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).