#!/usr/bin/perl -w
use strict;
use Carp;
use Data::Dumper;
use Getopt::Long;
#< documentation
#use constant VERSION => q$Id: dot-commitmail.pl,v 2.4 2006/02/20 16:48:50 gremio Exp $.$/;
use constant USAGE => <<"EOT"
usage: $0 [-o option] repository revision
EOT
;
=pod
=head1 NAME
dot-commitmail.pl - Subversion hook to send commit email to recipients listed in .commitmail files
=head1 SYNOPSYS
dot-commitmail.pl REPOS REVNUM [options]
=head1 DESCRIPTION
Look for .commitmail files in the repository, and send commit-email to
recipients listed therein, one per line, but only for commits in the
same directory or in subdirectories. We invoke commit-email.pl with
the appropriate -m argument and email addresses, passing on all other
options.
=head1 INSTALLATION
You will find, in your subversion repository, a "hooks" directory.
In it, there is a template post-commit.tmpl. It will tell you that
you can put something like:
/path/to/dot-commitmail.pl "$REPOS" "$REV" -s "[SVN Your_Repos]"
in a post-hook script or batch file to invoke this script.
Then, to start adding people, simply create .commitmail files in your
sandbox and check them in. They should contain one email address per
line. If a commit affects a directory with a .commitmail file, or any
of its subdirectories, then the recipients listed in that .commitmail
file will get the change message.
This script does not actually generate the change message sent, but
relies instead on the commit-email.pl program that was supplied with
Subversion. There are other programs that do this, some make pretty
html with colors for example, and as long as their command line syntax
is the same, you can use this program with one of those. To do so,
add that program to the @possible_commit_email_progs variable here.
=head1 NOTES
commit-email.pl is expected to live either in
/usr/lib/subversion/hook-scripts or in REPOS/hooks/
=head1 SEE ALSO
/usr/lib/subversion/hook-scripts/commit-email.pl REPOS/hooks/post-commit.tmpl
=head1 BUGS
Specifying the -m option will potentially send email to the wrong
recipients without warning.
=head1 AUTHOR
Copyright (c) 2006 Gregory Marton L
This program may be modified and distributed under the same terms as
Subversion itself.
=head1 DOWNLOAD
L
=cut
;
#>
my $COMMITFILENAME = ".commitmail";
##passing on all options, and I don't want to parse and resend just now:
#GetOptions ("help" => sub {exec qq(perldoc $0);},
# "Version" => sub {print VERSION;exit 0;},
# ) or die USAGE;
my ($REPOS, $VERSION, @args) = @ARGV;
#< find $commit_email program
my @possible_commit_email_progs
= ("$REPOS/hooks/commit-email.pl", # more specific first
"/usr/lib/subversion/hook-scripts/commit-email.pl",
);
my $commit_email;
foreach my $prog (@possible_commit_email_progs) {
if (-e $prog and -x _) {
$commit_email = $prog;
last;
}
}
unless ($commit_email) {
die "could not find an executable commit-email.pl\n";
}
#>
#< find $svnlook
my $svnlook;
foreach my $prog (qw(/usr/bin/svnlook)) {
if (-e $prog and -x _) {
$svnlook = $prog;
last;
}
}
unless ($svnlook) {
die "could not find an executable svnlook\n";
}
#>
#< get @dirs_changed
my @dirs_changed = ();
my $get_dirs_changed = qq($svnlook dirs-changed $REPOS -r $VERSION);
open(DCHG, "$get_dirs_changed |") or die "failed [$get_dirs_changed]: $@$!\n";
while () {
chomp;
push @dirs_changed, "/".$_;
}
#>
my %recipients = (); # { path-from-root => [ recipient ] }
#< find %recipients
my $gettree = qq($svnlook tree $REPOS -r $VERSION);
open(TREE, "$gettree|") or die "failed [$gettree]: $@$!\n";
my @path = ();
my $depth = 0;
while () {
my ($indent) = (/^(\s*)/);
my $cdepth = length $indent;
while ($cdepth < $depth) { pop @path, $depth--; }
if (m|\s*(.*[/\\])$|) {
push @path, $1;
$depth++;
} elsif (m/^\s*$COMMITFILENAME$/) {
my $prefix = join("", @path);
foreach my $changed (@dirs_changed) {
if ($changed =~ /^$prefix/) {
my $file = $prefix . $COMMITFILENAME;
my $getcontent = qq($svnlook cat $REPOS $file -r $VERSION);
open(ADDR, "$getcontent |")
or die "failed [$getcontent]: $@$!\n";
my @emails = ();
while () {
chomp;
push @emails, $_;
}
$recipients{join("", @path)} = \@emails;
last;
}
}
} else {
# ignore it
}
}
#>
foreach my $dir (keys %recipients) {
my $cmd = qq($commit_email "$REPOS" "$VERSION" -m "^$dir" ).
join(" ", map { (/\s/ ? qq("$_") : $_) } @args) . " " .
join(" ", @{$recipients{$dir}});
system($cmd) and die "failed [$cmd]: $@$!\n";
}