[PATCH] git-grep: Add ability to limit directory recursion

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This add a -R <limit> option to git-grep which will limit the depth of the
directories recursed when git is doing a grep.

This allows you to do something like:
        git grep -R 1 <pattern>
and see only the results of the grep on files in the current directory.

It defaults to a limit of "0" which disables the limiting.
---
 Documentation/git-grep.txt |    6 +++++
 builtin-grep.c             |   52 +++++++++++++++++++++++++++++++++++++++++--
 grep.h                     |    1 +
 3 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index a97f055..2f73c90 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -97,6 +97,12 @@ OPTIONS
 -f <file>::
 	Read patterns from <file>, one per line.
 
+-R <limit>::
+	Limit the recursion depth when grepping.  A limit of 1 stops
+	the grep from accessing any subdirectories from the specified
+	tree, cache, or working files.  A higher limit will limit the
+	files to N directories deep.
+
 -e::
 	The next parameter is the pattern. This option has to be
 	used for patterns starting with - and should be used in
diff --git a/builtin-grep.c b/builtin-grep.c
index ef29910..2877584 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -343,6 +343,15 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
 			continue;
 		if (!pathspec_matches(paths, ce->name))
 			continue;
+		if (opt->recurse_limit) {
+			int d = 0;
+			const char* cp = ce->name + ce_namelen(ce);
+			while (--cp > ce->name)
+				if (*cp == '/' && opt->recurse_limit < ++d)
+					break;
+			if (opt->recurse_limit <= d)
+				continue;
+		}
 		name = ce->name;
 		if (name[0] == '-') {
 			int len = ce_namelen(ce);
@@ -399,6 +408,16 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
 			continue;
 		if (!pathspec_matches(paths, ce->name))
 			continue;
+		if (opt->recurse_limit) {
+			int d = 0;
+			const char* cp = ce->name + ce_namelen(ce);
+			while (--cp > ce->name)
+				if (*cp == '/' && opt->recurse_limit < ++d)
+					break;
+			if (opt->recurse_limit <= d)
+				continue;
+		}
+
 		if (cached) {
 			if (ce_stage(ce))
 				continue;
@@ -420,7 +439,8 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
 
 static int grep_tree(struct grep_opt *opt, const char **paths,
 		     struct tree_desc *tree,
-		     const char *tree_name, const char *base)
+		     const char *tree_name, const char *base,
+		     int recurse_depth)
 {
 	int len;
 	int hit = 0;
@@ -460,12 +480,17 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
 			void *data;
 			unsigned long size;
 
+			if (opt->recurse_limit &&
+					opt->recurse_limit <= recurse_depth)
+				continue;
+
 			data = read_sha1_file(entry.sha1, &type, &size);
 			if (!data)
 				die("unable to read tree (%s)",
 				    sha1_to_hex(entry.sha1));
 			init_tree_desc(&sub, data, size);
-			hit |= grep_tree(opt, paths, &sub, tree_name, down);
+			hit |= grep_tree(opt, paths, &sub, tree_name, down,
+					recurse_depth+1);
 			free(data);
 		}
 	}
@@ -487,7 +512,7 @@ static int grep_object(struct grep_opt *opt, const char **paths,
 		if (!data)
 			die("unable to read tree (%s)", sha1_to_hex(obj->sha1));
 		init_tree_desc(&tree, data, size);
-		hit = grep_tree(opt, paths, &tree, name, "");
+		hit = grep_tree(opt, paths, &tree, name, "", 1);
 		free(data);
 		return hit;
 	}
@@ -499,6 +524,8 @@ static const char builtin_grep_usage[] =
 
 static const char emsg_invalid_context_len[] =
 "%s: invalid context length argument";
+static const char emsg_invalid_recurse_limit[] =
+"%s: invalid recursion limit argument";
 static const char emsg_missing_context_len[] =
 "missing context length argument";
 static const char emsg_missing_argument[] =
@@ -704,6 +731,25 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 			}
 			die(emsg_missing_argument, arg);
 		}
+		if (!strcmp("-R", arg)) {
+			unsigned num;
+			const char *scan;
+			if (1 < argc) {
+				int i;
+				scan = *++argv;
+				argc--;
+				if (strtoul_ui(scan, 10, &num))
+					die(emsg_invalid_recurse_limit, scan);
+				opt.recurse_limit = num;
+				/* increase by the depth of the prefix */
+				if (prefix && *prefix)
+					for (i = 0; i < strlen(prefix); i++)
+						if (prefix[i] == '/')
+							opt.recurse_limit++;
+				continue;
+			}
+			die(emsg_missing_argument, arg);
+		}
 		if (!strcmp("--full-name", arg)) {
 			opt.relative = 0;
 			continue;
diff --git a/grep.h b/grep.h
index d252dd2..b71dbf2 100644
--- a/grep.h
+++ b/grep.h
@@ -51,6 +51,7 @@ struct grep_opt {
 	struct grep_pat **pattern_tail;
 	struct grep_expr *pattern_expression;
 	int prefix_length;
+	int recurse_limit;
 	regex_t regexp;
 	unsigned linenum:1;
 	unsigned invert:1;
-- 
1.5.5.67.g9a49

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux