📄 commit-email.pl.in
字号:
#!/usr/bin/env perl
# ====================================================================
# commit-email.pl: send a commit email for commit REVISION in
# repository REPOS to some email addresses.
#
# For usage, see the usage subroutine or run the script with no
# command line arguments.
#
# $HeadURL: http://svn.collab.net/repos/svn/branches/1.1.x/tools/hook-scripts/commit-email.pl.in $
# $LastChangedDate: 2004-06-14 13:29:22 -0700 (Mon, 14 Jun 2004) $
# $LastChangedBy: breser $
# $LastChangedRevision: 9986 $
#
# ====================================================================
# Copyright (c) 2000-2004 CollabNet. All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://subversion.tigris.org/license-1.html.
# If newer versions of this license are posted there, you may use a
# newer version instead, at your option.
#
# This software consists of voluntary contributions made by many
# individuals. For exact contribution history, see the revision
# history and logs, available at http://subversion.tigris.org/.
# ====================================================================
# Turn on warnings the best way depending on the Perl version.
BEGIN {
if ( $] >= 5.006_000)
{ require warnings; import warnings; }
else
{ $^W = 1; }
}
use strict;
use Carp;
######################################################################
# Configuration section.
# Sendmail path.
my $sendmail = "/usr/sbin/sendmail";
# Svnlook path.
my $svnlook = "@SVN_BINDIR@/svnlook";
# By default, when a file is deleted from the repository, svnlook diff
# prints the entire contents of the file. If you want to save space
# in the log and email messages by not printing the file, then set
# $no_diff_deleted to 1.
my $no_diff_deleted = 0;
# Since the path to svnlook depends upon the local installation
# preferences, check that the required programs exist to insure that
# the administrator has set up the script properly.
{
my $ok = 1;
foreach my $program ($sendmail, $svnlook)
{
if (-e $program)
{
unless (-x $program)
{
warn "$0: required program `$program' is not executable, ",
"edit $0.\n";
$ok = 0;
}
}
else
{
warn "$0: required program `$program' does not exist, edit $0.\n";
$ok = 0;
}
}
exit 1 unless $ok;
}
######################################################################
# Initial setup/command-line handling.
# Each value in this array holds a hash reference which contains the
# associated email information for one project. Start with an
# implicit rule that matches all paths.
my @project_settings_list = (&new_project);
# Process the command line arguments till there are none left. The
# first two arguments that are not used by a command line option are
# the repository path and the revision number.
my $repos;
my $rev;
# Use the reference to the first project to populate.
my $current_project = $project_settings_list[0];
# This hash matches the command line option to the hash key in the
# project. If a key exists but has a false value (''), then the
# command line option is allowed but requires special handling.
my %opt_to_hash_key = ('--from' => 'from_address',
'-h' => 'hostname',
'-l' => 'log_file',
'-m' => '',
'-r' => 'reply_to',
'-s' => 'subject_prefix');
while (@ARGV)
{
my $arg = shift @ARGV;
if ($arg =~ /^-/)
{
my $hash_key = $opt_to_hash_key{$arg};
unless (defined $hash_key)
{
die "$0: command line option `$arg' is not recognized.\n";
}
unless (@ARGV)
{
die "$0: command line option `$arg' is missing a value.\n";
}
my $value = shift @ARGV;
if ($hash_key)
{
$current_project->{$hash_key} = $value;
}
else
{
# Here handle -m.
unless ($arg eq '-m')
{
die "$0: internal error: should only handle -m here.\n";
}
$current_project = &new_project;
$current_project->{match_regex} = $value;
push(@project_settings_list, $current_project);
}
}
elsif ($arg =~ /^-/)
{
die "$0: command line option `$arg' is not recognized.\n";
}
else
{
if (! defined $repos)
{
$repos = $arg;
}
elsif (! defined $rev)
{
$rev = $arg;
}
else
{
push(@{$current_project->{email_addresses}}, $arg);
}
}
}
# If the revision number is undefined, then there were not enough
# command line arguments.
&usage("$0: too few arguments.") unless defined $rev;
# Check the validity of the command line arguments. Check that the
# revision is an integer greater than 0 and that the repository
# directory exists.
unless ($rev =~ /^\d+/ and $rev > 0)
{
&usage("$0: revision number `$rev' must be an integer > 0.");
}
unless (-e $repos)
{
&usage("$0: repos directory `$repos' does not exist.");
}
unless (-d _)
{
&usage("$0: repos directory `$repos' is not a directory.");
}
# Check that all of the regular expressions can be compiled and
# compile them.
{
my $ok = 1;
for (my $i=0; $i<@project_settings_list; ++$i)
{
my $match_regex = $project_settings_list[$i]->{match_regex};
# To help users that automatically write regular expressions
# that match the root directory using ^/, remove the / character
# because subversion paths, while they start at the root level,
# do not begin with a /.
$match_regex =~ s#^\^/#^#;
my $match_re;
eval { $match_re = qr/$match_regex/ };
if ($@)
{
warn "$0: -m regex #$i `$match_regex' does not compile:\n$@\n";
$ok = 0;
next;
}
$project_settings_list[$i]->{match_re} = $match_re;
}
exit 1 unless $ok;
}
######################################################################
# Harvest data using svnlook.
# Change into /tmp so that svnlook diff can create its .svnlook
# directory.
my $tmp_dir = '/tmp';
chdir($tmp_dir)
or die "$0: cannot chdir `$tmp_dir': $!\n";
# Get the author, date, and log from svnlook.
my @svnlooklines = &read_from_process($svnlook, 'info', $repos, '-r', $rev);
my $author = shift @svnlooklines;
my $date = shift @svnlooklines;
shift @svnlooklines;
my @log = map { "$_\n" } @svnlooklines;
# Figure out what directories have changed using svnlook.
my @dirschanged = &read_from_process($svnlook, 'dirs-changed', $repos,
'-r', $rev);
# Lose the trailing slash in the directory names if one exists, except
# in the case of '/'.
my $rootchanged = 0;
for (my $i=0; $i<@dirschanged; ++$i)
{
if ($dirschanged[$i] eq '/')
{
$rootchanged = 1;
}
else
{
$dirschanged[$i] =~ s#^(.+)[/\\]$#$1#;
}
}
# Figure out what files have changed using svnlook.
@svnlooklines = &read_from_process($svnlook, 'changed', $repos, '-r', $rev);
# Parse the changed nodes.
my @adds;
my @dels;
my @mods;
foreach my $line (@svnlooklines)
{
my $path = '';
my $code = '';
# Split the line up into the modification code and path, ignoring
# property modifications.
if ($line =~ /^(.). (.*)$/)
{
$code = $1;
$path = $2;
}
if ($code eq 'A')
{
push(@adds, $path);
}
elsif ($code eq 'D')
{
push(@dels, $path);
}
else
{
push(@mods, $path);
}
}
# Get the diff from svnlook.
my @no_diff_deleted = $no_diff_deleted ? ('--no-diff-deleted') : ();
my @difflines = &read_from_process($svnlook, 'diff', $repos,
'-r', $rev, @no_diff_deleted);
######################################################################
# Modified directory name collapsing.
# Collapse the list of changed directories only if the root directory
# was not modified, because otherwise everything is under root and
# there's no point in collapsing the directories, and only if more
# than one directory was modified.
my $commondir = '';
if (!$rootchanged and @dirschanged > 1)
{
my $firstline = shift @dirschanged;
my @commonpieces = split('/', $firstline);
foreach my $line (@dirschanged)
{
my @pieces = split('/', $line);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -