codepot/etc/post-revprop-change.in

234 lines
5.8 KiB
Perl

#!/usr/bin/perl
use strict;
use Config::Simple;
use DBI;
use File::Basename;
use POSIX;
use SVN::Core;
use SVN::Repos;
use SVN::Fs;
my $CFG_FILE = '@CFGDIR@/codepot.ini';
my $REPOFS = $ARGV[0];
my $REPOBASE = basename($REPOFS);
my $REV = $ARGV[1];
my $USER = $ARGV[2];
my $PROPNAME = $ARGV[3];
my $ACTION = $ARGV[4];
my $QC = '';
# [STDIN] PROPVAL ** the old property value is passed via STDIN.
sub get_config
{
my $cfg = new Config::Simple();
if (!$cfg->read ($CFG_FILE))
{
return undef;
}
my $config = {
database_hostname => $cfg->param ("database_hostname"),
database_port => $cfg->param ("database_port"),
database_username => $cfg->param ("database_username"),
database_password => $cfg->param ("database_password"),
database_name => $cfg->param ("database_name"),
database_driver => $cfg->param ("database_driver"),
database_prefix => $cfg->param ("database_prefix"),
database_store_gmt => $cfg->param ("database_store_gmt")
};
return $config;
}
sub open_database
{
my ($cfg) = @_;
my $dbtype = $cfg->{database_driver};
my $dbname = $cfg->{database_name};
my $dbhost = $cfg->{database_hostname};
my $dbport = $cfg->{database_port};
if ($dbtype eq 'postgre') { $dbtype = 'Pg'; }
elsif ($dbtype eq 'oci8') { $dbtype = 'Oracle'; }
elsif ($dbtype eq 'mysqli') { $dbtype = 'mysql'; }
elsif ($dbtype eq 'sqlite') { $dbtype = 'SQLite'; }
my $dbstr;
my $dbuser;
my $dbpass;
if ($dbtype eq 'Oracle')
{
$QC = '"';
$dbstr = "DBI:$dbtype:";
$dbuser = $cfg->{database_username} . '/' . $cfg->{database_password} . '@' . $dbhost;
$dbpass = '';
}
elsif ($dbtype eq 'SQLite')
{
$dbstr = "DBI:$dbtype:database=$dbhost;";
$dbuser = $cfg->{database_username};
$dbpass = $cfg->{database_password};
}
else
{
$dbstr = "DBI:$dbtype:database=$dbname;";
if (length($dbhost) > 0) { $dbstr .= "host=$dbhost;"; }
if (length($dbport) > 0) { $dbstr .= "port=$dbport;"; }
$dbuser = $cfg->{database_username};
$dbpass = $cfg->{database_password};
}
my $dbh = DBI->connect(
$dbstr, $dbuser, $dbpass,
{ RaiseError => 0, PrintError => 0, AutoCommit => 0 }
);
return $dbh;
}
sub close_database
{
my ($dbh) = @_;
$dbh->disconnect ();
}
sub find_issue_reference_in_commit_message
{
my ($dbh, $prefix, $projectid, $revision, $commit_message) = @_;
# find [[#IXXXX]]
my @issue_ids = ($commit_message =~ /\[\[#I(\d+)\]\]/g);
# find #XXXX
my @issue_ids2 = ($commit_message =~ /(^|[^#])#(\d+)(\D|$)/g);
# find unique issue ids in the findings.
my %tmp;
@tmp{@issue_ids} = 1;
for (my $i = 0; $i < scalar(@issue_ids2); $i += 3)
{
my $id = @issue_ids2[$i + 1];
@tmp{$id} = 1;
}
my @unique_issue_ids = keys(%tmp);
$dbh->begin_work ();
my $query = $dbh->prepare ("DELETE FROM ${QC}${prefix}issue_coderev${QC} WHERE ${QC}codeproid${QC}=? AND ${QC}coderev${QC}=?");
if (!$query || !$query->execute ($projectid, $revision))
{
my $errstr = $dbh->errstr();
if ($query) { $query->finish (); }
$dbh->rollback ();
return (-1, $errstr);
}
$query->finish ();
for my $issue_id(@unique_issue_ids)
{
my $query = $dbh->prepare ("INSERT INTO ${QC}${prefix}issue_coderev${QC} (${QC}projectid${QC},${QC}issueid${QC},${QC}codeproid${QC},${QC}coderev${QC}) VALUES (?,?,?,?)");
if ($query)
{
# ignore errors
$query->execute ($projectid, $issue_id, $projectid, $revision);
$query->finish ();
}
}
$dbh->commit ();
return (0, undef);
}
sub write_revprop_change_log
{
my ($dbh, $prefix, $projectid, $revision, $userid, $propname, $action, $store_gmt) = @_;
#+------+---------+-----------+---------------------------+---------------------+---------------+-----------------+
#| id | type | projectid | message | createdon | action | userid |
#+------+---------+-----------+---------------------------+---------------------+---------------+-----------------+
#| 1610 | code | codepot | svn,codepot,98,svn:log,M | 2014-05-16 22:27:36 | revpropchange | hyunghwan.chung |
my $message = "svn,$projectid,$revision,$propname,$action";
my $timestamp;
if (($store_gmt =~ /^\d+?$/ && int($store_gmt) != 0) || (lc($store_gmt) eq 'yes'))
{
$timestamp = POSIX::strftime ('%Y-%m-%d %H:%M:%S', gmtime());
}
else
{
$timestamp = POSIX::strftime ('%Y-%m-%d %H:%M:%S', localtime());
}
$dbh->begin_work ();
my $query = $dbh->prepare ("INSERT INTO ${QC}${prefix}log${QC} (${QC}type${QC},${QC}projectid${QC},${QC}message${QC},${QC}createdon${QC},${QC}action${QC},${QC}userid${QC}) VALUES (?,?,?,?,?,?)");
if (!$query || !$query->execute ('code', $projectid, $message, $timestamp, 'revpropchange', $userid))
{
my $errstr = $dbh->errstr();
if ($query) { $query->finish (); }
$dbh->rollback ();
return (-1, $errstr);
}
$query->finish ();
$dbh->commit ();
return (0, undef);
}
sub get_commit_message
{
my $pool = SVN::Pool->new(undef);
my $svn = eval { SVN::Repos::open ($REPOFS, $pool) };
if (!defined($svn))
{
print (STDERR "Cannot open svn - $REPOFS\n");
return undef;
}
my $fs = $svn->fs ();
if (!defined($fs))
{
print (STDERR "Cannot open fs - $REPOFS\n");
return undef;
}
my $logmsg = $fs->revision_prop ($REV, 'svn:log');
return $logmsg;
}
#------------------------------------------------------------
# MAIN
#------------------------------------------------------------
my $cfg = get_config ();
if (!defined($cfg))
{
print (STDERR "Cannot load codepot configuration file\n");
exit (1);
}
my $dbh = open_database ($cfg);
if (!defined($dbh))
{
printf (STDERR "Cannot open database - %s\n", $DBI::errstr);
exit (1);
}
my $raw_commit_message = get_commit_message();
find_issue_reference_in_commit_message ($dbh, $cfg->{database_prefix}, $REPOBASE, $REV, $raw_commit_message);
write_revprop_change_log ($dbh, $cfg->{database_prefix}, $REPOBASE, $REV, $USER, $PROPNAME, $ACTION, $cfg->{database_store_gmt});
close_database ($dbh);
exit (0);