#!/usr/bin/perl
use strict; use warnings;

=pod

=head1 NAME

vox-backup-wiki - backup a pollwiki

=head1 SYNOPSIS

> vox-backup-wiki

> vox-backup-server VS

=head1 DESCRIPTION

Backs up the local pollwiki.  It creates the following files:

  /var/cache/pollwiki/backup/cur/
    wiki-dump-current.xml
    wiki-dump-full.xml
    wiki-images.tar.gz
    wikidb-dump.sql

Normally you will also back up any vote-servers immediately afterward, as their backups
currently fit in the same directory structure.

Reference: http://www.mediawiki.org/wiki/Manual:Backing_up_a_wiki

=head1 RESTORING

=head2 MySQL restoration

This is the preferred restoration method.  It has yet to be tested locally, so no specific
instructions are documented yet.  Meantime see the general instructions:

http://www.mediawiki.org/wiki/Manual:Restoring_a_wiki_from_backup

http://dev.mysql.com/doc/mysql-backup-excerpt/5.1/en/reloading-sql-format-dumps.html

http://dev.mysql.com/doc/refman/5.1/en/mysqldump.html

=head2 MediaWiki restoration

This is the failsafe restoration method.  It is less complete and more complicated than
the MySQL method.  Resort to it only if necessary.

=over

=item 1

> e /etc/apache2/modules.d/90_mediawiki.conf

Close access to the wiki, stopping the web server if necessary.

=item 2

> mysql --password

Create the wiki user and database by entering the following commands in the mysql database
shell:

  @mysql> create database wikidb;

  @mysql> grant index, create, select, insert, update, delete, alter, lock tables on wikidb.* to 'wikiuser'@'localhost' identified by 'mw376ze';

Those commands are documented at http://www.mediawiki.org/wiki/Manual:Installing_MediaWiki#MySQL

  @mysql> grant create temporary tables, drop on wikidb.* to 'wikiuser'@'localhost';

The added permissions above are required for Semantic MediaWiki.
See http://semantic-mediawiki.org/wiki/Help:Installation

=item 3

Install MediaWiki.  Choose the recommended default (binary mode) for characters.

http://www.mediawiki.org/wiki/Manual:Installing_MediaWiki

=item 4

Adjust the configuration in LocalSettings.php.

=item 5

Install the extensions, including Semantic MediaWiki and its Validator.

=item 6

Temporarily disable Semantic MediaWiki queries in LocalSettings.php:

  $smwgQEnabled = false;

Otherwise importDump might fail with "Unable to free MySQL result".
See also http://wikimedia.7.x6.nabble.com/Embedding-an-ask-query-td563478.html

=item 7

Restore the pages and revisions (dry run).

  > (m=/var/www/localhost/htdocs/mediawiki; nice php $m/maintenance/importDump.php --conf $m/LocalSettings.php --dry-run /var/cache/pollwiki/backup/cur/wiki-dump-full.xml)

http://www.mediawiki.org/wiki/Manual:Importing_XML_dumps

=item 8

Restore the pages and revisions.

  > (m=/var/www/localhost/htdocs/mediawiki; nice php $m/maintenance/importDump.php --conf $m/LocalSettings.php /var/cache/pollwiki/backup/cur/wiki-dump-full.xml)

=item 9

Delete the Main_Page that was automatically generated by the installation process, unless
you want to keep it.

=item 10

Unpack the images backup file:

  /var/cache/pollwiki/backup/cur/wiki-images.tar.gz

To here:

  /tmp/wiki-images

=item 11

Delete /tmp/wiki-images/archive, temp and thumb subdirectories.  Delete all other files in
/tmp/wiki-images/ except those in content subdirectories /tmp/wiki-images/0 to f.

=item 12

Ensure the installed images directory is writable by the web server (Apache).

  /var/www/localhost/htdocs/mediawiki/images

Otherwise thumbnails might not be created for the restored images.  Instead you'll see an
error message on the image pages.

=item 13

Restore the images (dry run).

  > nice php /var/www/localhost/htdocs/mediawiki/maintenance/importImages.php --comment='restore from backup' --dry --search-recursively /tmp/wiki-images

http://www.mediawiki.org/wiki/Manual:ImportImages.php

=item 14

Restore the images.

  > nice php /var/www/localhost/htdocs/mediawiki/maintenance/importImages.php --comment='restore from backup' --search-recursively /tmp/wiki-images

=item 15

Ensure that the newly created image files and directories are writable by the web server.

  > chown apache:apache /var/www/localhost/htdocs/mediawiki/images --recursive

=item 16

Eagerly refresh the MediaWiki indices:

  > nice php /var/www/localhost/htdocs/mediawiki/maintenance/rebuildall.php
  > nice php /var/www/localhost/htdocs/mediawiki/maintenance/updateArticleCount.php --update

=item 17

Enable Semantic MediaWiki queries in LocalSettings.php by commenting out or removing this line:

  $smwgQEnabled = true; # or just remove this, because the default value is true

=item 18

Eagerly refresh the Semantic MediaWiki indices.  First to parse the category, property and
type pages (cpt):

  > nice php /var/www/localhost/htdocs/mediawiki/extensions/SemanticMediaWiki/maintenance/SMW_refreshData.php -cpt -v

Next to parse all the other pages, with 5 ms delay (d) to limit server IO load:

  > nice php /var/www/localhost/htdocs/mediawiki/extensions/SemanticMediaWiki/maintenance/SMW_refreshData.php -d 5 -v

http://semantic-mediawiki.org/wiki/Help:SMW_refreshData.php

=item 19

> e /etc/apache2/modules.d/90_mediawiki.conf

Restore access to the wiki.

=back

=cut


sub rmdirRecursive( $ )
{
    use IO::Handle qw( flush );

    my $dir = shift;
    print "remove directory $dir, and continue with backup? y/n ";
    flush STDOUT; # for sake of remote terminals
    my $reply = <STDIN>; chomp $reply;
    $reply eq 'y' or die "backup aborted\n";

    system( "rm --recursive $dir" ) and die;

    -e $dir and die;
}



# ----------------------------------------------------------------------------------------


   # Create a new backup subdirectory
   # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    my $backDir = "/var/cache/pollwiki/backup"; -d $backDir or die;
    my $backDirNew = $backDir . '/new';
    -e $backDirNew and rmdirRecursive( $backDirNew );
    mkdir $backDirNew or die;

   # Lock the wiki
   # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   # To obtain an atomic snapshot of the wiki content: database + filebase.  The database
   # snapshot from mysqldump will be atomic in itself regardless.

    my $mwDir = '/var/www/localhost/htdocs/mediawiki'; -d $mwDir or die;
    my $wgReadOnlyFile = $mwDir . '/images/lock_yBgMBwiR';
      # http://www.mediawiki.org/wiki/Manual:$wgReadOnlyFile
    open FILE, ">$wgReadOnlyFile" or die "$wgReadOnlyFile: $!";
    print FILE "A routine backup is in progress, it shouldn't take more than a few minutes.";
    close FILE;

   # MySQL content
   # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    {
        my $command =
          "nice mysqldump --default-character-set=binary --password --single-transaction wikidb > $backDirNew/wikidb-dump.sql";
          # http://dev.mysql.com/doc/refman/5.1/en/mysqldump.html
          # --default-character-set per http://www.mediawiki.org/wiki/Manual:$wgDBTableOptions
        print "   $command\n";
        system $command and die 'unable to execute: ' . $command;
        print "\n";
    }

   # MediaWiki content - failsafe alternative to MySQL restoration
   # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    {
        my $command =
          "nice php $mwDir/maintenance/dumpBackup.php --current > $backDirNew/wiki-dump-current.xml";
        print "   $command\n";
        system $command and die 'unable to execute: ' . $command;
        print "\n";
    }
    {
        my $command =
          "nice php $mwDir/maintenance/dumpBackup.php --full > $backDirNew/wiki-dump-full.xml";
        print "   $command\n";
        system $command and die 'unable to execute: ' . $command;
        print "\n";
    }

   # Filebase - images and such
   # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    {
        my $command =
          "tar --create --directory $mwDir/images/ --exclude=lock_yBgMBwiR --file $backDirNew/wiki-images.tar.gz --gzip .";
        print "   $command\n";
        system $command and die 'unable to execute: ' . $command;
        print "\n";
    }

   # Unlock the wiki
   # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    open FILE, ">$wgReadOnlyFile" or die "$wgReadOnlyFile: $!";
    close FILE;

   # Rotate the backup directories
   # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    my $backDirOld = $backDir . '/old';
    -e $backDirOld and rmdirRecursive( $backDirOld );
    my $backDirCur = $backDir . '/cur';
    if( -e $backDirCur )
    {
        system( "mv $backDirCur $backDirOld" ) and die;
    }
    system( "mv $backDirNew $backDirCur" ) and die;