Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[cdt-patch] Re: [cdt-dev] commit list

Sebastien> Tom, can you first email the scripts so we can figure out
Sebastien> how to hook it into the cvs server?

I went ahead and made a patch against the CDT CVSROOT.
A couple notes:

* Search for FIXME in the patch to see where the name of the mailing
  list should be inserted

* Make sure log_accum and commit_prep are chmod +x before `cvs add'ing
  them.

* I looked up the URL, so this patch puts cvsweb URLs into the commit
  messages

* If your perl isn't in /usr/bin, you'll have to change the scripts a
  little.  (I don't know what kind of box dev.eclipse.org is...)

I'm happy to help with debugging if required.

Tom

Index: checkoutlist
===================================================================
RCS file: /home/tools/CVSROOT/checkoutlist,v
retrieving revision 1.1
diff -u -r1.1 checkoutlist
--- checkoutlist 6 Dec 2001 18:45:46 -0000 1.1
+++ checkoutlist 8 Oct 2002 20:59:52 -0000
@@ -11,3 +11,5 @@
 #	[<whitespace>]<filename><whitespace><error message><end-of-line>
 #
 # comment lines begin with '#'
+log_accum	CVS commits will continue to use the old script
+commit_prep	CVS commits will continue to use the old script
Index: commit_prep
===================================================================
RCS file: commit_prep
diff -N commit_prep
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ commit_prep 8 Oct 2002 20:59:53 -0000
@@ -0,0 +1,249 @@
+#!/usr/bin/perl
+# -*-Perl-*-
+#
+# $Id: commit_prep,v 1.7 2001/12/07 08:59:38 jsm Exp $
+#
+# Perl filter to handle pre-commit checking of files.  This program
+# records the last directory where commits will be taking place for
+# use by the log_accum.pl script.  For new files, it forces the
+# existence of a RCS "Id" keyword in the first ten lines of the file.
+# For existing files, it checks version number in the "Id" line to
+# prevent losing changes because an old version of a file was copied
+# into the direcory.
+#
+# Possible future enhancements:
+#
+#    Check for cruft left by unresolved conflicts.  Search for
+#    "^<<<<<<<$", "^-------$", and "^>>>>>>>$".
+#
+#    Look for a copyright and automagically update it to the
+#    current year.  [[ bad idea!  -- woods ]]
+#
+#
+# Contributed by David Hampton <hampton@xxxxxxxxx>
+#
+# Hacked on lots by Greg A. Woods <woods@xxxxxxx>
+
+#
+#	Configurable options
+#
+
+# Constants (remember to protect strings from RCS keyword substitution)
+#
+$ENTRIES       = "CVS/Entries";
+
+$TMPDIR = "/sourceware/cvs-tmp";
+
+# Patterns to find $Log keywords in files
+#
+$LogString1 = "\\\$\\Log: .* \\\$";
+$LogString2 = "\\\$\\Log\\\$";
+$NoLog = "%s - contains an RCS \$Log keyword.  It must not!\n";
+
+# pattern to match an RCS Id keyword line with an existing ID
+#
+$IDstring = "\"@\\(#\\)[^:]*:.*\\\$\Id: .*\\\$\"";
+$NoId = "
+%s - Does not contain a properly formatted line with the keyword \"Id:\".
+	I.e. no lines match \"" . $IDstring . "\".
+	Please see the template files for an example.\n";
+
+# pattern to match an RCS Id keyword line for a new file (i.e. un-expanded)
+#
+$NewId = "\"@(#)[^:]*:.*\\$\Id\\$\"";
+
+$NoName = "
+%s - The ID line should contain only \"@(#)module/path:\$Name\$:\$\Id\$\"
+	for a newly created file.\n";
+
+$BadName = "
+%s - The file name '%s' in the ID line does not match
+	the actual filename.\n";
+
+$BadVersion = "
+%s - How dare you!!!  You replaced your copy of the file '%s',
+	which was based upon version %s, with an %s version based
+	upon %s.  Please move your '%s' out of the way, perform an
+	update to get the current version, and them merge your changes
+	into that file, then try the commit again.\n";
+
+#
+#	Subroutines
+#
+
+sub write_line {
+    local($filename, $line) = @_;
+    open(FILE, ">$filename") || die("Cannot open $filename: $!\n");
+    print(FILE $line, "\n");
+    close(FILE);
+}
+
+sub check_version {
+    local($i, $id, $rname, $version);
+    local($filename, $cvsversion) = @_;
+
+    open(FILE, "<$filename") || return(0);
+
+    @all_lines = ();
+    $idpos = -1;
+    $newidpos = -1;
+    for ($i = 0; <FILE>; $i++) {
+	chop;
+	push(@all_lines, $_);
+	if ($_ =~ /$IDstring/) {
+	    $idpos = $i;
+	}
+	if ($_ =~ /$NewId/) {
+	    $newidpos = $i;
+	}
+    }
+
+    if (grep(/$LogString1/, @all_lines) || grep(/$LogString2/, @all_lines)) {
+	print STDERR sprintf($NoLog, $filename);
+	return(1);
+    }
+
+    if ($debug != 0) {
+	print STDERR sprintf("file = %s, version = %d.\n", $filename, $cvsversion{$filename});
+    }
+
+    if ($cvsversion{$filename} == 0) {
+	if ($newidpos != -1 && $all_lines[$newidpos] !~ /$NewId/) {
+	    print STDERR sprintf($NoName, $filename);
+	    return(1);
+	}
+	return(0);
+    }
+
+    if ($idpos == -1) {
+	print STDERR sprintf($NoId, $filename);
+	return(1);
+    }
+
+    $line = $all_lines[$idpos];
+    $pos = index($line, "Id: ");
+    if ($debug != 0) {
+	print STDERR sprintf("%d in '%s'.\n", $pos, $line);
+    }
+    ($id, $rname, $version) = split(' ', substr($line, $pos));
+    if ($rname ne "$filename,v") {
+	print STDERR sprintf($BadName, $filename, substr($rname, 0, length($rname)-2));
+	return(1);
+    }
+    if ($cvsversion{$filename} < $version) {
+	print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename},
+			     "newer", $version, $filename);
+	return(1);
+    }
+    if ($cvsversion{$filename} > $version) {
+	print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename},
+			     "older", $version, $filename);
+	return(1);
+    }
+    return(0);
+}
+
+#
+#	Main Body	
+#
+
+$id = getpgrp();		# You *must* use a shell that does setpgrp()!
+
+# Check each file (except dot files) for an RCS "Id" keyword.
+#
+$check_id = 0;
+
+# Record the directory for later use by the log_accumulate stript.
+#
+$record_directory = 0;
+
+# Default temp file prefix.
+$temp_name = 'temp';
+
+# parse command line arguments
+#
+while (@ARGV) {
+    $arg = shift @ARGV;
+
+    if ($arg eq '-d') {
+	$debug = 1;
+	print STDERR "Debug turned on...\n";
+    } elsif ($arg eq '-c') {
+	$check_id = 1;
+    } elsif ($arg eq '-r') {
+	$record_directory = 1;
+    } elsif ($arg eq '-T') {
+	$temp_name = shift @ARGV;
+    } elsif ($arg eq '-L') {
+	$log_name = shift @ARGV;
+    } else {
+	push(@files, $arg);
+    }
+}
+
+$LAST_FILE     = sprintf ("$TMPDIR/#%s.lastdir", $temp_name);
+
+$directory = shift @files;
+
+if ($debug != 0) {
+    print STDERR "dir   - ", $directory, "\n";
+    print STDERR "files - ", join(":", @files), "\n";
+    print STDERR "id    - ", $id, "\n";
+}
+
+# Keep a record of all files modified, and the times they were modified,
+# for optimized remote copying (e.g. periodically rsyncing over only
+# the files which have been modified).
+
+if (defined ($log_name)) {
+    if ($directory =~ m#^$ENV{"CVSROOT"}([/.])*/(.*)#) {
+        $print_dir = $2;
+    } else {
+        $print_dir = $directory;
+    }
+        
+    $now = time ();
+    if (open LOGFILE, ">> $log_name") {
+        foreach (@files) {
+            print LOGFILE "$now $print_dir/$_\n";
+        }
+        close (LOGFILE);
+        if ($debug != 0) {
+            print STDERR "Wrote commit log entries to $log_name\n";
+        }
+    }
+}
+
+# Suck in the CVS/Entries file
+#
+open(ENTRIES, $ENTRIES) || die("Cannot open $ENTRIES: $!\n");
+while (<ENTRIES>) {
+    local($filename, $version) = split('/', substr($_, 1));
+    $cvsversion{$filename} = $version;
+}
+
+# Now check each file name passed in, except for dot files.  Dot files
+# are considered to be administrative files by this script.
+#
+if ($check_id != 0) {
+    $failed = 0;
+    foreach $arg (@files) {
+	if (index($arg, ".") == 0) {
+	    next;
+	}
+	$failed += &check_version($arg);
+    }
+    if ($failed) {
+	print STDERR "\n";
+	exit(1);
+    }
+}
+
+# Record this directory as the last one checked.  This will be used
+# by the log_accumulate script to determine when it is processing
+# the final directory of a multi-directory commit.
+#
+if ($record_directory != 0) {
+    &write_line("$LAST_FILE.$id", $directory);
+}
+exit(0);
Index: commitinfo
===================================================================
RCS file: /home/tools/CVSROOT/commitinfo,v
retrieving revision 1.1
diff -u -r1.1 commitinfo
--- commitinfo 6 Dec 2001 18:45:46 -0000 1.1
+++ commitinfo 8 Oct 2002 20:59:53 -0000
@@ -13,3 +13,5 @@
 #
 # If the name "ALL" appears as a regular expression it is always used
 # in addition to the first matching regex or "DEFAULT".
+
+DEFAULT		/home/tools/CVSROOT/commit_prep -T cdt -r
Index: log_accum
===================================================================
RCS file: log_accum
diff -N log_accum
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ log_accum 8 Oct 2002 20:59:56 -0000
@@ -0,0 +1,946 @@
+#!/usr/bin/perl
+# -*-Perl-*-
+#
+# Perl filter to handle the log messages from the checkin of files in
+# a directory.  This script will group the lists of files by log
+# message, and mail a single consolidated log message at the end of
+# the commit.
+#
+# This file assumes a pre-commit checking program that leaves the
+# names of the first and last commit directories in a temporary file.
+#
+# Contributed by David Hampton <hampton@xxxxxxxxx>
+#
+# hacked greatly by Greg A. Woods <woods@xxxxxxx>
+
+# Usage: log_accum.pl [-d] [-s] [-M module] [[-m mailto] ...] [-f logfile]
+#	-d		- turn on debugging
+#       -G database     - interface to Gnats
+#	-m mailto	- send mail to "mailto" (multiple)
+#	-M modulename	- set module name to "modulename"
+#	-f logfile	- write commit messages to logfile too
+#	-s		- *don't* run "cvs status -v" for each file
+#       -T text         - use TEXT in temp file names.
+#       -C name         - Generate cvsweb URLS; must be run using %{sVv}
+#                         format string.
+#       -U URL          - Base URL for cvsweb if -C option (above) is used.
+#       -D DOMAIN       - Domain from which mail should appear
+#       -l              - Update list of modified files in CVSROOT/commits.  
+#                         Must be run using %{sVv}.
+
+use POSIX;
+
+#
+#	Configurable options
+#
+
+$TMPDIR = "/sourceware/cvs-tmp";
+
+# Set this to something that takes "-s"
+$MAILER	       = "/usr/bin/Mail";
+
+# Used with sprintf to form name of Gnats root directory.  Potential
+# PR info is appended to see if PR actually exists.  %s argument comes
+# from -G option.
+$GNATS_ROOT_FORMAT = "/sourceware/gnats/%s-db";
+
+# Base name of cvsweb specification.
+$CVSWEB_URL = "http://sources.redhat.com/cgi-bin/cvsweb.cgi/";;
+
+# Constants (don't change these!)
+#
+$STATE_NONE    = 0;
+$STATE_CHANGED = 1;
+$STATE_ADDED   = 2;
+$STATE_REMOVED = 3;
+$STATE_LOG     = 4;
+
+#
+#	Subroutines
+#
+
+sub set_temp_vars {
+    local ($name) = @_;
+
+    $LAST_FILE     = sprintf ("$TMPDIR/#%s.lastdir", $name);
+
+    $CHANGED_FILE  = sprintf ("$TMPDIR/#%s.files.changed", $name);
+    $ADDED_FILE    = sprintf ("$TMPDIR/#%s.files.added", $name);
+    $REMOVED_FILE  = sprintf ("$TMPDIR/#%s.files.removed", $name);
+    $LOG_FILE      = sprintf ("$TMPDIR/#%s.files.log", $name);
+    $URL_FILE      = sprintf ("$TMPDIR/#%s.files.urls", $name);
+    $COMMITS_FILE  = sprintf ("$TMPDIR/#%s.files.commits", $name);
+
+    # Quote for use in a regexp.
+    ($FILE_PREFIX   = sprintf ("#%s.files", $name)) =~ s/(\W)/\\$1/g;
+}
+
+sub cleanup_tmpfiles {
+    local($wd, @files);
+
+    $wd = `pwd`;
+    chdir("$TMPDIR") || die("Can't chdir(\"$TMPDIR\")\n");
+    opendir(DIR, ".");
+    push(@files, grep(/^$FILE_PREFIX\..*\.$id$/, readdir(DIR)));
+    closedir(DIR);
+    foreach (@files) {
+	unlink $_;
+    }
+    unlink $LAST_FILE . "." . $id;
+
+    chdir($wd);
+}
+
+sub write_logfile {
+    local($filename, @lines) = @_;
+
+    open(FILE, ">$filename") || die("Cannot open log file $filename.\n");
+    print FILE join("\n", @lines), "\n";
+    close(FILE);
+}
+
+sub format_names {
+    local($dir, @files) = @_;
+    local(@lines);
+
+    if ($dir =~ /^\.\//) {
+	$dir = $';
+    }
+    if ($dir =~ /\/$/) {
+	$dir = $`;
+    }
+    if ($dir eq "") {
+	$dir = ".";
+    }
+
+    $format = "\t%-" . sprintf("%d", length($dir) > 15 ? length($dir) : 15) . "s%s ";
+
+    $lines[0] = sprintf($format, $dir, ":");
+
+    if ($debug) {
+	print STDERR "format_names(): dir = ", $dir, "; files = ", join(":", @files), ".\n";
+    }
+    foreach $file (@files) {
+	if (length($lines[$#lines]) + length($file) > 65) {
+	    $lines[++$#lines] = sprintf($format, " ", " ");
+	}
+	$lines[$#lines] .= $file . " ";
+    }
+
+    @lines;
+}
+
+sub format_lists {
+    local(@lines) = @_;
+    local(@text, @files, $lastdir);
+
+    if ($debug) {
+	print STDERR "format_lists(): ", join(":", @lines), "\n";
+    }
+    @text = ();
+    @files = ();
+    $lastdir = shift @lines;	# first thing is always a directory
+    if ($lastdir !~ /.*\/$/) {
+	die("Damn, $lastdir doesn't look like a directory!\n");
+    }
+    foreach $line (@lines) {
+	if ($line =~ /.*\/$/) {
+	    push(@text, &format_names($lastdir, @files));
+	    $lastdir = $line;
+	    @files = ();
+	} else {
+	    push(@files, $line);
+	}
+    }
+    push(@text, &format_names($lastdir, @files));
+
+    @text;
+}
+
+sub accum_subject {
+    local(@lines) = @_;
+    local(@files, $lastdir);
+
+    $lastdir = shift @lines;	# first thing is always a directory
+    @files = ($lastdir);
+    if ($lastdir !~ /.*\/$/) {
+	die("Damn, $lastdir doesn't look like a directory!\n");
+    }
+    foreach $line (@lines) {
+	if ($line =~ /.*\/$/) {
+	    $lastdir = $line;
+	    push(@files, $line);
+	} else {
+	    push(@files, $lastdir . $line);
+	}
+    }
+
+    @files;
+}
+
+sub compile_subject {
+    local(@files) = @_;
+    local($text, @a, @b, @c, $dir, $topdir, $topdir_length);
+
+    # find the highest common directory
+    $dir = '-';
+    do {
+	$topdir = $dir;
+	foreach $file (@files) {
+	    if ($file =~ /.*\/$/) {
+		if ($dir eq '-') {
+		    $dir = $file;
+		} else {
+		    if (index($dir,$file) == 0) {
+			$dir = $file;
+		    } elsif (index($file,$dir) != 0) {
+			@a = split /\//,$file;
+			@b = split /\//,$dir;
+			@c = ();
+			CMP: while ($#a > 0 && $#b > 0) {
+			    if ($a[0] eq $b[0]) {
+				push(@c, $a[0]);
+				shift @a;
+				shift @b;
+			    } else {
+				last CMP;
+			    }
+			}
+			$dir = join('/',@c) . '/';
+		    }
+		}
+	    }
+	}
+    } until $dir eq $topdir;
+
+    # strip out directories and the common prefix topdir.
+    chop $topdir;
+
+    if ($topdir eq "") {
+        @c = $modulename;
+        $topdir_length = 0;
+    } else {
+        if ($topdir eq ".") {
+            @c = $modulename;
+        } else {
+            @c = ($modulename . '/' . $topdir);
+        }
+        $topdir_length = length ($topdir) + 1;
+    }
+
+    foreach $file (@files) {
+        if ($file !~ /.*\/$/) {
+            push(@c, substr($file, $topdir_length));
+        }
+    }
+
+    # put it together and limit the length.
+    $text = join(' ',@c);
+    if (length($text) > 50) {
+	$text = substr($text, 0, 46) . ' ...';
+    }
+
+    $text;
+}
+
+sub append_names_to_file {
+    local($filename, $dir, @files) = @_;
+
+    if (@files) {
+	open(FILE, ">>$filename") || die("Cannot open file $filename.\n");
+	if (defined ($dir)) {
+            print FILE $dir, "\n";
+        }
+	print FILE join("\n", @files), "\n";
+	close(FILE);
+    }
+}
+
+sub read_line {
+    local($line);
+    local($filename) = @_;
+
+    open(FILE, "<$filename") || die("Cannot open file $filename.\n");
+    $line = <FILE>;
+    close(FILE);
+    chop($line);
+    $line;
+}
+
+sub read_logfile {
+    local(@text);
+    local($filename, $leader) = @_;
+
+    open(FILE, "<$filename");
+    while (<FILE>) {
+	chop;
+	push(@text, $leader.$_);
+    }
+    close(FILE);
+    @text;
+}
+
+sub build_header {
+    local($header);
+    local($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
+    $header = sprintf("CVSROOT:\t%s\nModule name:\t%s\n",
+		      $cvsroot,
+		      $modulename);
+    if (defined($branch)) {
+	$header .= sprintf("Branch: \t%s\n",
+		      $branch);
+    }
+    $header .= sprintf("Changes by:\t%s@%s\t%04d-%02d-%02d %02d:%02d:%02d",
+		      $login, $hostdomain,
+		      $year + 1900, $mon+1, $mday,
+		      $hour, $min, $sec);
+}
+
+sub mail_notification {
+    local($name, $subject, @text) = @_;
+    open(MAIL, "| $MAILER -s \"$subject\" $name");
+    print MAIL join("\n", @text), "\n";
+    close(MAIL);
+}
+
+sub write_commitlog {
+    local($logfile, @text) = @_;
+
+    open(FILE, ">>$logfile");
+    print FILE join("\n", @text), "\n\n";
+    close(FILE);
+}
+
+# Return a list of all cvsweb URLs for this commit.
+sub generate_cvsweb_urls {
+    local ($dir, $branch, @files) = @_;
+    local (@sp, @result);
+    local ($start) = $CVSWEB_URL . $dir . '/';
+    local ($args) = '.diff?cvsroot=' . $cvsweb_name;
+    if ($branch ne '') {
+	$args .= '&only_with_tag=' . $branch;
+    }
+    local ($r1);
+    foreach (@files) {
+	# List is (FILE OLD-REV NEW-REV).
+	@sp = split (',');
+	$r1 = $sp[1];
+	if ($r1 eq 'NONE') {
+	    # This lets us make a diff corresponding to the first
+	    # revision.
+	    $r1 = '0';
+	}
+	push (@result, ($start . $sp[0] . $args
+			. '&r1=' . $sp[1] . '&r2=' . $sp[2]));
+    }
+    return @result;
+}
+
+######
+## cvs commits logging for processing by other programs
+##
+## Everything takes place in $CVSROOT/commits - as long as that dir is
+## writable and exists, the functions should handle the rest.
+######
+
+sub generate_modlist {
+   my $path = shift;
+   my $changed_files = shift;  # incl operation, but not what rev #
+   my $added_files = shift;
+   my $removed_files = shift;
+   my @filerevs = @_;          # incl revision #'s but not what op changed them
+
+   my @filelist = ();
+
+   if ($#changed_files >= 0) {
+     push @filelist, modlist_add_files ("chg", $path, $changed_files, 
+                                        \@filerevs);
+   }
+   if ($#added_files >= 0) {
+       push @filelist, modlist_add_files ("add", $path, $added_files, 
+                                          \@filerevs);
+   }
+   if ($#removed_files >= 0) {
+       push @filelist, modlist_add_files ("rm", $path, $removed_files, 
+                                          \@filerevs);
+   }
+
+   return @filelist;
+}
+
+sub modlist_add_files {
+   my ($type, $topdir, $filelist, $filerevs) = @_;
+
+   my $type_print = $type;
+   my @lines_to_add = ();
+
+   $topdir =~ s#^\./##;
+   $topdir =~ s#/$##;
+   $topdir =~ s#^\.$##;
+
+   if ($topdir eq "./" || $topdir eq ".") {
+      $topdir = "";
+   } else {
+      $topdir = $topdir . "/";
+   }
+
+   foreach $entry (@$filelist) {
+     my $revs = modlist_get_file_revs ($entry, $filerevs);
+     my $revstr = "NA NA";
+     if (defined ($revs)) {
+       $revstr = "@$revs[0] @$revs[1]";
+     }
+
+     if (defined ($branch)) {
+         $type_print = "${type},branch=$branch";
+     }
+     if ($type eq "rm") {
+       push @lines_to_add, "$type_print $revstr ${topdir}Attic/" . $entry;
+     }
+     push @lines_to_add, "$type_print $revstr $topdir" . $entry;
+  }
+
+  return @lines_to_add;
+}
+
+sub modlist_get_file_revs {
+   my $desired_filename = shift;
+   my $filerevs = shift;
+
+   my $filename = undef;
+   my $oldrev = "NONE";
+   my $newrev = "NONE";
+   my @revpair;
+
+   foreach (@$filerevs) {
+     if (m#^\Q${desired_filename}\E#) {
+       if (m/(.*),([0-9.NONE]*),([0-9.NONE]*)$/) {
+          $filename = $1;
+          $oldrev = $2;
+          $newrev = $3;
+       } elsif ($desired_filename eq $_) {
+          $filename = $_;
+       }
+     }
+   }
+
+   if (!defined ($filename)) {
+      return undef;
+   }
+
+   @revpair = ($oldrev, $newrev);
+   return \@revpair;
+}
+
+sub modlist_newdir {
+   my $dirname = shift;
+
+   my @filelist = ();
+
+   $dirname =~ s#^\./##;
+   $dirname =~ s#^/##;
+   $dirname =~ s#/$##;
+   $dirname = $dirname . "/";
+   
+   push @filelist, "newdir NA NA " . $dirname;
+   modlist_write_to_log (@filelist);
+}
+
+sub modlist_import {
+   my $parent_dir = shift;
+   my $text = shift;
+
+   my @filelist = ();
+
+   $parent_dir =~ s#/$##;
+   foreach (@$text) {
+      chomp;
+      if (m/^    ([UNC]) (.*)/) {
+          my $type = $1;
+          my $file = $2;
+          $file =~ s#^\./##;
+          $file =~ s#^/##;
+          push @filelist, "import,stat=$type NA NA " . $file;
+      }
+   }
+
+   modlist_write_to_log (@filelist);
+}
+
+# Add lines to the commit list logfile of the format
+# <EPOCH SECONDS> <USERNAME> <TYPE OF CMD> <OLDREV> <NEWREV> <FILENAME/DIRNAME>
+
+sub modlist_write_to_log {
+   my @files = @_;
+   my @lines = ();
+   my $now = time ();
+   my $month = sprintf ("%02d", (localtime)[4] + 1);
+   my $year = (localtime)[5] + 1900;
+
+   my $root_dir = "$cvsroot/CVSROOT/commits";
+   my $logdir = "$root_dir/commit-logs";
+   my $logfile = "$logdir/${year}-${month}";
+   my $plugins = "$root_dir/plugins";
+
+   foreach my $dir ("$root_dir", "$logdir")
+     {
+       if (! -d "$dir")
+         {
+           mkdir ("$dir", 0777) or warn "Unable to create commit-list log dir $dir";
+           chmod 0777, "$dir";
+         }
+     }
+
+# Remove "./" at the beg of filenames; add ",v" at the end of filenames,
+# add username/timestamp to each line for printing.
+
+   foreach my $f (@files) {
+       next if (!defined ($f) or $f eq "");
+       $f =~ s#^\./##;
+       $f =~ s# \./# #;
+       if ($f !~ m#/$# && $f !~ m#,v$#) {
+          $f = $f . ",v";
+       }
+       if ($f =~ m#(.*)/$#) {
+          $f = $1;
+       }
+       push @lines, "$now $login $f\n";
+   }
+
+## Save the commit lines to the main log file
+      
+   if (open LOG, ">> $logfile") {
+      foreach (@lines) {
+         print LOG;
+       }
+      close (LOG);
+      if (-o "$logfile") {
+         chmod 0666, "$logfile";
+      }
+   } else {
+     warn "Warning: Unable to write to $logfile !\n";
+   }
+
+## Run any plugin scripts and pass them the lines.
+
+   if (-f "$plugins" && open PLUGINS, "< $plugins") {
+     my $name;
+     while (<PLUGINS>) {
+       chomp;
+       next if m/^\s*#/;
+       next if (! -x $_);
+
+       do { $name = tmpnam(); } until sysopen 
+                                (TMP, $name, O_RDWR | O_CREAT | O_EXCL, 0600);
+       foreach (@lines) { print TMP; }
+       close (TMP);
+
+       open (OUTPUT, "$_ $name 1>&2|") or
+              warn "Warning: Unable to execute plugin '$_' at commit-time";
+       while (<OUTPUT>) { print; }
+       close (OUTPUT);
+       unlink "$name";
+     }
+     close (PLUGINS);
+   }
+
+}
+
+#
+#	Main Body
+#
+
+# Initialize basic variables
+#
+$debug = 0;
+$id = getpgrp();		# note, you *must* use a shell which does setpgrp()
+$state = $STATE_NONE;
+$login = $ENV{'USER'} || (getpwuid($<))[0] || "nobody";
+chop($hostname = `hostname`);
+$cvsroot = $ENV{'CVSROOT'};
+$do_status = 1;
+$modulename = "";
+$temp_name = "temp";
+$do_cvsweb = 0;
+$cvsweb_name = '';
+$do_modlist = 0;
+
+# parse command line arguments (file list is seen as one arg)
+#
+while (@ARGV) {
+    $arg = shift @ARGV;
+
+    if ($arg eq '-d') {
+	$debug = 1;
+	print STDERR "Debug turned on...\n";
+    } elsif ($arg eq '-m') {
+	$mailto = "$mailto " . shift @ARGV;
+    } elsif ($arg eq '-M') {
+	$modulename = shift @ARGV;
+    } elsif ($arg eq '-s') {
+	$do_status = 0;
+    } elsif ($arg eq '-f') {
+	($commitlog) && die("Too many '-f' args\n");
+	$commitlog = shift @ARGV;
+    } elsif ($arg eq '-G') {
+	($gnatsdb) && die("Too many '-G' args\n");
+	$gnatsdb = shift @ARGV;
+    } elsif ($arg eq '-T') {
+	$temp_name = shift @ARGV;
+    } elsif ($arg eq '-C') {
+	$do_cvsweb = 1;
+	$cvsweb_name = shift @ARGV;
+    } elsif ($arg eq '-U') {
+	$CVSWEB_URL = shift @ARGV;
+    } elsif ($arg eq '-D') {
+	$hostdomain = shift @ARGV;
+    } elsif ($arg eq '-l') {
+	$do_modlist = 1;
+    } else {
+	($donefiles) && die("Too many arguments!  Check usage.\n");
+	$donefiles = 1;
+	@files = split(/ /, $arg);
+    }
+}
+
+if (defined ($hostdomain)) {
+    # nothing
+} elsif ($hostname !~ /\./) {
+    chop($domainname = `domainname`);
+    $hostdomain = $hostname . "." . $domainname;
+} else {
+    $hostdomain = $hostname;
+}
+
+$hostdomain = 'sources.redhat.com' if $hostdomain eq 'sourceware.cygnus.com';
+# Used with sprintf to form name of Gnats notification mailing list.
+# %s argument comse from -G option.
+$GNATS_MAIL_FORMAT = "%s-gnats\@$hostdomain";
+
+($mailto) || die("No -m mail recipient specified\n");
+&set_temp_vars ($temp_name);
+
+# for now, the first "file" is the repository directory being committed,
+# relative to the $CVSROOT location
+#
+@path = split('/', $files[0]);
+
+# XXX there are some ugly assumptions in here about module names and
+# XXX directories relative to the $CVSROOT location -- really should
+# XXX read $CVSROOT/CVSROOT/modules, but that's not so easy to do, since
+# XXX we have to parse it backwards.
+#
+if ($modulename eq "") {
+    $modulename = $path[0];	# I.e. the module name == top-level dir
+}
+if ($commitlog ne "") {
+    $commitlog = $cvsroot . "/" . $modulename . "/" . $commitlog unless ($commitlog =~ /^\//);
+}
+if ($#path == 0) {
+    $dir = ".";
+} else {
+    $dir = join('/', @path[1..$#path]);
+}
+$dir = $dir . "/";
+
+if ($debug) {
+    print STDERR "module - ", $modulename, "\n";
+    print STDERR "dir    - ", $dir, "\n";
+    print STDERR "path   - ", join(":", @path), "\n";
+    print STDERR "files  - ", join(":", @files), "\n";
+    print STDERR "id     - ", $id, "\n";
+}
+
+# Check for a new directory first.  This appears with files set as follows:
+#
+#    files[0] - "path/name/newdir"
+#    files[1] - "-"
+#    files[2] - "New"
+#    files[3] - "directory"
+#
+if ($files[2] =~ /New/ && $files[3] =~ /directory/) {
+    local(@text);
+
+    @text = ();
+    push(@text, &build_header());
+    push(@text, "");
+    push(@text, $files[0]);
+    push(@text, "");
+
+    while (<STDIN>) {
+	chop;			# Drop the newline
+	push(@text, $_);
+    }
+
+    &mail_notification($mailto, $files[0], @text);
+
+    if ($commitlog) {
+	&write_commitlog($commitlog, @text);
+    }
+
+    if ($do_modlist) {
+	modlist_newdir ($files[0]);
+    }
+
+    exit 0;
+}
+
+# Iterate over the body of the message collecting information.
+#
+while (<STDIN>) {
+    chop;			# Drop the newline
+
+    if (/^Modified Files/) { $state = $STATE_CHANGED; next; }
+    if (/^Added Files/)    { $state = $STATE_ADDED;   next; }
+    if (/^Removed Files/)  { $state = $STATE_REMOVED; next; }
+    if (/^Log Message/)    { $state = $STATE_LOG;     next; }
+    if (/^\s*Tag:|Revision\/Branch/) { /^[^:]+:\s*(.*)/; $branch = $+; next; }
+
+    s/^[ \t\n]+//;		# delete leading whitespace
+    s/[ \t\n]+$//;		# delete trailing whitespace
+
+    if ($state == $STATE_CHANGED) { push(@changed_files, split); }
+    if ($state == $STATE_ADDED)   { push(@added_files,   split); }
+    if ($state == $STATE_REMOVED) { push(@removed_files, split); }
+    if ($state == $STATE_LOG)     { push(@log_lines,     $_); }
+}
+
+# Strip leading and trailing blank lines from the log message.  Also
+# compress multiple blank lines in the body of the message down to a
+# single blank line.
+#
+while ($#log_lines > -1) {
+    last if ($log_lines[0] ne "");
+    shift(@log_lines);
+}
+while ($#log_lines > -1) {
+    last if ($log_lines[$#log_lines] ne "");
+    pop(@log_lines);
+}
+for ($i = $#log_lines; $i > 0; $i--) {
+    if (($log_lines[$i - 1] eq "") && ($log_lines[$i] eq "")) {
+	splice(@log_lines, $i, 1);
+    }
+}
+
+# Check for an import command.  This appears with files set as follows:
+#
+#    files[0] - "path/name"
+#    files[1] - "-"
+#    files[2] - "Imported"
+#    files[3] - "sources"
+#
+if ($files[2] =~ /Imported/ && $files[3] =~ /sources/) {
+    local(@text);
+
+    @text = ();
+    push(@text, &build_header());
+    push(@text, "");
+
+    push(@text, "Log message:");
+    while ($#log_lines > -1) {
+	push (@text, "    " . $log_lines[0]);
+	shift(@log_lines);
+    }
+
+    &mail_notification($mailto, "Import $file[0]", @text);
+
+    if ($commitlog) {
+	&write_commitlog($commitlog, @text);
+    }
+
+    if ($do_modlist) {
+	modlist_import ($files[0], \@text);
+    }
+
+    exit 0;
+}
+
+# Compute the list of cvsweb URLs if necessary.
+if ($do_cvsweb) {
+    @urls = &generate_cvsweb_urls (join ('/', @path), $branch,
+				   @files[1 .. $#files]);
+}
+
+if ($do_modlist) {
+    @modlist = generate_modlist (join ('/', @path),
+                              \@changed_files, \@added_files, \@removed_files,
+                               @files[1 .. $#files]);
+}
+
+if ($debug) {
+    print STDERR "Searching for log file index...";
+}
+# Find an index to a log file that matches this log message
+#
+for ($i = 0; ; $i++) {
+    local(@text);
+
+    last if (! -e "$LOG_FILE.$i.$id"); # the next available one
+    @text = &read_logfile("$LOG_FILE.$i.$id", "");
+    last if ($#text == -1);	# nothing in this file, use it
+    last if (join(" ", @log_lines) eq join(" ", @text)); # it's the same log message as another
+}
+if ($debug) {
+    print STDERR " found log file at $i.$id, now writing tmp files.\n";
+}
+
+# Spit out the information gathered in this pass.
+#
+&append_names_to_file("$CHANGED_FILE.$i.$id", $dir, @changed_files);
+&append_names_to_file("$ADDED_FILE.$i.$id",   $dir, @added_files);
+&append_names_to_file("$REMOVED_FILE.$i.$id", $dir, @removed_files);
+&append_names_to_file("$URL_FILE.$i.$id",     $dir, @urls);
+&append_names_to_file("$COMMITS_FILE.$i.$id", undef, @modlist);
+&write_logfile("$LOG_FILE.$i.$id", @log_lines);
+    
+
+# Check whether this is the last directory.  If not, quit.
+#
+if ($debug) {
+    print STDERR "Checking current dir against last dir.\n";
+}
+$_ = &read_line("$LAST_FILE.$id");
+
+if ($_ ne $cvsroot . "/" . $files[0]) {
+    if ($debug) {
+	print STDERR sprintf("Current directory %s is not last directory %s.\n", $cvsroot . "/" .$files[0], $_);
+    }
+    exit 0;
+}
+if ($debug) {
+    print STDERR sprintf("Current directory %s is last directory %s -- all commits done.\n", $files[0], $_);
+}
+
+#
+#	End Of Commits!
+#
+
+# This is it.  The commits are all finished.  Lump everything together
+# into a single message, fire a copy off to the mailing list, and drop
+# it on the end of the Changes file.
+#
+
+#
+# Produce the final compilation of the log messages
+#
+@text = ();
+@status_txt = ();
+@subject_files = ();
+@log_txt = ();
+@modlist_txt = ();
+push(@text, &build_header());
+push(@text, "");
+
+for ($i = 0; ; $i++) {
+    last if (! -e "$LOG_FILE.$i.$id"); # we're done them all!
+    @lines = &read_logfile("$CHANGED_FILE.$i.$id", "");
+    if ($#lines >= 0) {
+	push(@text, "Modified files:");
+	push(@text, &format_lists(@lines));
+	push(@subject_files, &accum_subject(@lines));
+    }
+    @lines = &read_logfile("$ADDED_FILE.$i.$id", "");
+    if ($#lines >= 0) {
+	push(@text, "Added files:");
+	push(@text, &format_lists(@lines));
+	push(@subject_files, &accum_subject(@lines));
+    }
+    @lines = &read_logfile("$REMOVED_FILE.$i.$id", "");
+    if ($#lines >= 0) {
+	push(@text, "Removed files:");
+	push(@text, &format_lists(@lines));
+	push(@subject_files, &accum_subject(@lines));
+    }
+    if ($#text >= 0) {
+	push(@text, "");
+    }
+    @log_txt = &read_logfile("$LOG_FILE.$i.$id", "\t");
+    if ($#log_txt >= 0) {
+	push(@text, "Log message:");
+	push(@text, @log_txt);
+	push(@text, "");
+    }
+    @url_txt = &read_logfile("$URL_FILE.$i.$id", "");
+    if ($#url_txt >= 0) {
+	push (@text, "Patches:");
+	# Exclude directories listed in the file.
+	push (@text, grep (! /\/$/, @url_txt));
+	push (@text, "");
+    }
+    if ($do_modlist) {
+        push (@modlist_txt, read_logfile("$COMMITS_FILE.$i.$id", ""));
+    }
+    if ($do_status) {
+	local(@changed_files);
+
+	@changed_files = ();
+	push(@changed_files, &read_logfile("$CHANGED_FILE.$i.$id", ""));
+	push(@changed_files, &read_logfile("$ADDED_FILE.$i.$id", ""));
+	push(@changed_files, &read_logfile("$REMOVED_FILE.$i.$id", ""));
+
+	if ($debug) {
+	    print STDERR "main: pre-sort changed_files = ", join(":", @changed_files), ".\n";
+	}
+	@changed_files = sort(@changed_files);
+	if ($debug) {
+	    print STDERR "main: post-sort changed_files = ", join(":", @changed_files), ".\n";
+	}
+
+	foreach $dofile (@changed_files) {
+	    if ($dofile =~ /\/$/) {
+		next;		# ignore the silly "dir" entries
+	    }
+	    if ($debug) {
+		print STDERR "main(): doing status on $dofile\n";
+	    }
+	    open(STATUS, "-|") || exec 'cvs', '-nQq', 'status', '-v', $dofile;
+	    while (<STATUS>) {
+		chop;
+		push(@status_txt, $_);
+	    }
+	}
+    }
+}
+
+$subject_txt = &compile_subject(@subject_files);
+
+# Write to the commitlog file
+#
+if ($commitlog) {
+    &write_commitlog($commitlog, @text);
+}
+
+if ($#modlist_txt >= 0) {
+    modlist_write_to_log (@modlist_txt);
+}
+
+if ($#status_txt >= 0) {
+    push(@text, @status_txt);
+}
+
+# Mailout the notification.
+#
+&mail_notification($mailto, $subject_txt, @text);
+
+# Send mail to Gnats, if required.
+if ($gnatsdb ne '') {
+    $log_txt = join ("\n", @log_txt);
+    while ($log_txt =~ m,PR ([a-z.+]+/[0-9]+)(.*)$,s) {
+	$pr = $1;
+	$log_txt = $2;
+	$file = sprintf ($GNATS_ROOT_FORMAT, $gnatsdb) . "/" . $pr;
+	if (-f $file) {
+	    &mail_notification(sprintf ($GNATS_MAIL_FORMAT, $gnatsdb),
+			       $pr, @text);
+	}
+    }
+}
+
+# cleanup
+#
+if (! $debug) {
+    &cleanup_tmpfiles();
+}
+
+exit 0;
Index: loginfo
===================================================================
RCS file: /home/tools/CVSROOT/loginfo,v
retrieving revision 1.1
diff -u -r1.1 loginfo
--- loginfo 6 Dec 2001 18:45:46 -0000 1.1
+++ loginfo 8 Oct 2002 20:59:56 -0000
@@ -24,3 +24,5 @@
 #DEFAULT (echo ""; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog
 # or
 #DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog
+
+DEFAULT (/home/tools/CVSROOT/log_accum -D eclipse.org -T cdt -C Tools_Project -U "http://dev.eclipse.org/viewcvs/index.cgi/"; -m FIXME@xxxxxxxxxxx -s %{sVv})


Back to the top