[
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})