cmpilato@collab.net wrote:
> Tim Moloney <moloney@mrsl.com> writes:
>
>
>>Following the example of http://svn.collab.net/repos/svn/, I've
>>created a repository that has the following structure
>>
>> /svn/project/trunk
>> /svn/project/tags
>> /svn/project/branches
>>
>>I know that the only difference between tags and branches is that
>>tags won't (shouldn't) have anything commited back to them.
>>
>>Unfortunately, people make mistakes, is there a way to make the
>>tags directory read-only to prevent accidental commits that would
>>corrupt the tagged revision?
>
>
> You could write a pre-commit hook that uses svnlook to determine which
> paths were being modified. If the tags directory is being modified,
> and if those mods were anything more than just the creation of a new
> tag, the hook returns and error, and the commit doesn't happen. You
> could even have the script send email to the would-be committer
> saying, "I know what you tried to do, buck-o!"
I think that I have a pre-commit script that verifies that only copies
are made to the tags directory. This is implemented in the two files
below.
Please note that I haven't done perl in a while (and I probably wasn't
any good then either). If there are any perl gurus out there, feel
free to clean up the style, "perlize" it (versus my lame C-like style),
etc.
Hopefully, somebody else will find this useful. =)
===== begin svn_hook_utils.pm =====
#!/usr/bin/perl -w
#
# /usr/lib/perl/site_perl/5.6.0/i386-linux/svn_hook_utils.pm
#
package svn_hook_utils;
require Exporter;
@ISA =qw(Exporter);
@EXPORT = qw(
svn_hook_init svn_fatal_error svn_mail_error svn_svnlook
svn_check_log svn_check_tags
);
@EXPORT_OK = qw($author $date $log_size $log_msg @changed @dirs_changed);
#
# Configuration
#
$domain = 'mrsl.com';
$sendmail = '/usr/sbin/sendmail';
$svnlook = '/usr/local/bin/svnlook';
$svn_dir = '/var/svn';
$svn_admin = 'moloney';
#
# Constants
#
@months = ('Jan' ,'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
#
# Functions
#
#
# svn_fatal_error()
#
# Write a time-stamped message to the error log.
#
sub svn_fatal_error {
my($msg) = @_;
my($sec, $min, $hour, $day, $mon) = localtime;
if (open(ERROR_LOG, ">>$svn_dir/error.log")) {
printf(ERROR_LOG "\n");
printf(ERROR_LOG "%s %2d %02d:%02d:%02d\n",
$months[$mon], $day, $hour, $min, $sec);
printf(ERROR_LOG "\n");
printf(ERROR_LOG "%s", $msg);
}
else {
#
# Don't bother doing anything here because no one will ever see it.
#
}
exit(1);
}
#
# svn_mail_error()
#
# Mail an error message to the author.
#
sub svn_mail_error {
my($msg) = @_;
my($cmd) = "| $sendmail $author\@$domain";
if (open(SENDMAIL, $cmd)) {
print(SENDMAIL "To: $author\@$domain\n");
print(SENDMAIL "From: svn_server\n");
print(SENDMAIL "Subject: Subversion Commit Error\n");
print(SENDMAIL "Reply-to: $svn_admin\@$domain\n");
print(SENDMAIL $msg);
close(SENDMAIL);
}
else {
svn_fatal_error("Failed to execute '$cmd'\n");
}
exit(1);
}
#
# svn_get_args()
#
# Verify and load the command line arguments based on the hook type.
#
# TODO - Add the following hook types:
# post-commit, read-sentinels, write-sentinals
#
sub svn_get_args {
my($hook_type, @in_args) = @_;
my(%out_args);
if ($hook_type eq 'precommit') {
if ($#in_args != 1) {
$msg = " Invalid number of parameters for pre-commit script.\n";
$msg .= " The following arguments were passed:\n";
$msg .= "\n";
if ($#in_args == -1) {
$msg .= " <none>\n";
}
else {
for ($i = 0; $i <= $#in_args; $i++) {
$msg .= sprintf(" %d - '%s'\n", $i, $in_args[$i]);
}
}
svn_fatal_error($msg);
}
$out_args{repos} = $in_args[0];
$out_args{txn_rev} = "txn $in_args[1]";
}
return(%out_args);
}
#
# svn_hook_init()
#
# Get all of the transaction data based on the hook type and command line
# arguments.
#
sub svn_hook_init {
my($hook_type, @args) = @_;
%args = svn_get_args($hook_type, @args);
($author, $date, $log_size, $log_msg) = svn_svnlook('info');
chomp($author);
chomp($date);
chomp($log_size);
@changed = svn_svnlook('changed');
@dirs_changed = svn_svnlook('dirs-changed');
}
#
# svn_svnlook()
#
# Get the specified transaction data.
#
sub svn_svnlook {
my($subcmd) = @_;
my($cmd) = "$svnlook $args{repos} $args{txn_rev} $subcmd";
return(`$cmd`);
}
#
# svn_check_log()
#
# Verifies that some sort of log was entered.
#
sub svn_check_log {
if ($log_msg !~ m/[a-zA-Z0-9]/) {
return(1);
}
return(0);
}
#
# build_id_table()
#
# Builds the table that contains the directory entries and their node ids.
#
sub build_id_table {
my(@lines) = split(/\n/, svn_svnlook('ids'));
my($line);
my(@parents);
my($full_dir);
my($dir);
my($id);
my(%table);
foreach $line (@lines) {
chomp($line);
$full_dir = '';
for ($i = 0; substr($line, $i, 1) eq ' '; $i++) {
$full_dir .= $parents[$i];
};
($dir, $id) = split(/ /, substr($line, $i));
$parents[$i] = $dir;
$full_dir .= $dir;
$table{$full_dir} = $id;
}
return(%table);
}
#
# svn_check_tags()
#
# Verifies that no changes are made to the tags directory. Only copies are
# made.
#
sub svn_check_tags {
$check = 0;
foreach $dir (@dirs_changed) {
if ($dir =~ m/^tags/) {
$check = 1;
last;
}
}
if ($check) {
my(%ids) = build_id_table();
my($key);
my($tag_file);
my($trunk_file);
foreach $key (sort keys %ids) {
if ($key =~ m/$dirs_changed[1].+/) {
$tag_file = $key;
$trunk_file = $key;
$trunk_file =~ s/$dirs_changed[1]/trunk\//;
if ($ids{$tag_file} ne $ids{$trunk_file}) {
return(1);
}
}
}
}
return(0);
}
===== end svn_hook_utils.pm =====
===== begin pre-commit =====
#!/usr/bin/perl -w
#
# <repos-dir>/hooks/pre-commit
#
use svn_hook_utils;
svn_hook_init('precommit', @ARGV);
$changed = join('', @svn_hook_utils::changed);
#
# Make sure that some sort of log message was provided.
#
if (svn_check_log() != 0) {
$msg = "
The following commit was rejected because there was no log message.
Changes
=========
$changed
";
svn_mail_error($msg);
}
#
# Make sure that no changes to the tags directory were made.
#
if (svn_check_tags() != 0) {
$msg = "
The following commit was rejected because it attempted to change
the tags directory.
Changes
=========
$changed
Log
=====
$svn_hook_utils::log_msg
";
svn_mail_error($msg);
}
#
# Return success.
#
exit(0);
===== end pre-commit =====
--
Tim Moloney
ManTech Real-time Systems Laboratory
2015 Cattlemen Road \ /
Sarasota, FL 34232 .________\(O)/________.
(941) 377-6775 x208 ' ' O(.)O ' '
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Tue Apr 16 06:06:21 2002