@@ -4576,28 +4576,33 @@ sub git_tag {
45764576}
45774577
45784578sub git_blame {
4579- my $fd ;
4580- my $ftype ;
4581-
4579+ # permissions
45824580 gitweb_check_feature(' blame' )
4583- or die_error(403, " Blame view not allowed" );
4581+ or die_error(403, " Blame view not allowed" );
45844582
4583+ # error checking
45854584 die_error(400, " No file name given" ) unless $file_name ;
45864585 $hash_base ||= git_get_head_hash($project );
4587- die_error(404, " Couldn't find base commit" ) unless ( $hash_base ) ;
4586+ die_error(404, " Couldn't find base commit" ) unless $hash_base ;
45884587 my %co = parse_commit($hash_base )
45894588 or die_error(404, " Commit not found" );
4589+ my $ftype = " blob" ;
45904590 if (!defined $hash ) {
45914591 $hash = git_get_hash_by_path($hash_base , $file_name , " blob" )
45924592 or die_error(404, " Error looking up file" );
4593+ } else {
4594+ $ftype = git_get_type($hash );
4595+ if ($ftype !~ " blob" ) {
4596+ die_error(400, " Object is not a blob" );
4597+ }
45934598 }
4594- $ftype = git_get_type($hash );
4595- if ($ftype !~ " blob" ) {
4596- die_error(400, " Object is not a blob" );
4597- }
4598- open ($fd , " -|" , git_cmd(), " blame" , ' -p' , ' --' ,
4599- $file_name , $hash_base )
4599+
4600+ # run git-blame --porcelain
4601+ open my $fd , " -|" , git_cmd(), " blame" , ' -p' ,
4602+ $hash_base , ' --' , $file_name
46004603 or die_error(500, " Open git-blame failed" );
4604+
4605+ # page header
46014606 git_header_html();
46024607 my $formats_nav =
46034608 $cgi -> a({-href => href(action => " blob" , -replay => 1)},
@@ -4611,42 +4616,46 @@ sub git_blame {
46114616 git_print_page_nav(' ' ,' ' , $hash_base ,$co {' tree' },$hash_base , $formats_nav );
46124617 git_print_header_div(' commit' , esc_html($co {' title' }), $hash_base );
46134618 git_print_page_path($file_name , $ftype , $hash_base );
4614- my @rev_color = (qw( light2 dark2) );
4619+
4620+ # page body
4621+ my @rev_color = qw( light2 dark2) ;
46154622 my $num_colors = scalar (@rev_color );
46164623 my $current_color = 0;
4617- my $last_rev ;
4624+ my %metainfo = ();
4625+
46184626 print <<HTML ;
46194627<div class =" page_body" >
46204628<table class =" blame" >
46214629<tr ><th >Commit</th ><th >Line</th ><th >Data</th ></tr >
46224630HTML
4623- my %metainfo = ();
4624- while (1) {
4625- $_ = <$fd >;
4626- last unless defined $_ ;
4631+ LINE:
4632+ while (my $line = <$fd >) {
4633+ chomp $line ;
4634+ # the header: <SHA-1> <src lineno> <dst lineno> [<lines in group>]
4635+ # no <lines in group> for subsequent lines in group of lines
46274636 my ($full_rev , $orig_lineno , $lineno , $group_size ) =
4628- / ^([0-9a-f]{40}) (\d +) (\d +)(?: (\d +))?$ / ;
4637+ ( $line =~ / ^([0-9a-f]{40}) (\d +) (\d +)(?: (\d +))?$ / ) ;
46294638 if (!exists $metainfo {$full_rev }) {
46304639 $metainfo {$full_rev } = {};
46314640 }
46324641 my $meta = $metainfo {$full_rev };
4633- while (<$fd >) {
4634- last if (s / ^\t // );
4635- if (/ ^(\S +) (.*)$ / ) {
4642+ my $data ;
4643+ while ($data = <$fd >) {
4644+ chomp $data ;
4645+ last if ($data =~ s / ^\t // ); # contents of line
4646+ if ($data =~ / ^(\S +) (.*)$ / ) {
46364647 $meta -> {$1 } = $2 ;
46374648 }
46384649 }
4639- my $data = $_ ;
4640- chomp $data ;
4641- my $rev = substr ($full_rev , 0, 8);
4650+ my $short_rev = substr ($full_rev , 0, 8);
46424651 my $author = $meta -> {' author' };
4643- my %date = parse_date( $meta -> { ' author-time ' },
4644- $meta -> {' author-tz' });
4652+ my %date =
4653+ parse_date( $meta -> { ' author-time ' }, $meta -> {' author-tz' });
46454654 my $date = $date {' iso-tz' };
46464655 if ($group_size ) {
4647- $current_color = ++ $current_color % $num_colors ;
4656+ $current_color = ( $current_color + 1) % $num_colors ;
46484657 }
4649- print " <tr class=\" $rev_color [$current_color ]\" >\n " ;
4658+ print " <tr id= \" l $lineno \" class=\" $rev_color [$current_color ]\" >\n " ;
46504659 if ($group_size ) {
46514660 print " <td class=\" sha1\" " ;
46524661 print " title=\" " . esc_html($author ) . " , $date \" " ;
@@ -4655,20 +4664,25 @@ sub git_blame {
46554664 print $cgi -> a({-href => href(action => " commit" ,
46564665 hash => $full_rev ,
46574666 file_name => $file_name )},
4658- esc_html($rev ));
4667+ esc_html($short_rev ));
46594668 print " </td>\n " ;
46604669 }
4661- open (my $dd , " -|" , git_cmd(), " rev-parse" , " $full_rev ^" )
4662- or die_error(500, " Open git-rev-parse failed" );
4663- my $parent_commit = <$dd >;
4664- close $dd ;
4665- chomp ($parent_commit );
4670+ my $parent_commit ;
4671+ if (!exists $meta -> {' parent' }) {
4672+ open (my $dd , " -|" , git_cmd(), " rev-parse" , " $full_rev ^" )
4673+ or die_error(500, " Open git-rev-parse failed" );
4674+ $parent_commit = <$dd >;
4675+ close $dd ;
4676+ chomp ($parent_commit );
4677+ $meta -> {' parent' } = $parent_commit ;
4678+ } else {
4679+ $parent_commit = $meta -> {' parent' };
4680+ }
46664681 my $blamed = href(action => ' blame' ,
46674682 file_name => $meta -> {' filename' },
46684683 hash_base => $parent_commit );
46694684 print " <td class=\" linenr\" >" ;
46704685 print $cgi -> a({ -href => " $blamed #l$orig_lineno " ,
4671- -id => " l$lineno " ,
46724686 -class => " linenr" },
46734687 esc_html($lineno ));
46744688 print " </td>" ;
@@ -4679,6 +4693,8 @@ sub git_blame {
46794693 print " </div>" ;
46804694 close $fd
46814695 or print " Reading blob failed\n " ;
4696+
4697+ # page footer
46824698 git_footer_html();
46834699}
46844700
0 commit comments