#!/usr/bin/perl
####################################################################################################################################
# release.pl - PgBackRest Release Manager
####################################################################################################################################

####################################################################################################################################
# Perl includes
####################################################################################################################################
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';

$SIG{__DIE__} = sub { Carp::confess @_ };

use Cwd qw(abs_path);
use File::Basename qw(dirname);
use Getopt::Long qw(GetOptions);
use Pod::Usage qw(pod2usage);
use Storable;

use lib dirname($0) . '/lib';
use lib dirname(dirname($0)) . '/build/lib';
use lib dirname(dirname($0)) . '/lib';
use lib dirname(dirname($0)) . '/test/lib';

use BackRestDoc::Common::Doc;
use BackRestDoc::Common::DocConfig;
use BackRestDoc::Common::DocManifest;
use BackRestDoc::Common::DocRender;
use BackRestDoc::Html::DocHtmlSite;
use BackRestDoc::Latex::DocLatex;
use BackRestDoc::Markdown::DocMarkdown;

use pgBackRest::Common::Exception;
use pgBackRest::Common::Log;
use pgBackRest::Common::String;
use pgBackRest::Storage::Local;
use pgBackRest::Storage::Posix::Driver;
use pgBackRest::Version;

use pgBackRestTest::Common::ExecuteTest;

####################################################################################################################################
# Usage
####################################################################################################################################

=head1 NAME

release.pl - pgBackRest Release Manager

=head1 SYNOPSIS

release.pl [options]

 General Options:
   --help           Display usage and exit
   --version        Display pgBackRest version
   --quiet          Sets log level to ERROR
   --log-level      Log level for execution (e.g. ERROR, WARN, INFO, DEBUG)

 Release Options:
   --build          Build the cache before release (should be included in the release commit)
   --deploy         Deploy documentation to website (can be done as docs are updated)
=cut

####################################################################################################################################
# Load command line parameters and config (see usage above for details)
####################################################################################################################################
my $bHelp = false;
my $bVersion = false;
my $bQuiet = false;
my $strLogLevel = 'info';
my $strHost = 'root@www.pgbackrest.org';
my $strUser = 'www-data';
my $strGroup = 'www-data';
my $strPath = '/data/http/backrest';
my $bBuild = false;
my $bDeploy = false;

GetOptions ('help' => \$bHelp,
            'version' => \$bVersion,
            'quiet' => \$bQuiet,
            'log-level=s' => \$strLogLevel,
            'build' => \$bBuild,
            'deploy' => \$bDeploy)
    or pod2usage(2);

####################################################################################################################################
# Run in eval block to catch errors
####################################################################################################################################
eval
{
    # Display version and exit if requested
    if ($bHelp || $bVersion)
    {
        print BACKREST_NAME . ' ' . BACKREST_VERSION . " Release Manager\n";

        if ($bHelp)
        {
            print "\n";
            pod2usage();
        }

        exit 0;
    }

    # If neither build nor deploy is requested then error
    if (!$bBuild && !$bDeploy)
    {
        confess &log(ERROR, 'neither --build nor --deploy requested, nothing to do');
    }

    # Set console log level
    if ($bQuiet)
    {
        $strLogLevel = 'error';
    }

    logLevelSet(undef, uc($strLogLevel), OFF);

    # Set the paths
    my $strDocPath = dirname(abs_path($0));
    my $strDocHtml = "${strDocPath}/output/html";
    my $strDocExe = "${strDocPath}/doc.pl";

    my $oStorageDoc = new pgBackRest::Storage::Local(
        $strDocPath, new pgBackRest::Storage::Posix::Driver({bFileSync => false, bPathSync => false}));

    # Determine if this is a dev release
    my $bDev = BACKREST_VERSION =~ /dev$/;
    my $strVersion = $bDev ? 'dev' : BACKREST_VERSION;

    if ($bBuild)
    {
        # Remove permanent cache file
        $oStorageDoc->remove("${strDocPath}/resource/exe.cache", {bIgnoreMissing => true});

        # Remove all docker containers to get consistent IP address assignments
        executeTest('docker rm -f $(docker ps -a -q)', {bSuppressError => true});

        # Generate deployment docs for RHEL/Centos 6
        &log(INFO, "Generate RHEL/CentOS 6 documentation");

        executeTest("${strDocExe} --deploy --keyword=co6 --out=pdf", {bShowOutputAsync => true});
        executeTest("${strDocExe} --deploy --cache-only --keyword=co6 --out=pdf --var=\"project-name=Crunchy BackRest\"");

        # Generate deployment docs for Debian
        &log(INFO, "Generate Debian/Ubuntu documentation");

        executeTest("${strDocExe} --deploy", {bShowOutputAsync => true});
        executeTest("${strDocExe} --deploy --cache-only --out=man --out=html --var=project-url-root=index.html");
    }

    if ($bDeploy)
    {
        # Generate deployment docs for the website history
        &log(INFO, 'Generate website ' . ($bDev ? 'dev' : 'history') . ' documentation');

        executeTest(
            $strDocExe . ($bDev ? '' : ' --deploy --cache-only') . ' --out=html --var=project-url-root=index.html' .
            ($bDev ? ' --keyword=default --keyword=dev' :  ' --exclude=release'));

        # Deploy to server
        &log(INFO, '...Deploy to server');
        executeTest("ssh ${strHost} rm -rf ${strPath}/${strVersion}");
        executeTest("ssh ${strHost} mkdir ${strPath}/${strVersion}");
        executeTest("scp ${strDocHtml}/* ${strHost}:${strPath}/${strVersion}");

        # Generate deployment docs for the main website
        if (!$bDev)
        {
            &log(INFO, "Generate website documentation");

            executeTest("${strDocExe} --deploy --cache-only --out=html");

            &log(INFO, '...Deploy to server');
            executeTest("ssh ${strHost} rm -rf ${strPath}/dev");
            executeTest("ssh ${strHost} find ${strPath} -maxdepth 1 -type f -exec rm {} +");
            executeTest("scp ${strDocHtml}/* ${strHost}:${strPath}");
        }

        # Update permissions
        executeTest("ssh ${strHost} chown -R ${strUser}:${strGroup} ${strPath}");
        executeTest("ssh ${strHost} find ${strPath} -type d -exec chmod 550 {} +");
        executeTest("ssh ${strHost} find ${strPath} -type f -exec chmod 440 {} +");
    }

    # Exit with success
    exit 0;
}

####################################################################################################################################
# Check for errors
####################################################################################################################################
or do
{
    # If a backrest exception then return the code
    exit $EVAL_ERROR->code() if (isException(\$EVAL_ERROR));

    # Else output the unhandled error
    print $EVAL_ERROR;
    exit ERROR_UNHANDLED;
};

# It shouldn't be possible to get here
&log(ASSERT, 'execution reached invalid location in ' . __FILE__ . ', line ' . __LINE__);
exit ERROR_ASSERT;
