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