From 3a5eaf434144f16a82213d04ff32fa0b4199ff2a Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Thu, 26 Apr 2018 15:07:07 -0400 Subject: [PATCH] Bug 20669: Add upgrade method to plugins It would be nice if plugins had an upgrade method to handle altering tables and such when a new version of a plugin is installed. Right now it must be done in a completely bespoke manner. Test Plan: 1) Apply this patch 2) Download the 2 most recent releases of the Kitchen Sink plugin https://github.com/bywatersolutions/koha-plugin-kitchen-sink/releases 3) Install the earlier release 4) Look at the configuration page, at the bottom it should say the plugin has never been upgraded 5) Install the newer release 6) Reload the configuration page, it should now say that the plugin was upgraded and give you the date and time of the upgrade Signed-off-by: Claire Gravely --- Koha/Plugins/Base.pm | 51 +++++++++++++++++++++++++++++++++++++++++++++++ t/db_dependent/Plugins.t | 17 ++++++++++++++-- t/lib/Koha/Plugin/Test.pm | 5 +++++ 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/Koha/Plugins/Base.pm b/Koha/Plugins/Base.pm index c39a8c9..ed87253 100644 --- a/Koha/Plugins/Base.pm +++ b/Koha/Plugins/Base.pm @@ -21,6 +21,7 @@ use Modern::Perl; use Module::Pluggable require => 1; use Cwd qw(abs_path); +use List::Util qw(max); use base qw{Module::Bundled::Files}; @@ -43,13 +44,26 @@ sub new { my $self = bless( $args, $class ); + my $plugin_version = $self->get_metadata->{version}; + my $database_version = $self->retrieve_data('__INSTALLED_VERSION__'); + ## Run the installation method if it exists and hasn't been run before if ( $self->can('install') && !$self->retrieve_data('__INSTALLED__') ) { if ( $self->install() ) { $self->store_data( { '__INSTALLED__' => 1 } ); + if ( my $version = $plugin_version ) { + $self->store_data({ '__INSTALLED_VERSION__' => $version }); + } } else { warn "Plugin $class failed during installation!"; } + } elsif ( $self->can('upgrade') && $plugin_version && $database_version ) { + if ( _version_compare( $plugin_version, $database_version ) == 1 ) { + if ( $self->upgrade() ) { + $self->store_data({ '__INSTALLED_VERSION__' => $plugin_version }); + warn "Plugin $class failed during upgrade!"; + } + } } return $self; @@ -218,6 +232,43 @@ sub output { output_with_http_headers( $self->{cgi}, undef, $data, $content_type, $status, $extra_options ); } +=head2 _version_compare + +Utility method to compare two version numbers. +Returns 1 if the first argument is the higher version +Returns -1 if the first argument is the lower version +Returns 0 if both versions are equal + +if ( _version_compare( '2.6.26', '2.6.0' ) == 1 ) { + print "2.6.26 is greater than 2.6.0\n"; +} + +=cut + +sub _version_compare { + my $ver1 = shift || 0; + my $ver2 = shift || 0; + + my @v1 = split /[.+:~-]/, $ver1; + my @v2 = split /[.+:~-]/, $ver2; + + for ( my $i = 0 ; $i < max( scalar(@v1), scalar(@v2) ) ; $i++ ) { + + # Add missing version parts if one string is shorter than the other + # i.e. 0 should be lt 0.2.1 and not equal, so we append .0 + # 0.0.0 <=> 0.2.1 = -1 + push( @v1, 0 ) unless defined( $v1[$i] ); + push( @v2, 0 ) unless defined( $v2[$i] ); + if ( int( $v1[$i] ) > int( $v2[$i] ) ) { + return 1; + } + elsif ( int( $v1[$i] ) < int( $v2[$i] ) ) { + return -1; + } + } + return 0; +} + 1; __END__ diff --git a/t/db_dependent/Plugins.t b/t/db_dependent/Plugins.t index f82d3b2..e4e987e 100755 --- a/t/db_dependent/Plugins.t +++ b/t/db_dependent/Plugins.t @@ -2,14 +2,14 @@ use Modern::Perl; -use Test::More tests => 35; +use Archive::Extract; use CGI; use File::Basename; use File::Temp qw( tempdir tempfile ); use FindBin qw($Bin); -use Archive::Extract; use Module::Load::Conditional qw(can_load); use Test::MockModule; +use Test::More tests => 37; use C4::Context; @@ -49,6 +49,7 @@ ok( $plugin->can('opac_head'), 'Test plugin can opac_head' ); ok( $plugin->can('opac_js'), 'Test plugin can opac_js' ); ok( $plugin->can('configure'), 'Test plugin can configure' ); ok( $plugin->can('install'), 'Test plugin can install' ); +ok( $plugin->can('upgrade'), 'Test plugin can upgrade' ); ok( $plugin->can('uninstall'), 'Test plugin can install' ); is( Koha::Plugins::Handler->run({ class => "Koha::Plugin::Test", method => 'report', enable_plugins => 1 }), "Koha::Plugin::Test::report", 'Test run plugin report method' ); @@ -151,3 +152,15 @@ subtest 'output and output_html tests' => sub { like($stdout, qr{Content-Type: text/html; charset=UTF-8}, 'Correct content-type'); like($stdout, qr{¡Hola output_html!}, 'Correct data'); }; + +subtest 'Test _version_compare' => sub { + + plan tests => 6; + + is( Koha::Plugins::Base::_version_compare( '1.1.1', '2.2.2' ), -1, "1.1.1 is less then 2.2.2" ); + is( Koha::Plugins::Base::_version_compare( '2.2.2', '1.1.1' ), 1, "1.1.1 is greater then 2.2.2" ); + is( Koha::Plugins::Base::_version_compare( '1.1.1', '1.1.1' ), 0, "1.1.1 is equal to 1.1.1" ); + is( Koha::Plugins::Base::_version_compare( '1.01.001', '1.1.1' ), 0, "1.01.001 is equal to 1.1.1" ); + is( Koha::Plugins::Base::_version_compare( '1', '1.0.0' ), 0, "1 is equal to 1.0.0" ); + is( Koha::Plugins::Base::_version_compare( '1.0', '1.0.0' ), 0, "1.0 is equal to 1.0.0" ); +}; diff --git a/t/lib/Koha/Plugin/Test.pm b/t/lib/Koha/Plugin/Test.pm index f817438..bf03b0b 100644 --- a/t/lib/Koha/Plugin/Test.pm +++ b/t/lib/Koha/Plugin/Test.pm @@ -80,6 +80,11 @@ sub install { return "Koha::Plugin::Test::install"; } +sub upgrade { + my ( $self, $args ) = @_; + return "Koha::Plugin::Test::install"; +} + sub uninstall { my ( $self, $args ) = @_; return "Koha::Plugin::Test::uninstall"; -- 2.1.4