gitweb: use blame --porcelain
[gitweb.git] / gitweb / gitweb.perl
index e4ebce6224f8f557c7a0eeb943a9c88390d93580..68347ac975f4f831ee99547ff26753957dec74da 100755 (executable)
@@ -59,6 +59,9 @@
 # URI of GIT favicon, assumed to be image/png type
 our $favicon = "++GITWEB_FAVICON++";
 
+our $githelp_url = "http://git.or.cz/";
+our $githelp_label = "git homepage";
+
 # source of projects list
 our $projects_list = "++GITWEB_LIST++";
 
@@ -971,6 +974,9 @@ sub parse_date {
        $date{'hour_local'} = $hour;
        $date{'minute_local'} = $min;
        $date{'tz_local'} = $tz;
+       $date{'iso-tz'} = sprintf ("%04d-%02d-%02d %02d:%02d:%02d %s",
+                                  1900+$year, $mon+1, $mday,
+                                  $hour, $min, $sec, $tz);
        return %date;
 }
 
@@ -1411,7 +1417,9 @@ sub git_header_html {
        }
 
        print "<div class=\"page_header\">\n" .
-             "<a href=\"http://www.kernel.org/pub/software/scm/git/docs/\" title=\"git documentation\">" .
+             "<a href=\"" . esc_html($githelp_url) .
+             "\" title=\"" . esc_html($githelp_label) .
+             "\">" .
              "<img src=\"$logo\" width=\"72\" height=\"27\" alt=\"git\" style=\"float:right; border-width:0px;\"/>" .
              "</a>\n";
        print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / ";
@@ -2496,7 +2504,8 @@ sub git_blame2 {
        if ($ftype !~ "blob") {
                die_error("400 Bad Request", "Object is not a blob");
        }
-       open ($fd, "-|", git_cmd(), "blame", '-l', '--', $file_name, $hash_base)
+       open ($fd, "-|", git_cmd(), "blame", '--porcelain', '--',
+             $file_name, $hash_base)
                or die_error(undef, "Open git-blame failed");
        git_header_html();
        my $formats_nav =
@@ -2520,33 +2529,52 @@ sub git_blame2 {
 <table class="blame">
 <tr><th>Commit</th><th>Line</th><th>Data</th></tr>
 HTML
-       while (<$fd>) {
-               my ($full_rev, $author, $date, $lineno, $data) =
-                       /^([0-9a-f]{40}).*?\s\((.*?)\s+([-\d]+ [:\d]+ [-+\d]+)\s+(\d+)\)\s(.*)/;
+       my %metainfo = ();
+       while (1) {
+               $_ = <$fd>;
+               last unless defined $_;
+               my ($full_rev, $lineno, $orig_lineno, $group_size) =
+                   /^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/;
+               if (!exists $metainfo{$full_rev}) {
+                       $metainfo{$full_rev} = {};
+               }
+               my $meta = $metainfo{$full_rev};
+               while (<$fd>) {
+                       last if (s/^\t//);
+                       if (/^(\S+) (.*)$/) {
+                               $meta->{$1} = $2;
+                       }
+               }
+               my $data = $_;
                my $rev = substr($full_rev, 0, 8);
-               my $print_c8 = 0;
-
-               if (!defined $last_rev) {
-                       $last_rev = $full_rev;
-                       $print_c8 = 1;
-               } elsif ($last_rev ne $full_rev) {
-                       $last_rev = $full_rev;
+               my $author = $meta->{'author'};
+               my %date = parse_date($meta->{'author-time'},
+                                     $meta->{'author-tz'});
+               my $date = $date{'iso-tz'};
+               if ($group_size) {
                        $current_color = ++$current_color % $num_colors;
-                       $print_c8 = 1;
                }
                print "<tr class=\"$rev_color[$current_color]\">\n";
-               print "<td class=\"sha1\"";
-               if ($print_c8 == 1) {
+               if ($group_size) {
+                       print "<td class=\"sha1\"";
                        print " title=\"$author, $date\"";
-               }
-               print ">";
-               if ($print_c8 == 1) {
-                       print $cgi->a({-href => href(action=>"commit", hash=>$full_rev, file_name=>$file_name)},
+                       print " rowspan=\"$group_size\"" if ($group_size > 1);
+                       print ">";
+                       print $cgi->a({-href => href(action=>"commit",
+                                                    hash=>$full_rev,
+                                                    file_name=>$file_name)},
                                      esc_html($rev));
+                       print "</td>\n";
                }
-               print "</td>\n";
-               print "<td class=\"linenr\"><a id=\"l$lineno\" href=\"#l$lineno\" class=\"linenr\">" .
-                     esc_html($lineno) . "</a></td>\n";
+               my $blamed = href(action => 'blame',
+                                 file_name => $meta->{'filename'},
+                                 hash_base => $full_rev);
+               print "<td class=\"linenr\">";
+               print $cgi->a({ -href => "$blamed#l$orig_lineno",
+                               -id => "l$lineno",
+                               -class => "linenr" },
+                             esc_html($lineno));
+               print "</td>";
                print "<td class=\"pre\">" . esc_html($data) . "</td>\n";
                print "</tr>\n";
        }
@@ -2891,9 +2919,12 @@ sub git_snapshot {
                -content_disposition => 'inline; filename="' . "$filename" . '"',
                -status => '200 OK');
 
-       my $git_command = git_cmd_str();
-       open my $fd, "-|", "$git_command tar-tree $hash \'$project\' | $command" or
-               die_error(undef, "Execute git-tar-tree failed.");
+       my $git = git_cmd_str();
+       my $name = $project;
+       $name =~ s/\047/\047\\\047\047/g;
+       open my $fd, "-|",
+       "$git archive --format=tar --prefix=\'$name\'/ $hash | $command"
+               or die_error(undef, "Execute git-tar-tree failed.");
        binmode STDOUT, ':raw';
        print <$fd>;
        binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
@@ -2990,11 +3021,6 @@ sub git_commit {
                        $cgi->a({-href => href(action=>"blame", hash_parent=>$parent, file_name=>$file_name)},
                                "blame");
        }
-       if (defined $co{'parent'}) {
-               push @views_nav,
-                       $cgi->a({-href => href(action=>"shortlog", hash=>$hash)}, "shortlog"),
-                       $cgi->a({-href => href(action=>"log", hash=>$hash)}, "log");
-       }
        git_header_html(undef, $expires);
        git_print_page_nav('commit', defined $co{'parent'} ? '' : 'commitdiff',
                           $hash, $co{'tree'}, $hash,