diff options
Diffstat (limited to 'gitweb')
-rw-r--r-- | gitweb/README | 6 | ||||
-rw-r--r-- | gitweb/gitweb.css | 9 | ||||
-rwxr-xr-x | gitweb/gitweb.perl | 332 |
3 files changed, 250 insertions, 97 deletions
diff --git a/gitweb/README b/gitweb/README index 9056d1e090..66c6a9391d 100644 --- a/gitweb/README +++ b/gitweb/README @@ -165,6 +165,12 @@ not include variables usually directly set during build): Full URL and absolute URL of gitweb script; in earlier versions of gitweb you might have need to set those variables, now there should be no need to do it. + * $base_url + Base URL for relative URLs in pages generated by gitweb, + (e.g. $logo, $favicon, @stylesheets if they are relative URLs), + needed and used only for URLs with nonempty PATH_INFO via + <base href="$base_url>. Usually gitweb sets its value correctly, + and there is no need to set this variable, e.g. to $my_uri or "/". * $home_link Target of the home link on top of all pages (the first part of view "breadcrumbs"). By default set to absolute URI of a page ($my_uri). diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css index a01eac814e..d05bc37646 100644 --- a/gitweb/gitweb.css +++ b/gitweb/gitweb.css @@ -28,6 +28,10 @@ img.logo { border-width: 0px; } +img.avatar { + vertical-align: middle; +} + div.page_header { height: 25px; padding: 8px; @@ -132,11 +136,14 @@ div.list_head { font-style: italic; } +.author_date, .author { + font-style: italic; +} + div.author_date { padding: 8px; border: solid #d9d8d1; border-width: 0px 0px 1px 0px; - font-style: italic; } a.list { diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 3f99361ed0..7fbd5ff89e 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -94,7 +94,7 @@ our $favicon = "++GITWEB_FAVICON++"; # URI and label (title) of GIT logo link #our $logo_url = "http://www.kernel.org/pub/software/scm/git/docs/"; #our $logo_label = "git documentation"; -our $logo_url = "http://git.or.cz/"; +our $logo_url = "http://git-scm.com/"; our $logo_label = "git homepage"; # source of projects list @@ -195,6 +195,14 @@ our %known_snapshot_format_aliases = ( 'x-zip' => undef, '' => undef, ); +# Pixel sizes for icons and avatars. If the default font sizes or lineheights +# are changed, it may be appropriate to change these values too via +# $GITWEB_CONFIG. +our %avatar_size = ( + 'default' => 16, + 'double' => 32 +); + # You define site-wide feature defaults here; override them with # $GITWEB_CONFIG as necessary. our %feature = ( @@ -365,6 +373,27 @@ our %feature = ( 'sub' => \&feature_patches, 'override' => 0, 'default' => [16]}, + + # Avatar support. When this feature is enabled, views such as + # shortlog or commit will display an avatar associated with + # the email of the committer(s) and/or author(s). + + # Currently available providers are gravatar and picon. + # If an unknown provider is specified, the feature is disabled. + + # Gravatar depends on Digest::MD5. + # Picon currently relies on the indiana.edu database. + + # To enable system wide have in $GITWEB_CONFIG + # $feature{'avatar'}{'default'} = ['<provider>']; + # where <provider> is either gravatar or picon. + # To have project specific config enable override in $GITWEB_CONFIG + # $feature{'avatar'}{'override'} = 1; + # and in project config gitweb.avatar = <provider>; + 'avatar' => { + 'sub' => \&feature_avatar, + 'override' => 0, + 'default' => ['']}, ); sub gitweb_get_feature { @@ -433,6 +462,12 @@ sub feature_patches { return ($_[0]); } +sub feature_avatar { + my @val = (git_get_project_config('avatar')); + + return @val ? @val : @_; +} + # checking HEAD file with -e is fragile if the repository was # initialized long time ago (i.e. symlink HEAD) and was pack-ref'ed # and then pruned. @@ -458,8 +493,8 @@ sub filter_snapshot_fmts { @fmts = map { exists $known_snapshot_format_aliases{$_} ? $known_snapshot_format_aliases{$_} : $_} @fmts; - @fmts = grep(exists $known_snapshot_formats{$_}, @fmts); - + @fmts = grep { + exists $known_snapshot_formats{$_} } @fmts; } our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++"; @@ -690,9 +725,10 @@ sub evaluate_path_info { # format key itself, with a prepended dot while (my ($fmt, $opt) = each %known_snapshot_formats) { my $hash = $refname; - my $sfx; - $hash =~ s/(\Q$opt->{'suffix'}\E|\Q.$fmt\E)$//; - next unless $sfx = $1; + unless ($hash =~ s/(\Q$opt->{'suffix'}\E|\Q.$fmt\E)$//) { + next; + } + my $sfx = $1; # a valid suffix was found, so set the snapshot format # and reset the hash parameter $input_params{'snapshot_format'} = $fmt; @@ -813,6 +849,19 @@ $git_dir = "$projectroot/$project" if $project; our @snapshot_fmts = gitweb_get_feature('snapshot'); @snapshot_fmts = filter_snapshot_fmts(@snapshot_fmts); +# check that the avatar feature is set to a known provider name, +# and for each provider check if the dependencies are satisfied. +# if the provider name is invalid or the dependencies are not met, +# reset $git_avatar to the empty string. +our ($git_avatar) = gitweb_get_feature('avatar'); +if ($git_avatar eq 'gravatar') { + $git_avatar = '' unless (eval { require Digest::MD5; 1; }); +} elsif ($git_avatar eq 'picon') { + # no dependencies +} else { + $git_avatar = ''; +} + # dispatch if (!defined $action) { if (defined $hash) { @@ -828,7 +877,7 @@ if (!defined $action) { if (!defined($actions{$action})) { die_error(400, "Unknown action"); } -if ($action !~ m/^(opml|project_list|project_index)$/ && +if ($action !~ m/^(?:opml|project_list|project_index)$/ && !$project) { die_error(400, "Project needed"); } @@ -838,7 +887,7 @@ exit; ## ====================================================================== ## action links -sub href (%) { +sub href { my %params = @_; # default is to use -absolute url() i.e. $my_uri my $href = $params{-full} ? $my_url : $my_uri; @@ -1036,7 +1085,7 @@ sub esc_url { } # replace invalid utf8 character with SUBSTITUTION sequence -sub esc_html ($;%) { +sub esc_html { my $str = shift; my %opts = @_; @@ -1235,7 +1284,7 @@ sub chop_and_escape_str { if ($chopped eq $str) { return esc_html($chopped); } else { - $str =~ s/([[:cntrl:]])/?/g; + $str =~ s/[[:cntrl:]]/?/g; return $cgi->span({-title=>$str}, esc_html($chopped)); } } @@ -1296,7 +1345,7 @@ use constant { }; # submodule/subproject, a commit object reference -sub S_ISGITLINK($) { +sub S_ISGITLINK { my $mode = shift; return (($mode & S_IFMT) == S_IFGITLINK) @@ -1458,6 +1507,7 @@ sub format_subject_html { $extra = '' unless defined($extra); if (length($short) < length($long)) { + $long =~ s/[[:cntrl:]]/?/g; return $cgi->a({-href => $href, -class => "list subject", -title => to_utf8($long)}, esc_html($short) . $extra); @@ -1467,6 +1517,82 @@ sub format_subject_html { } } +# Rather than recomputing the url for an email multiple times, we cache it +# after the first hit. This gives a visible benefit in views where the avatar +# for the same email is used repeatedly (e.g. shortlog). +# The cache is shared by all avatar engines (currently gravatar only), which +# are free to use it as preferred. Since only one avatar engine is used for any +# given page, there's no risk for cache conflicts. +our %avatar_cache = (); + +# Compute the picon url for a given email, by using the picon search service over at +# http://www.cs.indiana.edu/picons/search.html +sub picon_url { + my $email = lc shift; + if (!$avatar_cache{$email}) { + my ($user, $domain) = split('@', $email); + $avatar_cache{$email} = + "http://www.cs.indiana.edu/cgi-pub/kinzler/piconsearch.cgi/" . + "$domain/$user/" . + "users+domains+unknown/up/single"; + } + return $avatar_cache{$email}; +} + +# Compute the gravatar url for a given email, if it's not in the cache already. +# Gravatar stores only the part of the URL before the size, since that's the +# one computationally more expensive. This also allows reuse of the cache for +# different sizes (for this particular engine). +sub gravatar_url { + my $email = lc shift; + my $size = shift; + $avatar_cache{$email} ||= + "http://www.gravatar.com/avatar/" . + Digest::MD5::md5_hex($email) . "?s="; + return $avatar_cache{$email} . $size; +} + +# Insert an avatar for the given $email at the given $size if the feature +# is enabled. +sub git_get_avatar { + my ($email, %opts) = @_; + my $pre_white = ($opts{-pad_before} ? " " : ""); + my $post_white = ($opts{-pad_after} ? " " : ""); + $opts{-size} ||= 'default'; + my $size = $avatar_size{$opts{-size}} || $avatar_size{'default'}; + my $url = ""; + if ($git_avatar eq 'gravatar') { + $url = gravatar_url($email, $size); + } elsif ($git_avatar eq 'picon') { + $url = picon_url($email); + } + # Other providers can be added by extending the if chain, defining $url + # as needed. If no variant puts something in $url, we assume avatars + # are completely disabled/unavailable. + if ($url) { + return $pre_white . + "<img width=\"$size\" " . + "class=\"avatar\" " . + "src=\"$url\" " . + "alt=\"\" " . + "/>" . $post_white; + } else { + return ""; + } +} + +# format the author name of the given commit with the given tag +# the author name is chopped and escaped according to the other +# optional parameters (see chop_str). +sub format_author_html { + my $tag = shift; + my $co = shift; + my $author = chop_and_escape_str($co->{'author_name'}, @_); + return "<$tag class=\"author\">" . + git_get_avatar($co->{'author_email'}, -pad_after => 1) . + $author . "</$tag>"; +} + # format git diff header line, i.e. "diff --(git|combined|cc) ..." sub format_git_diff_header_line { my $line = shift; @@ -1838,7 +1964,7 @@ sub git_cmd { # Try to avoid using this function wherever possible. sub quote_command { return join(' ', - map( { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ )); + map { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ ); } # get HEAD ref of given project as hash @@ -2050,7 +2176,7 @@ sub git_get_project_description { my $path = shift; $git_dir = "$projectroot/$path"; - open my $fd, "$git_dir/description" + open my $fd, '<', "$git_dir/description" or return git_get_project_config('description'); my $descr = <$fd>; close $fd; @@ -2065,18 +2191,17 @@ sub git_get_project_ctags { my $ctags = {}; $git_dir = "$projectroot/$path"; - unless (opendir D, "$git_dir/ctags") { - return $ctags; - } - foreach (grep { -f $_ } map { "$git_dir/ctags/$_" } readdir(D)) { - open CT, $_ or next; - my $val = <CT>; + opendir my $dh, "$git_dir/ctags" + or return $ctags; + foreach (grep { -f $_ } map { "$git_dir/ctags/$_" } readdir($dh)) { + open my $ct, '<', $_ or next; + my $val = <$ct>; chomp $val; - close CT; + close $ct; my $ctag = $_; $ctag =~ s#.*/##; $ctags->{$ctag} = $val; } - closedir D; + closedir $dh; $ctags; } @@ -2129,7 +2254,7 @@ sub git_get_project_url_list { my $path = shift; $git_dir = "$projectroot/$path"; - open my $fd, "$git_dir/cloneurl" + open my $fd, '<', "$git_dir/cloneurl" or return wantarray ? @{ config_to_multi(git_get_project_config('url')) } : config_to_multi(git_get_project_config('url')); @@ -2187,7 +2312,7 @@ sub git_get_projects_list { # 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin' # 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman' my %paths; - open my ($fd), $projects_list or return; + open my $fd, '<', $projects_list or return; PROJECT: while (my $line = <$fd>) { chomp $line; @@ -2250,7 +2375,7 @@ sub git_get_project_list_from_file { # 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin' # 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman' if (-f $projects_list) { - open (my $fd , $projects_list); + open(my $fd, '<', $projects_list); while (my $line = <$fd>) { chomp $line; my ($pr, $ow) = split ' ', $line; @@ -2398,8 +2523,14 @@ sub parse_tag { $tag{'name'} = $1; } elsif ($line =~ m/^tagger (.*) ([0-9]+) (.*)$/) { $tag{'author'} = $1; - $tag{'epoch'} = $2; - $tag{'tz'} = $3; + $tag{'author_epoch'} = $2; + $tag{'author_tz'} = $3; + if ($tag{'author'} =~ m/^([^<]+) <([^>]*)>/) { + $tag{'author_name'} = $1; + $tag{'author_email'} = $2; + } else { + $tag{'author_name'} = $tag{'author'}; + } } elsif ($line =~ m/--BEGIN/) { push @comment, $line; last; @@ -2615,7 +2746,7 @@ sub parsed_difftree_line { } # parse line of git-ls-tree output -sub parse_ls_tree_line ($;%) { +sub parse_ls_tree_line { my $line = shift; my %opts = @_; my %res; @@ -2804,18 +2935,18 @@ sub mimetype_guess_file { -r $mimemap or return undef; my %mimemap; - open(MIME, $mimemap) or return undef; - while (<MIME>) { + open(my $mh, '<', $mimemap) or return undef; + while (<$mh>) { next if m/^#/; # skip comments - my ($mime, $exts) = split(/\t+/); + my ($mimetype, $exts) = split(/\t+/); if (defined $exts) { my @exts = split(/\s+/, $exts); foreach my $ext (@exts) { - $mimemap{$ext} = $mime; + $mimemap{$ext} = $mimetype; } } } - close(MIME); + close($mh); $filename =~ /\.([^.]*)$/; return $mimemap{$1}; @@ -3213,22 +3344,54 @@ sub git_print_header_div { "\n</div>\n"; } -#sub git_print_authorship (\%) { +sub print_local_time { + my %date = @_; + if ($date{'hour_local'} < 6) { + printf(" (<span class=\"atnight\">%02d:%02d</span> %s)", + $date{'hour_local'}, $date{'minute_local'}, $date{'tz_local'}); + } else { + printf(" (%02d:%02d %s)", + $date{'hour_local'}, $date{'minute_local'}, $date{'tz_local'}); + } +} + +# Outputs the author name and date in long form sub git_print_authorship { my $co = shift; + my %opts = @_; + my $tag = $opts{-tag} || 'div'; my %ad = parse_date($co->{'author_epoch'}, $co->{'author_tz'}); - print "<div class=\"author_date\">" . + print "<$tag class=\"author_date\">" . esc_html($co->{'author_name'}) . " [$ad{'rfc2822'}"; - if ($ad{'hour_local'} < 6) { - printf(" (<span class=\"atnight\">%02d:%02d</span> %s)", - $ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'}); - } else { - printf(" (%02d:%02d %s)", - $ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'}); + print_local_time(%ad) if ($opts{-localtime}); + print "]" . git_get_avatar($co->{'author_email'}, -pad_before => 1) + . "</$tag>\n"; +} + +# Outputs table rows containing the full author or committer information, +# in the format expected for 'commit' view (& similia). +# Parameters are a commit hash reference, followed by the list of people +# to output information for. If the list is empty it defalts to both +# author and committer. +sub git_print_authorship_rows { + my $co = shift; + # too bad we can't use @people = @_ || ('author', 'committer') + my @people = @_; + @people = ('author', 'committer') unless @people; + foreach my $who (@people) { + my %wd = parse_date($co->{"${who}_epoch"}, $co->{"${who}_tz"}); + print "<tr><td>$who</td><td>" . esc_html($co->{$who}) . "</td>" . + "<td rowspan=\"2\">" . + git_get_avatar($co->{"${who}_email"}, -size => 'double') . + "</td></tr>\n" . + "<tr>" . + "<td></td><td> $wd{'rfc2822'}"; + print_local_time(%wd); + print "</td>" . + "</tr>\n"; } - print "]</div>\n"; } sub git_print_page_path { @@ -3269,8 +3432,7 @@ sub git_print_page_path { print "<br/></div>\n"; } -# sub git_print_log (\@;%) { -sub git_print_log ($;%) { +sub git_print_log { my $log = shift; my %opts = @_; @@ -3328,7 +3490,7 @@ sub git_get_link_target { open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash or return; { - local $/; + local $/ = undef; $link_target = <$fd>; } close $fd @@ -3341,10 +3503,7 @@ sub git_get_link_target { # return target of link relative to top directory (top tree); # return undef if it is not possible (including absolute links). sub normalize_link_target { - my ($link_target, $basedir, $hash_base) = @_; - - # we can normalize symlink target only if $hash_base is provided - return unless $hash_base; + my ($link_target, $basedir) = @_; # absolute symlinks (beginning with '/') cannot be normalized return if (substr($link_target, 0, 1) eq '/'); @@ -3400,7 +3559,7 @@ sub git_print_tree_entry { if (S_ISLNK(oct $t->{'mode'})) { my $link_target = git_get_link_target($t->{'hash'}); if ($link_target) { - my $norm_target = normalize_link_target($link_target, $basedir, $hash_base); + my $norm_target = normalize_link_target($link_target, $basedir); if (defined $norm_target) { print " -> " . $cgi->a({-href => href(action=>"object", hash_base=>$hash_base, @@ -3993,7 +4152,7 @@ sub fill_project_list_info { ($pname !~ /\/$/) && (-d "$projectroot/$pname")) { $pr->{'forks'} = "-d $projectroot/$pname"; - } else { + } else { $pr->{'forks'} = 0; } } @@ -4146,11 +4305,9 @@ sub git_shortlog_body { print "<tr class=\"light\">\n"; } $alternate ^= 1; - my $author = chop_and_escape_str($co{'author_name'}, 10); # git_summary() used print "<td><i>$co{'age_string'}</i></td>\n" . print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" . - "<td><i>" . $author . "</i></td>\n" . - "<td>"; + format_author_html('td', \%co, 10) . "<td>"; print format_subject_html($co{'title'}, $co{'title_short'}, href(action=>"commit", hash=>$commit), $ref); print "</td>\n" . @@ -4197,11 +4354,9 @@ sub git_history_body { print "<tr class=\"light\">\n"; } $alternate ^= 1; - # shortlog uses chop_str($co{'author_name'}, 10) - my $author = chop_and_escape_str($co{'author_name'}, 15, 3); print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" . - "<td><i>" . $author . "</i></td>\n" . - "<td>"; + # shortlog: format_author_html('td', \%co, 10) + format_author_html('td', \%co, 15, 3) . "<td>"; # originally git_history used chop_str($co{'title'}, 50) print format_subject_html($co{'title'}, $co{'title_short'}, href(action=>"commit", hash=>$commit), $ref); @@ -4354,9 +4509,8 @@ sub git_search_grep_body { print "<tr class=\"light\">\n"; } $alternate ^= 1; - my $author = chop_and_escape_str($co{'author_name'}, 15, 5); print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" . - "<td><i>" . $author . "</i></td>\n" . + format_author_html('td', \%co, 15, 5) . "<td>" . $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), -class => "list subject"}, @@ -4590,11 +4744,7 @@ sub git_tag { $tag{'type'}) . "</td>\n" . "</tr>\n"; if (defined($tag{'author'})) { - my %ad = parse_date($tag{'epoch'}, $tag{'tz'}); - print "<tr><td>author</td><td>" . esc_html($tag{'author'}) . "</td></tr>\n"; - print "<tr><td></td><td>" . $ad{'rfc2822'} . - sprintf(" (%02d:%02d %s)", $ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'}) . - "</td></tr>\n"; + git_print_authorship_rows(\%tag, 'author'); } print "</table>\n\n" . "</div>\n"; @@ -4803,11 +4953,10 @@ sub git_blob_plain { -content_disposition => ($sandbox ? 'attachment' : 'inline') . '; filename="' . $save_as . '"'); - undef $/; + local $/ = undef; binmode STDOUT, ':raw'; print <$fd>; binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi - $/ = "\n"; close $fd; } @@ -4909,12 +5058,16 @@ sub git_tree { } } die_error(404, "No such tree") unless defined($hash); - $/ = "\0"; - open my $fd, "-|", git_cmd(), "ls-tree", '-z', $hash - or die_error(500, "Open git-ls-tree failed"); - my @entries = map { chomp; $_ } <$fd>; - close $fd or die_error(404, "Reading tree failed"); - $/ = "\n"; + + my @entries = (); + { + local $/ = "\0"; + open my $fd, "-|", git_cmd(), "ls-tree", '-z', $hash + or die_error(500, "Open git-ls-tree failed"); + @entries = map { chomp; $_ } <$fd>; + close $fd + or die_error(404, "Reading tree failed"); + } my $refs = git_get_references(); my $ref = format_ref_marker($refs, $hash_base); @@ -5095,9 +5248,9 @@ sub git_log { " | " . $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree") . "<br/>\n" . - "</div>\n" . - "<i>" . esc_html($co{'author_name'}) . " [$ad{'rfc2822'}]</i><br/>\n" . "</div>\n"; + git_print_authorship(\%co, -tag => 'span'); + print "<br/>\n</div>\n"; print "<div class=\"log_body\">\n"; git_print_log($co{'comment'}, -final_empty_line=> 1); @@ -5116,8 +5269,6 @@ sub git_commit { $hash ||= $hash_base || "HEAD"; my %co = parse_commit($hash) or die_error(404, "Unknown commit object"); - my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'}); - my %cd = parse_date($co{'committer_epoch'}, $co{'committer_tz'}); my $parent = $co{'parent'}; my $parents = $co{'parents'}; # listref @@ -5184,22 +5335,7 @@ sub git_commit { } print "<div class=\"title_text\">\n" . "<table class=\"object_header\">\n"; - print "<tr><td>author</td><td>" . esc_html($co{'author'}) . "</td></tr>\n". - "<tr>" . - "<td></td><td> $ad{'rfc2822'}"; - if ($ad{'hour_local'} < 6) { - printf(" (<span class=\"atnight\">%02d:%02d</span> %s)", - $ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'}); - } else { - printf(" (%02d:%02d %s)", - $ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'}); - } - print "</td>" . - "</tr>\n"; - print "<tr><td>committer</td><td>" . esc_html($co{'committer'}) . "</td></tr>\n"; - print "<tr><td></td><td> $cd{'rfc2822'}" . - sprintf(" (%02d:%02d %s)", $cd{'hour_local'}, $cd{'minute_local'}, $cd{'tz_local'}) . - "</td></tr>\n"; + git_print_authorship_rows(\%co); print "<tr><td>commit</td><td class=\"sha1\">$co{'id'}</td></tr>\n"; print "<tr>" . "<td>tree</td>" . @@ -5580,7 +5716,11 @@ sub git_commitdiff { git_header_html(undef, $expires); git_print_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash); - git_print_authorship(\%co); + print "<div class=\"title_text\">\n" . + "<table class=\"object_header\">\n"; + git_print_authorship_rows(\%co); + print "</table>". + "</div>\n"; print "<div class=\"page_body\">\n"; if (@{$co{'comment'}} > 1) { print "<div class=\"log\">\n"; @@ -5809,7 +5949,7 @@ sub git_search { print "<table class=\"pickaxe search\">\n"; my $alternate = 1; - $/ = "\n"; + local $/ = "\n"; open my $fd, '-|', git_cmd(), '--no-pager', 'log', @diff_opts, '--pretty=format:%H', '--no-abbrev', '--raw', "-S$searchtext", ($search_use_regexp ? '--pickaxe-regex' : ()); @@ -5879,7 +6019,7 @@ sub git_search { print "<table class=\"grep_search\">\n"; my $alternate = 1; my $matches = 0; - $/ = "\n"; + local $/ = "\n"; open my $fd, "-|", git_cmd(), 'grep', '-n', $search_use_regexp ? ('-E', '-i') : '-F', $searchtext, $co{'tree'}; @@ -6282,7 +6422,7 @@ XML # end of feed if ($format eq 'rss') { print "</channel>\n</rss>\n"; - } elsif ($format eq 'atom') { + } elsif ($format eq 'atom') { print "</feed>\n"; } } |