Browse Source

gitweb: Adding a `blame' interface.

This patch adds an interface for `git-blame' to `gitweb.cgi'.
Links to it are placed in `git_blob'.

Internally the code uses `git-annotate' because `git-blame's output
differs for files that have been renamed in the past. However, I like
the term `blame' better.

[jc: blame can be told to produce the compatible format btw...]

Signed-off-by: Florian Forster <octo@verplant.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
maint
Florian Forster 19 years ago committed by Junio C Hamano
parent
commit
e34ef62148
  1. 108
      gitweb/gitweb.cgi

108
gitweb/gitweb.cgi

@ -203,6 +203,9 @@ if (!defined $action || $action eq "summary") { @@ -203,6 +203,9 @@ if (!defined $action || $action eq "summary") {
} elsif ($action eq "tag") {
git_tag();
exit;
} elsif ($action eq "blame") {
git_blame();
exit;
} else {
undef $action;
die_error(undef, "Unknown action.");
@ -1228,6 +1231,107 @@ sub git_tag { @@ -1228,6 +1231,107 @@ sub git_tag {
git_footer_html();
}

sub git_blame {
my $fd;
die_error('404 Not Found', "What file will it be, master?") if (!$file_name);
$hash_base ||= git_read_head($project);
die_error(undef, "Reading commit failed.") unless ($hash_base);
my %co = git_read_commit($hash_base)
or die_error(undef, "Reading commit failed.");
if (!defined $hash) {
$hash = git_get_hash_by_path($hash_base, $file_name, "blob")
or die_error(undef, "Error lookup file.");
}
open ($fd, "-|", "$gitbin/git-annotate", '-l', '-t', '-r', $file_name, $hash_base)
or die_error(undef, "Open failed.");
git_header_html();
print "<div class=\"page_nav\">\n" .
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "shortlog") .
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "log") .
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base")}, "commit") .
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash_base")}, "commitdiff") .
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash_base")}, "tree") . "<br/>\n";
print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash;hb=$hash_base;f=$file_name")}, "blob") .
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;f=$file_name")}, "head") . "<br/>\n";
print "</div>\n".
"<div>" .
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) .
"</div>\n";
print "<div class=\"page_path\"><b>" . esc_html($file_name) . "</b></div>\n";
print "<div class=\"page_body\">\n";
print <<HTML;
<table style="border-collapse: collapse;">
<tr>
<th>Commit</th>
<th>Age</th>
<th>Author</th>
<th>Line</th>
<th>Data</th>
</tr>
HTML
my @line_class = (qw(light dark));
my $line_class_len = scalar (@line_class);
my $line_class_num = $#line_class;
while (my $line = <$fd>) {
my $long_rev;
my $short_rev;
my $author;
my $time;
my $lineno;
my $data;
my $age;
my $age_str;
my $age_style;

chomp $line;
$line_class_num = ($line_class_num + 1) % $line_class_len;

if ($line =~ m/^([0-9a-fA-F]{40})\t\(\s*([^\t]+)\t(\d+) \+\d\d\d\d\t(\d+)\)(.*)$/) {
$long_rev = $1;
$author = $2;
$time = $3;
$lineno = $4;
$data = $5;
} else {
print qq( <tr><td colspan="5" style="color: red; background-color: yellow;">Unable to parse: $line</td></tr>\n);
next;
}
$short_rev = substr ($long_rev, 0, 8);
$age = time () - $time;
$age_str = age_string ($age);
$age_str =~ s/ /&nbsp;/g;
$age_style = 'font-style: italic;';
$age_style .= ' color: #009900; background: transparent;' if ($age < 60*60*24*2);
$age_style .= ' font-weight: bold;' if ($age < 60*60*2);
$author = esc_html ($author);
$author =~ s/ /&nbsp;/g;
# escape tabs
while ((my $pos = index($data, "\t")) != -1) {
if (my $count = (8 - ($pos % 8))) {
my $spaces = ' ' x $count;
$data =~ s/\t/$spaces/;
}
}
$data = esc_html ($data);
$data =~ s/ /&nbsp;/g;

print <<HTML;
<tr class="$line_class[$line_class_num]">
<td style="font-family: monospace;"><a href="$my_uri?${\esc_param ("p=$project;a=commit;h=$long_rev")}" class="text">$short_rev..</a></td>
<td style="$age_style">$age_str</td>
<td>$author</td>
<td style="text-align: right;"><a id="$lineno" href="#$lineno" class="linenr">$lineno</a></td>
<td style="font-family: monospace;">$data</td>
</tr>
HTML
} # while (my $line = <$fd>)
print "</table>\n\n";
close $fd or print "Reading blob failed.\n";
print "</div>";
git_footer_html();
}

sub git_tags {
my $head = git_read_head($project);
git_header_html();
@ -1375,7 +1479,8 @@ sub git_blob { @@ -1375,7 +1479,8 @@ sub git_blob {
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash_base")}, "commitdiff") .
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash_base")}, "tree") . "<br/>\n";
if (defined $file_name) {
print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash;f=$file_name")}, "plain") .
print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;h=$hash;hb=$hash_base;f=$file_name")}, "blame") .
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash;f=$file_name")}, "plain") .
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;hb=HEAD;f=$file_name")}, "head") . "<br/>\n";
} else {
print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash")}, "plain") . "<br/>\n";
@ -1496,6 +1601,7 @@ sub git_tree { @@ -1496,6 +1601,7 @@ sub git_tree {
"</td>\n" .
"<td class=\"link\">" .
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$t_hash$base_key;f=$base$t_name")}, "blob") .
# " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;h=$t_hash$base_key;f=$base$t_name")}, "blame") .
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=history;h=$hash_base;f=$base$t_name")}, "history") .
"</td>\n";
} elsif ($t_type eq "tree") {

Loading…
Cancel
Save