File:  [LON-CAPA] / CVSROOT / loginfo.pl
Revision 1.10: download - view: text, annotated - select for diffs
Mon Jul 4 18:32:49 2011 UTC (12 years, 9 months ago) by raeburn
Branches: MAIN
CVS tags: HEAD
- Include charset="us-ascii" in e-mail header.

    1: #!/usr/bin/perl -w
    2: # include this script in your loginfo as:
    3: # <modulename>   /path/to/loginfo.pl sender@domain recipient@domain %{sVv}
    4: #
    5: # Copyright (c) 1999, 2000 Sascha Schumann <sascha@schumann.cx>
    6: 
    7: # This makes some basic assumptions -- you are only checking
    8: # in to a single CVS module.
    9: 
   10: # This also doesn't like files or directories with spaces in them.
   11: 
   12: use strict;
   13: 
   14: use Socket;
   15: use POSIX;
   16: 
   17: $SIG{PIPE} = 'IGNORE';
   18: 
   19: my $last_file  = "/var/cvs/lastdir";
   20: my $summary    = "/var/cvs/summary";
   21: my $smtpserver = "127.0.0.1";
   22: my $smtpport   = 25;
   23: my $cvs        = "/usr/bin/cvs";
   24: my $cvsroot    = $ENV{CVSROOT}."/";
   25: # remove double trailing slash
   26: $cvsroot =~ s/\/\/$/\//;
   27: my $cvsusers   = "/repository/CVSROOT/cvsusers";
   28: my $cvshost = "source.lon-capa.org";
   29: 
   30: # get the id of this process group for use in figuring out
   31: # whether this is the last directory with checkins or not
   32: my $id = getpgrp();
   33: 
   34: # the command line looks something like this for a normal commit:
   35: #  ("user@example.com", "cvsuser",
   36: #   "module changedfile,1.1,1.2 addedfile,NONE,1.1 removedfile,1.1,NONE")
   37: my $mailto = shift;
   38: my $envaddr = $mailto;
   39: 
   40: my $cvsuser = shift;
   41: my @args = split(" ", $ARGV[0]);
   42: my $directory = shift @args;
   43: 
   44: # extract just the module name from the directory
   45: my $module = $directory;
   46: $module =~ s/\/.+$//;
   47: 
   48: if ($cvsuser eq "changelog" && $module ne "php-gtk") {
   49: 	$envaddr = "php-cvs-daily-private\@lists.php.net";
   50: 	$mailto  = "php-cvs-daily\@lists.php.net";
   51: }
   52: 
   53: # bail when this is a new directory
   54: &bail if $args[0] eq '-' && "$args[1] $args[2]" eq 'New directory';
   55: 
   56: # bail if this is an import
   57: &bail if $args[0] eq '-' && $args[1] eq 'Imported';
   58: 
   59: # find out the last directory being processed
   60: open FC, "$last_file.$id"
   61: 	or die "last file does not exist";
   62: my $last_directory = <FC>;
   63: chop $last_directory;
   64: close FC;
   65: # remove the cvsroot from the front
   66: $last_directory =~ s/^$cvsroot//;
   67: 
   68: # add our changed files to the summary
   69: open(FC, ">>$summary.$id") || die "cannot open summary file";
   70: foreach my $arg (@args) {
   71: 	print FC "$directory/$arg\n";
   72: }
   73: close(FC);
   74: 
   75: # is this script already in the last changed directory?
   76: 
   77: # exit if this isn't the last directory
   78: &bail if($last_directory ne $directory);
   79: 
   80: # get the log message and tag -- we throw away everything from STDIN
   81: # before a line that begins with "Log Message"
   82: my ($logmsg,$tag) = &get_log_message();
   83: 
   84: # now we fork off into the background and generate the email
   85: exit 0 if(fork() != 0);
   86: 
   87: $| = 1;
   88: 
   89: #print "Reading summary file\n";
   90: 
   91: open(FC, "<$summary.$id");
   92: 
   93: my (@added_files, @removed_files, @modified_files, @modified_files_info);
   94: while (<FC>) {
   95: 	chop;
   96: 	my ($file, $old, $new) = split(",");
   97: 	if($old eq "NONE") {
   98: 		push @added_files, $file;
   99: 	} elsif($new eq "NONE") {
  100: 		push @removed_files, $file;
  101: 	} else {
  102: 		push @modified_files, $file;
  103: 		push @modified_files_info, [ $file, $old, $new ];
  104: 	}
  105: }
  106: close FC;
  107: 
  108: #print "Unlinking helper files\n";
  109: 
  110: # clean up a little bit
  111: 
  112: unlink("$summary.$id");
  113: unlink("$last_file.$id");
  114: 
  115: #print "Running rdiff\n";
  116: 
  117: # build a diff (and new files) if necessary
  118: my $diffmsg = '';
  119: 
  120: foreach my $info (@modified_files_info) {
  121: 	my ($file, $old, $new) = @$info;
  122:         if ($file =~ m|TexConvert/tt.dynamic|  ||
  123: 	    $file =~ m|foxr/londtest| ||
  124: 	    $file =~ m|purdue| ||
  125:             $file =~ m|vcu/| ||
  126:             $file =~ m|modules/[^/]+/private/| ) {
  127: 		$diffmsg='Diffs for '.$file.' not shown.'."\n";
  128: 		next;
  129: 	}
  130: 	open(LOG, "$cvs -Qn rdiff -r $old -r $new -u $file|") || die;
  131: 	while(<LOG>) { s/\r\n/\n/; $diffmsg .= $_; }
  132: 	close(LOG);
  133: }
  134: 
  135: # add the added files
  136: 
  137: foreach my $file (@added_files) {
  138: 	next if $file =~ /\.(gif|jpe|jpe?g|pdf|png|exe|class|tgz|tar.gz|jar)$/i
  139: 		or $file !~ /\./;
  140:         if ($file =~ m|TexConvert/tt.dynamic|  ||
  141:             $file =~ m|foxr/londtest| ||
  142:             $file =~ m|purdue|  ||
  143:             $file =~ m|vcu/| ||
  144:             $file =~ m|modules/[^/]+/private/| ) {
  145:                 $diffmsg='Contents of added file: '.$file.' not shown.'."\n";
  146:                 next;
  147:         }
  148: 	$diffmsg .= "\nIndex: $file\n+++ $file\n";
  149: 	open(LOG, "$cvs -Qn checkout -p -r1.1 $file |") || die;
  150: 	while(<LOG>) { s/\r\n/\n/; $diffmsg .= $_; }
  151: 	close(LOG);
  152: }
  153: 
  154: #print "Building commit email\n";
  155: 
  156: my $subj_tag = $tag ? "($tag)" : '';
  157: my $body_tag = $tag ? "(Branch: $tag)" : '';
  158: 
  159: # build our email
  160: my $msg = "";
  161: if($#added_files ne -1) {
  162: 	$msg .= "\n  Added files:                 $body_tag";
  163: 	$msg .= &build_list(@added_files);
  164: 	$body_tag = '';
  165: }
  166: if($#removed_files ne -1) {
  167: 	$msg .= "\n  Removed files:               $body_tag";
  168: 	$msg .= &build_list(@removed_files);
  169: 	$body_tag = '';
  170: }
  171: if($#modified_files ne -1) {
  172: 	$msg .= "\n  Modified files:              $body_tag";
  173: 	$msg .= &build_list(@modified_files);
  174: 	$body_tag = '';
  175: }
  176: 
  177: my $subj = "";
  178: my %dirfiles;
  179: my @dirs = &get_dirs(@added_files, @removed_files, @modified_files);
  180: 
  181: foreach my $dir (@dirs) {
  182:     $subj .= "$dir @{ $dirfiles{$dir} }  ";
  183: }
  184: 
  185: my $msgid = "Message-ID: <cvs$cvsuser".time()."\@cvsserver>\n";
  186: 
  187: my $from;
  188: if (open FD, $cvsusers) {
  189: 	while(<FD>) {
  190: 		chop;
  191: 		if (m/^$cvsuser:(.+?):(.+)$/) {
  192: 			$from = "\"$1\" <$2>";
  193: 		}
  194: 	}
  195: 	close(FD);
  196: }
  197: 
  198: $from ||= "$cvsuser <$cvsuser\@$cvshost>";
  199: 
  200: # "Reply-to: $mailto\n".
  201: # "Date: ".localtime()."\n".
  202: my (@DAYABBR) = qw(Sun Mon Tue Wed Thu Fri Sat);
  203: my (@MONABBR) = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
  204: 
  205: my (@gmtime) = gmtime();
  206: my $rfc822date = sprintf("Date: %s, %02d %s %d %02d:%02d:%02d -0000\n",
  207:         $DAYABBR[$gmtime[6]], $gmtime[3], $MONABBR[$gmtime[4]],
  208:         $gmtime[5] + 1900, $gmtime[2], $gmtime[1], $gmtime[0]);
  209: 
  210: no strict; # quiet warnings after here
  211: 
  212: my $email;
  213: my $common_header = "".
  214: 	"From: $from\n".
  215: 	"To: $mailto\n".
  216: 	$msgid.
  217: 	$rfc822date.
  218: 	"Subject: cvs: $module$subj_tag $subj\n";
  219: 
  220: my $common_body = "".
  221: 	"$cvsuser\t\t".localtime()." EDT\n".
  222: 	"$msg".
  223: 	"  Log:\n".
  224: 	&indent($logmsg,2)."\n";
  225: 
  226: my $boundary = $cvsuser.time();
  227: 
  228: if (length($diffmsg) > 8000) {
  229: 	my $now = POSIX::strftime("%Y%m%d%H%M%S", localtime);
  230: 	$email = $common_header.
  231: 		"MIME-Version: 1.0\n".
  232: 		"Content-Type: multipart/mixed; boundary=\"$boundary\"\n".
  233: 		"\n".
  234: 		"This is a MIME encoded message\n\n".
  235: 		"--$boundary\n".
  236: 		'Content-Type: text/plain; charset="us-ascii"'."\n".
  237: 		"\n".
  238: 		$common_body.
  239: 		"--$boundary\n".
  240: 		'Content-Type: text/plain; charset="us-ascii"'."\n".
  241: 		"Content-Disposition: attachment; filename=\"$cvsuser-$now.txt\"\n".
  242: 		"\n".
  243: 		"$diffmsg\n".
  244: 		"--$boundary--\n";
  245: } else {
  246: 	$email = $common_header.
  247:                 'Content-Type: text/plain; charset="us-ascii"'."\n".
  248: 		"\n".
  249: 		$common_body.
  250: 		"$diffmsg\n";
  251: }
  252: 
  253: $email =~ s/\r//g;
  254: $email =~ s/\n/\r\n/g;
  255: 
  256: # send our email
  257: 
  258: print "Mailing the commit email to $mailto\n";
  259: 
  260: #print $email;
  261: 
  262: my $paddr = sockaddr_in($smtpport, inet_aton($smtpserver));
  263: socket(SOCK, PF_INET, SOCK_STREAM, 0) || die "socket failed";
  264: connect(SOCK, $paddr) || die "connect $smtpserver:$smtpport failed";
  265: select(SOCK);
  266: $|=1;
  267: 
  268: print "HELO cvsserver\r\n".
  269: "MAIL FROM:<this-will-bounce\@php.net>\r\n" . 
  270: "RCPT TO:<$envaddr>\r\n" .
  271: "DATA\r\n".
  272: "$email\r\n".
  273: ".\r\n".
  274: "QUIT\r\n";
  275: 
  276: while(<SOCK>) { alarm(20); };
  277: 
  278: close(SOCK);
  279: exit 0;
  280: 
  281: sub get_log_message {
  282:   my ($logmsg, $tag);
  283:   while (<STDIN>) {
  284:     $logmsg .= $_ if defined $logmsg;
  285:     if (/^Log Message/) { $logmsg = ""; }
  286:     if (/^\s+Tag:\s+(\w+)/) { $tag = $1; }
  287:   }
  288:   return ($logmsg, $tag);
  289: }
  290: 
  291: sub build_list {
  292:   my(@arr) = @_;
  293:   my($curdir, $curlen, $msg);
  294: 
  295:   $msg = "";
  296:   $curdir = "";
  297:   foreach (@arr) {
  298:     /^(.*)\/([^\/]+)$/;
  299:     my $dir = $1;
  300:     my $file = $2;
  301:     if($dir ne $curdir) {
  302:       $curdir = $dir;
  303:       $msg .= "\n    /$curdir\t";
  304:       $curlen = length($curdir) + 5;
  305:     }
  306:     if(($curlen + length($file)) > 70) {
  307:       $msg .= "\n     ".sprintf("%-".length($curdir)."s", "")."\t";
  308:       $curlen = length($curdir) + 5;
  309:     }
  310:     $msg .= $file." ";
  311:     $curlen += length($file) + 1;
  312:   }
  313: 
  314:   $msg .= "\n";
  315: 
  316:   return $msg;
  317: }
  318: 
  319: sub get_dirs {
  320:   my @files = sort @_;
  321:   foreach my $file (@files) {
  322:     (my $dir = $file) =~ s#[^/]+$##;
  323:     $dir =~ s/^$module//;
  324:     $dir =~ s/(.+)\//$1/;
  325:     $file =~ s#^.+/(.+)$#$1#;
  326:     push @{ $dirfiles{$dir} }, $file;
  327:   } 
  328:   return sort keys %dirfiles;
  329: } 
  330: 
  331: sub indent {
  332:   my ($msg,$nr) = @_;
  333:   my $s = " " x $nr;
  334:   $msg =~ s/\n/\n$s/g;
  335:   return $s.$msg;
  336: }
  337: 
  338: sub trim {
  339:   my ($x) = @_;
  340:   $x =~ s/^\s+//;
  341:   $x =~ s/\s+$//;
  342:   return $x;
  343: }
  344: 
  345: # eat STDIN (to avoid parent getting SIGPIPE) and exit with supplied exit code
  346: sub bail {
  347:   my @toss = <STDIN>;
  348:   exit @_;
  349: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>