#!/usr/bin/perl

# cvs blame inspired by Bonsai
# Author: Bernd Gehrmann <bernd@physik.hu-berlin.de>

=head1 NAME

cvsblame - Shows a blame-annotated representation of a CVS controlled file in netscape.

=head1 SYNOPSIS

cvsblame <filename>

=head1 DESCRIPTION

cvsblame opens netscape to display the output of cvs annotate of
a cvs controlled file. When the mouse is on a revision number shown
in the second column, a popup with the respective log message
appears. 

In the popup, a proper mailto: link to the author of a revision
can be created as follows: In your home directory, make a file
.cvsblame. In that file, enter for each repository you are working
with a line like

      accounts :pserver:gehrmab@cvs.kde.org:/home/kde /home/bernd/.kdeaccounts

where the accounts file contains a simple list of cvs usernames in
the first column and the respective mail address in the second.

=head1 BUGS

=over 4

=item Does not really work for filenames which are not in the current directory

=item Is a hack. Really.

=back 

=head1 AUTHOR

Bernd Gehrmann <bernd@physik.hu-berlin.de>

=cut

$file = $ARGV[0];
$outputfile = ">#cvsblame.html#";
$configfile = $ENV{HOME}. "/.cvsblame";
$rootfile = "`pwd`/CVS/Root";
$cvsroot = `cat $rootfile`;
chop $cvsroot;

#
# Look for a username -> mail address mapping
#

if (open(CONFIG, $configfile)) {
    while (<CONFIG>) {
	if (/accounts\s*([^\s]*)\s+([^\s]*)/) {
	    if ($1 eq $cvsroot) {
		$accountfile = $2;
            }
        }
    }
    close CONFIG;
}
if ($accountfile) {
    open(ACCOUNTS, $accountfile) || die "Account file not found: $accountfile";
    while (<ACCOUNTS>) {
	if (/([^\s]*)\s+([^\s]*)/) {
	    $mail{$1} = $2;
        }
    }
}


#
# The real work, first the html header
#


open(OUTPUT, $outputfile);
print OUTPUT <<EOF;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Blame annotation for $file</title>
  </head>
  <script>
    function poplog(event, rev) {
      var popup = document.layers['popup'];
      popup.left = event.target.x;
      popup.top = event.target.y;
      popup.document.write("<table border=0 cellspacing=0 cellpadding=10><tr><td bgcolor='#FFCC99'<tt>");
      popup.document.write(rev);
      popup.document.write("</td></tr></table>");
      popup.document.close();
      popup.visibility = "show";
      return true;
    }
EOF

#
# Translate information from cvs log in javascript stuff
#

$revision = "";
open (LOG, "cvs log $file|");
while (<LOG>) {
      chop;
      $line = $_;
      if ($line =~ /revision (.*)/) {
             $revision = $1;
             $revstr = "log$revision";
             $revstr =~ s/\./_/g;
      } elsif ($line =~ /date: ([^;]*);\s*author: ([^;]*);.*/) {
             $date = $1;
             $author = $2;
             if ($mail{$author}) {
		 $author = "<a href=mailto:$mail{$author}>$author</a>";
             }
             $content = "<b>$revision</b>&nbsp;&nbsp;$author&nbsp;&nbsp;<b>$date<b>";
      } elsif ($line eq "----------------------------" && !($revision eq "")) {
             print OUTPUT "$revstr = \"$content\";\n";
      } elsif ($line eq "=============================================================================" && !($revision eq "")) {
             print OUTPUT "$revstr = \"$content\";\n";
      } else {
             $line =~ s/\"/\\\"/g;
             $content = "$content<br>$line";
      }
}
close LOG;

print OUTPUT <<EOF;
  </script>
  <body bgcolor="#EEEEE0">
     <layer name='popup' onmouseout="this.visibility='hide';" visibility='hide'></layer>
    <h1>$file</h1>
    <table border=0 cellpadding=0 cellspacing=0 width="100%">
EOF

#
# Information from cvs annotate
#

$color = 1;
$lineno = 1;
$oldrevision = "";
$oldlineno = "";
$oldrevstr = "";
open (ANNOTATE, "cvs annotate $file 2>/dev/null|");
while (<ANNOTATE>) {
      chop;
      $line = $_;
      $revision = substr $line, 0, 13;
      $revision =~ s/\s//g;
      $author = substr $line, 14, 9;
      $author =~ s/\s//g;
      $date = substr $line, 23, 9;
      $content = substr $line, 35;
      $content =~ s/\&/&amp;/g;
      $content =~ s/\</&lt;/g;
      $content =~ s/\>/&gt;/g;
      $revstr = "log$revision";
      $revstr =~ s/\./_/g;
      if ($revision eq $oldrevision) {
	  if ($lineno == $oldlineno+20) {
	      $linkstr = "<a href=\"\" onmouseover='return poplog(event,$revstr)'>";
	      $linkendstr = "</a>";
              $revauthor = "$author $revision";
              $oldlineno = $lineno;
	  } else {
	      $linkstr = "";
	      $linkendstr = "";
	      $revauthor = "";
	  }
      } else {
          $color = ($color == 0)? 1 : 0;
	  $linkstr = "<a href=\"\" onmouseover='return poplog(event,$revstr)'>";
	  $linkendstr = "</a>";
	  $revauthor = "$author $revision";
	  $oldlineno = $lineno;
	  $oldrevision = $revision;
      }
      print OUTPUT "<tr><td bgcolor=\"", ($color==1)? "#EEEEE0" : "#FFFFCC", "\"><pre>";
      print OUTPUT sprintf "%-5i$linkstr%-14s$linkendstr$content", $lineno, $revauthor;
      print OUTPUT "</td></tr>\n";
      $lineno++;
}
close ANNOTATE;

# 
# Finally, the html footer
#

print OUTPUT <<EOF;
    </table>
  </body>
</html>
EOF

close OUTPUT;

system("netscape file://`pwd`/%23cvsblame.html%23");

