gitweb: Add support for grep searches
The 'grep' type of search greps the currently selected tree for given regexp and shows the results in a fancy table with links into blob view. The number of shown matches is limited to 1000 and the whole feature can be turned off (grepping linux-2.6.git already makes repo.or.cz a bit unhappy). This second revision makes it in documentation explicit that grep accepts regexps, and makes grep accept extended regexps instead of basic regexps. Signed-off-by: Petr Baudis <pasky@suse.cz> Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
parent
d77b5673e9
commit
e773855372
@ -484,3 +484,7 @@ span.atnight {
|
|||||||
span.match {
|
span.match {
|
||||||
color: #e00000;
|
color: #e00000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.binary {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
@ -146,6 +146,19 @@ our %feature = (
|
|||||||
'override' => 0,
|
'override' => 0,
|
||||||
'default' => [1]},
|
'default' => [1]},
|
||||||
|
|
||||||
|
# Enable grep search, which will list the files in currently selected
|
||||||
|
# tree containing the given string. Enabled by default. This can be
|
||||||
|
# potentially CPU-intensive, of course.
|
||||||
|
|
||||||
|
# To enable system wide have in $GITWEB_CONFIG
|
||||||
|
# $feature{'grep'}{'default'} = [1];
|
||||||
|
# To have project specific config enable override in $GITWEB_CONFIG
|
||||||
|
# $feature{'grep'}{'override'} = 1;
|
||||||
|
# and in project config gitweb.grep = 0|1;
|
||||||
|
'grep' => {
|
||||||
|
'override' => 0,
|
||||||
|
'default' => [1]},
|
||||||
|
|
||||||
# Enable the pickaxe search, which will list the commits that modified
|
# Enable the pickaxe search, which will list the commits that modified
|
||||||
# a given string in a file. This can be practical and quite faster
|
# a given string in a file. This can be practical and quite faster
|
||||||
# alternative to 'blame', but still potentially CPU-intensive.
|
# alternative to 'blame', but still potentially CPU-intensive.
|
||||||
@ -245,6 +258,18 @@ sub gitweb_have_snapshot {
|
|||||||
return $have_snapshot;
|
return $have_snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub feature_grep {
|
||||||
|
my ($val) = git_get_project_config('grep', '--bool');
|
||||||
|
|
||||||
|
if ($val eq 'true') {
|
||||||
|
return (1);
|
||||||
|
} elsif ($val eq 'false') {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($_[0]);
|
||||||
|
}
|
||||||
|
|
||||||
sub feature_pickaxe {
|
sub feature_pickaxe {
|
||||||
my ($val) = git_get_project_config('pickaxe', '--bool');
|
my ($val) = git_get_project_config('pickaxe', '--bool');
|
||||||
|
|
||||||
@ -364,10 +389,17 @@ if (defined $page) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
our $searchtype = $cgi->param('st');
|
||||||
|
if (defined $searchtype) {
|
||||||
|
if ($searchtype =~ m/[^a-z]/) {
|
||||||
|
die_error(undef, "Invalid searchtype parameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
our $searchtext = $cgi->param('s');
|
our $searchtext = $cgi->param('s');
|
||||||
our $search_regexp;
|
our $search_regexp;
|
||||||
if (defined $searchtext) {
|
if (defined $searchtext) {
|
||||||
if ($searchtext =~ m/[^a-zA-Z0-9_\.\/\-\+\:\@ ]/) {
|
if ($searchtype ne 'grep' and $searchtext =~ m/[^a-zA-Z0-9_\.\/\-\+\:\@ ]/) {
|
||||||
die_error(undef, "Invalid search parameter");
|
die_error(undef, "Invalid search parameter");
|
||||||
}
|
}
|
||||||
if (length($searchtext) < 2) {
|
if (length($searchtext) < 2) {
|
||||||
@ -1927,7 +1959,7 @@ EOF
|
|||||||
$cgi->hidden(-name => "a") . "\n" .
|
$cgi->hidden(-name => "a") . "\n" .
|
||||||
$cgi->hidden(-name => "h") . "\n" .
|
$cgi->hidden(-name => "h") . "\n" .
|
||||||
$cgi->popup_menu(-name => 'st', -default => 'commit',
|
$cgi->popup_menu(-name => 'st', -default => 'commit',
|
||||||
-values => ['commit', 'author', 'committer', 'pickaxe']) .
|
-values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) .
|
||||||
$cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) .
|
$cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) .
|
||||||
" search:\n",
|
" search:\n",
|
||||||
$cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
|
$cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
|
||||||
@ -4626,6 +4658,12 @@ sub git_search {
|
|||||||
die_error('403 Permission denied', "Permission denied");
|
die_error('403 Permission denied', "Permission denied");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($searchtype eq 'grep') {
|
||||||
|
my ($have_grep) = gitweb_check_feature('grep');
|
||||||
|
if (!$have_grep) {
|
||||||
|
die_error('403 Permission denied', "Permission denied");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
git_header_html();
|
git_header_html();
|
||||||
|
|
||||||
@ -4742,6 +4780,73 @@ sub git_search {
|
|||||||
|
|
||||||
print "</table>\n";
|
print "</table>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($searchtype eq 'grep') {
|
||||||
|
git_print_page_nav('','', $hash,$co{'tree'},$hash);
|
||||||
|
git_print_header_div('commit', esc_html($co{'title'}), $hash);
|
||||||
|
|
||||||
|
print "<table cellspacing=\"0\">\n";
|
||||||
|
my $alternate = 1;
|
||||||
|
my $matches = 0;
|
||||||
|
$/ = "\n";
|
||||||
|
open my $fd, "-|", git_cmd(), 'grep', '-n', '-i', '-E', $searchtext, $co{'tree'};
|
||||||
|
my $lastfile = '';
|
||||||
|
while (my $line = <$fd>) {
|
||||||
|
chomp $line;
|
||||||
|
my ($file, $lno, $ltext, $binary);
|
||||||
|
last if ($matches++ > 1000);
|
||||||
|
if ($line =~ /^Binary file (.+) matches$/) {
|
||||||
|
$file = $1;
|
||||||
|
$binary = 1;
|
||||||
|
} else {
|
||||||
|
(undef, $file, $lno, $ltext) = split(/:/, $line, 4);
|
||||||
|
}
|
||||||
|
if ($file ne $lastfile) {
|
||||||
|
$lastfile and print "</td></tr>\n";
|
||||||
|
if ($alternate++) {
|
||||||
|
print "<tr class=\"dark\">\n";
|
||||||
|
} else {
|
||||||
|
print "<tr class=\"light\">\n";
|
||||||
|
}
|
||||||
|
print "<td class=\"list\">".
|
||||||
|
$cgi->a({-href => href(action=>"blob", hash=>$co{'hash'},
|
||||||
|
file_name=>"$file"),
|
||||||
|
-class => "list"}, esc_path($file));
|
||||||
|
print "</td><td>\n";
|
||||||
|
$lastfile = $file;
|
||||||
|
}
|
||||||
|
if ($binary) {
|
||||||
|
print "<div class=\"binary\">Binary file</div>\n";
|
||||||
|
} else {
|
||||||
|
$ltext = untabify($ltext);
|
||||||
|
if ($ltext =~ m/^(.*)($searchtext)(.*)$/i) {
|
||||||
|
$ltext = esc_html($1, -nbsp=>1);
|
||||||
|
$ltext .= '<span class="match">';
|
||||||
|
$ltext .= esc_html($2, -nbsp=>1);
|
||||||
|
$ltext .= '</span>';
|
||||||
|
$ltext .= esc_html($3, -nbsp=>1);
|
||||||
|
} else {
|
||||||
|
$ltext = esc_html($ltext, -nbsp=>1);
|
||||||
|
}
|
||||||
|
print "<div class=\"pre\">" .
|
||||||
|
$cgi->a({-href => href(action=>"blob", hash=>$co{'hash'},
|
||||||
|
file_name=>"$file").'#l'.$lno,
|
||||||
|
-class => "linenr"}, sprintf('%4i', $lno))
|
||||||
|
. ' ' . $ltext . "</div>\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($lastfile) {
|
||||||
|
print "</td></tr>\n";
|
||||||
|
if ($matches > 1000) {
|
||||||
|
print "<div class=\"diff nodifferences\">Too many matches, listing trimmed</div>\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print "<div class=\"diff nodifferences\">No matches found</div>\n";
|
||||||
|
}
|
||||||
|
close $fd;
|
||||||
|
|
||||||
|
print "</table>\n";
|
||||||
|
}
|
||||||
git_footer_html();
|
git_footer_html();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4752,6 +4857,20 @@ sub git_search_help {
|
|||||||
<dl>
|
<dl>
|
||||||
<dt><b>commit</b></dt>
|
<dt><b>commit</b></dt>
|
||||||
<dd>The commit messages and authorship information will be scanned for the given string.</dd>
|
<dd>The commit messages and authorship information will be scanned for the given string.</dd>
|
||||||
|
EOT
|
||||||
|
my ($have_grep) = gitweb_check_feature('grep');
|
||||||
|
if ($have_grep) {
|
||||||
|
print <<EOT;
|
||||||
|
<dt><b>grep</b></dt>
|
||||||
|
<dd>All files in the currently selected tree (HEAD unless you are explicitly browsing
|
||||||
|
a different one) are searched for the given
|
||||||
|
<a href="http://en.wikipedia.org/wiki/Regular_expression">regular expression</a>
|
||||||
|
(POSIX extended) and the matches are listed. On large
|
||||||
|
trees, this search can take a while and put some strain on the server, so please use it with
|
||||||
|
some consideration.</dd>
|
||||||
|
EOT
|
||||||
|
}
|
||||||
|
print <<EOT;
|
||||||
<dt><b>author</b></dt>
|
<dt><b>author</b></dt>
|
||||||
<dd>Name and e-mail of the change author and date of birth of the patch will be scanned for the given string.</dd>
|
<dd>Name and e-mail of the change author and date of birth of the patch will be scanned for the given string.</dd>
|
||||||
<dt><b>committer</b></dt>
|
<dt><b>committer</b></dt>
|
||||||
|
Loading…
Reference in New Issue
Block a user