WikiSVN

From Wikitech
Jump to navigation Jump to search
#!/usr/bin/perl -w

# Script to pull bug info from SVN and dump them
# to a log to be used for IRC bot.

# Original version by AzaToth 2006-12-23

use strict;
use utf8;

my $TYPES = {
	'Log Message'		=> 'msg',
	'Property Changed'	=> 'prop',
	'Modified Paths'	=> 'mod',
	'Added Paths'		=> 'add',
	'Deleted Paths'		=> 'del',
};

my $FILES = {
	'mod'	=> 'modified',
	'add'	=> 'added',
	'del'	=> 'deleted',
	'prop'	=> 'changed property on',

}; # will contain list of files

my $MAX_COMMENT_LENGTH = 300;
my $LINE_LENGTH = 130;
my $MAX_ONELINE_MODIFIER = 1.5;
my $VIEWVC_URL = "http://svn.wikimedia.org/viewvc/mediawiki?view=rev&revision=";

$/ = undef;

my $output;
my $filelist = '';
my @allfiles;
my %fields;

my ($author, $rev, $date, $path);

my $contents = <STDIN>;

$contents =~ s/\r\n/\n/g;

if ($contents =~ /^Content-Transfer-Encoding: base64/m) {
	use MIME::Base64;
	$contents =~ s/.*?\n([\S\n]+)\s*$/$1/sg;
	$contents = decode_base64($contents);
	$contents =~ s/\w+[^\n]*?\n={20,}.*//s;
} else {
	$contents =~ s/^\s*.*?\n{2,}(.*?)\w+[^\n]*?\n={20,}.*/$1/s;
}

$contents =~ s/^Author:\s+(\S+)\n//m	and $author = $1 or $author = 'none';
$contents =~ s/^Revision:\s+(\d+)\n//m	and $rev = $1 or $rev = '0';
$contents =~ s/^Date:\s+(.*?)\n\n//m	and $date = $1 or $date = 'now';
chomp($contents);
use Data::Dumper;

my @field = split /\s*\n*(\w+\s\w+):\n-{5,}\n\s*/s, $contents;
shift @field;
foreach (my $i=0; $i <= $#field; $i += 2) {
	my $type = $TYPES->{$field[$i]};
	if(defined $FILES->{$type}) {
		my $file_list = $field[$i + 1];
		my @files = split /\s+/, $file_list;
		$fields{$type} = \@files;

	} else {
		$fields{$type} = $field[$i + 1];
	}
}

foreach my $key(keys %{$FILES}) {
	foreach my $file(@{$fields{$key}}) {
		push @allfiles, [split /\//, $file];
	}
}

my $nbr_of_files = $#allfiles + 1;

my @base = @{ shift @allfiles };
foreach my $file (@allfiles) {
	for my $i(0..$#base) {
		pop	@base if defined $base[$i] and $$file[$i] ne $base[$i];
	}
}

$path = join '/', @base;


my %alldirs;
foreach my $file (@allfiles) {
	my @f = @$file;
	pop @f;
	my $key = join '/', @f;
	next if length $key <= length $path;
	$key = substr ($key, (length $path)+1);
	$alldirs{$key} = 1;
}

my @alldirs = keys %alldirs;
my $nbr_of_dirs = $#alldirs + 1;
$nbr_of_dirs = 1 if $nbr_of_dirs < 1;

if ($nbr_of_files <= 3 and $nbr_of_files > 1) {
	my @extra_files;
	foreach my $file(@allfiles) {
		my $nfile = substr(join('/', @{$file}), (length $path)+1);
		$nfile =~ s/\n//g;
		push @extra_files, $nfile;
	}
	$path .= " (" . join( ', ', @extra_files). ")";
} elsif($nbr_of_files > 1) {
	$path .= " ($nbr_of_files file".($nbr_of_files>1?'s':'')." in $nbr_of_dirs dir".($nbr_of_dirs>1?'s':'').")";
}


$path = 'strange places' if $path eq '';


my @files;
if( $nbr_of_files > 0 ) {
	foreach my $key(keys %{$FILES}) {
		if(defined $fields{$key} and $#{$fields{$key}} +1 > 0) {
			push @files, "$FILES->{$key} \002".($#{$fields{$key}}+1)."\002";
		}
	}
	$filelist = join( ', ' , @files) . ' ' . ( $nbr_of_files > 1 ? 'files' : 'file');
}

$output = "\002SVN\002 (\00303r$rev\003): \00302$author\003 in \00303$path\003 $filelist";

$fields{'msg'} =~ s/([^\n]{$LINE_LENGTH,}?)\s/$1\n/g;
my $submsg = substr ($fields{'msg'}, 0 , $MAX_COMMENT_LENGTH);
if(length $fields{'msg'} > length $submsg) {
	substr( $submsg, -3) = '...';
}

if(length ($output) + length ($submsg) <= $LINE_LENGTH * $MAX_ONELINE_MODIFIER) {
	$output .= ": $submsg\n";
} else {
	$output .= ":\n". join ("\n", map { $_ = "\002|\002 $_"} split /\n/, $submsg) ."\n";
}

$output .= "$VIEWVC_URL$rev\n";

if ($output)
{
	open (OUT, ">>/var/wikisvn/wikisvn.log");
	print $output;
	#print OUT $output;
	close OUT;
}