pjs/tools/cvsmgmt/fix-checkin-message

226 строки
6.3 KiB
Perl
Executable File

#!/usr/bin/perl -w
use File::Temp qw(tempdir);
my $cvs_host = "dm-cvs01";
my $bonsai_host = "dm-webtools02";
my $cvsroot_path = "/cvsroot";
my $bonsai_path = "/var/www/webtools/bonsai-cvs";
my $remote_cvs_path = "/cvsdisk/jail$cvsroot_path";
my $local_cvs_path = "/cvsdisk/jail$cvsroot_path";
$|=1;
my $hostname=`hostname`;
chomp $hostname;
$hostname =~ s/\..*$//; # truncate at a dot in case of a poorly configured hostname
if ($hostname ne $bonsai_host) {
print "You must only run this program on $bonsai_host.";
exit 1;
}
my $tempdir = tempdir('/tmp/cvsfix-temp-XXXXXXXXX', CLEANUP => 1);
$::ENV{'CVS_RSH'} = 'ssh';
my @files = ();
sub verify_file {
my ($cvsroot, $filename, $rev) = @_;
chdir $tempdir;
system("cvs -q -d $cvsroot co -r $rev $filename");
if (!-e $filename) {
print "File $filename does not exist.\n";
return 0;
}
return 1;
}
print "--\nNOTICE: you must have ssh agent forwarding enabled with your CVS key\n";
print "available via your agent for this to work!! You must also have root access\n";
print "to $cvs_host with a key available to your agent!!\n";
print "\nPlease enter your email address used for CVS: ";
my $cvsuser = <STDIN>;
chomp $cvsuser;
$cvsuser =~ s/\@/%/;
my $cvsroot = "$cvsuser\@$cvs_host:$cvsroot_path";
my $groups = `ssh $cvs_host groups $cvsuser`;
if ($groups !~ /\bcvsadm\b/) {
print "ERROR: The $cvsuser account on $cvs_host is not a member of the cvsadm group.\n";
print "Aborted.\n";
exit;
}
sub parse_bonsai_backout_file {
my $data = $_[0];
my @lines = split("\n", $data);
foreach my $line (@lines) {
if ($line =~ /^cvs update -j(\S+) -j\S+ (\S+)$/) {
print "$2 rev:$1\n";
push @files, [$2, $1] if verify_file($cvsroot, $2, $1);
}
}
}
if (($::ARGV[0]) && ($::ARGV[0] =~ /^http/)) {
print "--\n";
my $url = $::ARGV[0];
if ($url !~ m/generateBackoutCVSCommands/) {
$url .= '&generateBackoutCVSCommands=1';
}
my $data = `wget -O- -nv "$::ARGV[0]"`;
parse_bonsai_backout_file($data);
}
elsif (($::ARGV[0]) && (-r $::ARGV[0])) {
print "--\n";
open INFILES, "<", $::ARGV[0];
local $/;
print "Reading files from $::ARGV[0]...\n";
my $data = <INFILES>;
close INFILES;
parse_bonsai_backout_file($data);
}
if (0 == @files) {
print <<EOF;
--
Enter one filename per line, including the leading 'mozilla'. Enter revision
numbers as prompted. Hit Enter on a blank line to end. Alternatively, you
may also enter the URL to the "Show commands which could be used to back out
these changes" page on Bonsai, listing only the files from this checkin.
EOF
print "file: ";
my $filename = <STDIN>;
chomp $filename;
if ($filename =~ /^http/) {
print "--\n";
if ($filename !~ m/generateBackoutCVSCommands/) {
$filename .= '&generateBackoutCVSCommands=1';
}
my $data = `wget -O- -nv "$filename"`;
parse_bonsai_backout_file($data);
if (0 == @files) {
print "I didn't find any files at that URL, try again.\n";
exit 1;
}
}
else {
while ($filename) {
print "revision: ";
my $rev = "";
while (!$rev) {
$rev = <STDIN>;
chomp $rev;
if ($rev !~ /^\d+(\.\d+)+$/) {
print "Invalid revision.\n";
$rev = "";
}
}
push @files, [$filename, $rev] if verify_file($cvsroot, $filename, $rev);
print "file: ";
$filename = <STDIN>;
chomp $filename;
}
}
}
sub get_log_message {
my ($cvsroot, $filename, $rev) = @_;
my $cvslog = `cvs -d $cvsroot log -r$rev $filename`;
if ($cvslog !~ /----\nrevision $rev\n/s) {
print "$filename revision $rev not found.\n";
exit;
}
$cvslog =~ s/^.*?----\nrevision $rev\n//s;
$cvslog =~ s/^date.*?\n//s;
$cvslog =~ s/^branches:\s+\d.*?\n//s;
$cvslog =~ s/\n=============================================================================\n$//s;
return $cvslog;
}
my $have_first = 0;
my $first_log = "";
print "--\nReading existing commit messages...\n";
foreach $fileref (@files) {
my $log = get_log_message($cvsroot, $fileref->[0], $fileref->[1]);
if (!$have_first) {
$first_log = $log;
$have_first = 1;
}
else {
if ($log ne $first_log) {
print "ERROR: " . $fileref->[0] . " revision " . $fileref->[1] . "\n" .
"is not part of the same commit. Please only enter files that are\n" .
"part of the same commit.\n\nAborted.\n";
print "Original message:\n-----\n$first_log\n-----\nThis file's message:\n-----\n$log\n-----\n";
print "Tempdir at $tempdir\nPress Enter when done examining: ";
my $foo = <STDIN>;
exit;
}
}
}
open FILE, ">$tempdir/cvsmsgfix";
print FILE "$first_log\n";
print FILE <<EOF;
CVS: ==================================================================
CVS: Please edit the log message for
EOF
foreach $fileref (@files) {
print FILE "CVS: " . $fileref->[0] . " rev:" . $fileref->[1] . "\n";
}
print FILE <<EOF;
CVS: Lines begining with CVS: will be ignored.
CVS: ==================================================================
EOF
close FILE;
my $editor = "/usr/bin/vim";
if ($::ENV{'EDITOR'}) {
$editor = $::ENV{'EDITOR'};
}
print "Running external editor on commit message...\n";
system($editor,"$tempdir/cvsmsgfix");
my $logmsg = `cat $tempdir/cvsmsgfix | grep -v ^CVS:`;
chomp $logmsg;
unlink "$tempdir/cvsmsgfix";
if ($logmsg eq $first_log) {
print "You appear to have made no changes. Aborting.\n";
exit;
}
print "--\nYour revised log message is:\n--------\n$logmsg\n--------\n";
my $answer = "";
while ($answer !~ /^[yn]$/i) {
print "Ready to commit? (y/n) ";
$answer = <STDIN>;
chomp $answer;
}
if ($answer =~ /n/i) {
print "Aborted.\n";
exit;
}
print "--\nApplying change:\n";
foreach my $fileref (@files) {
system("cvs","-d",$cvsroot,"admin","-m" . $fileref->[1] . ":$logmsg\n",$fileref->[0]);
}
print "--\nForcing update of local mirrored repository copy for bonsai...\n";
sleep 1; # give $cvs_host time for kernel buffers to flush? Seems to miss the first couple files if we don't do this.
foreach my $fileref (@files) {
system("rsync","-e","ssh","-ai","root\@$cvs_host:$remote_cvs_path/" . $fileref->[0] . ",v","$local_cvs_path/" . $fileref->[0] . ",v");
}
print "--\nRebuilding bonsai cvs history:\n";
chdir "$bonsai_path";
foreach my $fileref (@files) {
system("perl","rebuildcvshistory.cgi","default","1970/01/01 00:00:00",$fileref->[0]);
}