#!/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"; }