Merge branch 'maint-1.6.3' into maint
authorJunio C Hamano <gitster@pobox.com>
Fri, 28 Aug 2009 03:42:42 +0000 (20:42 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 28 Aug 2009 03:42:42 +0000 (20:42 -0700)
* maint-1.6.3:
Fix overridable written with an extra 'e'
Documentation: git-archive: mark --format as optional in summary
Round-down years in "years+months" relative date view

1  2 
gitweb/gitweb.perl
diff --combined gitweb/gitweb.perl
index 4f051942bd9697008acce4ea563056e41a8e9095,6f355d80699dabc315cec5a6eaea133ca55c3e6f..2cb832753a449aba64cc0e4b0f2c7878bb3871f5
@@@ -94,7 -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,14 -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 = (
                '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 {
                @{$feature{$name}{'default'}});
        if (!$override) { return @defaults; }
        if (!defined $sub) {
-               warn "feature $name is not overrideable";
+               warn "feature $name is not overridable";
                return @defaults;
        }
        return $sub->(@defaults);
@@@ -462,12 -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.
@@@ -493,8 -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++";
@@@ -725,10 -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;
@@@ -849,19 -813,6 +849,19 @@@ $git_dir = "$projectroot/$project" if $
  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) {
  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");
  }
@@@ -887,7 -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;
@@@ -1085,7 -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 = @_;
  
@@@ -1284,7 -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));
        }
  }
@@@ -1345,7 -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)
@@@ -1507,7 -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);
        }
  }
  
 +# 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} ? "&nbsp;" : "");
 +      my $post_white = ($opts{-pad_after}  ? "&nbsp;" : "");
 +      $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;
@@@ -1964,7 -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
@@@ -2176,7 -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;
@@@ -2191,17 -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;
  }
  
@@@ -2254,7 -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'));
@@@ -2312,7 -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;
@@@ -2375,7 -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;
@@@ -2523,14 -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;
@@@ -2570,7 -2439,7 +2570,7 @@@ sub parse_commit_text 
                } elsif ((!defined $withparents) && ($line =~ m/^parent ([0-9a-fA-F]{40})$/)) {
                        push @parents, $1;
                } elsif ($line =~ m/^author (.*) ([0-9]+) (.*)$/) {
 -                      $co{'author'} = $1;
 +                      $co{'author'} = to_utf8($1);
                        $co{'author_epoch'} = $2;
                        $co{'author_tz'} = $3;
                        if ($co{'author'} =~ m/^([^<]+) <([^>]*)>/) {
                                $co{'author_name'} = $co{'author'};
                        }
                } elsif ($line =~ m/^committer (.*) ([0-9]+) (.*)$/) {
 -                      $co{'committer'} = $1;
 +                      $co{'committer'} = to_utf8($1);
                        $co{'committer_epoch'} = $2;
                        $co{'committer_tz'} = $3;
 -                      $co{'committer_name'} = $co{'committer'};
                        if ($co{'committer'} =~ m/^([^<]+) <([^>]*)>/) {
                                $co{'committer_name'}  = $1;
                                $co{'committer_email'} = $2;
@@@ -2745,7 -2615,7 +2745,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;
@@@ -2934,18 -2804,18 +2934,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};
@@@ -3343,54 -3213,22 +3343,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 {
        print "<br/></div>\n";
  }
  
 -# sub git_print_log (\@;%) {
 -sub git_print_log ($;%) {
 +sub git_print_log {
        my $log = shift;
        my %opts = @_;
  
@@@ -3489,7 -3328,7 +3489,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
  # 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 '/');
@@@ -3558,7 -3400,7 +3558,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,
@@@ -4151,7 -3993,7 +4151,7 @@@ sub fill_project_list_info 
                            ($pname !~ /\/$/) &&
                            (-d "$projectroot/$pname")) {
                                $pr->{'forks'} = "-d $projectroot/$pname";
 -                      }       else {
 +                      } else {
                                $pr->{'forks'} = 0;
                        }
                }
@@@ -4304,9 -4146,11 +4304,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" .
@@@ -4353,9 -4197,11 +4353,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);
@@@ -4508,8 -4354,9 +4508,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"},
@@@ -4743,7 -4590,11 +4743,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";
@@@ -4952,10 -4803,11 +4952,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;
  }
  
@@@ -5057,16 -4909,12 +5057,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);
@@@ -5247,9 -5095,9 +5247,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);
@@@ -5268,6 -5116,8 +5268,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
        }
        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>" .
@@@ -5715,11 -5580,7 +5715,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";
@@@ -5948,7 -5809,7 +5948,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' : ());
                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'};
@@@ -6421,7 -6282,7 +6421,7 @@@ XM
        # end of feed
        if ($format eq 'rss') {
                print "</channel>\n</rss>\n";
 -      }       elsif ($format eq 'atom') {
 +      } elsif ($format eq 'atom') {
                print "</feed>\n";
        }
  }