Skip to content

Commit

Permalink
gitweb: Add support for grep searches
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Petr Baudis authored and Junio C Hamano committed May 18, 2007
1 parent d77b567 commit e773855
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 2 deletions.
4 changes: 4 additions & 0 deletions gitweb/gitweb.css
Original file line number Diff line number Diff line change
Expand Up @@ -484,3 +484,7 @@ span.atnight {
span.match {
color: #e00000;
}

div.binary {
font-style: italic;
}
123 changes: 121 additions & 2 deletions gitweb/gitweb.perl
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,19 @@ BEGIN
'override' => 0,
'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
# a given string in a file. This can be practical and quite faster
# alternative to 'blame', but still potentially CPU-intensive.
Expand Down Expand Up @@ -245,6 +258,18 @@ sub gitweb_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 {
my ($val) = git_get_project_config('pickaxe', '--bool');

Expand Down Expand Up @@ -364,10 +389,17 @@ sub check_export_ok {
}
}

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 $search_regexp;
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");
}
if (length($searchtext) < 2) {
Expand Down Expand Up @@ -1927,7 +1959,7 @@ sub git_header_html {
$cgi->hidden(-name => "a") . "\n" .
$cgi->hidden(-name => "h") . "\n" .
$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")}, "?")) .
" search:\n",
$cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
Expand Down Expand Up @@ -4626,6 +4658,12 @@ sub git_search {
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();

Expand Down Expand Up @@ -4742,6 +4780,73 @@ sub git_search {

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();
}

Expand All @@ -4752,6 +4857,20 @@ sub git_search_help {
<dl>
<dt><b>commit</b></dt>
<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>
<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>
Expand Down

0 comments on commit e773855

Please sign in to comment.