FreeBSD-comittmails dazu

This commit is contained in:
Stefan Bethke 2006-01-20 12:16:39 +00:00
parent 8bb2918dcd
commit 074f2b7e48
19 changed files with 2239 additions and 3 deletions

8
CVSROOT/access Normal file
View file

@ -0,0 +1,8 @@
#
# $Id$
#
# Wer committen darf
lea10010
bes10033
wiw10050
jgz10052

17
CVSROOT/avail Normal file
View file

@ -0,0 +1,17 @@
#
# $Id$
#
# Wer welche Teile bearbeiten darf
#
# Beispiele:
# Gruppendefinition
#group|meisters|peter,jdp,markm,joe
# Gruppendefinition aus Datei
#group|penaltybox|!badcommitters
# Verboten fuer alle
#unavail||src/contrib/binutils,src/contrib/file
# Erlaubt fuer einige
#avail|:meisters|CVSROOT
#
# Alle duerfen ueberall
avail

284
CVSROOT/cfg.pm Executable file
View file

@ -0,0 +1,284 @@
# $Id$
# $FreeBSD: cfg.pm,v 1.50 2003/02/28 18:28:11 peter Exp $
####################################################################
####################################################################
# This file contains the default configuration for the CVSROOT
# perl scripts. You are advised to override the configuration
# in the cfg_local.pm file instead of here.
#
# WARNING: You are strongly advised to check for syntax errors
# in this file before committing it. Use: perl -cw cfg.pm
####################################################################
####################################################################
package cfg;
use strict;
use vars qw(
$ADD_TO_LINE $AVAIL_FILE $CHECK_HEADERS $COMMITCHECK_EXTRA
@COMMIT_HOSTS $COMMITTER $DEBUG $DIFF_BLOCK_TOTAL_LINES $EXCLUDE_FILE
$FILE_PREFIX $IDHEADER $LAST_FILE @LOG_FILE_MAP $MAILADDRS $MAILBANNER
$MAILCMD $MAIL_BRANCH_HDR $MAIL_ON_DIR_CREATION $MAIL_TRANSFORM
$MINCVSVERSION $MAX_DIFF_SIZE $NO_DOS_LINEBREAKS $PID $PROG_CVS
$PROG_MV %TEMPLATE_HEADERS $TMPDIR $UNEXPAND_RCSID $WARN_HEADERS
);
my $CVSROOT = $ENV{'CVSROOT'} || die "Can't determine \$CVSROOT!";
######################
### global options ###
######################
### WARNING: these aren't global across all the scripts yet.
### This is work in progress.
# Process group id; used as a unique number in temporary file names.
$PID = getpgrp();
# Debug level, 0 = off, 1 = on.
$DEBUG = 0;
# Location of temporary directory.
$TMPDIR = "/tmp/";
# The filename prefix used for temporary files.
$FILE_PREFIX = "#cvs.files.$PID";
# The file used to store the name of the last directory examined
# when processing a multi-directory commit.
$LAST_FILE = "$TMPDIR/$FILE_PREFIX.lastdir";
# System tools.
$PROG_CVS = '/usr/bin/cvs'; # cvs(1)
$PROG_MV = '/bin/mv'; # mv(1)
# The username of the committer.
$COMMITTER = $ENV{"LOGNAME"} || $ENV{'USER'} || getlogin
|| (getpwuid($<))[0] || sprintf("uid#%d",$<);
###################
### commitcheck ###
###################
# A list of hosts the it's ok to commit on. Useful if your committers
# take local copies of the repository to work off-line.
# (Empty if you don't want checks.)
@COMMIT_HOSTS = ();
# The minimum version of cvs that we will work with.
$MINCVSVERSION = "1090900"; # 1.9.9p0
# Additional commit time checks. This is an anonymous subroutine
# that gets called early on in the validation process to see whether
# the committer is allowed to commit. It should return true if
# everything is ok, otherwise the commit will be terminated.
$COMMITCHECK_EXTRA = "";
###################
### cvs_acls.pl ###
###################
# The name of the avail file that defines who's allow to
# commit to what.
$AVAIL_FILE = "$CVSROOT/CVSROOT/avail";
################
### logcheck ###
################
# These are the optional headers that can be filled at the end of
# each commit message. The associated value is a regular-expression
# that is used to type-check the entered value. If a match fails
# then the commit is rejected. (See rcstemplate).
#
# Make sure that these are also described in the rcstemplate to
# make their usage clear to committers.
#
# In addition any of these entries that are left blank are removed
# from the log at commit time. [Please note that for them to be
# removed from the rcslog in the repository you need to be running
# the version of cvs in the FreeBSD source tree. We've got a local
# patch that causes cvs to read back the commit message after the
# commit_prep.pl script has had a chance to modify it (via the
# 'commitinfo' hook). ]
%TEMPLATE_HEADERS = (
# "Reviewed by" => '.*',
# "Submitted by" => '.*',
# "Obtained from" => '.*',
# "Approved by" => '.*',
# "PR" => '.*',
# "MFC after" => '\d+(\s+(days?|weeks?|months?))?'
);
######################
### commit_prep.pl ###
######################
# Check for instances of $IDHEADER in committed files, and
# bomb out if they're not present, or corrupted.
# Exclusions can be specified in the exclude file.
# Currently $IDHEADER must be an instance of '$ CVSHeader $', or an alias
# defined in CVSROOT/options.
$CHECK_HEADERS = 0;
$EXCLUDE_FILE = "$CVSROOT/CVSROOT/exclude";
# Make a header check a non-fatal error - just warn, don't exit.
$WARN_HEADERS = 0;
# WARNING: You will also need to be running the version of cvs that
# the FreeBSD project is using; I believe that we have some local patches
# that aren't in the main 'cvs' source.
# Additionally you'll need to tweak CVSROOT/options if you wish to use your
# own ident header.
$IDHEADER = 'CVSHeader';
# Contract any instances of $IDHEADER in the source file before committing.
# This is useful because it means that expanded headers aren't stored in
# the repository as part of the delta.
$UNEXPAND_RCSID = 0;
# Check for DOS/WINDOWS/MAC linebreaks in the file, bomb out if present.
# Exclusions can be specified in the exclude file.
$NO_DOS_LINEBREAKS = 0;
####################
### log_accum.pl ###
####################
# The command used to mail the log messages.
# Usually something like '/usr/sbin/sendmail'.
$MAILCMD = "/usr/sbin/sendmail";
# Email addresses of recipients of commit mail.
$MAILADDRS = 'nobody';
# Extra banner added to the top of commit email.
# Use "" if you don't want one.
# i.e. $MAILBANNER = "Project X CVS Repository";
$MAILBANNER = "";
# Send mail when directories are created in the repository.
# 0 = off, 1 = on.
$MAIL_ON_DIR_CREATION = 0;
# Include the names of the branches committed to in the commit email,
# using this header (leave off the trailing ':').
# Use "" if you don't want one.
$MAIL_BRANCH_HDR = "X-CVS-Branch";
# Include a 'To:' header in the generated commit mail?
$ADD_TO_LINE = 1;
# This is a way to post-process the log email before it is mailed.
# Some people find it useful to use this to create URLs in their
# commit mails to show the patch in a web page (using cvsweb) for
# instance.
#
# The $MAIL_TRANSFORM variable should be "" if you don't want to
# use this feature. Otherwise it should be a reference to a
# subroutine that is passed the email message as a list, and returns
# the modified list to the log_accum.pl script. The list has one
# element per email line, with no trailing line feeds. This function
# shouldn't add them. If $DEBUG is switched on the log_accum.pl
# script will show the before and after on stdout at commit time.
#
# The example below shows a way of inserting links to cvsweb.
$MAIL_TRANSFORM = "";
#$MAIL_TRANSFORM = sub {
# add_cvsweb_entry("http://www.example.org/cgi-bin/cvsweb.cgi", @_);
#};
# A copy of the commit summary is saved locally as well as being
# emailed to the committers. The name of the local log is obtained
# by performing a pattern match on the directory that the files are
# in. The following map defines the file names and their associated
# pattern match. They are checked in order. The name 'other' is
# used if none of the patterns match.
#
# XXX The directory that the logs are placed in should be a
# configuration option too.
@LOG_FILE_MAP = (
'CVSROOT' => '^CVSROOT/',
'doc' => '^doc/',
'user' => '^src/',
'other' => '.*'
);
# Include diffs of not greater than this size in kbytes in the
# commit mail for each file modified. (0 = off).
$MAX_DIFF_SIZE = 0;
# Maximum size of in lines of the diff block.
$DIFF_BLOCK_TOTAL_LINES = 200;
######################
# EXAMPLES
######################
# A function for post-processing a log message
# and outputing it with URLs to a cvsweb.cgi in.
sub add_cvsweb_entry {
my $url_to_cvsweb = shift;
my @input = @_;
my @output = ();
# Skip down to the revision summary.
while (1) {
my $line = shift @input;
last unless defined($line);
push @output, $line;
last if $line =~ /^\s*Revision\s*Changes\s*Path\s*$/;
}
# Add the url links
my $skip = 0;
foreach (@input) {
# The revision block is terminated with an empty line.
$skip = 1 if $_ =~ /^\s*$/;
push @output, $_;
next if $skip;
my ($rev, $add, $sub, $file, $status) = split;
$rev =~ /(?:(.*)\.)?([^\.]+)\.([^\.]+)$/;
my ($base, $r1, $r2) = ($1, $2, $3);
my $prevrev = "";
if ($r2 == 1) {
$prevrev = $base;
} else {
$prevrev = "$base." if $base;
$prevrev .= "$r1." . ($r2 - 1);
}
my $baseurl = "$url_to_cvsweb/$file";
my $extra;
if (defined($status)) {
$rev = $prevrev if $status =~ /dead/;
$extra = "?rev=$rev&content-type=text/plain";
} else {
$extra = ".diff?r1=$prevrev&r2=$rev&f=h";
}
push @output, "$baseurl$extra";
}
return @output;
};
######################################################################
# Load the local configuration file, that allows the entries in this
# file to be overridden.
######################################################################
eval { require "$CVSROOT/CVSROOT/cfg_local.pm" }
if -e "$CVSROOT/CVSROOT/cfg_local.pm";
warn $@ if $@;
1; # Perl requires all modules to return true. Don't delete!!!!
#end

70
CVSROOT/cfg_local.pm Normal file
View file

@ -0,0 +1,70 @@
# $Id$
# $FreeBSD: cfg_local.pm,v 1.26 2003/02/28 21:17:06 peter Exp $
####################################################################
####################################################################
# This file contains local configuration for the CVSROOT perl
# scripts. It is loaded by cfg.pm and overrides the default
# configuration in that file.
#
# It is advised that you test it with
# 'env CVSROOT=/path/to/cvsroot perl -cw cfg.pm'
# before you commit any changes. The check is to cfg.pm which
# loads this file.
####################################################################
####################################################################
# Noch nicht
#$CHECK_HEADERS = 1;
$IDHEADER = 'Id';
$UNEXPAND_RCSID = 1;
%TEMPLATE_HEADERS = (
# "Reviewed by" => '.*',
# "Submitted by" => '.*',
# "Obtained from" => '.*',
# "Approved by" => '.*',
# "PR" => '.*',
# "MFC after" => '\d+(\s+(days?|weeks?|months?))?'
);
$MAILADDRS = 'schlepperbande-commit@zs64.net';
#$MAILCMD = "/usr/local/bin/mailsend -H";
$MAIL_BRANCH_HDR = "X-SCHLEPPERBANDE";
$MAILBANNER = "Schlepperbande repository";
if (defined $ENV{'CVS_COMMIT_ATTRIB'}) {
my $attrib = $ENV{'CVS_COMMIT_ATTRIB'};
$MAILBANNER .= " ($attrib committer)";
}
$MAIL_TRANSFORM = sub {
add_cvsweb_entry("https://koef.zs64.net/schlepperbande/cvs/cvsweb.cgi", @_);
};
$MAX_DIFF_SIZE = 4096;
# Sanity check to make sure we've been run through the wrapper and are
# now primary group 'ncvs'.
#
#$COMMITCHECK_EXTRA = sub {
# my $GRP=`/usr/bin/id -gn`;
# chomp $GRP;
# unless ( $GRP =~ /^ncvs$/ ) {
# print "You do not have group ncvs (commitcheck)!\n";
# exit 1; # We could return false here. But there's
# # nothing to stop us taking action here instead.
# }
# return 1;
#};
@LOG_FILE_MAP = (
'CVSROOT' => '^CVSROOT/',
'distrib' => '^distrib/',
'test' => '^test/',
'other' => '.*'
);
1; # Perl requires all modules to return true. Don't delete!!!!
#end

View file

@ -8,6 +8,21 @@
#
# File format:
#
# [<whitespace>]<filename>[<whitespace><error message>]<end-of-line>
# [<whitespace>]<filename><whitespace><error message><end-of-line>
#
# comment lines begin with '#'
access
avail
cfg.pm
cfg_local.pm
commit_prep.pl
commitcheck
cvs_acls.pl
exclude
log_accum.pl
logcheck
options
rcstemplate
tagcheck
unwrap
wrap

313
CVSROOT/commit_prep.pl Executable file
View file

@ -0,0 +1,313 @@
#!/usr/bin/perl -w
#
# $Id$
# $FreeBSD: commit_prep.pl,v 1.65 2002/08/31 06:07:42 jmallett 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 the 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.
#
# Contributed by David Hampton <hampton@cisco.com>
#
require 5.003; # to be sure. log_accum needs perl5
use strict;
use lib $ENV{CVSROOT};
use CVSROOT::cfg;
my $CVSROOT = $ENV{'CVSROOT'} || die "Can't determine \$CVSROOT!";
############################################################
#
# Constants
#
############################################################
my $ENTRIES = "CVS/Entries";
# The "Id" header to check for.
my $HEADER = $cfg::IDHEADER;
############################################################
#
# Error messages
#
############################################################
my $NoId = "%s - \"\$$HEADER\$\" keyword is either missing or corrupt.\n";
# Protect string from substitution by RCS.
my $NoName = "%s - The ID line should contain only \$$HEADER\$ for " .
"a newly created file.\n";
#$DelPath = "
#%s - The old path and version has been deleted from \$$HEADER\$.\n";
my $BadName = "%s - The pathname '%s'
in the \$$HEADER\$ line does not match the actual filename.\n";
my $BadVersion = "%s - GRRR!! You spammed your copy of the file
which was based upon version %s, with a different version based
upon %s. Please move your '%s' out of the way,
perform an update to get the current version, and then
CAREFULLY merge your changes into that file.\n";
my $DOSLineBreak = "%s - Dos/Windows/Mac linebreaks encountered (line %d).\n";
my $DOSLineErr = "PLEASE use only UNIX linebreaks.\n";
############################################################
#
# Subroutines
#
############################################################
# Write a single line to a file.
sub write_line {
my $filename = shift; # File to write to.
my $line = shift; # Line to write to the file.
open FILE, ">$filename" or die "Cannot open $filename, stopped\n";
print FILE "$line\n";
close FILE;
}
# Check to see whether a file is mentioned in the exclusion file.
sub exclude_file {
my $filename = shift;
my $directory = shift;
my $path = "$directory/$filename";
if (open(EX, "< $cfg::EXCLUDE_FILE")) {
while (<EX>) {
chomp;
my $ex_entry = $_;
# Skip comments and blank lines.
next if $ex_entry =~ /^#/;
next if $ex_entry =~ /^$/;
if ($path =~ /$ex_entry/) {
close(EX);
return(1);
}
}
close(EX);
}
# File shouldn't be excluded.
return(0);
}
sub check_version {
my $filename = shift;
my $directory = shift;
my $hastag = shift;
my $lastversion = shift;
my $found_rcsid; # True if our rcsid was found in the file.
my $rcsid; # The rcsid that was in the file.
my $rcsid_info; # The expanded values of the rcsid.
my $rname; # The file pathname, parsed from the rcsid.
my $version; # The file version, parsed from the rcsid.
my $dos_line_brk_found; # True if we found a DOS line break in the file.
my $line_number; # Keep track of where the line break is.
# not present - either removed or let cvs deal with it.
return 0 unless -f $filename;
# Search the file for our rcsid.
open FILE, $filename or die "Cannot open $filename, stopped\n";
$found_rcsid = 0;
$dos_line_brk_found = 0;
$line_number = 0;
$rcsid_info = "";
while (<FILE>) {
$line_number++;
if ( /^.*(\$$HEADER(: ([^\$]* )?)?\$)/) {
$rcsid = $1;
$rcsid_info = $3 || "";
$found_rcsid = 1;
} elsif ( $cfg::NO_DOS_LINEBREAKS and /\r/ ) {
# Found a DOS linebreak
printf($DOSLineBreak, "$directory/$filename",
$line_number);
$dos_line_brk_found = 1;
}
}
close FILE;
($rname, $version) = split /\s/, $rcsid_info;
# The file must not contain DOS linebreaks.
if ($dos_line_brk_found) {
print $DOSLineErr;
return(1);
}
# The file should have had an rcsid in it!
unless ($found_rcsid) {
printf($NoId, "$directory/$filename");
return(1);
}
# Ignore version mismatches (MFC spamming etc) on branches.
if ($hastag) {
return (0);
}
# A new file should have an unexpanded rcsid.
if ($lastversion eq '0') {
unless ($rcsid_info eq "") {
printf($NoName, "$directory/$filename");
return(1);
}
return(0);
}
# It's ok for the rcsid to be not expanded.
if ($rcsid_info eq "") {
return (0);
# if ($directory =~ /^ports\//) {
# return (0); # ok for ports
# }
# # Don't know whether to allow or trap this. It means
# # one could bypass the version spam checks by simply
# # using a bare tag.
# printf($DelPath, "$directory/$filename");
# return(1);
}
# Check that the file name in the rcsid matches reality.
if ($rname ne "$directory/$filename,v") {
# If ports and the pathname is just the basename
# (eg: somebody sent in a port with $Id$ and the
# committer changed Id -> $HEADER and the version
# numbers otherwise match.
if (!($directory =~ /^ports\// && $rname eq "$filename,v")) {
printf($BadName, "$directory/$filename,v", $rname);
return(1);
}
}
# Check that the version in the rcsid matches reality.
if ($lastversion ne $version) {
printf($BadVersion, $filename, $lastversion,
$version, "$directory/$filename");
return(1);
}
return(0);
}
# Do file fixups, i.e. replacing $ Id: .* $ with $ Id $.
sub fix_up_file {
my $filename = shift;
# not present - either removed or let cvs deal with it.
return 0 unless -f $filename;
open F, "< $filename" or die "Can't open $filename!\n";
my @file = <F>;
close F;
open F, "> $filename.tmp" or die "Can't create $filename tmpfile!\n";
while (@file) {
my $line = shift @file;
$line =~ s/\$$HEADER:.*?\$/\$$HEADER\$/g;
print F $line or die "Out of disk space?\n";
}
close F;
# overwrite the original file......
system($cfg::PROG_MV, "$filename.tmp", $filename);
die "Can't recreate $filename!\n" if $? >> 8;
}
#############################################################
#
# Main Body
#
############################################################
#print("ARGV - ", join(":", @ARGV), "\n");
#print("id - ", $cfg::PID, "\n");
#
# Suck in the Entries file
#
my %cvsversion;
my %cvstag;
open ENTRIES, $ENTRIES or die "Cannot open $ENTRIES.\n";
while (<ENTRIES>) {
chomp;
next if /^D/;
my ($filename, $ver, $stamp, $opt, $tag) = split '/', substr($_, 1);
$cvsversion{$filename} = $ver;
$cvstag{$filename} = $tag;
$stamp = $opt; #silence -w
}
close ENTRIES;
my $directory = $ARGV[0];
shift @ARGV;
$directory =~ s,^$CVSROOT[/]+,,;
my $check_id = 0;
if ($directory =~ /^src\/contrib/) {
$check_id = 3;
}
if ($directory =~ /^src\/crypto/) {
$check_id = 3;
}
#
# Now check each file name passed in, except those excluded.
#
if ($cfg::CHECK_HEADERS or $cfg::WARN_HEADERS) {
my $failed = 0;
foreach my $arg (@ARGV) {
my $hastag = ($cvstag{$arg} ne '');
next if ($check_id == 3 && $hastag);
# Ignore the file if it's in the exclude list.
next if exclude_file($arg, $directory);
# Check to make sure that the file hasn't had
# it's revision string changed.
$failed += &check_version($arg, $directory, $hastag,
$cvsversion{$arg});
# Unexpand the rcsid if required.
fix_up_file($arg) if $cfg::UNEXPAND_RCSID and !$failed;
}
if ($failed and not $cfg::WARN_HEADERS) {
print "\n";
unlink($cfg::LAST_FILE);
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.
#
&write_line($cfg::LAST_FILE, $directory);
exit(0);

74
CVSROOT/commitcheck Executable file
View file

@ -0,0 +1,74 @@
#!/usr/bin/perl -w
#
# $Id$
# $FreeBSD: commitcheck,v 1.26 2002/10/13 23:25:06 peter Exp $
#
# This script is the first thing that is run at commit time
# to determine whether the committer has commit priviledges.
# (See CVSROOT/commitinfo).
#
use strict;
use lib $ENV{CVSROOT};
use CVSROOT::cfg;
my $CVSROOT = $ENV{CVSROOT} || die "Can't determine CVSROOT (commitcheck)!\n";
# Check that the user is committing on the right machine.
#
use Sys::Hostname;
my $hostname = hostname();
if (@cfg::COMMIT_HOSTS && !grep(/^\Q$hostname\E$/i, @cfg::COMMIT_HOSTS)) {
print "Please don't commit on this host!\n";
print "Please commit on ",
join(" or ", @cfg::COMMIT_HOSTS),
" instead.\n";
exit 1;
}
# Run locally defined extra commitchecks.
if (defined($cfg::COMMITCHECK_EXTRA) && $cfg::COMMITCHECK_EXTRA) {
die 'commitcheck: $cfg::COMMITCHECK_EXTRA isn\'t a sub!'
unless ref($cfg::COMMITCHECK_EXTRA) eq "CODE";
die "Failed commitcheck_extra\n" unless &$cfg::COMMITCHECK_EXTRA();
}
#
# Ensure the minimum version of cvs is installed.
#
#my $VERSTR = `$cfg::PROG_CVS -v`;
#$VERSTR =~ s/.*Concurrent\D*(\S*).*/$1/s;
#$VERSTR =~ s/\D+/./g;
#my $VERSION = sprintf "%d%02d%02d%02d\n", split /\./, $VERSTR;
#unless ($VERSION && $VERSION >= $cfg::MINCVSVERSION) {
# print "The wrong version of CVS is installed (commitcheck)!\n";
# exit 1;
#}
#
# Does the access control list allow them commit access?
#
system("$CVSROOT/CVSROOT/cvs_acls.pl", @ARGV);
if ($? >> 8) {
print "Access control checks failed! (cvs_acls.pl)\n";
exit 1;
}
#
# Last minute checks and preparations for log_accum.pl later. This
# records the last directory in this commit so that log_accum knows when
# to finish coalescing commit messages and mail it.
#
system("$CVSROOT/CVSROOT/commit_prep.pl", @ARGV);
if ($? >> 8) {
print "commit_prep.pl failed!\n";
exit 1;
}
exit 0; # Lets do it!
#end

View file

@ -13,3 +13,4 @@
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".
ALL $CVSROOT/CVSROOT/commitcheck

View file

@ -9,9 +9,9 @@
# command.
#TopLevelAdmin=no
# Set `LogHistory' to `all' or `TOEFWUPCGMAR' to log all transactions to the
# Set `LogHistory' to `all' or `TOFEWGCMAR' to log all transactions to the
# history file, or a subset as needed (ie `TMAR' logs all write operations)
#LogHistory=TOEFWUPCGMAR
#LogHistory=TOFEWGCMAR
# Set `RereadLogAfterVerify' to `always' (the default) to allow the verifymsg
# script to change the log message. Set it to `stat' to force CVS to verify# that the file has changed before reading it (this can take up to an extra

246
CVSROOT/cvs_acls.pl Executable file
View file

@ -0,0 +1,246 @@
#!/usr/bin/perl -w
#
# $Id$
# $FreeBSD: cvs_acls.pl,v 1.24 2002/07/22 17:24:29 joe Exp $
#
# Access control lists for CVS. dgg@ksr.com (David G. Grubbs)
#
# ==== 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.
#
# Additional (2001/11/16): I've added a group function for labelling
# groups of users. To define a group add a line in the avail file of
# the form:
# group|grpname1|joe,fred,bob
# group|grpname2|pete,:grpname1,simon
# group|grpname2|sid,:grpname2,mike
# group|anothergroup|!filename/containing/listofusers
#
# The group name can be used in any place a user name could be used in
# an avail or unavail line. Just precede the group name with a ':'
# character. In the example above you'll note that you can define a
# group more than once. Each definition overrides the previous one,
# but can include itself to add to it.
#
# In place of a username in any of the above rules, you can specify
# a group name preceeded with a ':' character, or a filename preceeded
# with a '!' character. In the case of a file it is assumed relative to
# $CVSROOT/CVSROOT/ unless it started witha leading '/'. All blank lines
# and comments are ignored, and the remaining lines are treated as one
# username per line.
use strict;
use lib $ENV{CVSROOT};
use CVSROOT::cfg;
my $CVSROOT = $ENV{'CVSROOT'} || die "Can't determine \$CVSROOT!";
my $debug = $cfg::DEBUG;
my %GROUPS; # List of committer groups
my $exit_val = 0; # Good Exit value
my $universal_off = 0;
#######################################
# process any variable=value switches
#######################################
my $die = '';
eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';"
while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV));
exit 255 if $die;
#######################################
# Work out where in the repo we're at.
#######################################
my $repos = shift;
$repos =~ s:^$CVSROOT/::;
grep($_ = $repos . '/' . $_, @ARGV);
print "$$ Repos: $repos\n","$$ ==== ",join("\n$$ ==== ",@ARGV),"\n" if $debug;
#######################################
# Check that the user has permission.
#######################################
# It is ok for the avail file not to exist.
exit 0 unless -e $cfg::AVAIL_FILE;
# Suck in a list of committer groups from the avail file.
open (AVAIL, $cfg::AVAIL_FILE) || die "open $cfg::AVAIL_FILE: $!\n";
while (<AVAIL>) {
next unless /^group\|/;
chomp;
my ($keywrd, $gname, $members) = split /\|/, $_;
$GROUPS{$gname} = expand_users($members);
}
close(AVAIL);
open (AVAIL, $cfg::AVAIL_FILE) || die "open $cfg::AVAIL_FILE: $!\n";
while (<AVAIL>) {
chomp;
next if /^\s*\#/;
next if /^\s*$/;
next if /^group\|/;
print "--------------------\n" if $debug;
my $rule = $_;
my ($flagstr, $u, $m) = split(/[\s,]*\|[\s,]*/, $rule);
# Skip anything not starting with "avail" or "unavail" and complain.
if ($flagstr !~ /^avail/ && $flagstr !~ /^unavail/) {
print "Bad avail line: $rule\n";
next;
}
# Set which bit we are playing with. ('0' is OK == Available).
my $flag = (($& eq "avail") ? 0 : 1);
# If we find a "universal off" flag (i.e. a simple "unavail")
# remember it
my $universal_off = 1 if ($flag && !$u && !$m);
# Expand any group names into a full user list.
my $users = expand_users($u);
# $cfg::COMMITTER considered "in user list" if actually in list
# or is NULL
my $in_user = (!$u || grep ($_ eq $cfg::COMMITTER,
split(/[\s,]+/, $users)));
print "$$ \$cfg::COMMITTER ($cfg::COMMITTER) in user list: $rule\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.
my $in_repo = (!$m || 0);
unless ($in_repo) {
my @tmp = split(/[\s,]+/, $m);
for my $j (@tmp) {
# If the repos from avail is a parent(or equal)
# dir of $repos, OK
if ($repos eq $j || $repos =~ /^$j\//) {
$in_repo = 1;
last;
}
}
unless ($in_repo) {
#$in_repo = 1;
for my $j (@ARGV) {
last unless $in_repo = grep ($_ eq $j, @tmp);
}
}
}
print "$$ \$repos($repos) in repository list: $rule\n"
if $debug && $in_repo;
print "$$ Expanded user list: $users\n" if $debug;
$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 ($cfg::COMMITTER|$repos)\n"
if $exit_val;
print "**** Access allowed: Personal Karma exceeds Environmental Karma.\n"
if $debug && $universal_off && !$exit_val;
exit($exit_val);
# Expand a user specification containing group names and deltas into
# a definitive list of users.
sub expand_users {
my $user_list = shift || "";
# Parse the members.
my @members = split /,/, $user_list;
my %members;
foreach my $m (@members) {
if ($m =~ s/^://) {
if (!defined($GROUPS{$m})) {
warn "Group '$m' not defined before use in " .
"$cfg::AVAIL_FILE.\n";
next;
}
# Add the specified group to the membership.
foreach (split /,/, $GROUPS{$m}) {
$members{$_} = 1;
}
} elsif ($m =~ s/\!//) {
$m = "$CVSROOT/CVSROOT/$m" if $m !~ /^\//;
if (open USERLIST, $m) {
while (<USERLIST>) {
chomp;
s/\s*(#.*)?$//;
next if /^$/;
$members{$_} = 1;
}
close USERLIST;
} else {
warn "Can't open user file $m " .
"defined in $cfg::AVAIL_FILE.\n";
}
} else {
$members{$m} = 1;
}
}
return join("," , sort keys %members);
}

75
CVSROOT/exclude Normal file
View file

@ -0,0 +1,75 @@
# Exclusions list for header checking.
# $Id$
# $FreeBSD: exclude,v 1.105 2003/11/07 04:27:59 kan Exp $
#
# Skip dot files.
^(.*/)?\.
# A number of files in CVSROOT don't need to be checked.
^CVSROOT/cvsignore
^CVSROOT/options
^CVSROOT/rcstemplate
^distrib/
^www/
^doc/.*\.eps
^doc/.*\.png
^doc/.*\.scr
# Skip all ports files except for Makefiles.
^ports/.*(?<!/Makefile)$
^src/contrib/gdb/gdb/version.in
^src/contrib/groff/tmac/
^src/contrib/nvi/catalog
^src/etc/minfree
^src/etc/motd
^src/lib/libc_r/test/.*\.exp
^src/lib/libz/.*(?<!/Makefile)$
^src/release/sysinstall/help/.*\.hlp
^src/share/examples/cvsup/refuse
^src/share/examples/etc/bsd-style-copyright
^src/share/info/dir-tmpl
^src/share/man/man0
^src/sys/boot/common/help.common
^src/sys/boot/i386/loader/help.i386
^src/sys/boot/pc98/loader/help.pc98
^src/sys/boot/sparc64/loader/help.sparc64
^src/sys/contrib/dev/acpica
^src/sys/contrib/dev/ath
^src/sys/contrib/ia64/libuwx/
^src/tools/.*\.gif
^src/tools/.*\.png
^src/tools/regression/.*\.(in|out)
^src/usr.bin/doscmd/fonts.dir
^src/usr.bin/more/more.help
^src/usr.bin/mail/misc/mail.help
^src/usr.bin/mail/misc/mail.tildehelp
^src/usr.sbin/sysinstall/help/.*\.hlp
^src/.*\.ps
# src/share/zoneinfo is an externally-maintained database
# (would have been in src/contrib had the latter existed sooner).
# We don't normally keep local modifications to it, but it's no
# longer on the vendor branch for historical reasons.
# Exclude it so that we can use the vendor files verbatim.
^src/share/zoneinfo/[Ta-z]
# Treat the TrustedBSD Web site just as the FreeBSD Web site.
^projects/trustedbsd/www/
# Skip the CVSweb icon files
^projects/cvsweb/icons/
# Dictionaries should have no extra noise in them
^src/share/dict/*
# OpenSSL Generated manpages
^src/secure/lib/libcrypto/man
^src/secure/lib/libssl/man
^src/secure/usr.bin/openssl/man
# OpenSSH sources
^src/crypto/openssh

903
CVSROOT/log_accum.pl Executable file
View file

@ -0,0 +1,903 @@
#!/usr/bin/perl -w
#
# $Id$
# $FreeBSD: log_accum.pl,v 1.122 2003/02/28 18:28:11 peter Exp $
#
# 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.
#
# Originally by David Hampton <hampton@cisco.com>
#
# Extensively hacked for FreeBSD by Peter Wemm <peter@netplex.com.au>,
# with parts stolen from Greg Woods <woods@most.wierd.com> version.
#
# Extensively cleaned up and re-worked to use an external configuration
# file by Josef Karthauser <joe@tao.org.uk>.
require 5.003; # might work with older perl5
use strict;
use Text::Tabs;
use lib $ENV{CVSROOT};
use CVSROOT::cfg;
my $CVSROOT = $ENV{'CVSROOT'} || die "Can't determine \$CVSROOT!";
############################################################
#
# Constants
#
############################################################
my $STATE_NONE = 0;
my $STATE_CHANGED = 1;
my $STATE_ADDED = 2;
my $STATE_REMOVED = 3;
my $STATE_LOG = 4;
my $BASE_FN = "$cfg::TMPDIR/$cfg::FILE_PREFIX";
my $LAST_FILE = $cfg::LAST_FILE;
my $CHANGED_FILE = "$BASE_FN.changed";
my $ADDED_FILE = "$BASE_FN.added";
my $REMOVED_FILE = "$BASE_FN.removed";
my $LOG_FILE = "$BASE_FN.log";
my $SUMMARY_FILE = "$BASE_FN.summary";
my $LOGNAMES_FILE = "$BASE_FN.lognames";
my $SUBJ_FILE = "$BASE_FN.subj";
my $TAGS_FILE = "$BASE_FN.tags";
my $DIFF_FILE = "$BASE_FN.diff";
############################################################
#
# Subroutines
#
############################################################
# Remove the temporary files.
sub cleanup_tmpfiles {
my @files; # The list of temporary files.
# Don't clean up afterwards if in debug mode.
return if $cfg::DEBUG;
opendir DIR, $cfg::TMPDIR or die "Cannot open directory: $cfg::TMPDIR!";
push @files, grep /^$cfg::FILE_PREFIX\..*$/, readdir(DIR);
closedir DIR;
foreach (@files) {
unlink "$cfg::TMPDIR/$_";
}
}
# Append a line to a named file.
sub append_line {
my $filename = shift; # File to append to.
my $line = shift; # Line to append.
open FILE, ">>$filename" or
die "Cannot open for append file $filename.\n";
print FILE "$line\n";
close FILE;
}
# Read the first line from a named file.
sub read_line {
my $filename = shift; # The file to read the line from.
my $line; # The line read from the file.
open FILE, "<$filename" or die "Cannot read file $filename!";
$line = <FILE>;
close FILE;
chomp $line;
return $line;
}
# Return the contents of a file as a list of strings,
# with trailing line feeds removed.
# Return an empty list of the file couldn't be opened for some reason.
sub read_logfile {
my $filename = shift; # The file to read from.
my @text = (); # The contents of the file.
if (open FILE, "<$filename") {
while (<FILE>) {
chomp;
push @text, $_;
}
close FILE;
}
return @text;
}
# Write a list to a file.
sub write_logfile {
my $filename = shift; # File to write to.
my @lines = @_; # Contents to write to file.
open FILE, ">$filename" or
die "Cannot open for write log file $filename.";
print FILE map { "$_\n" } @lines;
close FILE;
}
sub format_names {
my $dir = shift;
my @files = @_;
my $indent = length($dir);
$indent = 20 if $indent < 20;
my $format = " %-" . sprintf("%d", $indent) . "s ";
my @lines = (sprintf($format, $dir));
if ($cfg::DEBUG) {
print STDERR "format_names(): dir = ", $dir;
#print STDERR "; tag = ", $tag;
print STDERR "; files = ", join(":", @files), ".\n";
}
foreach my $file (@files) {
if (length($lines[$#lines]) + length($file) > 66) {
$lines[++$#lines] = sprintf($format, "", "");
}
$lines[$#lines] .= $file . " ";
}
return @lines;
}
sub format_lists {
my $header = shift;
my @lines = @_;
print STDERR "format_lists(): ", join(":", @lines), "\n" if $cfg::DEBUG;
my $lastdir = '';
my $lastsep = '';
my $tag = '';
my @files = ();
my @text = ();
foreach my $line (@lines) {
if ($line =~ /.*\/$/) {
push @text, &format_names($lastdir, @files) if $lastdir;
@files = ();
$lastdir = $line;
$lastdir =~ s,/$,,;
$tag = ""; # next thing is a tag
} elsif (!$tag) {
$tag = $line;
next if "$header$tag" eq $lastsep;
$lastsep = $header . $tag;
if ($tag eq 'HEAD') {
push @text, " $header files:";
} else {
push @text, sprintf(" %-22s (Branch: %s)",
"$header files:", $tag);
}
} else {
push @files, $line;
}
}
push @text, &format_names($lastdir, sort @files);
return @text;
}
sub append_names_to_file {
my $filename = shift;
my $dir = shift;
my $tag = shift;
my @files = @_;
return unless @files;
open FILE, ">>$filename" or die "Cannot append to file $filename.";
print FILE $dir, "\n";
print FILE $tag, "\n";
print FILE map { "$_\n" } @files;
close FILE;
}
#
# Use cvs status to obtain the current revision number of a given file.
#
sub get_revision_number {
my $file = shift;
my $rcsfile = "";
my $revision = "";
open(RCS, "-|") || exec $cfg::PROG_CVS, '-Qn', 'status', $file;
while (<RCS>) {
if (/^[ \t]*Repository revision/) {
chomp;
my @revline = split;
$revision = $revline[2];
$revline[3] =~ m|^$CVSROOT/+(.*),v$|;
$rcsfile = $1;
last;
}
}
close RCS;
$rcsfile =~ s|/Attic/|/|; # Remove 'Attic/' if present.
return($revision, $rcsfile);
}
#
# Return the previous revision number.
#
sub previous_revision {
my $rev = shift;
$rev =~ /(?:(.*)\.)?([^\.]+)\.([^\.]+)$/;
my ($base, $r1, $r2) = ($1, $2, $3);
my $prevrev = "";
if ($r2 == 1) {
$prevrev = $base;
} else {
$prevrev = "$base." if $base;
$prevrev .= "$r1." . ($r2 - 1);
}
return $prevrev;
}
#
# Count the number of lines in a given revision of a file.
#
sub count_lines_in_revision {
my $file = shift; # File in repository.
my $rev = shift; # Revision number.
my $lines = 0;
open(RCS, "-|") ||
exec $cfg::PROG_CVS, '-Qn', 'update', '-p', "-r$rev", $file;
while (<RCS>) {
++$lines;
}
close RCS;
return $lines;
}
#
# Summarise details of the file modifications.
#
sub change_summary_changed {
my $outfile = shift; # File name of output file.
my @filenames = @_; # List of files to check.
foreach my $file (@filenames) {
next unless $file;
my $delta = "";
my ($rev, $rcsfile) = get_revision_number($file);
if ($rev and $rcsfile) {
open(RCS, "-|") ||
exec $cfg::PROG_CVS, '-Qn', 'log', "-r$rev", $file;
while (<RCS>) {
if (/^date:.*lines:\s(.*)$/) {
$delta = $1;
last;
}
}
close RCS;
}
&append_line($outfile, "$rev,$delta,,$rcsfile");
}
}
#
# Summarise details of added files.
#
sub change_summary_added {
my $outfile = shift; # File name of output file.
my @filenames = @_; # List of files to check.
foreach my $file (@filenames) {
next unless $file;
my $delta = "";
my ($rev, $rcsfile) = get_revision_number($file);
if ($rev and $rcsfile) {
my $lines = count_lines_in_revision($file, $rev);
$delta = "+$lines -0";
}
&append_line($outfile, "$rev,$delta,new,$rcsfile");
}
}
#
# Summarise details of removed files.
#
sub change_summary_removed {
my $outfile = shift; # File name of output file.
my @filenames = @_; # List of files to check.
foreach my $file (@filenames) {
next unless $file;
my $delta = "";
my ($rev, $rcsfile) = get_revision_number($file);
if ($rev and $rcsfile) {
my $prevrev = previous_revision($rev);
my $lines = count_lines_in_revision($file, $prevrev);
$delta = "+0 -$lines";
}
&append_line($outfile, "$rev,$delta,dead,$rcsfile");
}
}
sub build_header {
delete $ENV{'TZ'};
my $datestr = `/bin/date +"%Y/%m/%d %H:%M:%S %Z"`;
chomp $datestr;
my $header = sprintf("%-8s %s", $cfg::COMMITTER, $datestr);
my @text;
push @text, $header;
push @text, "";
push @text, " $cfg::MAILBANNER", "" if $cfg::MAILBANNER;
return @text;
}
# !!! Mailing-list and commitlog history file mappings here !!!
# This needs pulling out as a configuration block somewhere so
# that others can easily change it.
sub get_log_name {
my $dir = shift; # Directory name
for my $i (0 .. ($#cfg::LOG_FILE_MAP - 1) / 2) {
my $log = $cfg::LOG_FILE_MAP[$i * 2];
my $pattern = $cfg::LOG_FILE_MAP[$i * 2 + 1];
return $log if $dir =~ /$pattern/;
}
return 'other';
}
sub do_changes_file {
my @text = @_;
my %unique = ();
my @mailaddrs = &read_logfile($LOGNAMES_FILE);
foreach my $category (@mailaddrs) {
next if ($unique{$category});
$unique{$category} = 1;
my $changes = "$CVSROOT/CVSROOT/commitlogs/$category";
open CHANGES, ">>$changes"
or die "Cannot open $changes.\n";
print CHANGES map { "$_\n" } @text;
print CHANGES "\n\n\n";
close CHANGES;
}
}
sub mail_notification {
my @text = @_;
# This is turned off since the To: lines go overboard.
# Also it has bit-rotted since, and can't just be switched on again.
# - but keep it for the time being in case we do something like cvs-stable
# my @mailaddrs = &read_logfile($LOGNAMES_FILE);
# print(MAIL 'To: cvs-committers' . $dom . ", cvs-all" . $dom);
# foreach $line (@mailaddrs) {
# next if ($unique{$line});
# $unique{$line} = 1;
# next if /^cvs-/;
# print(MAIL ", " . $line . $dom);
# }
# print(MAIL "\n");
my @email = ();
my $to = $cfg::MAILADDRS;
print "Mailing the commit message to '$to'.\n";
push @email, "To: $to" if $cfg::ADD_TO_LINE;
my $subject = 'Subject: Schlepperbande commit:';
my @subj = &read_logfile($SUBJ_FILE);
my $subjlines = 0;
my $subjwords = 0; # minimum of two "words" per line
LINE: foreach my $line (@subj) {
foreach my $word (split(/ /, $line)) {
if ($subjwords > 2 &&
length("$subject $word") > 75) {
if ($subjlines > 2) {
$subject .= " ...";
}
push @email, $subject;
if ($subjlines > 2) {
$subject = "";
last LINE;
}
# rfc822 continuation line
$subject = " ";
$subjwords = 0;
$subjlines++;
}
$subject .= " " . $word;
$subjwords++;
}
}
push @email, $subject if $subject;
# If required add a header to the mail msg showing
# which branches were modified during the commit.
if ($cfg::MAIL_BRANCH_HDR) {
my %tags = map { $_ => 1 } &read_logfile($TAGS_FILE);
if (keys %tags) {
push @email, $cfg::MAIL_BRANCH_HDR . ": " .
join(",", sort keys %tags);
}
}
push @email, "";
push @email, @text;
# Transform the email message?
if (defined($cfg::MAIL_TRANSFORM) && $cfg::MAIL_TRANSFORM) {
die 'log_accum.pl: $cfg::MAIL_TRANSFORM isn\'t a sub!'
unless ref($cfg::MAIL_TRANSFORM) eq "CODE";
if ($cfg::DEBUG) {
print "Email transform.\n";
print map { "Before: $_\n" } @email;
}
@email = &$cfg::MAIL_TRANSFORM(@email);
print map { "After: $_\n" } @email if $cfg::DEBUG;
}
# Send the email.
open MAIL, "| $cfg::MAILCMD $to"
or die "Please check $cfg::MAILCMD.";
print MAIL map { "$_\n" } @email;
close MAIL;
}
# Return the length of the longest value in the list.
sub longest_value {
my @values = @_;
my @sorted = sort { $b <=> $a } map { length $_ } @values;
return $sorted[0];
}
sub format_summaries {
my @filenames = @_;
my @revs;
my @deltas;
my @files;
my @statuses;
# Parse the summary file.
foreach my $filename (@filenames) {
open FILE, $filename or next;
while (<FILE>) {
chomp;
my ($r, $d, $s, $f) = split(/,/, $_, 4);
push @revs, $r;
push @deltas, $d;
push @statuses, $s;
push @files, $f;
}
close FILE;
}
# Format the output, extra spaces after "Changes"
# to match historic formatting.
my $r_max = longest_value("Revision", @revs) + 2;
my $d_max = longest_value("Changes ", @deltas) + 2;
my @text;
my $fmt = "%-" . $r_max . "s%-" . $d_max . "s%s";
push @text, sprintf $fmt, "Revision", "Changes", "Path";
my @order = sort { $files[$a] cmp $files[$b] } (0 .. $#revs);
foreach (@order) {
my $file = $files[$_];
my $status = $statuses[$_];
$file .= " ($status)" if $status;
push @text, sprintf $fmt, $revs[$_], $deltas[$_], $file;
}
return @text;
}
#
# Make a diff of the changes.
#
sub do_diff {
my $outfile = shift;
my @filenames = @_; # List of files to check.
foreach my $file (@filenames) {
next unless $file;
my $diff;
my ($rev, $rcsfile) = get_revision_number($file);
#
# 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|tar|tgz|gz)$/i) or (-B $file)) {
$diff .= "Index: $file\n";
$diff .= "=" x 67 . "\n";
$diff .= "\t<<Binary file>>\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]+)$/) {
my $prev_rev = previous_revision($rev);
my @args = ();
if ($rev eq '1.1') {
$diff .= "Index: $file\n"
. "=" x 68 . "\n";
@args = ('-Qn', 'update', '-p',
'-r1.1', $file);
} else {
@args = ('-Qn', 'diff', '-u',
"-r$prev_rev", "-r$rev", $file);
}
print "Generating diff: $cfg::PROG_CVS @args\n"
if $cfg::DEBUG;
open(DIFF, "-|") || exec $cfg::PROG_CVS, @args;
while(<DIFF>) {
$diff .= $_;
}
close DIFF;
}
}
my $diff_length = length($diff);
if ($diff_length > $cfg::MAX_DIFF_SIZE * 1024) {
$diff = "File/diff for $file is too large (" .
$diff_length . " bytes > " .
$cfg::MAX_DIFF_SIZE * 1024 . " bytes)!\n";
}
#&append_line($outfile, "$diff");
}
}
#############################################################
#
# Main Body
#
############################################################
#
# Setup environment
#
umask (002);
#
# Initialize basic variables
#
my $input_params = $ARGV[0];
my ($directory, @filenames) = split " ", $input_params;
#@files = split(' ', $input_params);
my @path = split('/', $directory);
my $dir;
if ($#path == 0) {
$dir = ".";
} else {
$dir = join('/', @path[1..$#path]);
}
$dir = $dir . "/";
#
# Throw some values at the developer if in debug mode
#
if ($cfg::DEBUG) {
print "ARGV - ", join(":", @ARGV), "\n";
print "directory - ", $directory, "\n";
print "filenames - ", join(":", @filenames), "\n";
print "path - ", join(":", @path), "\n";
print "dir - ", $dir, "\n";
print "pid - ", $cfg::PID, "\n";
}
# Was used for To: lines, still used for commitlogs naming.
&append_line($LOGNAMES_FILE, &get_log_name("$directory/"));
&append_line($SUBJ_FILE, "$directory " . join(" ", sort @filenames));
#
# Check for a new directory first. This will always appear as a
# single item in the argument list, and an empty log message.
#
if ($input_params =~ /New directory/) {
my @text = &build_header();
push @text, " $input_params";
&do_changes_file(@text);
&mail_notification(@text) if $cfg::MAIL_ON_DIR_CREATION;
&cleanup_tmpfiles();
exit 0;
}
#
# Check for an import command. This will always appear as a
# single item in the argument list, and a log message.
#
if ($input_params =~ /Imported sources/) {
my @text = &build_header();
my $vendor_tag;
push @text, " $input_params";
while (<STDIN>) {
chomp;
push @text, " $_";
$vendor_tag = $1 if /Vendor Tag:\s*(\S*)/;
}
&append_line($TAGS_FILE, $vendor_tag) if $vendor_tag;
&do_changes_file(@text);
&mail_notification(@text);
#system("/usr/local/bin/awake", $directory);
&cleanup_tmpfiles();
exit 0;
}
#
# Iterate over the body of the message collecting information.
#
my %added_files; # Hashes containing lists of files
my %changed_files; # that have been changed, keyed
my %removed_files; # by branch tag.
my @log_lines; # The lines of the log message.
my $tag = "HEAD"; # Default branch is HEAD.
my $state = $STATE_NONE; # Initially in no state.
while (<STDIN>) {
s/[ \t\n]+$//; # delete trailing space
# parse the revision tag if it exists.
if (/^Revision\/Branch:(.*)/) { $tag = $1; next; }
if (/^[ \t]+Tag: (.*)/) { $tag = $1; next; }
if (/^[ \t]+No tag$/) { $tag = "HEAD"; next; }
# check for a state change, guarding against similar markers
# in the log message itself.
unless ($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; }
}
# don't so anything if we're not in a state.
next if $state == $STATE_NONE;
# collect the log line (ignoring empty template entries)?
if ($state == $STATE_LOG) {
next if /^(.*):$/ and $cfg::TEMPLATE_HEADERS{$1};
push @log_lines, $_;
}
# otherwise collect information about which files changed.
my @files = split;
push @{ $changed_files{$tag} }, @files if $state == $STATE_CHANGED;
push @{ $added_files{$tag} }, @files if $state == $STATE_ADDED;
push @{ $removed_files{$tag} }, @files if $state == $STATE_REMOVED;
}
&append_line($TAGS_FILE, $tag);
#
# Strip leading and trailing blank lines from the log message.
# Compress multiple blank lines in the body of the message down to a
# single blank line.
# Convert tabs to spaces, so that when we indent the email message and
# log file everything still lines up.
# (Note, this only does the mail and changes log, not the rcs log).
#
my $log_message = join "\n", @log_lines;
$log_message =~ s/\n{3,}/\n\n/g;
$log_message =~ s/^\n+//;
$log_message =~ s/\n+$//;
@log_lines = expand(split /\n/, $log_message);
#
# Find the log file that matches this log message
#
my $message_index; # The index of this log message
for ($message_index = 0; ; $message_index++) {
last unless -e "$LOG_FILE.$message_index";
my @text = &read_logfile("$LOG_FILE.$message_index");
last unless @text;
last if "@log_lines" eq "@text";
}
#
# Spit out the information gathered in this pass.
#
foreach my $tag ( keys %added_files ) {
&append_names_to_file("$ADDED_FILE.$message_index", $dir, $tag,
@{ $added_files{$tag} });
}
foreach my $tag ( keys %changed_files ) {
&append_names_to_file("$CHANGED_FILE.$message_index", $dir, $tag,
@{ $changed_files{$tag} });
}
foreach my $tag ( keys %removed_files ) {
&append_names_to_file("$REMOVED_FILE.$message_index", $dir, $tag,
@{ $removed_files{$tag} });
}
&write_logfile("$LOG_FILE.$message_index", @log_lines);
#
# Save the info for the commit summary.
#
foreach my $tag ( keys %added_files ) {
&change_summary_added("$SUMMARY_FILE.$message_index",
@{ $added_files{$tag} });
&do_diff("$DIFF_FILE.$message_index", @{ $added_files{$tag} })
if ( $cfg::MAX_DIFF_SIZE > 0 );
}
foreach my $tag ( keys %changed_files ) {
&change_summary_changed("$SUMMARY_FILE.$message_index",
@{ $changed_files{$tag} });
&do_diff("$DIFF_FILE.$message_index", @{ $changed_files{$tag} })
if ( $cfg::MAX_DIFF_SIZE > 0 );
}
foreach my $tag ( keys %removed_files ) {
&change_summary_removed("$SUMMARY_FILE.$message_index",
@{ $removed_files{$tag} });
}
#
# Check whether this is the last directory. If not, quit.
# The last directory name was written by commit_prep.pl on
# the way in.
#
if (-e $LAST_FILE) {
$_ = &read_line($LAST_FILE);
my $tmpfiles = $directory;
$tmpfiles =~ s,([^a-zA-Z0-9_/]),\\$1,g;
unless (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.
#
#
# Produce the final compilation of the log messages
#
my $diff_num_lines = $cfg::DIFF_BLOCK_TOTAL_LINES;
for (my $i = 0; ; $i++) {
last unless -e "$LOG_FILE.$i";
my @log_msg = &build_header();
my @mod_lines = &read_logfile("$CHANGED_FILE.$i");
push @log_msg, &format_lists("Modified", @mod_lines) if @mod_lines;
my @add_lines = &read_logfile("$ADDED_FILE.$i");
push @log_msg, &format_lists("Added", @add_lines) if @add_lines;
my @rem_lines = &read_logfile("$REMOVED_FILE.$i");
push @log_msg, &format_lists("Removed", @rem_lines) if @rem_lines;
my @msg_lines = &read_logfile("$LOG_FILE.$i");
push @log_msg, " Log:", (map { " $_" } @msg_lines) if @msg_lines;
if (-e "$SUMMARY_FILE.$i") {
push @log_msg, " ", map {" $_"}
format_summaries("$SUMMARY_FILE.$i");
}
#
# Add a copy of the message in the relevant log files.
#
&do_changes_file(@log_msg);
#
# Add the diff after writing the log files.
#
if (-e "$DIFF_FILE.$i" and $diff_num_lines > 0) {
my @diff_block = read_logfile("$DIFF_FILE.$i");
my $lines_to_use = scalar @diff_block;
$lines_to_use = $diff_num_lines
if $lines_to_use > $diff_num_lines;
push @log_msg, " ",
map {" $_"} @diff_block[0 .. $lines_to_use - 1];
$diff_num_lines -= $lines_to_use;
if ($diff_num_lines <= 0) {
push @log_msg, "",
"----------------------------------------------",
"Diff block truncated. (Max lines = " .
$cfg::DIFF_BLOCK_TOTAL_LINES . ")",
"----------------------------------------------",
"";
}
}
#
# Mail out the notification.
#
&mail_notification(@log_msg);
}
#system("/usr/local/bin/awake", $directory);
&cleanup_tmpfiles();
exit 0;
# EOF

137
CVSROOT/logcheck Executable file
View file

@ -0,0 +1,137 @@
#! /usr/bin/perl -w
#
# $FreeBSD: logcheck,v 1.24 2001/12/24 15:00:18 joe Exp $
#
# This hack is to sanitise the results of what the user may have
# "done" while editing the commit log message.. :-) Peter Wemm.
#
# Note: this uses an enhancement to cvs's verifymsg functionality.
# Normally, the check is advisory only, the FreeBSD version reads
# back the file after the verifymsg file so that this script can
# make changes.
#
use strict;
use lib $ENV{CVSROOT};
use CVSROOT::cfg;
#############################################################
#
# Main Body
#
############################################################
my $filename = shift;
die "Usage: logcheck filename\n" unless $filename;
# Read the log file in, stripping 'CVS:' lines and removing trailing
# white spaces.
open IN, "< $filename" or
die "logcheck: Cannot open for reading: $filename: $!\n";
my @log_in = map { s/^(.*?)\s*$/$1/; $1 } grep { !/^CVS:/ } <IN>;
close IN;
# Remove duplicate blank lines.
my $i = 0;
while ($i < scalar(@log_in) - 1) {
if ($log_in[$i] eq "" && $log_in[$i + 1] eq "") {
splice(@log_in, $i, 1);
next;
}
++$i;
}
# Remove leading and trailing blank lines. (There will be at most
# one because of the duplicate removal above).
shift @log_in if $log_in[0] eq "";
pop @log_in if $log_in[-1] eq "";
# Scan through the commit message looking for templated headers
# as defined in the configuration file, and rcstemplate.
# Assume that these only exist in the last paragraph.
# Filter out blank entries, and type check if necessary.
my $j = $#log_in; # The index of the last entry in the commit msg.
my $error = 0;
while ($j >= 0) {
my $logline = $log_in[$j];
--$j;
# Hitting a blank line means that we've seen all of the last paragraph.
last if $logline eq "";
unless ($logline =~ /^(.*?):\s*(.*)$/) {
### XXX
# We're here because we saw a line that didn't match
# a template header (no ':'). This could be a continuation
# line from the previous header, or the log message proper.
# We don't know, so run the risk of checking the last paragraph
# of the log message for headers.
next;
}
my $header = $1;
my $value = $2;
my $pattern = $cfg::TEMPLATE_HEADERS{$header};
# Ignore unrecognised headers.
unless (defined($pattern)) {
### print "Warning: unknown template header: $header\n";
next;
}
# Filter out the template header if it's blank.
if ($value eq "") {
splice(@log_in, $j + 1, 1);
next;
}
# Type check the header
unless ($value =~ /^$pattern$/) {
print "Error: $header: should match '$pattern'.\n";
++$error;
next;
}
}
# Make sure that there is some content in the log message.
# XXX Note that logcheck isn't evoked if the log message is
# completely empty. This is a bug in cvs.
my $log = "@log_in";
die "Log message contains no content!\n" if $log =~ /^\s*$/;
# Write the modified log file back out.
my $tmpfile = $filename . "tmp";
open OUT, "> $tmpfile" or
die "logcheck: Cannot open for writing: $tmpfile: $!\n";
print OUT map { "$_\n" } @log_in;
close OUT;
# Stop the commit if there was a problem with the template headers.
if ($error) {
print "There were $error errors in the template headers.\n";
print "Please fix the log message and commit again.\n";
print "A copy of your log message was saved in $tmpfile.\n";
exit 1;
}
# Nuke likely editor backups.
unlink "$filename.~";
unlink "$filename.bak";
# Overwrite the log message with our sanitised one. (See the comment
# block at the top of this script for an explaination of why.)
rename($tmpfile, $filename) or
die "logcheck: Could not rename $tmpfile to $filename: $!";
exit 0;

View file

@ -24,3 +24,4 @@
#DEFAULT (echo ""; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog
# or
#DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog
DEFAULT $CVSROOT/CVSROOT/log_accum.pl %s

2
CVSROOT/options Normal file
View file

@ -0,0 +1,2 @@
tag=Schlepperbande=CVSHeader
tagexpand=iSchlepperbande

15
CVSROOT/rcstemplate Normal file
View file

@ -0,0 +1,15 @@
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
MFC after:
CVS: ----------------------------------------------------------------------
CVS: PR: Fill this in if a GNATS PR is affected by the change.
CVS: Submitted by: Fill this in if someone else sent in the change.
CVS: Reviewed by: Fill this in if someone else reviewed your modification.
CVS: Approved by: Fill this in if you needed approval for this commit.
CVS: Obtained from: Fill this in if the change is from third party software.
CVS: MFC after: N [day[s]|week[s]|month[s]]
CVS: Fill in to get MFC notification later. (days assumed unless specified)

31
CVSROOT/tagcheck Executable file
View file

@ -0,0 +1,31 @@
#! /bin/sh
#
# $FreeBSD: tagcheck,v 1.10 2003/01/10 03:05:43 kris Exp $
# TAG add/mov/del repo files...
# $1 $2 $3 $4 ...
case "$1" in
RELENG*)
;;
RELEASE*)
;;
*)
exit 0 # not reserved, ok.
;;
esac
USER=`/usr/bin/id -un`
case "$USER" in
peter | jdp | markm | obrien | murray | jhb | bmah | scottl | kris | nik)
exit 0 # ok
;;
*)
echo "$USER does not have permission to perform this tag operation!" 1>&2
echo "RELENG* tag operations are reserved for release engineering!" 1>&2
echo "RELEASE* tag operations are reserved for portmgr and doceng!" 1>&2
echo "Use 'cvs add' or 'cvs rm' to add/remove files from branches!" 1>&2
echo "$*" | /usr/bin/mail -s "NCVS TAG" cvs
exit 1
;;
esac

22
CVSROOT/unwrap Executable file
View file

@ -0,0 +1,22 @@
#! /bin/sh
#
# $Id$
# $FreeBSD: unwrap,v 1.3 1999/08/27 22:46:57 peter Exp $
#
# unwrap - extract the combined package (created with wrap)
# move the file to a new name with an extension
rm -rf $1.cvswrap
mv $1 $1.cvswrap
# untar the file
if `gzip -t $1.cvswrap > /dev/null 2>&1`
then
zcat -d $1.cvswrap | tar --preserve --sparse -x -f -
else
tar --preserve -x -f $1.cvswrap
fi
# remove the original
rm -rf $1.cvswrap

22
CVSROOT/wrap Executable file
View file

@ -0,0 +1,22 @@
#! /bin/sh
#
# $Id$
# $FreeBSD: wrap,v 1.3 1999/08/27 22:46:57 peter Exp $
#
# wrap - Combine a directory into a single tar package.
# This script is always called with the current directory set to
# where the file to be combined exists. but i may get called with a
# path to where cvs first started executing. (this probably should be
# fixed in cvs) so strip out all of the directory information. The
# first sed expression will only work if the path has a leading /
# if it doesn't the one in the if statement will work.
DIRNAME=`echo $1 | sed -e "s|/.*/||g"`
if [ ! -d $DIRNAME ] ; then
DIRNAME=`echo $1 | sed -e "s|.*/||g"`
fi
#
# Now tar up the directory but we now will only get a relative path
# even if the user did a cvs commit . at the top.
#
tar --preserve -cf - $DIRNAME | gzip --no-name --best -c > $2