You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdesdk/scripts/cvsblame

253 lines
6.4 KiB

#! /usr/bin/env 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 Konqueror.
=head1 SYNOPSIS
cvsblame <filename>
=head1 DESCRIPTION
cvsblame opens Konqueror 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 = `kde-config --path tmp` || './#'; # if we put the file in the cwd, then we keep a '#' at the beggining to help CVS ignore it
($outputfile) = split(/:/,$outputfile);
chomp $outputfile;
$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].*[^\s])\s+([^\s]+)/) {
$mail{$1} = "$2 &lt;$3&gt;";
}
elsif (/([^\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 type="text/javascript">
function hidelog(event) {
var target = event.relatedTarget;
while (target && target.id != "popup")
target = target.offsetParent;
if (target)
return;
target = event.target;
while (target.id != "popup")
target = target.offsetParent;
target.style.visibility = "hidden";
}
function init() {
document.getElementById("popup").addEventListener("mouseout", hidelog, false);
}
function poplog(target, rev) {
var popup = document.getElementById("popup");
var x = 120, y = 0;
while (target && target != document)
{
x += target.offsetLeft;
y += target.offsetTop;
target = target.offsetParent;
}
popup.style.pixelLeft = x;
popup.style.pixelTop = y;
popup.innerHTML = rev;
popup.style.visibility = "visible";
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 "var $revstr = \"$content\";\n";
} elsif ($line eq "=============================================================================" && !($revision eq "")) {
print OUTPUT "var $revstr = \"$content\";\n";
} else {
$line =~ s/\"/\\\"/g;
$line =~ s/&/&amp;/g;
$line =~ s/</&lt;/g;
$line =~ s/>/&gt;/g;
$content = "$content<br>$line";
}
}
close LOG;
print OUTPUT <<EOF;
</script>
<style type="text/css">
body {
background: #eeeee0;
}
#popup {
position: absolute;
background: #ffcc99;
border: 1px solid #80664D;
padding: 2px;
}
a:link {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>
<body text="#000000" onload="init()">
<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 = "<span onmouseover=\"return poplog(this, $revstr)\"'>";
$linkendstr = "</span>";
$revauthor = "$author $revision";
$oldlineno = $lineno;
} else {
$linkstr = "";
$linkendstr = "";
$revauthor = "";
}
} else {
$color = ($color == 0)? 1 : 0;
$linkstr = "<span onmouseover=\"return poplog(this, $revstr)\"'>";
$linkendstr = "</span>";
$revauthor = "$author $revision";
$oldlineno = $lineno;
$oldrevision = $revision;
}
print OUTPUT "<tr><td nowrap style=\"background: ", ($color==1)? "#EEEEE0" : "#FFFFCC", "\"><pre>";
print OUTPUT sprintf '%-5i%s%-14s%s%s', $lineno, $linkstr, $revauthor,$linkendstr, $content;
print OUTPUT "</pre></td></tr>\n";
$lineno++;
}
close ANNOTATE;
#
# Finally, the html footer
#
print OUTPUT <<EOF;
</table>
<div id="popup" style="visibility: hidden"></div>
</body>
</html>
EOF
close OUTPUT;
system("kfmclient openProfile webbrowsing $outputfile");
exit 0;