[MLton-devel] CVSROOT avail,NONE,1.1 commit_prep.pl,NONE,1.1 commitcheck,NONE,1.1 cvs_acls.pl,NONE,1.1 log_accum.pl,NONE,1.1 checkoutlist,1.3,1.4 commitinfo,1.3,1.4 loginfo,1.11,1.12
sweeks@users.sourceforge.net
sweeks@users.sourceforge.net
Mon, 29 Apr 2002 12:21:15 -0700
Update of /cvsroot/mlton/CVSROOT
In directory usw-pr-cvs1:/tmp/cvs-serv32536
Modified Files:
checkoutlist commitinfo loginfo
Added Files:
avail commit_prep.pl commitcheck cvs_acls.pl log_accum.pl
Log Message:
Trying out commit emails based on the Apache developers setup.
--- NEW FILE: avail ---
avail
--- NEW FILE: commit_prep.pl ---
#!/usr/bin/perl
#
# 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.
#
# Contributed by David Hampton <hampton@cisco.com>
# Stripped to minimum by Roy Fielding
#
############################################################
$TMPDIR = $ENV{'TMPDIR'} || '/tmp';
$FILE_PREFIX = '#cvs.';
$LAST_FILE = "$TMPDIR/${FILE_PREFIX}lastdir"; # MUST match log_accum.pl
sub write_line {
local($filename, $line) = @_;
open(FILE, ">$filename") || die("Cannot open $filename: $!\n");
print(FILE $line, "\n");
close(FILE);
}
#
# 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.
#
$id = getpgrp();
&write_line("$LAST_FILE.$id", $ARGV[0]);
exit(0);
--- NEW FILE: commitcheck ---
#!/bin/sh
if $CVSROOT/CVSROOT/cvs_acls.pl ${1+"$@"}; then
if $CVSROOT/CVSROOT/commit_prep.pl ${1+"$@"}; then
exit 0
fi
fi
exit 1
--- NEW FILE: cvs_acls.pl ---
#!/usr/bin/perl
#
# Access control lists for CVS. dgg@ksr.com (David G. Grubbs)
#
# CVS "commitinfo" for matching repository names, running the program it finds
# on the same line. More information is available in the CVS man pages.
#
# ==== INSTALLATION:
#
# To use this program as I intended, do the following four things:
#
# 0. Install PERL. :-)
#
# 1. Put one line, as the *only* non-comment line, in your commitinfo file:
#
# DEFAULT /usr/local/bin/cvs_acls
#
# 2. Install this file as /usr/local/bin/cvs_acls and make it executable.
#
# 3. Create a file named $CVSROOT/CVSROOT/avail.
#
# ==== FORMAT OF THE avail FILE:
#
# The avail file determines whether you may commit files. It contains lines
# read from top to bottom, keeping track of a single "bit". The "bit"
# defaults to "on". It can be turned "off" by "unavail" lines and "on" by
# "avail" lines. ==> Last one counts.
#
# Any line not beginning with "avail" or "unavail" is ignored.
#
# Lines beginning with "avail" or "unavail" are assumed to be '|'-separated
# triples: (All spaces and tabs are ignored in a line.)
#
# {avail.*,unavail.*} [| user,user,... [| repos,repos,...]]
#
# 1. String starting with "avail" or "unavail".
# 2. Optional, comma-separated list of usernames.
# 3. Optional, comma-separated list of repository pathnames.
# These are pathnames relative to $CVSROOT. They can be directories or
# filenames. A directory name allows access to all files and
# directories below it.
#
# Example: (Text from the ';;' rightward may not appear in the file.)
#
# unavail ;; Make whole repository unavailable.
# avail|dgg ;; Except for user "dgg".
# avail|fred, john|bin/ls ;; Except when "fred" or "john" commit to
# ;; the module whose repository is "bin/ls"
#
# PROGRAM LOGIC:
#
# CVS passes to @ARGV an absolute directory pathname (the repository
# appended to your $CVSROOT variable), followed by a list of filenames
# within that directory.
#
# We walk through the avail file looking for a line that matches both
# the username and repository.
#
# A username match is simply the user's name appearing in the second
# column of the avail line in a space-or-comma separate list.
#
# A repository match is either:
# - One element of the third column matches $ARGV[0], or some
# parent directory of $ARGV[0].
# - Otherwise *all* file arguments ($ARGV[1..$#ARGV]) must be
# in the file list in one avail line.
# - In other words, using directory names in the third column of
# the avail file allows committing of any file (or group of
# files in a single commit) in the tree below that directory.
# - If individual file names are used in the third column of
# the avail file, then files must be committed individually or
# all files specified in a single commit must all appear in
# third column of a single avail line.
#
$debug = 0;
$cvsroot = $ENV{'CVSROOT'};
$availfile = $cvsroot . "/CVSROOT/avail";
$myname = $ENV{"USER"} if !($myname = $ENV{"LOGNAME"});
eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';"
while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV));
exit 255 if $die; # process any variable=value switches
die "Must set CVSROOT\n" if !$cvsroot;
($repos = shift) =~ s:^$cvsroot/::;
grep($_ = $repos . '/' . $_, @ARGV);
print "$$ Repos: $repos\n","$$ ==== ",join("\n$$ ==== ",@ARGV),"\n" if $debug;
$exit_val = 0; # Good Exit value
$universal_off = 0;
open (AVAIL, $availfile) || exit(0); # It is ok for avail file not to exist
while (<AVAIL>) {
chop;
next if /^\s*\#/;
next if /^\s*$/;
($flagstr, $u, $m) = split(/[\s,]*\|[\s,]*/, $_);
# Skip anything not starting with "avail" or "unavail" and complain.
(print "Bad avail line: $_\n"), next
if ($flagstr !~ /^avail/ && $flagstr !~ /^unavail/);
# Set which bit we are playing with. ('0' is OK == Available).
$flag = (($& eq "avail") ? 0 : 1);
# If we find a "universal off" flag (i.e. a simple "unavail") remember it
$universal_off = 1 if ($flag && !$u && !$m);
# $myname considered "in user list" if actually in list or is NULL
$in_user = (!$u || grep ($_ eq $myname, split(/[\s,]+/,$u)));
print "$$ \$myname($myname) in user list: $_\n" if $debug && $in_user;
# Module matches if it is a NULL module list in the avail line. If module
# list is not null, we check every argument combination.
if (!($in_repo = !$m)) {
@tmp = split(/[\s,]+/,$m);
for $j (@tmp) {
# If the repos from avail is a parent(or equal) dir of $repos, OK
$in_repo = 1, last if ($repos eq $j || $repos =~ /^$j\//);
}
if (!$in_repo) {
$in_repo = 1;
for $j (@ARGV) {
last if !($in_repo = grep ($_ eq $j, @tmp));
}
}
}
print "$$ \$repos($repos) in repository list: $_\n" if $debug && $in_repo;
$exit_val = $flag if ($in_user && $in_repo);
print "$$ ==== \$exit_val = $exit_val\n$$ ==== \$flag = $flag\n" if $debug;
}
close(AVAIL);
print "$$ ==== \$exit_val = $exit_val\n" if $debug;
print "**** Access denied: Insufficient Karma ($myname|$repos)\n" if $exit_val;
#print "**** Access allowed: Personal Karma exceeds Environmental Karma.\n"
# if $universal_off && !$exit_val;
exit($exit_val);
--- NEW FILE: log_accum.pl ---
#!/usr/bin/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@cisco.com>
# Roy Fielding removed useless code and added log/mail of new files
# Ken Coar added special processing (i.e., no diffs) for binary files
#
############################################################
#
# Configurable options
#
############################################################
#
# Where do you want the RCS ID and delta info?
# 0 = none,
# 1 = in mail only,
# 2 = rcsids in both mail and logs.
#
$rcsidinfo = 1;
############################################################
#
# Constants
#
############################################################
$STATE_NONE = 0;
$STATE_CHANGED = 1;
$STATE_ADDED = 2;
$STATE_REMOVED = 3;
$STATE_LOG = 4;
$TMPDIR = $ENV{'TMPDIR'} || '/tmp';
$FILE_PREFIX = '#cvs.';
$LAST_FILE = "$TMPDIR/${FILE_PREFIX}lastdir";
$CHANGED_FILE = "$TMPDIR/${FILE_PREFIX}files.changed";
$ADDED_FILE = "$TMPDIR/${FILE_PREFIX}files.added";
$REMOVED_FILE = "$TMPDIR/${FILE_PREFIX}files.removed";
$LOG_FILE = "$TMPDIR/${FILE_PREFIX}files.log";
$BRANCH_FILE = "$TMPDIR/${FILE_PREFIX}files.branch";
$SUMMARY_FILE = "$TMPDIR/${FILE_PREFIX}files.summary";
$CVSROOT = $ENV{'CVSROOT'};
$MAIL_TO = 'sweeks';
$MLISTHOST = 'sweeks.com';
############################################################
#
# Subroutines
#
############################################################
sub format_names {
local($dir, @files) = @_;
local(@lines);
$lines[0] = sprintf(" %-08s", $dir);
foreach $file (@files) {
if (length($lines[$#lines]) + length($file) > 60) {
$lines[++$#lines] = sprintf(" %8s", " ");
}
$lines[$#lines] .= " ".$file;
}
@lines;
}
sub cleanup_tmpfiles {
local(@files);
opendir(DIR, $TMPDIR);
push(@files, grep(/^${FILE_PREFIX}.*\.${id}$/, readdir(DIR)));
closedir(DIR);
foreach (@files) {
unlink "$TMPDIR/$_";
}
}
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 append_to_file {
local($filename, $dir, @files) = @_;
if (@files) {
local(@lines) = &format_names($dir, @files);
open(FILE, ">>$filename") || die ("Cannot open file $filename: $!\n");
print(FILE join("\n", @lines), "\n");
close(FILE);
}
}
sub write_line {
local($filename, $line) = @_;
open(FILE, ">$filename") || die("Cannot open file $filename: $!\n");
print(FILE $line, "\n");
close(FILE);
}
sub append_line {
local($filename, $line) = @_;
open(FILE, ">>$filename") || die("Cannot open file $filename: $!\n");
print(FILE $line, "\n");
close(FILE);
}
sub read_line {
local($filename) = @_;
local($line);
open(FILE, "<$filename") || die("Cannot open file $filename: $!\n");
$line = <FILE>;
close(FILE);
chomp($line);
$line;
}
sub read_file {
local($filename, $leader) = @_;
local(@text) = ();
open(FILE, "<$filename") || return ();
while (<FILE>) {
chomp;
push(@text, sprintf(" %-10s %s", $leader, $_));
$leader = "";
}
close(FILE);
@text;
}
sub read_logfile {
local($filename, $leader) = @_;
local(@text) = ();
open(FILE, "<$filename") || die ("Cannot open log file $filename: $!\n");
while (<FILE>) {
chomp;
push(@text, $leader.$_);
}
close(FILE);
@text;
}
#
# do an 'cvs -Qn status' on each file in the arguments, and extract info.
#
sub change_summary {
local($out, @filenames) = @_;
local(@revline);
local($file, $rev, $rcsfile, $line);
while (@filenames) {
$file = shift @filenames;
if ("$file" eq "") {
next;
}
open(RCS, "-|") || exec 'cvs', '-Qn', 'status', $file;
$rev = "";
$delta = "";
$rcsfile = "";
while (<RCS>) {
if (/^[ \t]*Repository revision/) {
chomp;
@revline = split(' ', $_);
$rev = $revline[2];
$rcsfile = $revline[3];
$rcsfile =~ s,^$CVSROOT/,,;
$rcsfile =~ s/,v$//;
}
}
close(RCS);
if ($rev ne '' && $rcsfile ne '') {
open(RCS, "-|") || exec 'cvs', '-Qn', 'log', "-r$rev", $file;
while (<RCS>) {
if (/^date:/) {
chomp;
$delta = $_;
$delta =~ s/^.*;//;
$delta =~ s/^[\s]+lines://;
}
}
close(RCS);
}
$diff = "\n\n";
#
# If this is a binary file, don't try to report a diff; not only is
# it meaningless, but it also screws up some mailers. We rely on
# Perl's 'is this binary' algorithm; it's pretty good. But not
# perfect.
#
if (($file =~ /\.(?:pdf|gif|jpg|mpg)$/i) || (-B $file)) {
$diff .= "\t<<Binary file>>\n\n";
}
else {
#
# Get the differences between this and the previous revision,
# being aware that new files always have revision '1.1' and
# new branches always end in '.n.1'.
#
if ($rev =~ /^(.*)\.([0-9]+)$/) {
$prev = $2 - 1;
$prev_rev = $1 . '.' . $prev;
$prev_rev =~ s/\.[0-9]+\.0$//;# Truncate if first rev on branch
if ($rev eq '1.1') {
open(DIFF, "-|")
|| exec 'cvs', '-Qn', 'update', '-p', '-r1.1', $file;
$diff .= "Index: $file\n=================================="
. "=================================\n";
}
else {
open(DIFF, "-|")
|| exec 'cvs', '-Qn', 'diff', '-u',
"-r$prev_rev", "-r$rev", $file;
}
while (<DIFF>) {
$diff .= $_;
}
close(DIFF);
$diff .= "\n\n";
}
}
&append_line($out, sprintf("%-9s%-12s%s%s", $rev, $delta,
$rcsfile, $diff));
}
}
sub build_header {
local($header);
delete $ENV{'TZ'};
local($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
$header = sprintf("%-8s %02d/%02d/%02d %02d:%02d:%02d",
$login, $year%100, $mon+1, $mday,
$hour, $min, $sec);
}
# !!! Mailing-list and history file mappings here !!!
sub mlist_map
{
local($path) = @_;
if ($path =~ /^([^\/]+)/) { return $1; }
else { return 'apache'; }
}
sub do_changes_file
{
local($category, @text) = @_;
local($changes);
$changes = "$CVSROOT/CVSROOT/commitlogs/$category";
if (open(CHANGES, ">>$changes")) {
print(CHANGES join("\n", @text), "\n\n");
close(CHANGES);
}
else {
warn "Cannot open $changes: $!\n";
}
}
sub mail_notification
{
local(@text) = @_;
print "Mailing the commit message...\n";
open(MAIL, "| mail -s \"cvs commit: $ARGV[0]\" $MAIL_TO");
print(MAIL join("\n", @text));
close(MAIL);
}
#############################################################
#
# Main Body
#
############################################################
#
# Setup environment
#
umask (002);
#
# Initialize basic variables
#
$id = getpgrp();
$state = $STATE_NONE;
$login = $ENV{'USER'} || getlogin || (getpwuid($<))[0] || sprintf("uid#%d",$<);
@files = split(' ', $ARGV[0]);
@path = split('/', $files[0]);
$repository = $path[0];
if ($#path == 0) {
$dir = ".";
} else {
$dir = join('/', @path[1..$#path]);
}
#print("ARGV - ", join(":", @ARGV), "\n");
#print("files - ", join(":", @files), "\n");
#print("path - ", join(":", @path), "\n");
#print("dir - ", $dir, "\n");
#print("id - ", $id, "\n");
#
# Map the repository directory to a name for commitlogs.
#
$mlist = &mlist_map($files[0]);
##########################
# Uncomment the following if we ever have per-repository cvs mail
if (defined($mlist)) {
$MAIL_TO = $mlist . "-cvs\@$MLISTHOST";
}
# else { undef $MAIL_TO; }
##########################
#
# Check for a new directory first. This will always appear as a
# single item in the argument list, and an empty log message.
#
if ($ARGV[0] =~ /New directory/) {
$header = &build_header;
@text = ();
push(@text, $header);
push(@text, "");
push(@text, " ".$ARGV[0]);
&do_changes_file($mlist, @text);
&mail_notification(@text) if defined($MAIL_TO);
exit 0;
}
#
# Iterate over the body of the message collecting information.
#
while (<STDIN>) {
chomp; # Drop the newline
if (/^Revision\/Branch:/) {
s,^Revision/Branch:,,;
push (@branch_lines, split);
next;
}
# next if (/^[ \t]+Tag:/ && $state != $STATE_LOG);
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; }
s/[ \t\n]+$//; # delete trailing space
push (@changed_files, split) if ($state == $STATE_CHANGED);
push (@added_files, split) if ($state == $STATE_ADDED);
push (@removed_files, split) if ($state == $STATE_REMOVED);
if ($state == $STATE_LOG) {
if (/^PR:$/i ||
/^Reviewed by:$/i ||
/^Submitted by:$/i ||
/^Obtained from:$/i) {
next;
}
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.
# (Note, this only does the mail and changes log, not the rcs log).
#
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);
}
}
#
# Find the log file that matches this log message
#
for ($i = 0; ; $i++) {
last if (! -e "$LOG_FILE.$i.$id");
@text = &read_logfile("$LOG_FILE.$i.$id", "");
last if ($#text == -1);
last if (join(" ", @log_lines) eq join(" ", @text));
}
#
# Spit out the information gathered in this pass.
#
&write_logfile("$LOG_FILE.$i.$id", @log_lines);
&append_to_file("$BRANCH_FILE.$i.$id", $dir, @branch_lines);
&append_to_file("$ADDED_FILE.$i.$id", $dir, @added_files);
&append_to_file("$CHANGED_FILE.$i.$id", $dir, @changed_files);
&append_to_file("$REMOVED_FILE.$i.$id", $dir, @removed_files);
if ($rcsidinfo) {
&change_summary("$SUMMARY_FILE.$i.$id", (@changed_files, @added_files));
}
#
# Check whether this is the last directory. If not, quit.
#
if (-e "$LAST_FILE.$id") {
$_ = &read_line("$LAST_FILE.$id");
$tmpfiles = $files[0];
$tmpfiles =~ s,([^a-zA-Z0-9_/]),\\$1,g;
if (! grep(/$tmpfiles$/, $_)) {
print "More commits to come...\n";
exit 0
}
}
#
# 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.
#
$header = &build_header;
#
# Produce the final compilation of the log messages
#
@text = ();
push(@text, $header);
push(@text, "");
for ($i = 0; ; $i++) {
last if (! -e "$LOG_FILE.$i.$id");
push(@text, &read_file("$BRANCH_FILE.$i.$id", "Branch:"));
push(@text, &read_file("$CHANGED_FILE.$i.$id", "Modified:"));
push(@text, &read_file("$ADDED_FILE.$i.$id", "Added:"));
push(@text, &read_file("$REMOVED_FILE.$i.$id", "Removed:"));
push(@text, " Log:");
push(@text, &read_logfile("$LOG_FILE.$i.$id", " "));
if ($rcsidinfo == 2) {
if (-e "$SUMMARY_FILE.$i.$id") {
push(@text, " ");
push(@text, " Revision Changes Path");
push(@text, &read_logfile("$SUMMARY_FILE.$i.$id", " "));
}
}
push(@text, "");
}
#
# Append the log message to the commitlogs/<module> file
#
&do_changes_file($mlist, @text);
#
# Now generate the extra info for the mail message..
#
if ($rcsidinfo == 1) {
$revhdr = 0;
for ($i = 0; ; $i++) {
last if (! -e "$LOG_FILE.$i.$id");
if (-e "$SUMMARY_FILE.$i.$id") {
if (!$revhdr++) {
push(@text, "Revision Changes Path");
}
push(@text, &read_logfile("$SUMMARY_FILE.$i.$id", ""));
}
}
if ($revhdr) {
push(@text, ""); # consistancy...
}
}
#
# Mail out the notification.
#
&mail_notification(@text) if defined($MAIL_TO);
&cleanup_tmpfiles;
exit 0;
Index: checkoutlist
===================================================================
RCS file: /cvsroot/mlton/CVSROOT/checkoutlist,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** checkoutlist 17 Apr 2002 18:51:51 -0000 1.3
--- checkoutlist 29 Apr 2002 19:21:13 -0000 1.4
***************
*** 12,15 ****
--- 12,20 ----
#
# comment lines begin with '#'
+ avail
+ commit_prep.pl
+ commitcheck
+ cvs_acls.pl
+ log_accum.pl
maybe-syncmail
syncmail
Index: commitinfo
===================================================================
RCS file: /cvsroot/mlton/CVSROOT/commitinfo,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** commitinfo 16 Apr 2002 03:37:03 -0000 1.3
--- commitinfo 29 Apr 2002 19:21:13 -0000 1.4
***************
*** 15,16 ****
--- 15,18 ----
# in addition to the first matching regex or "DEFAULT".
+ test $CVSROOT/CVSROOT/commitcheck
+ DEFAULT exit 0
Index: loginfo
===================================================================
RCS file: /cvsroot/mlton/CVSROOT/loginfo,v
retrieving revision 1.11
retrieving revision 1.12
diff -C2 -d -r1.11 -r1.12
*** loginfo 18 Apr 2002 03:27:31 -0000 1.11
--- loginfo 29 Apr 2002 19:21:13 -0000 1.12
***************
*** 26,29 ****
#DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog
! CVSROOT $CVSROOT/CVSROOT/syncmail %{sVv} MLton-devel@lists.sourceforge.net
DEFAULT $CVSROOT/CVSROOT/maybe-syncmail %{sVv} MLton-devel@lists.sourceforge.net
--- 26,30 ----
#DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog
! CVSROOT $CVSROOT/CVSROOT/syncmail %{sVv} sweeks@sweeks.com
! test $CVSROOT/CVSROOT/log_accum.pl %s
DEFAULT $CVSROOT/CVSROOT/maybe-syncmail %{sVv} MLton-devel@lists.sourceforge.net
_______________________________________________
MLton-devel mailing list
MLton-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mlton-devel