#!/usr/bin/perl
# Kyle Christensen <kyle@junglist.org>
# http://junglist.org/files/scripts/cvs2rss.pl
# 
# Updated for new cvs information format strings, to handle multiple
# file commits in a single folder, and improved handling of rdiffs
# by Kent Hulick <TopDriveDude@yahoo.com>
#
# This script (when setup properly) will magically create an RSS 2.0 compliant feed
# that logs your cvs commits as well as a diff of the changes made.
#
# Run this from your CVSROOT/loginfo like:
#
#	/path/to/cvs2rss.pl %{sVv}
#
# Also, make sure your apache server has an AddType for rss like:
#
# 	AddType application/rss+xml .rss
#
# Important note: 
# If you have html files (or files with html in them) in your CVS Repository, look in your RSS.pm for:
#
#	$text =~ s/</&lt;/g;
#
# I suggest commenting out this line because it will screw up this script (I think its a bug in the parser)
# If you do not, when this script uses XML:RSS's parsefile(), it will mess up any <descriptions> that 
# contain HTML.
#
# P.S. The "other" cvs2rss.pl isn't really cvs2rss, it is more like cvs2xml, boo!
# P.P.S. Parts of this are stolen from commit2rss.rb and the XML::RSS examples.
#
# Version 1.0 - 08.24.04 RSS Compliant, no cvs diff capability yet..
# Version 1.1 - 08.31.04 Adding CVS Diff capability
#
# This script is made available under the Creative Commons license. For more information about what this means,
# please visit http://creativecommons.org/licenses/by/2.5/
#
use strict;
use XML::RSS;
use POSIX;

# Stuff you need to setup
my $rssFeed ="/var/www/localhost/htdocs/rss/cvs.rss";
my $emailDomain = "varco.com";
my $channelTitle = "Varco CVS RSS Feed";
my $channelLink = "http://10.104.3.1/cgi-bin/viewcvs.cgi";
my $numEntries = 200;
my $viewcvsCmd = "&content-type=text/vnd.viewcvs-markup";

# Set this to 1 to enable cvs rdiff (is pretty broken if you are diffing html
# content)
my $cvsDiff = 1;
my $cvsroot = "/cvsroot";

# Leave everything else alone
my $author = getpwuid(getuid()) . "\@" . $emailDomain;
my $pubDate = strftime('%a, %d %b %Y %H:%M:%S %Z',localtime(time));
my $description;
my $differences;
my $path=$ARGV[0];

my $rss = new XML::RSS(version => '2.0');
$rss->channel(
	title=> $channelTitle,
	link => $channelLink,
	language => 'en',
	description => $channelTitle,
	copyright => '(c) 2004 SelectMinds Inc.'
);

# If rssFeed exists, parse it
if (-r "$rssFeed") {
	$rss->parsefile($rssFeed);
}

# Format the cvslog msg itself
while (<STDIN>) {
	chomp($_);
	if ($_=~/^[A-Z].*:\s*$/) {
		$_ = "<br /><b>" . $_ . "</b><br />";
	}
	else {
		$_ .= "<br />";
	}
	$description .= $_;
}

# Create an RSS entry for each updated file
# 3 arguments are supplied for each file in the directory that was updated.
# file name, old version, new version
shift(@ARGV);

while (@ARGV){
	my $filename=$ARGV[0];
	shift(@ARGV);
	my $oldversion=$ARGV[0];
	shift(@ARGV);
	my $newversion=$ARGV[0];
	shift(@ARGV);

	if ($cvsDiff == 1) {
		# If the old version of the file is not NONE (if it isn't a new file),
		# and if it is a .txt or .java file (that has no html)
		# This will rdiff it against the previous version, and include that
		# diff in the rss feed

		if (($oldversion != "NONE") && ($filename=~/(.*).(txt|java)$/)){
			my $tmpFile = "/tmp/diff.$$";
			my $cmdLine = "export CVSROOT=\"$cvsroot\"; cvs -n rdiff -kk -r "
				. $oldversion .  " -r " . $newversion . " " . $path . "/"
				. $filename . ">" . $tmpFile;
			system($cmdLine);

			$differences = "<br /><b>Differences:</b><br /><pre>";
			open CVSDIFF, "<" . $tmpFile;
			foreach my $line (<CVSDIFF>) {
				chomp($line);
				$differences .= $line . "<br />";
			}
			unlink($tmpFile);
			$differences .= "</pre><br />\n";
		}
	}

	$rss->add_item(
		title => "/" . $path . "/" . $filename . " - " . $oldversion
				. "/" . $newversion,
		link => $channelLink . "/" . $path . "/" . $filename . "?rev="
				. $newversion . $viewcvsCmd,
		author => $author,
		pubDate => $pubDate,
		description=> $description . $differences,
		mode => 'insert'
	);
}

# XML::RSS doesn't like HTML in the XML so Escape the description body with
# <![CDATA[ ]]>
# This is messy and stupid, but both XML::RSS and XML are sort of dumb, and
# I can't figure out a way around it.
# Certain RSS readers will try and render the HTML regardless of if it is
# wrapped in a CDATA tag or not so um, deal.
foreach my $element (@{$rss->{'items'}}) {
	$element->{'description'} = "<![CDATA[" . $element->{'description'} . "]]>";
}

# Limit entries in the feed to $numEntries
pop(@{$rss->{'items'}}) while (@{$rss->{'items'}} > $numEntries);

$rss->save($rssFeed);
