1175261Sobrien#! @PERL@ -T 281404Speter# -*-Perl-*- 3175261Sobrien 4175261Sobrien# Copyright (C) 1994-2005 The Free Software Foundation, Inc. 5175261Sobrien 6175261Sobrien# This program is free software; you can redistribute it and/or modify 7175261Sobrien# it under the terms of the GNU General Public License as published by 8175261Sobrien# the Free Software Foundation; either version 2, or (at your option) 9175261Sobrien# any later version. 1081404Speter# 11175261Sobrien# This program is distributed in the hope that it will be useful, 12175261Sobrien# but WITHOUT ANY WARRANTY; without even the implied warranty of 13175261Sobrien# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14175261Sobrien# GNU General Public License for more details. 15175261Sobrien 16175261Sobrien############################################################################### 17175261Sobrien############################################################################### 18175261Sobrien############################################################################### 19175261Sobrien# 20175261Sobrien# THIS SCRIPT IS PROBABLY BROKEN. REMOVING THE -T SWITCH ON THE #! LINE ABOVE 21175261Sobrien# WOULD FIX IT, BUT THIS IS INSECURE. WE RECOMMEND FIXING THE ERRORS WHICH THE 22175261Sobrien# -T SWITCH WILL CAUSE PERL TO REPORT BEFORE RUNNING THIS SCRIPT FROM A CVS 23175261Sobrien# SERVER TRIGGER. PLEASE SEND PATCHES CONTAINING THE CHANGES YOU FIND 24175261Sobrien# NECESSARY TO RUN THIS SCRIPT WITH THE TAINT-CHECKING ENABLED BACK TO THE 25175261Sobrien# <@PACKAGE_BUGREPORT@> MAILING LIST. 26175261Sobrien# 27175261Sobrien# For more on general Perl security and taint-checking, please try running the 28175261Sobrien# `perldoc perlsec' command. 29175261Sobrien# 30175261Sobrien############################################################################### 31175261Sobrien############################################################################### 32175261Sobrien############################################################################### 33175261Sobrien 3481404Speter# Perl filter to handle the log messages from the checkin of files in 3581404Speter# a directory. This script will group the lists of files by log 3681404Speter# message, and mail a single consolidated log message at the end of 3781404Speter# the commit. 3881404Speter# 3981404Speter# This file assumes a pre-commit checking program that leaves the 4081404Speter# names of the first and last commit directories in a temporary file. 4181404Speter# 42128266Speter# IMPORTANT: what the above means is, this script interacts with 43128266Speter# commit_prep, in that they have to agree on the tmpfile name to use. 44128266Speter# See $LAST_FILE below. 45128266Speter# 46128266Speter# How this works: CVS triggers this script once for each directory 47128266Speter# involved in the commit -- in other words, a single commit can invoke 48128266Speter# this script N times. It knows when it's on the last invocation by 49128266Speter# examining the contents of $LAST_FILE. Between invocations, it 50128266Speter# caches information for its future incarnations in various temporary 51128266Speter# files in /tmp, which are named according to the process group and 52128266Speter# the committer (by themselves, neither of these are unique, but 53128266Speter# together they almost always are, unless the same user is doing two 54128266Speter# commits simultaneously). The final invocation is the one that 55128266Speter# actually sends the mail -- it gathers up the cached information, 56128266Speter# combines that with what it found out on this pass, and sends a 57128266Speter# commit message to the appropriate mailing list. 58128266Speter# 59128266Speter# (Ask Karl Fogel <kfogel@collab.net> if questions.) 60128266Speter# 6181404Speter# Contributed by David Hampton <hampton@cisco.com> 62128266Speter# Roy Fielding removed useless code and added log/mail of new files 63128266Speter# Ken Coar added special processing (i.e., no diffs) for binary files 6481404Speter# 6581404Speter 66128266Speter############################################################ 6781404Speter# 68128266Speter# Configurable options 6981404Speter# 70128266Speter############################################################ 71128266Speter# 72128266Speter# Where do you want the RCS ID and delta info? 73128266Speter# 0 = none, 74128266Speter# 1 = in mail only, 75128266Speter# 2 = in both mail and logs. 76128266Speter# 77128266Speter$rcsidinfo = 2; 7881404Speter 79128266Speter#if you are using CVS web then set this to some value... if not set it to "" 80128266Speter# 81128266Speter# When set properly, this will cause links to aspects of the project to 82128266Speter# print in the commit emails. 83128266Speter#$CVSWEB_SCHEME = "http"; 84175261Sobrien#$CVSWEB_DOMAIN = "nongnu.org"; 85128266Speter#$CVSWEB_PORT = "80"; 86128266Speter#$CVSWEB_URI = "source/browse/"; 87128266Speter#$SEND_URL = "true"; 88128266Speter$SEND_DIFF = "true"; 8981404Speter 90128266Speter 91128266Speter# Set this to a domain to have CVS pretend that all users who make 92128266Speter# commits have mail accounts within that domain. 93175261Sobrien#$EMULATE_LOCAL_MAIL_USER="nongnu.org"; 94128266Speter 95128266Speter# Set this to '-c' for context diffs; defaults to '-u' for unidiff format. 96128266Speter$difftype = '-uN'; 97128266Speter 98128266Speter############################################################ 9981404Speter# 100128266Speter# Constants 10181404Speter# 102128266Speter############################################################ 10381404Speter$STATE_NONE = 0; 10481404Speter$STATE_CHANGED = 1; 10581404Speter$STATE_ADDED = 2; 10681404Speter$STATE_REMOVED = 3; 10781404Speter$STATE_LOG = 4; 10881404Speter 109128266Speter$TMPDIR = $ENV{'TMPDIR'} || '/tmp'; 110128266Speter$FILE_PREFIX = '#cvs.'; 11181404Speter 112128266Speter$LAST_FILE = "$TMPDIR/${FILE_PREFIX}lastdir"; # Created by commit_prep! 113128266Speter$ADDED_FILE = "$TMPDIR/${FILE_PREFIX}files.added"; 114128266Speter$REMOVED_FILE = "$TMPDIR/${FILE_PREFIX}files.removed"; 115128266Speter$LOG_FILE = "$TMPDIR/${FILE_PREFIX}files.log"; 116128266Speter$BRANCH_FILE = "$TMPDIR/${FILE_PREFIX}files.branch"; 117128266Speter$MLIST_FILE = "$TMPDIR/${FILE_PREFIX}files.mlist"; 118128266Speter$SUMMARY_FILE = "$TMPDIR/${FILE_PREFIX}files.summary"; 11981404Speter 120128266Speter$CVSROOT = $ENV{'CVSROOT'}; 12181404Speter 122128266Speter$MAIL_CMD = "| /usr/lib/sendmail -i -t"; 123128266Speter#$MAIL_CMD = "| /var/qmail/bin/qmail-inject"; 124128266Speter$MAIL_FROM = 'commitlogger'; #not needed if EMULATE_LOCAL_MAIL_USER 125128266Speter$SUBJECT_PRE = 'CVS update:'; 126128266Speter 127128266Speter 128128266Speter############################################################ 12981404Speter# 130128266Speter# Subroutines 13181404Speter# 132128266Speter############################################################ 13381404Speter 134128266Spetersub format_names { 135128266Speter local($dir, @files) = @_; 136128266Speter local(@lines); 137128266Speter 138128266Speter $lines[0] = sprintf(" %-08s", $dir); 139128266Speter foreach $file (@files) { 140128266Speter if (length($lines[$#lines]) + length($file) > 60) { 141128266Speter $lines[++$#lines] = sprintf(" %8s", " "); 142128266Speter } 143128266Speter $lines[$#lines] .= " ".$file; 144128266Speter } 145128266Speter @lines; 146128266Speter} 147128266Speter 14881404Spetersub cleanup_tmpfiles { 149128266Speter local(@files); 15081404Speter 151128266Speter opendir(DIR, $TMPDIR); 152128266Speter push(@files, grep(/^${FILE_PREFIX}.*\.${id}\.${cvs_user}$/, readdir(DIR))); 15381404Speter closedir(DIR); 15481404Speter foreach (@files) { 155128266Speter unlink "$TMPDIR/$_"; 15681404Speter } 15781404Speter} 15881404Speter 15981404Spetersub write_logfile { 16081404Speter local($filename, @lines) = @_; 16181404Speter 162128266Speter open(FILE, ">$filename") || die ("Cannot open log file $filename: $!\n"); 163128266Speter print(FILE join("\n", @lines), "\n"); 16481404Speter close(FILE); 16581404Speter} 16681404Speter 167128266Spetersub append_to_file { 168128266Speter local($filename, $dir, @files) = @_; 16981404Speter 170128266Speter if (@files) { 171128266Speter local(@lines) = &format_names($dir, @files); 172128266Speter open(FILE, ">>$filename") || die ("Cannot open file $filename: $!\n"); 173128266Speter print(FILE join("\n", @lines), "\n"); 174128266Speter close(FILE); 175128266Speter } 176128266Speter} 177128266Speter 178128266Spetersub write_line { 179128266Speter local($filename, $line) = @_; 180128266Speter 181128266Speter open(FILE, ">$filename") || die("Cannot open file $filename: $!\n"); 182128266Speter print(FILE $line, "\n"); 18381404Speter close(FILE); 18481404Speter} 18581404Speter 186128266Spetersub append_line { 187128266Speter local($filename, $line) = @_; 18881404Speter 189128266Speter open(FILE, ">>$filename") || die("Cannot open file $filename: $!\n"); 190128266Speter print(FILE $line, "\n"); 191128266Speter close(FILE); 192128266Speter} 19381404Speter 194128266Spetersub read_line { 195128266Speter local($filename) = @_; 196128266Speter local($line); 19781404Speter 198128266Speter open(FILE, "<$filename") || die("Cannot open file $filename: $!\n"); 199128266Speter $line = <FILE>; 200128266Speter close(FILE); 201128266Speter chomp($line); 202128266Speter $line; 203128266Speter} 20481404Speter 205128266Spetersub read_line_nodie { 206128266Speter local($filename) = @_; 207128266Speter local($line); 208128266Speter open(FILE, "<$filename") || return (""); 209128266Speter 210128266Speter $line = <FILE>; 211128266Speter close(FILE); 212128266Speter chomp($line); 213128266Speter $line; 21481404Speter} 21581404Speter 216128266Spetersub read_file_lines { 217128266Speter local($filename) = @_; 218128266Speter local(@text) = (); 21981404Speter 220128266Speter open(FILE, "<$filename") || return (); 221128266Speter while (<FILE>) { 222128266Speter chomp; 223128266Speter push(@text, $_); 22481404Speter } 225128266Speter close(FILE); 22681404Speter @text; 22781404Speter} 22881404Speter 229128266Spetersub read_file { 230128266Speter local($filename, $leader) = @_; 231128266Speter local(@text) = (); 23281404Speter 233128266Speter open(FILE, "<$filename") || return (); 234128266Speter while (<FILE>) { 235128266Speter chomp; 236128266Speter push(@text, sprintf(" %-10s %s", $leader, $_)); 237128266Speter $leader = ""; 23881404Speter } 23981404Speter close(FILE); 240128266Speter @text; 24181404Speter} 24281404Speter 24381404Spetersub read_logfile { 24481404Speter local($filename, $leader) = @_; 245128266Speter local(@text) = (); 24681404Speter 247128266Speter open(FILE, "<$filename") || die ("Cannot open log file $filename: $!\n"); 24881404Speter while (<FILE>) { 249128266Speter chomp; 250128266Speter push(@text, $leader.$_); 25181404Speter } 25281404Speter close(FILE); 25381404Speter @text; 25481404Speter} 25581404Speter 256128266Speter# 257128266Speter# do an 'cvs -Qn status' on each file in the arguments, and extract info. 258128266Speter# 259128266Spetersub change_summary { 260128266Speter local($out, @filenames) = @_; 261128266Speter local(@revline); 262128266Speter local($file, $rev, $rcsfile, $line, $vhost, $cvsweb_base); 263128266Speter 264128266Speter while (@filenames) { 265128266Speter $file = shift @filenames; 266128266Speter 267128266Speter if ("$file" eq "") { 268128266Speter next; 269128266Speter } 270128266Speter 271128266Speter open(RCS, "-|") || exec "$cvsbin/cvs", '-Qn', 'status', '--', $file; 272128266Speter 273128266Speter $rev = ""; 274128266Speter $delta = ""; 275128266Speter $rcsfile = ""; 276128266Speter 277128266Speter 278128266Speter while (<RCS>) { 279128266Speter if (/^[ \t]*Repository revision/) { 280128266Speter chomp; 281128266Speter @revline = split(' ', $_); 282128266Speter $rev = $revline[2]; 283128266Speter $rcsfile = $revline[3]; 284128266Speter $rcsfile =~ s,^$CVSROOT/,,; 285128266Speter $rcsfile =~ s/,v$//; 286128266Speter } 287128266Speter } 288128266Speter close(RCS); 289128266Speter 290128266Speter 291128266Speter if ($rev ne '' && $rcsfile ne '') { 292128266Speter open(RCS, "-|") || exec "$cvsbin/cvs", '-Qn', 'log', "-r$rev", 293128266Speter '--', $file; 294128266Speter while (<RCS>) { 295128266Speter if (/^date:/) { 296128266Speter chomp; 297128266Speter $delta = $_; 298128266Speter $delta =~ s/^.*;//; 299128266Speter $delta =~ s/^[\s]+lines://; 300128266Speter } 301128266Speter } 302128266Speter close(RCS); 303128266Speter } 304128266Speter 305128266Speter $diff = "\n\n"; 306175261Sobrien $vhost = $path[0]; 307128266Speter if ($CVSWEB_PORT eq "80") { 308128266Speter $cvsweb_base = "$CVSWEB_SCHEME://$vhost.$CVSWEB_DOMAIN/$CVSWEB_URI"; 309128266Speter } 310128266Speter else { 311128266Speter $cvsweb_base = "$CVSWEB_SCHEME://$vhost.$CVSWEB_DOMAIN:$CVSWEB_PORT/$CVSWEB_URI"; 312128266Speter } 313128266Speter if ($SEND_URL eq "true") { 314128266Speter $diff .= $cvsweb_base . join("/", @path) . "/$file"; 315128266Speter } 316128266Speter 317128266Speter # 318128266Speter # If this is a binary file, don't try to report a diff; not only is 319128266Speter # it meaningless, but it also screws up some mailers. We rely on 320128266Speter # Perl's 'is this binary' algorithm; it's pretty good. But not 321128266Speter # perfect. 322128266Speter # 323128266Speter if (($file =~ /\.(?:pdf|gif|jpg|mpg)$/i) || (-B $file)) { 324128266Speter if ($SEND_URL eq "true") { 325128266Speter $diff .= "?rev=$rev&content-type=text/x-cvsweb-markup\n\n"; 326128266Speter } 327128266Speter if ($SEND_DIFF eq "true") { 328128266Speter $diff .= "\t<<Binary file>>\n\n"; 329128266Speter } 330128266Speter } 331128266Speter else { 332128266Speter # 333128266Speter # Get the differences between this and the previous revision, 334128266Speter # being aware that new files always have revision '1.1' and 335128266Speter # new branches always end in '.n.1'. 336128266Speter # 337128266Speter if ($rev =~ /^(.*)\.([0-9]+)$/) { 338128266Speter $prev = $2 - 1; 339128266Speter $prev_rev = $1 . '.' . $prev; 340128266Speter 341128266Speter $prev_rev =~ s/\.[0-9]+\.0$//;# Truncate if first rev on branch 342128266Speter 343128266Speter if ($rev eq '1.1') { 344128266Speter if ($SEND_URL eq "true") { 345128266Speter $diff .= "?rev=$rev&content-type=text/x-cvsweb-markup\n\n"; 346128266Speter } 347128266Speter if ($SEND_DIFF eq "true") { 348128266Speter open(DIFF, "-|") 349128266Speter || exec "$cvsbin/cvs", '-Qn', 'update', '-p', '-r1.1', 350128266Speter '--', $file; 351128266Speter $diff .= "Index: $file\n==================================" 352128266Speter . "=================================\n"; 353128266Speter } 354128266Speter } 355128266Speter else { 356128266Speter if ($SEND_URL eq "true") { 357128266Speter $diff .= ".diff?r1=$prev_rev&r2=$rev\n\n"; 358128266Speter } 359128266Speter if ($SEND_DIFF eq "true") { 360128266Speter $diff .= "(In the diff below, changes in quantity " 361128266Speter . "of whitespace are not shown.)\n\n"; 362128266Speter open(DIFF, "-|") 363128266Speter || exec "$cvsbin/cvs", '-Qn', 'diff', "$difftype", 364128266Speter '-b', "-r$prev_rev", "-r$rev", '--', $file; 365128266Speter } 366128266Speter } 367128266Speter 368128266Speter if ($SEND_DIFF eq "true") { 369128266Speter while (<DIFF>) { 370128266Speter $diff .= $_; 371128266Speter } 372128266Speter close(DIFF); 373128266Speter } 374128266Speter $diff .= "\n\n"; 375128266Speter } 376128266Speter } 377128266Speter 378128266Speter &append_line($out, sprintf("%-9s%-12s%s%s", $rev, $delta, 379128266Speter $rcsfile, $diff)); 380128266Speter } 381128266Speter} 382128266Speter 383128266Speter 38481404Spetersub build_header { 38581404Speter local($header); 386128266Speter delete $ENV{'TZ'}; 387128266Speter local($sec,$min,$hour,$mday,$mon,$year) = localtime(time); 388128266Speter 389128266Speter $header = sprintf(" User: %-8s\n Date: %02d/%02d/%02d %02d:%02d:%02d", 390128266Speter $cvs_user, $year%100, $mon+1, $mday, 391128266Speter $hour, $min, $sec); 392128266Speter# $header = sprintf("%-8s %02d/%02d/%02d %02d:%02d:%02d", 393128266Speter# $login, $year%100, $mon+1, $mday, 394128266Speter# $hour, $min, $sec); 39581404Speter} 39681404Speter 397128266Speter# !!! Destination Mailing-list and history file mappings here !!! 39881404Speter 399128266Speter#sub mlist_map 400128266Speter#{ 401128266Speter# local($path) = @_; 402175261Sobrien# my $domain = "nongnu.org"; 403128266Speter# 404128266Speter# if ($path =~ /^([^\/]+)/) { 405128266Speter# return "cvs\@$1.$domain"; 406128266Speter# } else { 407128266Speter# return "cvs\@$domain"; 408128266Speter# } 409128266Speter#} 41081404Speter 411128266Spetersub derive_subject_from_changes_file () 412128266Speter{ 413128266Speter my $subj = ""; 41481404Speter 415128266Speter for ($i = 0; ; $i++) 416128266Speter { 417128266Speter open (CH, "<$CHANGED_FILE.$i.$id.$cvs_user") or last; 41881404Speter 419128266Speter while (my $change = <CH>) 420128266Speter { 421128266Speter # A changes file looks like this: 422128266Speter # 423128266Speter # src foo.c newfile.html 424128266Speter # www index.html project_nav.html 425128266Speter # 426128266Speter # Each line is " Dir File1 File2 ..." 427128266Speter # We only care about Dir, since the subject line should 428128266Speter # summarize. 429128266Speter 430128266Speter $change =~ s/^[ \t]*//; 431128266Speter $change =~ /^([^ \t]+)[ \t]*/; 432128266Speter my $dir = $1; 433128266Speter # Fold to rightmost directory component 434128266Speter $dir =~ /([^\/]+)$/; 435128266Speter $dir = $1; 436128266Speter if ($subj eq "") { 437128266Speter $subj = $dir; 438128266Speter } else { 439128266Speter $subj .= ", $dir"; 440128266Speter } 44181404Speter } 442128266Speter close (CH); 443128266Speter } 44481404Speter 445128266Speter if ($subj ne "") { 446128266Speter $subj = "MODIFIED: $subj ..."; 447128266Speter } 448128266Speter else { 449128266Speter # NPM: See if there's any file-addition notifications. 450128266Speter my $added = &read_line_nodie("$ADDED_FILE.$i.$id.$cvs_user"); 451128266Speter if ($added ne "") { 452128266Speter $subj .= "ADDED: $added "; 453128266Speter } 454128266Speter 455128266Speter# print "derive_subject_from_changes_file().. added== $added \n"; 456128266Speter 457128266Speter ## NPM: See if there's any file-removal notications. 458128266Speter my $removed = &read_line_nodie("$REMOVED_FILE.$i.$id.$cvs_user"); 459128266Speter if ($removed ne "") { 460128266Speter $subj .= "REMOVED: $removed "; 461128266Speter } 462128266Speter 463128266Speter# print "derive_subject_from_changes_file().. removed== $removed \n"; 464128266Speter 465128266Speter ## NPM: See if there's any branch notifications. 466128266Speter my $branched = &read_line_nodie("$BRANCH_FILE.$i.$id.$cvs_user"); 467128266Speter if ($branched ne "") { 468128266Speter $subj .= "BRANCHED: $branched"; 469128266Speter } 470128266Speter 471128266Speter# print "derive_subject_from_changes_file().. branched== $branched \n"; 472128266Speter 473128266Speter ## NPM: DEFAULT: DIRECTORY CREATION (c.f. "Check for a new directory first" in main mody) 474128266Speter if ($subj eq "") { 475128266Speter my $subject = join("/", @path); 476128266Speter $subj = "NEW: $subject"; 477128266Speter } 478128266Speter } 47981404Speter 480128266Speter return $subj; 481128266Speter} 48281404Speter 483128266Spetersub mail_notification 484128266Speter{ 485128266Speter local($addr_list, @text) = @_; 486128266Speter local($mail_to); 487128266Speter 488128266Speter my $subj = &derive_subject_from_changes_file (); 489128266Speter 490175261Sobrien if ($EMULATE_LOCAL_MAIL_USER ne "") { 491128266Speter $MAIL_FROM = "$cvs_user\@$EMULATE_LOCAL_MAIL_USER"; 49281404Speter } 49381404Speter 494128266Speter $mail_to = join(", ", @{$addr_list}); 49581404Speter 496128266Speter print "Mailing the commit message to $mail_to (from $MAIL_FROM)\n"; 497128266Speter 498128266Speter $ENV{'MAILUSER'} = $MAIL_FROM; 499128266Speter # Commented out on hocus, so comment it out here. -kff 500128266Speter # $ENV{'QMAILINJECT'} = 'f'; 501128266Speter 502128266Speter open(MAIL, "$MAIL_CMD -f$MAIL_FROM"); 503128266Speter print MAIL "From: $MAIL_FROM\n"; 504128266Speter print MAIL "To: $mail_to\n"; 505128266Speter print MAIL "Subject: $SUBJECT_PRE $subj\n\n"; 506128266Speter print(MAIL join("\n", @text)); 50781404Speter close(MAIL); 508128266Speter# print "Mailing the commit message to $MAIL_TO...\n"; 509128266Speter# 510128266Speter# #added by jrobbins@collab.net 1999/12/15 511128266Speter# # attempt to get rid of anonymous 512128266Speter# $ENV{'MAILUSER'} = 'commitlogger'; 513128266Speter# $ENV{'QMAILINJECT'} = 'f'; 514128266Speter# 515128266Speter# open(MAIL, "| /var/qmail/bin/qmail-inject"); 516128266Speter# print(MAIL "To: $MAIL_TO\n"); 517128266Speter# print(MAIL "Subject: cvs commit: $ARGV[0]\n"); 518128266Speter# print(MAIL join("\n", @text)); 519128266Speter# close(MAIL); 52081404Speter} 52181404Speter 522128266Speter## process the command line arguments sent to this script 523128266Speter## it returns an array of files, %s, sent from the loginfo 524128266Speter## command 525128266Spetersub process_argv 526128266Speter{ 527128266Speter local(@argv) = @_; 528128266Speter local(@files); 529128266Speter local($arg); 530128266Speter print "Processing log script arguments...\n"; 53181404Speter 532128266Speter while (@argv) { 533128266Speter $arg = shift @argv; 534128266Speter 535128266Speter if ($arg eq '-u') { 536128266Speter $cvs_user = shift @argv; 537128266Speter } else { 538128266Speter ($donefiles) && die "Too many arguments!\n"; 539128266Speter $donefiles = 1; 540128266Speter $ARGV[0] = $arg; 541128266Speter @files = split(' ', $arg); 542128266Speter } 543128266Speter } 544128266Speter return @files; 54581404Speter} 54681404Speter 547128266Speter 548128266Speter############################################################# 54981404Speter# 550128266Speter# Main Body 55181404Speter# 552128266Speter############################################################ 55381404Speter# 554128266Speter# Setup environment 55581404Speter# 556128266Speterumask (002); 55781404Speter 558128266Speter# Connect to the database 559128266Speter$cvsbin = "/usr/bin"; 56081404Speter 56181404Speter# 562128266Speter# Initialize basic variables 563128266Speter# 564128266Speter$id = getpgrp(); 565128266Speter$state = $STATE_NONE; 566128266Speter$cvs_user = $ENV{'USER'} || getlogin || (getpwuid($<))[0] || sprintf("uid#%d",$<); 567128266Speter@files = process_argv(@ARGV); 56881404Speter@path = split('/', $files[0]); 56981404Speterif ($#path == 0) { 57081404Speter $dir = "."; 57181404Speter} else { 572128266Speter $dir = join('/', @path[1..$#path]); 57381404Speter} 574128266Speter#print("ARGV - ", join(":", @ARGV), "\n"); 575128266Speter#print("files - ", join(":", @files), "\n"); 576128266Speter#print("path - ", join(":", @path), "\n"); 577128266Speter#print("dir - ", $dir, "\n"); 578128266Speter#print("id - ", $id, "\n"); 57981404Speter 58081404Speter# 581128266Speter# Map the repository directory to an email address for commitlogs to be sent 582128266Speter# to. 58381404Speter# 584128266Speter#$mlist = &mlist_map($files[0]); 58581404Speter 586128266Speter########################## 58781404Speter# 588128266Speter# Check for a new directory first. This will always appear as a 589128266Speter# single item in the argument list, and an empty log message. 59081404Speter# 591128266Speterif ($ARGV[0] =~ /New directory/) { 592128266Speter $header = &build_header; 59381404Speter @text = (); 594128266Speter push(@text, $header); 59581404Speter push(@text, ""); 596128266Speter push(@text, " ".$ARGV[0]); 597128266Speter &mail_notification([ $mlist ], @text); 59881404Speter exit 0; 59981404Speter} 60081404Speter 601128266Speter# 60281404Speter# Iterate over the body of the message collecting information. 60381404Speter# 60481404Speterwhile (<STDIN>) { 605128266Speter chomp; # Drop the newline 606128266Speter if (/^Revision\/Branch:/) { 607128266Speter s,^Revision/Branch:,,; 608128266Speter push (@branch_lines, split); 609128266Speter next; 61081404Speter } 611128266Speter# next if (/^[ \t]+Tag:/ && $state != $STATE_LOG); 61281404Speter if (/^Modified Files/) { $state = $STATE_CHANGED; next; } 61381404Speter if (/^Added Files/) { $state = $STATE_ADDED; next; } 61481404Speter if (/^Removed Files/) { $state = $STATE_REMOVED; next; } 61581404Speter if (/^Log Message/) { $state = $STATE_LOG; next; } 616128266Speter s/[ \t\n]+$//; # delete trailing space 61781404Speter 618128266Speter push (@changed_files, split) if ($state == $STATE_CHANGED); 619128266Speter push (@added_files, split) if ($state == $STATE_ADDED); 620128266Speter push (@removed_files, split) if ($state == $STATE_REMOVED); 621128266Speter if ($state == $STATE_LOG) { 622128266Speter if (/^PR:$/i || 623128266Speter /^Reviewed by:$/i || 624128266Speter /^Submitted by:$/i || 625128266Speter /^Obtained from:$/i) { 626128266Speter next; 627128266Speter } 628128266Speter push (@log_lines, $_); 629128266Speter } 63081404Speter} 63181404Speter 632128266Speter# 63381404Speter# Strip leading and trailing blank lines from the log message. Also 63481404Speter# compress multiple blank lines in the body of the message down to a 63581404Speter# single blank line. 636128266Speter# (Note, this only does the mail and changes log, not the rcs log). 63781404Speter# 63881404Speterwhile ($#log_lines > -1) { 63981404Speter last if ($log_lines[0] ne ""); 64081404Speter shift(@log_lines); 64181404Speter} 64281404Speterwhile ($#log_lines > -1) { 64381404Speter last if ($log_lines[$#log_lines] ne ""); 64481404Speter pop(@log_lines); 64581404Speter} 64681404Speterfor ($i = $#log_lines; $i > 0; $i--) { 64781404Speter if (($log_lines[$i - 1] eq "") && ($log_lines[$i] eq "")) { 648128266Speter splice(@log_lines, $i, 1); 64981404Speter } 65081404Speter} 65181404Speter 65281404Speter# 653128266Speter# Find the log file that matches this log message 654128266Speter# 65581404Speterfor ($i = 0; ; $i++) { 656128266Speter last if (! -e "$LOG_FILE.$i.$id.$cvs_user"); 657128266Speter @text = &read_logfile("$LOG_FILE.$i.$id.$cvs_user", ""); 658128266Speter last if ($#text == -1); 659128266Speter last if (join(" ", @log_lines) eq join(" ", @text)); 66081404Speter} 66181404Speter 662128266Speter# 66381404Speter# Spit out the information gathered in this pass. 66481404Speter# 665128266Speter&write_logfile("$LOG_FILE.$i.$id.$cvs_user", @log_lines); 666128266Speter&append_to_file("$BRANCH_FILE.$i.$id.$cvs_user", $dir, @branch_lines); 667128266Speter&append_to_file("$ADDED_FILE.$i.$id.$cvs_user", $dir, @added_files); 668128266Speter&append_to_file("$CHANGED_FILE.$i.$id.$cvs_user", $dir, @changed_files); 669128266Speter&append_to_file("$REMOVED_FILE.$i.$id.$cvs_user", $dir, @removed_files); 670128266Speter&append_line("$MLIST_FILE.$i.$id.$cvs_user", $mlist); 671128266Speterif ($rcsidinfo) { 672128266Speter &change_summary("$SUMMARY_FILE.$i.$id.$cvs_user", (@changed_files, @added_files)); 673128266Speter} 67481404Speter 675128266Speter# 67681404Speter# Check whether this is the last directory. If not, quit. 67781404Speter# 678128266Speterif (-e "$LAST_FILE.$id.$cvs_user") { 679128266Speter $_ = &read_line("$LAST_FILE.$id.$cvs_user"); 680128266Speter $tmpfiles = $files[0]; 681128266Speter $tmpfiles =~ s,([^a-zA-Z0-9_/]),\\$1,g; 682128266Speter if (! grep(/$tmpfiles$/, $_)) { 683128266Speter print "More commits to come...\n"; 684128266Speter exit 0 685128266Speter } 68681404Speter} 68781404Speter 68881404Speter# 68981404Speter# This is it. The commits are all finished. Lump everything together 69081404Speter# into a single message, fire a copy off to the mailing list, and drop 69181404Speter# it on the end of the Changes file. 69281404Speter# 693128266Speter$header = &build_header; 69481404Speter 69581404Speter# 69681404Speter# Produce the final compilation of the log messages 69781404Speter# 69881404Speter@text = (); 699128266Speter@mlist_list = (); 700128266Speterpush(@text, $header); 70181404Speterpush(@text, ""); 70281404Speterfor ($i = 0; ; $i++) { 703128266Speter last if (! -e "$LOG_FILE.$i.$id.$cvs_user"); 704128266Speter push(@text, &read_file("$BRANCH_FILE.$i.$id.$cvs_user", "Branch:")); 705128266Speter push(@text, &read_file("$CHANGED_FILE.$i.$id.$cvs_user", "Modified:")); 706128266Speter push(@text, &read_file("$ADDED_FILE.$i.$id.$cvs_user", "Added:")); 707128266Speter push(@text, &read_file("$REMOVED_FILE.$i.$id.$cvs_user", "Removed:")); 708128266Speter push(@text, " Log:"); 709128266Speter push(@text, &read_logfile("$LOG_FILE.$i.$id.$cvs_user", " ")); 710128266Speter push(@mlist_list, &read_file_lines("$MLIST_FILE.$i.$id.$cvs_user")); 711128266Speter if ($rcsidinfo == 2) { 712128266Speter if (-e "$SUMMARY_FILE.$i.$id.$cvs_user") { 713128266Speter push(@text, " "); 714128266Speter push(@text, " Revision Changes Path"); 715128266Speter push(@text, &read_logfile("$SUMMARY_FILE.$i.$id.$cvs_user", " ")); 716128266Speter } 71781404Speter } 718128266Speter push(@text, ""); 71981404Speter} 72081404Speter 72181404Speter# 722128266Speter# Now generate the extra info for the mail message.. 723128266Speter# 724128266Speterif ($rcsidinfo == 1) { 725128266Speter $revhdr = 0; 726128266Speter for ($i = 0; ; $i++) { 727128266Speter last if (! -e "$LOG_FILE.$i.$id.$cvs_user"); 728128266Speter if (-e "$SUMMARY_FILE.$i.$id.$cvs_user") { 729128266Speter if (!$revhdr++) { 730128266Speter push(@text, "Revision Changes Path"); 731128266Speter } 732128266Speter push(@text, &read_logfile("$SUMMARY_FILE.$i.$id.$cvs_user", "")); 733128266Speter } 734128266Speter } 735128266Speter if ($revhdr) { 736128266Speter push(@text, ""); # consistancy... 737128266Speter } 73881404Speter} 73981404Speter 740128266Speter%mlist_hash = (); 74181404Speter 742128266Speterforeach (@mlist_list) { $mlist_hash{ $_ } = 1; } 74381404Speter 74481404Speter# 745128266Speter# Mail out the notification. 746128266Speter# 747128266Speter&mail_notification([ keys(%mlist_hash) ], @text); 748128266Speter&cleanup_tmpfiles; 74981404Speterexit 0; 750