use strict;
use CGI qw(:standard);
my $gSvnlookCmd = '/usr/local/bin/svnlook';
my $gSvnadminCmd = '/usr/local/bin/svnadmin';
my $gReposPath = '/usr/www/repositories/svn';
my $gActionURL = './tweak-log.cgi';
my $gTempfilePrefix = '/tmp/tweak-cgi';
my $gHistoryFile = './TWEAKLOG';
my $gBypassRevpropHooks = 0; my $gNumRecentCommits = 20;
my %gCGIValues = &doCGI( );
&main( );
sub html_escape
{
my $str = shift;
$str =~ s/&/&/g;
$str =~ s/>/>/g;
$str =~ s/</</g;
return $str;
}
sub doCGI
{
my $lCGI = new CGI;
my @lFields = $lCGI->param;
my $lField;
my %lCGIData = ();
foreach $lField ( @lFields )
{
$lCGIData{ uc $lField } = $lCGI->param( $lField );
}
return( %lCGIData );
}
sub doError
{
my $error = shift @_;
print "<html><head><title>Tweak Log - Error</title></head>\n";
print "<body><h1>ERROR</h1>\n<p>$error</p></body></html>\n";
return;
}
sub main
{
print "Content-type: text/html; charset=UTF-8\n\n";
if( $gCGIValues{'ACTION'} =~ /fetch/i )
{
&doFetchLog();
}
elsif( $gCGIValues{'ACTION'} =~ /commit/i )
{
&doCommitLog();
}
else
{
&doInitialForm();
}
return;
}
sub doInitialForm
{
my $youngest = `$gSvnlookCmd youngest $gReposPath`;
my $rev;
my $oldest;
print "<html>\n<head>\n<title>Tweak Log</title>\n</head>\n";
print "<body>\n<form action=\"$gActionURL\" method=\"post\">\n";
print "<a name=\"__top__\"></a>\n";
print "<p>\n";
print "Boy, I sure would like to modify that log message for \n";
print "revision <input type=\"text\" name=\"rev\" value\"\">\n";
print "<input type=\"submit\" name=\"action\" value=\"Fetch Log\">\n";
print "</p></form>\n";
print "<p>\n";
print "For convenience, here are the most recent $gNumRecentCommits\n";
print "commits (click the revision number to edit that revision's log):\n";
print "</p>\n";
chomp $youngest;
$oldest = $youngest - $gNumRecentCommits + 1;
$oldest = 1 if( $oldest < 1 );
$rev = $youngest;
while( $rev >= $oldest )
{
my @infolines = `$gSvnlookCmd info $gReposPath -r $rev`;
my $author = shift @infolines;
my $date = shift @infolines;
my $log_size = shift @infolines;
print "<hr />\n";
print "<a href=\"$gActionURL?action=Fetch+Log&rev=$rev\">Revision $rev</a>:<br />\n";
print "<i>Author: $author</i><br />\n";
print "<i>Date: $date</i><br />\n";
print "<i>Log: </i><br /><pre>\n";
map {
$_ = &html_escape ($_);
} @infolines;
print @infolines;
print "</pre><br />\n";
print "<a href=\"#__top__\">(back to top)</a>\n";
$rev--;
}
print "</body></html>\n";
return;
}
sub isValidRev
{
my $youngest = `$gSvnlookCmd youngest $gReposPath`;
my $rev = shift @_;
if(not (( $youngest =~ /^\d+$/) and
( $youngest > 0 )))
{
&doError( "Unable to determine youngest revision" );
return 0;
}
if(not (( $rev =~ /^\d+$/) and
( $rev <= $youngest )))
{
&doError( "'$rev' is not a valid revision number" );
return 0;
}
return 1;
}
sub doFetchLog
{
my $rev = $gCGIValues{'REV'};
my $log;
my $escaped_log;
if( not &isValidRev( $rev ))
{
return;
}
$log = `$gSvnlookCmd log $gReposPath -r $rev`;
$escaped_log = &html_escape ($log);
print "<html>\n<head>\n<title>Tweak Log - Log Edit</title>\n</head>\n";
print "<body>\n";
print "<h1>Editing Log Message for Revision $rev</h1>\n";
print "<h2>Current log message:</h2>\n";
print "<blockquote><hr /><pre>$escaped_log</pre><hr /></blockquote>\n";
print "<p><font color=\"red\">\n";
print "<i>Every change made is logged in <tt>${gHistoryFile}</tt>.\n";
print "If you make a bogus\n";
print "change, you can still recover the old message from there.</i>\n";
print "</font></p>\n";
print "<form action=\"$gActionURL\" method=\"post\">\n";
print "<h2>New log message:</h2>\n";
print "<blockquote>\n";
print "<textarea cols=\"80\" rows=\"25\" wrap=\"off\" name=\"log\">\n";
print $escaped_log;
print "</textarea><br />\n";
print "<input type=\"hidden\" name=\"rev\" value=\"$rev\">\n";
print "<input type=\"submit\" name=\"action\" value=\"Commit Changes\">\n";
print "</blockquote>\n";
print "</form></body></html>\n";
return;
}
sub doCommitLog
{
my $rev = $gCGIValues{'REV'};
my $log = $gCGIValues{'LOG'};
my $orig_log;
my $tempfile = "$gTempfilePrefix.$$";
if (not &isValidRev( $rev ))
{
return;
}
$orig_log = `$gSvnlookCmd log $gReposPath -r $rev`;
if ($log eq $orig_log)
{
&doError ("Log message doesn't appear to have been edited.");
return;
}
if (not (open( LOGFILE, "> $tempfile")))
{
&doError ("Unable to open temporary file.");
return;
}
print LOGFILE $log;
close LOGFILE;
if ($gHistoryFile)
{
if (not (open (HISTORY, ">> $gHistoryFile")))
{
&doError ("Unable to open history file.");
return;
}
print HISTORY "====================================================\n";
print HISTORY "REVISION $rev WAS:\n";
print HISTORY "----------------------------------------------------\n";
print HISTORY $orig_log;
print HISTORY "\n";
}
if ($gBypassRevpropHooks)
{
`$gSvnadminCmd setlog $gReposPath -r$rev $tempfile --bypass-hooks`;
}
else
{
`$gSvnadminCmd setlog $gReposPath -r$rev $tempfile`;
}
unlink $tempfile;
if ($gHistoryFile)
{
print HISTORY "----------------------------------------------------\n";
print HISTORY "REVISION $rev IS:\n";
print HISTORY "----------------------------------------------------\n";
print HISTORY $log;
print HISTORY "\n";
close HISTORY;
}
$log = `$gSvnlookCmd log $gReposPath -r $rev`;
$log = &html_escape ($log);
print "<html>\n<head>\n<title>Tweak Log - Log Changed</title>\n</head>\n";
print "<body>\n";
print "<h1>Success!</h1>\n";
print "<h2>New Log Message for Revision $rev</h2>\n";
print "<blockquote><hr /><pre>$log</pre><hr /></blockquote>\n";
print "</body></html>\n";
return;
}