X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=C4%2FInstaller.pm;h=a1c47149f82375a2f0703a21b67208aed5f711c6;hb=7d71d9507202ff667776bf9cb6de0bf2603ad0dd;hp=a7eb1f6ed614b0d699eeeeb556e4f5a30a912e3e;hpb=f21577986f8ff5da5fde88deaae2302a8b40dbe7;p=koha.git diff --git a/C4/Installer.pm b/C4/Installer.pm index a7eb1f6ed6..a1c47149f8 100644 --- a/C4/Installer.pm +++ b/C4/Installer.pm @@ -4,25 +4,34 @@ package C4::Installer; # # This file is part of Koha. # -# Koha is free software; you can redistribute it and/or modify it under the -# terms of the GNU General Public License as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) any later -# version. +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. # -# Koha is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. # -# You should have received a copy of the GNU General Public License along -# with Koha; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . -use strict; -#use warnings; FIXME - Bug 2505 +use Modern::Perl; -our $VERSION = 3.00; +use Encode qw( encode is_utf8 ); +use DBIx::RunSQL; use C4::Context; -use C4::Installer::PerlModules 1.000000; +use C4::Installer::PerlModules; +use DBI; +use Koha; + +use vars qw(@ISA @EXPORT); +BEGIN { + require Exporter; + @ISA = qw( Exporter ); + push @EXPORT, qw( foreign_key_exists index_exists column_exists ); +}; =head1 NAME @@ -34,11 +43,11 @@ C4::Installer my $installer = C4::Installer->new(); my $all_languages = getAllLanguages(); my $error = $installer->load_db_schema(); - my $list = $installer->sql_file_list('en', 'marc21', { optional => 1, mandatory => 1 }); + my $list; + #fill $list with list of sql files my ($fwk_language, $error_list) = $installer->load_sql_in_order($all_languages, @$list); $installer->set_version_syspref(); $installer->set_marcflavour_syspref('MARC21'); - $installer->set_indexing_engine(0); =head1 DESCRIPTION @@ -66,8 +75,17 @@ sub new { $self->{'port'} = C4::Context->config("port"); $self->{'user'} = C4::Context->config("user"); $self->{'password'} = C4::Context->config("pass"); + $self->{'tls'} = C4::Context->config("tls"); + if( $self->{'tls'} && $self->{'tls'} eq 'yes' ) { + $self->{'ca'} = C4::Context->config('ca'); + $self->{'cert'} = C4::Context->config('cert'); + $self->{'key'} = C4::Context->config('key'); + $self->{'tlsoptions'} = ";mysql_ssl=1;mysql_ssl_client_key=".$self->{key}.";mysql_ssl_client_cert=".$self->{cert}.";mysql_ssl_ca_file=".$self->{ca}; + $self->{'tlscmdline'} = " --ssl-cert ". $self->{cert} . " --ssl-key " . $self->{key} . " --ssl-ca ".$self->{ca}." " + } $self->{'dbh'} = DBI->connect("DBI:$self->{dbms}:dbname=$self->{dbname};host=$self->{hostname}" . - ( $self->{port} ? ";port=$self->{port}" : "" ), + ( $self->{port} ? ";port=$self->{port}" : "" ). + ( $self->{tlsoptions} ? $self->{tlsoptions} : ""), $self->{'user'}, $self->{'password'}); $self->{'language'} = undef; $self->{'marcflavour'} = undef; @@ -78,27 +96,6 @@ sub new { return $self; } -=head2 marcflavour_list - - my ($marcflavours) = $installer->marcflavour_list($lang); - -Return a arrayref of the MARC flavour sets available for the -specified language C<$lang>. Returns 'undef' if a directory -for the language does not exist. - -=cut - -sub marcflavour_list { - my $self = shift; - my $lang = shift; - - my $dir = C4::Context->config('intranetdir') . "/installer/data/$self->{dbms}/$lang/marcflavour"; - opendir(MYDIR, $dir) or return; - my @list = grep { !/^\.|CVS/ && -d "$dir/$_" } readdir(MYDIR); - closedir MYDIR; - return \@list; -} - =head2 marc_framework_sql_list my ($defaulted_to_en, $list) = @@ -154,17 +151,16 @@ sub marc_framework_sql_list { my @frameworklist; map { my $name = substr( $_, 0, -4 ); - open FILE, "<:utf8","$dir/$requirelevel/$name.txt"; - my $lines = ; - $lines =~ s/\n|\r/
/g; - use utf8; - utf8::encode($lines) unless ( utf8::is_utf8($lines) ); + open my $fh, "<:encoding(UTF-8)", "$dir/$requirelevel/$name.txt"; + my $line = <$fh>; + $line = Encode::encode('UTF-8', $line) unless ( Encode::is_utf8($line) ); + my @lines = split /\n/, $line; my $mandatory = ($requirelevel =~ /(mandatory|requi|oblig|necess)/i); push @frameworklist, { 'fwkname' => $name, 'fwkfile' => "$dir/$requirelevel/$_", - 'fwkdescription' => $lines, + 'fwkdescription' => \@lines, 'checked' => ( ( $frameworksloaded{$_} || $mandatory ) ? 1 : 0 ), 'mandatory' => $mandatory, }; @@ -232,17 +228,16 @@ sub sample_data_sql_list { my @frameworklist; map { my $name = substr( $_, 0, -4 ); - open FILE, "<:utf8","$dir/$requirelevel/$name.txt"; - my $lines = ; - $lines =~ s/\n|\r/
/g; - use utf8; - utf8::encode($lines) unless ( utf8::is_utf8($lines) ); + open my $fh , "<:encoding(UTF-8)", "$dir/$requirelevel/$name.txt"; + my $line = <$fh>; + $line = Encode::encode('UTF-8', $line) unless ( Encode::is_utf8($line) ); + my @lines = split /\n/, $line; my $mandatory = ($requirelevel =~ /(mandatory|requi|oblig|necess)/i); push @frameworklist, { 'fwkname' => $name, 'fwkfile' => "$dir/$requirelevel/$_", - 'fwkdescription' => $lines, + 'fwkdescription' => \@lines, 'checked' => ( ( $frameworksloaded{$_} || $mandatory ) ? 1 : 0 ), 'mandatory' => $mandatory, }; @@ -258,41 +253,6 @@ sub sample_data_sql_list { return ($defaulted_to_en, \@levellist); } -=head2 sql_file_list - - my $list = $installer->sql_file_list($lang, $marcflavour, $subset_wanted); - -Returns an arrayref containing the filepaths of installer SQL scripts -available for laod. The C<$lang> and C<$marcflavour> arguments -specify the desired language and MARC flavour. while C<$subset_wanted> -is a hashref containing possible named parameters 'mandatory' and 'optional'. - -=cut - -sub sql_file_list { - my $self = shift; - my $lang = shift; - my $marcflavour = shift; - my $subset_wanted = shift; - - my ($marc_defaulted_to_en, $marc_sql) = $self->marc_framework_sql_list($lang, $marcflavour); - my ($sample_defaulted_to_en, $sample_sql) = $self->sample_data_sql_list($lang); - - my @sql_list = (); - map { - map { - if ($subset_wanted->{'mandatory'}) { - push @sql_list, $_->{'fwkfile'} if $_->{'mandatory'}; - } - if ($subset_wanted->{'optional'}) { - push @sql_list, $_->{'fwkfile'} unless $_->{'mandatory'}; - } - } @{ $_->{'frameworks'} } - } (@$marc_sql, @$sample_sql); - - return \@sql_list -} - =head2 load_db_schema my $error = $installer->load_db_schema(); @@ -354,9 +314,19 @@ sub load_sql_in_order { $request->execute; my ($systempreference) = $request->fetchrow; $systempreference = '' unless defined $systempreference; # avoid warning + # Make sure subtag_registry.sql is loaded second + my $subtag_registry = C4::Context->config('intranetdir') . "/installer/data/$self->{dbms}/mandatory/subtag_registry.sql"; + unshift(@fnames, $subtag_registry); + # Make sure authorised value categories are loaded at the beginning + my $av_cat = C4::Context->config('intranetdir') . "/installer/data/$self->{dbms}/mandatory/auth_val_cat.sql"; + unshift(@fnames, $av_cat); # Make sure the global sysprefs.sql file is loaded first my $globalsysprefs = C4::Context->config('intranetdir') . "/installer/data/$self->{dbms}/sysprefs.sql"; unshift(@fnames, $globalsysprefs); + push @fnames, C4::Context->config('intranetdir') . "/installer/data/mysql/userflags.sql"; + push @fnames, C4::Context->config('intranetdir') . "/installer/data/mysql/userpermissions.sql"; + push @fnames, C4::Context->config('intranetdir') . "/installer/data/mysql/audio_alerts.sql"; + push @fnames, C4::Context->config('intranetdir') . "/installer/data/mysql/account_offset_types.sql"; foreach my $file (@fnames) { # warn $file; undef $/; @@ -408,10 +378,10 @@ sub load_sql_in_order { Set the 'marcflavour' system preference. The incoming C<$marcflavour> references to a subdirectory of installer/data/$dbms/$lang/marcflavour, and is -normalized to MARC21 or UNIMARC. +normalized to MARC21, UNIMARC or NORMARC. FIXME: this method assumes that the MARC flavour will be either -MARC21 or UNIMARC. +MARC21, UNIMARC or NORMARC. =cut @@ -423,38 +393,14 @@ sub set_marcflavour_syspref { # marc_cleaned finds the marcflavour, without the variant. my $marc_cleaned = 'MARC21'; $marc_cleaned = 'UNIMARC' if $marcflavour =~ /unimarc/i; + $marc_cleaned = 'NORMARC' if $marcflavour =~ /normarc/i; my $request = $self->{'dbh'}->prepare( - "INSERT IGNORE INTO `systempreferences` (variable,value,explanation,options,type) VALUES('marcflavour','$marc_cleaned','Define global MARC flavor (MARC21 or UNIMARC) used for character encoding','MARC21|UNIMARC','Choice');" + "INSERT IGNORE INTO `systempreferences` (variable,value,explanation,options,type) VALUES('marcflavour','$marc_cleaned','Define global MARC flavor (MARC21, UNIMARC or NORMARC) used for character encoding','MARC21|UNIMARC|NORMARC','Choice');" ); $request->execute; } -=head2 set_indexing_engine - - $installer->set_indexing_engine($nozebra); - -Sets system preferences related to the indexing -engine. The C<$nozebra> argument is a boolean; -if true, turn on NoZebra mode and turn off QueryFuzzy, -QueryWeightFields, and QueryStemming. If false, turn -off NoZebra mode (i.e., use the Zebra search engine). - -=cut - -sub set_indexing_engine { - my $self = shift; - my $nozebra = shift; - - if ($nozebra) { - $self->{'dbh'}->do("UPDATE systempreferences SET value=1 WHERE variable='NoZebra'"); - $self->{'dbh'}->do("UPDATE systempreferences SET value=0 WHERE variable in ('QueryFuzzy','QueryWeightFields','QueryStemming')"); - } else { - $self->{'dbh'}->do("UPDATE systempreferences SET value=0 WHERE variable='NoZebra'"); - } - -} - =head2 set_version_syspref $installer->set_version_syspref(); @@ -467,7 +413,7 @@ Koha software version. sub set_version_syspref { my $self = shift; - my $kohaversion=C4::Context::KOHAVERSION; + my $kohaversion = Koha::version(); # remove the 3 last . to have a Perl number $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/; if (C4::Context->preference('Version')) { @@ -486,53 +432,39 @@ sub set_version_syspref { my $error = $installer->load_sql($filename); -Runs a the specified SQL using the DB's command-line -SQL tool, and returns any strings sent to STDERR -by the command-line tool. - -B there has been a long-standing desire to -replace this with an SQL loader that goes -through DBI; partly for portability issues -and partly to improve error handling. +Runs a the specified SQL file using a sql loader DBIx::RunSQL +Returns any strings sent to STDERR -B even using the command-line loader, some more -basic error handling should be added - deal -with missing files, e.g. +# FIXME This should be improved: sometimes the caller and load_sql warn the same +error. =cut sub load_sql { my $self = shift; my $filename = shift; - - my $datadir = C4::Context->config('intranetdir') . "/installer/data/$self->{dbms}"; my $error; - my $strcmd; - if ( $self->{dbms} eq 'mysql' ) { - $strcmd = "mysql " - . ( $self->{hostname} ? " -h $self->{hostname} " : "" ) - . ( $self->{port} ? " -P $self->{port} " : "" ) - . ( $self->{user} ? " -u $self->{user} " : "" ) - . ( $self->{password} ? " -p'$self->{password}'" : "" ) - . " $self->{dbname} "; - $error = qx($strcmd --default-character-set=utf8 <$filename 2>&1 1>/dev/null); - } elsif ( $self->{dbms} eq 'Pg' ) { - $strcmd = "psql " - . ( $self->{hostname} ? " -h $self->{hostname} " : "" ) - . ( $self->{port} ? " -p $self->{port} " : "" ) - . ( $self->{user} ? " -U $self->{user} " : "" ) -# . ( $self->{password} ? " -W $self->{password}" : "" ) # psql will NOT accept a password, but prompts... - . " $self->{dbname} "; # Therefore, be sure to run 'trust' on localhost in pg_hba.conf -fbcit - $error = qx($strcmd -f $filename 2>&1 1>/dev/null); - # Be sure to set 'client_min_messages = error' in postgresql.conf - # so that only true errors are returned to stderr or else the installer will - # report the import a failure although it really succeded -fbcit - } -# errors thrown while loading installer data should be logged - if($error) { - warn "C4::Installer::load_sql returned the following errors while attempting to load $filename:\n"; - warn "$error"; + + my $dbh = $self->{ dbh }; + + my $dup_stderr; + do { + local *STDERR; + open STDERR, ">>", \$dup_stderr; + + eval { + DBIx::RunSQL->run_sql_file( + dbh => $dbh, + sql => $filename, + ); + }; + }; + # errors thrown while loading installer data should be logged + if( $dup_stderr ) { + warn "C4::Installer::load_sql returned the following errors while attempting to load $filename:\n"; + $error = $dup_stderr; } + return $error; } @@ -574,6 +506,36 @@ sub get_file_path_from_name { } +sub foreign_key_exists { + my ( $table_name, $constraint_name ) = @_; + my $dbh = C4::Context->dbh; + my (undef, $infos) = $dbh->selectrow_array(qq|SHOW CREATE TABLE $table_name|); + return $infos =~ m|CONSTRAINT `$constraint_name` FOREIGN KEY|; +} + +sub index_exists { + my ( $table_name, $key_name ) = @_; + my $dbh = C4::Context->dbh; + my ($exists) = $dbh->selectrow_array( + qq| + SHOW INDEX FROM $table_name + WHERE key_name = ? + |, undef, $key_name + ); + return $exists; +} + +sub column_exists { + my ( $table_name, $column_name ) = @_; + my $dbh = C4::Context->dbh; + my ($exists) = $dbh->selectrow_array( + qq| + SHOW COLUMNS FROM $table_name + WHERE Field = ? + |, undef, $column_name + ); + return $exists; +} =head1 AUTHOR