View | Details | Raw Unified | Return to bug 25078
Collapse All | Expand All

(-)a/C4/Installer.pm (-1 / +181 lines)
Lines 19-24 package C4::Installer; Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Try::Tiny;
22
use Encode qw( encode is_utf8 );
23
use Encode qw( encode is_utf8 );
23
use DBIx::RunSQL;
24
use DBIx::RunSQL;
24
use YAML::Syck qw( LoadFile );
25
use YAML::Syck qw( LoadFile );
Lines 30-36 use vars qw(@ISA @EXPORT); Link Here
30
BEGIN {
31
BEGIN {
31
    require Exporter;
32
    require Exporter;
32
    @ISA = qw( Exporter );
33
    @ISA = qw( Exporter );
33
    push @EXPORT, qw( primary_key_exists foreign_key_exists index_exists column_exists TableExists);
34
    push @EXPORT, qw( primary_key_exists foreign_key_exists index_exists column_exists TableExists TransformToNum CheckVersion update );
34
};
35
};
35
36
36
=head1 NAME
37
=head1 NAME
Lines 683-688 sub TableExists { # Could be renamed table_exists for consistency Link Here
683
    return 0;
684
    return 0;
684
}
685
}
685
686
687
sub execute_entry {
688
    my ( $DBversion, $bug_number, $description, $sub ) = @_;
689
690
    my $error;
691
    try {
692
        Koha::Database->schema->txn_do($sub);
693
    } catch {
694
        $error = $_;
695
    };
696
697
    return $error;
698
}
699
700
sub update {
701
    my ( $db_entries ) = @_;
702
703
    my ( @done, @errors );
704
    for my $db_entry ( @$db_entries ) {
705
706
        my $version = $db_entry->{version};
707
        next unless CheckVersion( $version );
708
709
        my $error = execute_entry(
710
            $version,
711
            $db_entry->{bug_number},
712
            $db_entry->{description},
713
            $db_entry->{sub}
714
        );
715
716
        $db_entry->{time} = POSIX::strftime("%H:%M:%S",localtime);
717
        $db_entry->{output} = output_version( { %$db_entry, done => !$error } );
718
        if ( $error ) {
719
            push @errors, { %$db_entry, error => $error };
720
            last; # We stop the update if an error occurred!
721
        }
722
723
        SetVersion($version);
724
        push @done, $db_entry;
725
    }
726
    return { success => \@done, error => \@errors };
727
}
728
729
sub output_version {
730
    my ( $db_entry) = @_;
731
732
    my $descriptions = $db_entry->{description};
733
    my $DBversion = $db_entry->{version};
734
    my $bug_number = $db_entry->{bug_number};
735
    my $time = $db_entry->{time};
736
    my $done = $db_entry->{done} ? "done" : "failed";
737
738
    unless ( ref($descriptions) ) {
739
        $descriptions = [ $descriptions ];
740
    }
741
742
    my $first = 1;
743
    my $output;
744
    for my $description ( @$descriptions ) {
745
        if ( @$descriptions > 1 ) {
746
            if ( $first ) {
747
                unless ( $bug_number ) {
748
                    $output = sprintf "Upgrade to %s %s [%s]: %s", $DBversion, $done, $time, $description;
749
                } else {
750
                    $output = sprintf "Upgrade to %s %s [%s]: Bug %5s - %s", $DBversion, $done, $time, $bug_number, $description;
751
                }
752
            } else {
753
                $output = sprintf "\t\t\t\t\t\t   - %s", $description;
754
            }
755
        } else {
756
            unless ( $bug_number ) {
757
                $output = sprintf "Upgrade to %s %s [%s]: %s", $DBversion, $done, $time, $description;
758
            } else {
759
                $output = sprintf "Upgrade to %s %s [%s]: Bug %5s - %s", $DBversion, $done, $time, $bug_number, $description;
760
            }
761
        }
762
        $first = 0;
763
    }
764
    return $output;
765
}
766
767
=head2 DropAllForeignKeys($table)
768
769
Drop all foreign keys of the table $table
770
771
=cut
772
773
sub DropAllForeignKeys {
774
    my ($table) = @_;
775
    # get the table description
776
    my $dbh = C4::Context->dbh;
777
    my $sth = $dbh->prepare("SHOW CREATE TABLE $table");
778
    $sth->execute;
779
    my $vsc_structure = $sth->fetchrow;
780
    # split on CONSTRAINT keyword
781
    my @fks = split /CONSTRAINT /,$vsc_structure;
782
    # parse each entry
783
    foreach (@fks) {
784
        # isolate what is before FOREIGN KEY, if there is something, it's a foreign key to drop
785
        $_ = /(.*) FOREIGN KEY.*/;
786
        my $id = $1;
787
        if ($id) {
788
            # we have found 1 foreign, drop it
789
            $dbh->do("ALTER TABLE $table DROP FOREIGN KEY $id");
790
            $id="";
791
        }
792
    }
793
}
794
795
796
=head2 TransformToNum
797
798
Transform the Koha version from a 4 parts string
799
to a number, with just 1 .
800
801
=cut
802
803
sub TransformToNum {
804
    my $version = shift;
805
    # remove the 3 last . to have a Perl number
806
    $version =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
807
    # three X's at the end indicate that you are testing patch with dbrev
808
    # change it into 999
809
    # prevents error on a < comparison between strings (should be: lt)
810
    $version =~ s/XXX$/999/;
811
    return $version;
812
}
813
814
=head2 SetVersion
815
816
set the DBversion in the systempreferences
817
818
=cut
819
820
sub SetVersion {
821
    return if $_[0]=~ /XXX$/;
822
      #you are testing a patch with a db revision; do not change version
823
    my $kohaversion = TransformToNum($_[0]);
824
    my $dbh = C4::Context->dbh;
825
    if (C4::Context->preference('Version')) {
826
      my $finish=$dbh->prepare("UPDATE systempreferences SET value=? WHERE variable='Version'");
827
      $finish->execute($kohaversion);
828
    } else {
829
      my $finish=$dbh->prepare("INSERT into systempreferences (variable,value,explanation) values ('Version',?,'The Koha database version. WARNING: Do not change this value manually, it is maintained by the webinstaller')");
830
      $finish->execute($kohaversion);
831
    }
832
    C4::Context::clear_syspref_cache(); # invalidate cached preferences
833
}
834
835
sub NewVersion {
836
    # void FIXME replace me
837
}
838
839
=head2 CheckVersion
840
841
Check whether a given update should be run when passed the proposed version
842
number. The update will always be run if the proposed version is greater
843
than the current database version and less than or equal to the version in
844
kohaversion.pl. The update is also run if the version contains XXX, though
845
this behavior will be changed following the adoption of non-linear updates
846
as implemented in bug 7167.
847
848
=cut
849
850
sub CheckVersion {
851
    my ($proposed_version) = @_;
852
    my $version_number = TransformToNum($proposed_version);
853
854
    # The following line should be deleted when bug 7167 is pushed
855
    return 1 if ( $proposed_version =~ m/XXX/ );
856
857
    if ( C4::Context->preference("Version") < $version_number
858
        && $version_number <= TransformToNum( $Koha::VERSION ) )
859
    {
860
        return 1;
861
    }
862
    else {
863
        return 0;
864
    }
865
}
686
866
687
=head1 AUTHOR
867
=head1 AUTHOR
688
868
(-)a/installer/data/mysql/updatedatabase.pl (-183 / +75 lines)
Lines 47-54 use MARC::File::XML ( BinaryEncoding => 'utf8' ); Link Here
47
use File::Path qw[remove_tree]; # perl core module
47
use File::Path qw[remove_tree]; # perl core module
48
use File::Slurp;
48
use File::Slurp;
49
49
50
use Try::Tiny;
51
52
# FIXME - The user might be installing a new database, so can't rely
50
# FIXME - The user might be installing a new database, so can't rely
53
# on /etc/koha.conf anyway.
51
# on /etc/koha.conf anyway.
54
52
Lines 23419-23492 if( CheckVersion( $DBversion ) ) { Link Here
23419
    NewVersion( $DBversion, "", "Koha 20.11.00 release" );
23417
    NewVersion( $DBversion, "", "Koha 20.11.00 release" );
23420
}
23418
}
23421
23419
23422
$DBversion = '20.12.00.000';
23420
our $db_entries = [
23423
if( CheckVersion( $DBversion ) ) {
23421
    {
23424
    NewVersion( $DBversion, "", "Sorry, this is my first life, I am still learning!" );
23422
        version     => '20.12.00.000',
23425
}
23423
        bug_number  => undef,
23426
23424
        description => "Sorry, this is my first life, I am still learning!",
23427
$DBversion = '20.12.00.001';
23425
    },
23428
if( CheckVersion( $DBversion ) ) {
23426
    {
23429
    $dbh->do(q{
23427
        version     => '20.12.00.001',
23428
        bug_number  => 27252,
23429
        description => "Add ElasticsearchCrossFields system preference",
23430
        sub         => sub {
23431
            $dbh->do(
23432
                q{
23430
        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
23433
        INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
23431
       ('ElasticsearchCrossFields', '1', '', 'Enable "cross_fields" option for searches using Elastic search.', 'YesNo')
23434
       ('ElasticsearchCrossFields', '1', '', 'Enable "cross_fields" option for searches using Elastic search.', 'YesNo')
23432
    });
23435
    }
23433
    NewVersion( $DBversion, 27252, "Add ElasticsearchCrossFields system preference");
23436
            );
23434
}
23437
        }
23435
23438
    },
23436
$DBversion = '20.12.00.002';
23439
    {
23437
if( CheckVersion( $DBversion ) ) {
23440
        version     => '20.12.00.002',
23438
    $dbh->do(q{UPDATE systempreferences SET `type` = 'Choice' WHERE `variable` = 'UsageStatsCountry'});
23441
        bug_number  => 27351,
23439
    NewVersion( $DBversion, 27351, "Set type for UsageStatsCountry to Choice");
23442
        description => "Set type for UsageStatsCountry to Choice",
23440
}
23443
        sub         => sub {
23441
23442
$DBversion = '20.12.00.003';
23443
if( CheckVersion( $DBversion ) ) {
23444
    $dbh->do(q{UPDATE systempreferences SET `type` = 'Choice' WHERE `variable` = 'Mana'});
23445
    NewVersion( $DBversion, 27349, "Update type for Mana system preference to Choice");
23446
}
23447
23448
$DBversion = '20.12.00.004';
23449
if( CheckVersion( $DBversion ) ) {
23450
    $dbh->do(q{UPDATE systempreferences set variable="TaxRates" WHERE variable="gist"});
23451
    NewVersion( $DBversion, 27485, "Rename system preference 'gist' to 'TaxRates'");
23452
}
23453
23454
$DBversion = '20.12.00.005';
23455
if( CheckVersion( $DBversion ) ) {
23456
    execute_entry(
23457
        $DBversion, 27491, "Rename system preference 'opaclanguages' to 'OPACLanguages'",
23458
        sub {
23459
            $dbh->do(
23444
            $dbh->do(
23460
                q{UPDATE systempreferences set variable="OPACLanguages" WHERE variable="opaclanguages"}
23445
q{UPDATE systempreferences SET `type` = 'Choice' WHERE `variable` = 'UsageStatsCountry'}
23461
            );
23446
            );
23462
        }
23447
        }
23463
    );
23448
    },
23464
}
23449
    {
23450
        version     => '20.12.00.003',
23451
        bug_number  => 27349,
23452
        description => "Update type for Mana system preference to Choice",
23453
        sub         => sub {
23454
            $dbh->do(
23455
q{UPDATE systempreferences SET `type` = 'Choice' WHERE `variable` = 'Mana'}
23456
            );
23457
        }
23458
    },
23465
23459
23466
$DBversion = '20.12.00.006';
23460
    {
23467
if( CheckVersion( $DBversion ) ) {
23461
        version     => '20.12.00.004',
23468
    execute_entry( $DBversion, 12345, "Testing failure",
23462
        bug_number  => 27485,
23469
        sub {
23463
        description => "Rename system preference 'gist' to 'TaxRates'",
23464
        sub         => sub {
23465
            $dbh->do(
23466
q{UPDATE systempreferences set variable="TaxRates" WHERE variable="gist"}
23467
            );
23468
        },
23469
    },
23470
23471
    {
23472
        version    => '20.12.00.005',
23473
        bug_number => 27491,
23474
        description => "Rename system preference 'opaclanguages' to 'OPACLanguages'",
23475
        sub => sub {
23470
            $dbh->do(
23476
            $dbh->do(
23471
                q{ALTER TABLE foo}
23477
q{UPDATE systempreferences set variable="OPACLanguages" WHERE variable="opaclanguages"}
23472
            );
23478
            );
23473
        }
23479
        }
23474
    );
23475
}
23476
23480
23481
    },
23482
    {
23483
        version     => '20.12.00.006',
23484
        bug_number  => 42424,
23485
        description => "Testing failure",
23486
        sub         => sub {
23487
            $dbh->do(q{ALTER TABLE foo});
23488
        }
23489
23490
    },
23477
23491
23478
sub execute_entry {
23492
];
23479
    my ( $DBversion, $bug_number, $description, $sub ) = @_;
23480
23493
23481
    try {
23482
        Koha::Database->schema->txn_do($sub);
23483
    } catch {
23484
        die sprintf "Something wrong happened during %s (%s):\n%s", $DBversion, $description, $_;
23485
    };
23486
23494
23487
    NewVersion( $DBversion, $bug_number, $description );
23495
sub get_db_entries { return $db_entries; }
23496
23497
unless ( $ENV{HTTP_HOST} ) { # Is that correct?
23498
    my $report = update( $db_entries );
23499
23500
    for my $s ( @{ $report->{success} } ) {
23501
        say $s->{output};
23502
    }
23503
    for my $e ( @{ $report->{error} } ) {
23504
        say $e->{output};
23505
        say "ERROR - " . $e->{error};
23506
    }
23488
}
23507
}
23489
23508
23509
23490
# SEE bug 13068
23510
# SEE bug 13068
23491
# if there is anything in the atomicupdate, read and execute it.
23511
# if there is anything in the atomicupdate, read and execute it.
23492
my $update_dir = C4::Context->config('intranetdir') . '/installer/data/mysql/atomicupdate/';
23512
my $update_dir = C4::Context->config('intranetdir') . '/installer/data/mysql/atomicupdate/';
Lines 23505-23636 foreach my $file ( sort readdir $dirh ) { Link Here
23505
    }
23525
    }
23506
}
23526
}
23507
23527
23508
=head1 FUNCTIONS
23509
23510
=head2 DropAllForeignKeys($table)
23511
23512
Drop all foreign keys of the table $table
23513
23514
=cut
23515
23516
sub DropAllForeignKeys {
23517
    my ($table) = @_;
23518
    # get the table description
23519
    my $sth = $dbh->prepare("SHOW CREATE TABLE $table");
23520
    $sth->execute;
23521
    my $vsc_structure = $sth->fetchrow;
23522
    # split on CONSTRAINT keyword
23523
    my @fks = split /CONSTRAINT /,$vsc_structure;
23524
    # parse each entry
23525
    foreach (@fks) {
23526
        # isolate what is before FOREIGN KEY, if there is something, it's a foreign key to drop
23527
        $_ = /(.*) FOREIGN KEY.*/;
23528
        my $id = $1;
23529
        if ($id) {
23530
            # we have found 1 foreign, drop it
23531
            $dbh->do("ALTER TABLE $table DROP FOREIGN KEY $id");
23532
            $id="";
23533
        }
23534
    }
23535
}
23536
23537
23538
=head2 TransformToNum
23539
23540
Transform the Koha version from a 4 parts string
23541
to a number, with just 1 .
23542
23543
=cut
23544
23545
sub TransformToNum {
23546
    my $version = shift;
23547
    # remove the 3 last . to have a Perl number
23548
    $version =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
23549
    # three X's at the end indicate that you are testing patch with dbrev
23550
    # change it into 999
23551
    # prevents error on a < comparison between strings (should be: lt)
23552
    $version =~ s/XXX$/999/;
23553
    return $version;
23554
}
23555
23556
=head2 SetVersion
23557
23558
set the DBversion in the systempreferences
23559
23560
=cut
23561
23562
sub SetVersion {
23563
    return if $_[0]=~ /XXX$/;
23564
      #you are testing a patch with a db revision; do not change version
23565
    my $kohaversion = TransformToNum($_[0]);
23566
    if (C4::Context->preference('Version')) {
23567
      my $finish=$dbh->prepare("UPDATE systempreferences SET value=? WHERE variable='Version'");
23568
      $finish->execute($kohaversion);
23569
    } else {
23570
      my $finish=$dbh->prepare("INSERT into systempreferences (variable,value,explanation) values ('Version',?,'The Koha database version. WARNING: Do not change this value manually, it is maintained by the webinstaller')");
23571
      $finish->execute($kohaversion);
23572
    }
23573
    C4::Context::clear_syspref_cache(); # invalidate cached preferences
23574
}
23575
23576
sub NewVersion {
23577
    my ( $DBversion, $bug_number, $descriptions ) = @_;
23578
23579
    SetVersion($DBversion);
23580
23581
    unless ( ref($descriptions) ) {
23582
        $descriptions = [ $descriptions ];
23583
    }
23584
    my $first = 1;
23585
    my $time = POSIX::strftime("%H:%M:%S",localtime);
23586
    for my $description ( @$descriptions ) {
23587
        if ( @$descriptions > 1 ) {
23588
            if ( $first ) {
23589
                unless ( $bug_number ) {
23590
                    say sprintf "Upgrade to %s done [%s]: %s", $DBversion, $time, $description;
23591
                } else {
23592
                    say sprintf "Upgrade to %s done [%s]: Bug %5s - %s", $DBversion, $time, $bug_number, $description;
23593
                }
23594
            } else {
23595
                say sprintf "\t\t\t\t\t\t   - %s", $description;
23596
            }
23597
        } else {
23598
            unless ( $bug_number ) {
23599
                say sprintf "Upgrade to %s done [%s]: %s", $DBversion, $time, $description;
23600
            } else {
23601
                say sprintf "Upgrade to %s done [%s]: Bug %5s - %s", $DBversion, $time, $bug_number, $description;
23602
            }
23603
        }
23604
        $first = 0;
23605
    }
23606
}
23607
23608
=head2 CheckVersion
23609
23610
Check whether a given update should be run when passed the proposed version
23611
number. The update will always be run if the proposed version is greater
23612
than the current database version and less than or equal to the version in
23613
kohaversion.pl. The update is also run if the version contains XXX, though
23614
this behavior will be changed following the adoption of non-linear updates
23615
as implemented in bug 7167.
23616
23617
=cut
23618
23619
sub CheckVersion {
23620
    my ($proposed_version) = @_;
23621
    my $version_number = TransformToNum($proposed_version);
23622
23623
    # The following line should be deleted when bug 7167 is pushed
23624
    return 1 if ( $proposed_version =~ m/XXX/ );
23625
23626
    if ( C4::Context->preference("Version") < $version_number
23627
        && $version_number <= TransformToNum( $Koha::VERSION ) )
23628
    {
23629
        return 1;
23630
    }
23631
    else {
23632
        return 0;
23633
    }
23634
}
23635
23636
exit;
23528
exit;
(-)a/installer/install.pl (-35 / +12 lines)
Lines 394-434 elsif ( $step && $step == 3 ) { Link Here
394
            chk_log( $logdir, "updatedatabase-error_$filename_suffix" )
394
            chk_log( $logdir, "updatedatabase-error_$filename_suffix" )
395
        );
395
        );
396
396
397
        my $cmd = C4::Context->config("intranetdir")
397
        my $updatedatabase_path = C4::Context->config("intranetdir")
398
          . "/installer/data/$info{dbms}/updatedatabase.pl >> $logfilepath 2>> $logfilepath_errors";
398
          . "/installer/data/$info{dbms}/updatedatabase.pl";
399
399
400
        system($cmd );
400
        eval { require $updatedatabase_path };
401
401
        my $db_entries = get_db_entries();
402
        my $fh;
402
        my $report = update( $db_entries );
403
        open( $fh, "<:encoding(utf-8)", $logfilepath )
403
404
          or die "Cannot open log file $logfilepath: $!";
404
        # FIXME restore log to logfilepath and logfilepath_errors
405
        my @report = <$fh>;
405
406
        close $fh;
406
        $template->param( success => $report->{success}, error => $report->{error} );
407
        if (@report) {
407
408
            $template->param( update_report =>
408
        #warn "The following errors were returned while attempting to run the updatedatabase.pl script:\n"; #FIXME restore this
409
                  [ map { { line => $_ =~ s/\t/&emsp;&emsp;/gr } } split( /\n/, join( '', @report ) ) ]
410
            );
411
            $template->param( has_update_succeeds => 1 );
412
        }
413
        else {
414
            eval { `rm $logfilepath` };
415
        }
416
        open( $fh, "<:encoding(utf-8)", $logfilepath_errors )
417
          or die "Cannot open log file $logfilepath_errors: $!";
418
        @report = <$fh>;
419
        close $fh;
420
        if (@report) {
421
            $template->param( update_errors =>
422
                  [ map { { line => $_ } } split( /\n/, join( '', @report ) ) ]
423
            );
424
            $template->param( has_update_errors => 1 );
425
            warn
426
"The following errors were returned while attempting to run the updatedatabase.pl script:\n";
427
            foreach my $line (@report) { warn "$line\n"; }
428
        }
429
        else {
430
            eval { `rm $logfilepath_errors` };
431
        }
432
        $template->param( $op => 1 );
409
        $template->param( $op => 1 );
433
    }
410
    }
434
    else {
411
    else {
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/installer/step3.tt (-14 / +12 lines)
Lines 248-275 Link Here
248
248
249
                [% IF ( updatestructure ) %]
249
                [% IF ( updatestructure ) %]
250
                    <h2>Updating database structure</h2>
250
                    <h2>Updating database structure</h2>
251
                    [% IF ( has_update_succeeds ) %]
251
                    [% IF success %]
252
                        <p>Update report:</p>
252
                        <p>Update report:</p>
253
                        <ul>
253
                        <ul>
254
                            [% FOREACH l IN update_report %]
254
                            [% FOR s IN success %]
255
                                [% SET line = l.line %]
255
                                <li>[% s.output | html %]</li>
256
                                [% IF line.match('^Upgrade to') %]
257
                                    <li>[% line | $raw %]</li>
258
                                [% ELSE %]
259
                                    [% line | $raw %]<br/>
260
                                [% END %]
261
                            [% END %]
256
                            [% END %]
262
                        </ul>
257
                        </ul>
263
                    [% END %]
258
                    [% END %]
264
                    [% IF ( has_update_errors ) %]
259
                    [% IF error %]
265
                        <p>Update errors :</p>
260
                        <p>Update error :</p>
266
                        <ul>
261
                        <ul>
267
                            [% FOREACH update_error IN update_errors %]
262
                            [% FOR e IN error %]
268
                                <li class="update_error">[% update_error.line | html %]</li>
263
                                <li class="update_error">
264
                                    [% e.output | html %]
265
                                    <br/>
266
                                    ERROR: [% e.error | html %]
267
                                </li>
269
                            [% END %]
268
                            [% END %]
270
                        </ul>
269
                        </ul>
271
                    [% END %]
270
                    [% END %]
272
                    [% UNLESS ( has_update_errors ) %]
271
                    [% UNLESS error %]
273
                        <p>Everything went okay. Update done.</p>
272
                        <p>Everything went okay. Update done.</p>
274
                    [% END %]
273
                    [% END %]
275
                    <p><a href="install.pl?step=3&amp;op=finished" class="btn btn-primary">Continue to log in to Koha</a></p>
274
                    <p><a href="install.pl?step=3&amp;op=finished" class="btn btn-primary">Continue to log in to Koha</a></p>
276
- 

Return to bug 25078