📄 commit-email.pl.in
字号:
#!/usr/bin/env perl# ====================================================================# commit-email.pl: send a notification email describing either a# commit or a revprop-change action on a Subversion repository.## For usage, see the usage subroutine or run the script with no# command line arguments.## This script requires Subversion 1.2.0 or later.## $HeadURL: https://svn.collab.net/repos/svn/branches/1.4.x/tools/hook-scripts/commit-email.pl.in $# $LastChangedDate: 2006-04-19 18:08:55 -0500 (Wed, 19 Apr 2006) $# $LastChangedBy: maxb $# $LastChangedRevision: 19424 $## ====================================================================# Copyright (c) 2000-2006 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;my ($sendmail, $smtp_server);####################################################################### Configuration section.# Sendmail path, or SMTP server address.# You should define exactly one of these two configuration variables,# leaving the other commented out, to select which method of sending# email should be used.#$sendmail = "/usr/sbin/sendmail";$smtp_server = "127.0.0.1";# 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;# By default, when a file is added to 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_added to 1.my $no_diff_added = 0;# End of Configuration section.####################################################################### Check that the required programs exist, and the email sending method# configuration is sane, to ensure that the administrator has set up# the script properly.{ my $ok = 1; foreach my $program ($sendmail, $svnlook) { next if not defined $program; 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; } } if (not (defined $sendmail xor defined $smtp_server)) { warn "$0: exactly one of \$sendmail or \$smtp_server must be ", "set, edit $0.\n"; $ok = 0; } exit 1 unless $ok;}require Net::SMTP if defined $smtp_server;####################################################################### 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.# In commit mode: The first two arguments that are not used by a command line# option are the repository path and the revision number.# In revprop-change mode: The first four arguments that are not used by a# command line option are the repository path, the revision number, the# author, and the property name. This script has no support for the fifth# argument (action) added to the post-revprop-change hook in Subversion# 1.2.0 yet - patches welcome!my $repos;my $rev;my $author;my $propname;my $mode = 'commit';my $diff_file;# 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', '--revprop-change' => '', '-d' => '', '-h' => 'hostname', '-l' => 'log_file', '-m' => '', '-r' => 'reply_to', '-s' => 'subject_prefix', '--diff' => '');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"; } my $value; if ($arg ne '--revprop-change') { unless (@ARGV) { die "$0: command line option `$arg' is missing a value.\n"; } $value = shift @ARGV; } if ($hash_key) { $current_project->{$hash_key} = $value; } else { if ($arg eq '-m') { $current_project = &new_project; $current_project->{match_regex} = $value; push(@project_settings_list, $current_project); } elsif ($arg eq '-d') { if ($mode ne 'revprop-change') { die "$0: `-d' is valid only when used after" . " `--revprop-change'.\n"; } if ($diff_file) { die "$0: command line option `$arg'" . " can only be used once.\n"; } $diff_file = $value; } elsif ($arg eq '--revprop-change') { if (defined $repos) { die "$0: `--revprop-change' must be specified before" . " the first non-option argument.\n"; } $mode = 'revprop-change'; } elsif ($arg eq '--diff') { $current_project->{show_diff} = parse_boolean($value); } else { die "$0: internal error:" . " should not be handling `$arg' here.\n"; } } } else { if (! defined $repos) { $repos = $arg; } elsif (! defined $rev) { $rev = $arg; } elsif (! defined $author && $mode eq 'revprop-change') { $author = $arg; } elsif (! defined $propname && $mode eq 'revprop-change') { $propname = $arg; } else { push(@{$current_project->{email_addresses}}, $arg); } } }if ($mode eq 'commit') { &usage("$0: too few arguments.") unless defined $rev; }elsif ($mode eq 'revprop-change') { &usage("$0: too few arguments.") unless defined $propname; }# 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 common data needed for both commit or revprop-change.# 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.my @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); } }# Declare variables which carry information out of the inner scope of# the conditional blocks below.my $subject_base;my @body;# $author - declared above for use as a command line parameter in# revprop-change mode. In commit mode, gets filled in below.if ($mode eq 'commit') { ###################################################################### # Harvest data using svnlook. # Get the author, date, and log from svnlook. my @infolines = &read_from_process($svnlook, 'info', $repos, '-r', $rev); $author = shift @infolines; my $date = shift @infolines; shift @infolines; my @log = map { "$_\n" } @infolines; ###################################################################### # 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 = ''; my @edited_dirschanged = @dirschanged; if (!$rootchanged and @edited_dirschanged > 1) { my $firstline = shift @edited_dirschanged; my @commonpieces = split('/', $firstline); foreach my $line (@edited_dirschanged) { my @pieces = split('/', $line); my $i = 0; while ($i < @pieces and $i < @commonpieces) { if ($pieces[$i] ne $commonpieces[$i]) { splice(@commonpieces, $i, @commonpieces - $i); last; } $i++; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -