summaryrefslogtreecommitdiffstats
path: root/scripts/cvsblame
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/cvsblame')
-rwxr-xr-xscripts/cvsblame252
1 files changed, 252 insertions, 0 deletions
diff --git a/scripts/cvsblame b/scripts/cvsblame
new file mode 100755
index 00000000..bd3635ed
--- /dev/null
+++ b/scripts/cvsblame
@@ -0,0 +1,252 @@
+#! /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;