mirror of
https://github.com/pragma-/pbot.git
synced 2025-01-11 04:22:35 +01:00
Add data/config migration framework
This commit is contained in:
parent
b007cb3b9d
commit
b9d3fa5f03
89
PBot/Migration.pm
Normal file
89
PBot/Migration.pm
Normal file
@ -0,0 +1,89 @@
|
||||
# File: Migration.pm
|
||||
# Author: pragma_
|
||||
#
|
||||
# Purpose: Migrates data/configration files to new locations/formats based
|
||||
# on versioning information. Ensures data/configuration files are in the
|
||||
# proper location and using the latest data structure.
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package PBot::Migration;
|
||||
use parent 'PBot::Class';
|
||||
|
||||
use warnings; use strict;
|
||||
use feature 'unicode_strings';
|
||||
|
||||
use File::Basename;
|
||||
|
||||
sub initialize {
|
||||
my ($self, %conf) = @_;
|
||||
$self->{data_dir} = $conf{data_dir};
|
||||
$self->{migration_dir} = $conf{migration_dir};
|
||||
}
|
||||
|
||||
sub migrate {
|
||||
my ($self) = @_;
|
||||
|
||||
$self->{pbot}->{logger}->log("Checking if migration needed...\n");
|
||||
|
||||
my $current_version = $self->get_current_version;
|
||||
my $last_migration_version = $self->get_last_migration_version;
|
||||
|
||||
$self->{pbot}->{logger}->log("Current version: $current_version; last migration version: $last_migration_version\n");
|
||||
|
||||
if ($last_migration_version >= $current_version) {
|
||||
$self->{pbot}->{logger}->log("No migration necessary.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
my @migrations = $self->get_available_migrations($last_migration_version);
|
||||
|
||||
if (not @migrations ) {
|
||||
$self->{pbot}->{logger}->log("No migrations available.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
foreach my $migration (@migrations) {
|
||||
$self->{pbot}->{logger}->log("Executing migration script: $migration\n");
|
||||
my $output = `$migration $self->{data_dir}`;
|
||||
my $exit = $? >> 8;
|
||||
$self->{pbot}->{logger}->log("Script completed. Exit $exit. Output: $output");
|
||||
return $exit if $exit != 0;
|
||||
}
|
||||
|
||||
return $self->put_last_migration_version($current_version);
|
||||
}
|
||||
|
||||
sub get_available_migrations {
|
||||
my ($self, $last_migration_version) = @_;
|
||||
my @migrations = sort glob "$self->{migration_dir}/*";
|
||||
return grep { my ($version) = split /_/, basename $_; $version > $last_migration_version ? 1 : 0 } @migrations;
|
||||
}
|
||||
|
||||
sub get_current_version {
|
||||
return PBot::VERSION::BUILD_REVISION;
|
||||
}
|
||||
|
||||
sub get_last_migration_version {
|
||||
my ($self) = @_;
|
||||
open(my $fh, '<', "$self->{data_dir}/last_migration") or return 0;
|
||||
chomp(my $last_migration = <$fh>);
|
||||
close $fh;
|
||||
return $last_migration;
|
||||
}
|
||||
|
||||
sub put_last_migration_version {
|
||||
my ($self, $version) = @_;
|
||||
if (open(my $fh, '>', "$self->{data_dir}/last_migration")) {
|
||||
print $fh "$version\n";
|
||||
close $fh;
|
||||
return 0;
|
||||
} else {
|
||||
$self->{pbot}->{logger}->log("Could not save last migration to $self->{data_dir}/last_migration: $!\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
42
PBot/PBot.pm
42
PBot/PBot.pm
@ -50,6 +50,7 @@ use PBot::Plugins;
|
||||
use PBot::Functions;
|
||||
use PBot::Modules;
|
||||
use PBot::ProcessManager;
|
||||
use PBot::Migration;
|
||||
|
||||
sub new {
|
||||
my ($proto, %conf) = @_;
|
||||
@ -66,21 +67,23 @@ sub initialize {
|
||||
my $data_dir = $conf{data_dir};
|
||||
my $module_dir = $conf{module_dir};
|
||||
my $plugin_dir = $conf{plugin_dir};
|
||||
my $migration_dir = $conf{migration_dir};
|
||||
|
||||
# check command-line arguments for directory overrides
|
||||
foreach my $arg (@ARGV) {
|
||||
if ($arg =~ m/^-?(?:general\.)?((?:data|module|plugin)_dir)=(.*)$/) {
|
||||
if ($arg =~ m/^-?(?:general\.)?((?:data|module|plugin|migration)_dir)=(.*)$/) {
|
||||
my $override = $1;
|
||||
my $value = $2;
|
||||
$data_dir = $value if $override eq 'data_dir';
|
||||
$module_dir = $value if $override eq 'module_dir';
|
||||
$plugin_dir = $value if $override eq 'plugin_dir';
|
||||
$migration_dir = $value if $override eq 'migration_dir';
|
||||
}
|
||||
}
|
||||
|
||||
# check command-line arguments for registry overrides
|
||||
foreach my $arg (@ARGV) {
|
||||
next if $arg =~ m/^-?(?:general\.)?(?:config|data|module|plugin)_dir=.*$/; # already processed
|
||||
next if $arg =~ m/^-?(?:general\.)?(?:config|data|module|plugin|migration)_dir=.*$/; # already processed
|
||||
my ($item, $value) = split /=/, $arg, 2;
|
||||
|
||||
if (not defined $item or not defined $value) {
|
||||
@ -102,15 +105,16 @@ sub initialize {
|
||||
$self->{atexit} = PBot::Registerable->new(%conf, pbot => $self);
|
||||
$self->register_signal_handlers;
|
||||
|
||||
# create logger
|
||||
$self->{logger} = PBot::Logger->new(pbot => $self, filename => "$data_dir/log/log", %conf);
|
||||
|
||||
# make sure the environment is sane
|
||||
# make sure the data directory exists
|
||||
if (not -d $data_dir) {
|
||||
$self->{logger}->log("Data directory ($data_dir) does not exist; aborting...\n");
|
||||
print STDERR "Data directory ($data_dir) does not exist; aborting...\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
# create logger
|
||||
$self->{logger} = PBot::Logger->new(pbot => $self, filename => "$data_dir/log/log", %conf);
|
||||
|
||||
# make sure the rest of the environment is sane
|
||||
if (not -d $module_dir) {
|
||||
$self->{logger}->log("Modules directory ($module_dir) does not exist; aborting...\n");
|
||||
exit;
|
||||
@ -121,10 +125,23 @@ sub initialize {
|
||||
exit;
|
||||
}
|
||||
|
||||
# then capabilities so commands can add new capabilities
|
||||
if (not -d $migration_dir) {
|
||||
$self->{logger}->log("Migration directory ($migration_dir) does not exist; aborting...\n");
|
||||
exit;
|
||||
}
|
||||
|
||||
# migrate/update any data files to new locations/formats
|
||||
$self->{migrator} = PBot::Migration->new(pbot => $self, data_dir => $data_dir, migration_dir => $migration_dir);
|
||||
|
||||
if ($self->{migrator}->migrate) {
|
||||
$self->{logger}->log("Migration failed.\n");
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# create capabilities so commands can add new capabilities
|
||||
$self->{capabilities} = PBot::Capabilities->new(pbot => $self, filename => "$data_dir/capabilities", %conf);
|
||||
|
||||
# then commands so the modules can register new commands
|
||||
# create commands so the modules can register new commands
|
||||
$self->{commands} = PBot::Commands->new(pbot => $self, filename => "$data_dir/commands", %conf);
|
||||
|
||||
# add some commands
|
||||
@ -143,10 +160,11 @@ sub initialize {
|
||||
$self->{logger}->log($self->{version}->version . "\n");
|
||||
$self->{logger}->log("Args: @ARGV\n") if @ARGV;
|
||||
|
||||
# log the configured paths
|
||||
$self->{logger}->log("data_dir: $data_dir\n");
|
||||
$self->{logger}->log("module_dir: $module_dir\n");
|
||||
$self->{logger}->log("plugin_dir: $plugin_dir\n");
|
||||
$self->{logger}->log("data_dir: $data_dir\n");
|
||||
$self->{logger}->log("migration_dir: $migration_dir\n");
|
||||
|
||||
|
||||
$self->{timer} = PBot::Timer->new(pbot => $self, timeout => 10, name => 'PBot Timer', %conf);
|
||||
$self->{modules} = PBot::Modules->new(pbot => $self, %conf);
|
||||
@ -159,6 +177,7 @@ sub initialize {
|
||||
$self->{registry}->add_default('text', 'general', 'data_dir', $data_dir);
|
||||
$self->{registry}->add_default('text', 'general', 'module_dir', $module_dir);
|
||||
$self->{registry}->add_default('text', 'general', 'plugin_dir', $plugin_dir);
|
||||
$self->{registry}->add_default('text', 'general', 'migration_dir', $migration_dir);
|
||||
$self->{registry}->add_default('text', 'general', 'trigger', $conf{trigger} // '!');
|
||||
|
||||
$self->{registry}->add_default('text', 'irc', 'debug', $conf{irc_debug} // 0);
|
||||
@ -186,6 +205,7 @@ sub initialize {
|
||||
$self->{registry}->set('general', 'data_dir', 'value', $data_dir, 0, 1);
|
||||
$self->{registry}->set('general', 'module_dir', 'value', $module_dir, 0, 1);
|
||||
$self->{registry}->set('general', 'plugin_dir', 'value', $plugin_dir, 0, 1);
|
||||
$self->{registry}->set('general', 'migration_dir', 'value', $migration_dir, 0, 1);
|
||||
|
||||
# override registry entries with command-line arguments, if any
|
||||
foreach my $override (keys %{$self->{overrides}}) {
|
||||
|
@ -16,6 +16,7 @@ use warnings; use strict;
|
||||
use feature 'unicode_strings';
|
||||
|
||||
use Module::Refresh;
|
||||
use File::Basename;
|
||||
|
||||
sub initialize {
|
||||
my ($self, %conf) = @_;
|
||||
@ -25,6 +26,14 @@ sub initialize {
|
||||
|
||||
sub refresh {
|
||||
my ($self, $from, $nick, $user, $host, $arguments) = @_;
|
||||
|
||||
my $last_migration = $self->{pbot}->{migrator}->get_last_migration_version;
|
||||
my @migrations = $self->{pbot}->{migrator}->get_available_migrations($last_migration);
|
||||
|
||||
if (@migrations) {
|
||||
return "Migration available; cannot refresh. Please restart PBot to begin migration of " . join(', ', map { basename $_ } @migrations);
|
||||
}
|
||||
|
||||
my $refresh_error;
|
||||
local $SIG{__WARN__} = sub {
|
||||
my $warning = shift;
|
||||
@ -55,6 +64,7 @@ sub refresh {
|
||||
$self->{pbot}->{logger}->log("Error refreshing: $@\n");
|
||||
return $@;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
0
migration/.keep
Normal file
0
migration/.keep
Normal file
Loading…
Reference in New Issue
Block a user