#!/usr/bin/env php
<?php
/**
 * Database migration script.
 *
 * Usage: horde-db-migrate
 *        [-c|--config=filename]
 *        [-d|--debug]
 *        [-s|--halt-on-error]
 *        [(application|directory|--) [(up|down|status|<version>)]]
 *
 * Copyright 2010-2017 Horde LLC (http://www.horde.org/)
 *
 * See the enclosed file LICENSE for license information (LGPL-2). If you
 * did not receive this file, see http://www.horde.org/licenses/lgpl.
 *
 * @author   Chuck Hagenbuch <chuck@horde.org>
 * @author   Jan Schneider <jan@horde.org>
 * @category Horde
 * @license  http://www.horde.org/licenses/lgpl LGPL-2
 * @package  Horde
 */

$baseFile = __DIR__ . '/../lib/Application.php';
if (file_exists($baseFile)) {
    require_once $baseFile;
} else {
    require_once 'PEAR/Config.php';
    require_once PEAR_Config::singleton()
        ->get('horde_dir', null, 'pear.horde.org') . '/lib/Application.php';
}
Horde_Registry::appInit('horde', array(
    'authentication' => 'none',
    'cli' => true
));

// Parse command line arguments.
$parser = new Horde_Argv_Parser(
    array(
        'usage' => "%prog\n\t[-c|--config=filename]\n\t[-d|--debug]\n\t[-s|--halt-on-error]\n\t[(application|directory|--) [(up|down|status|<version>)]]",
        'optionList' => array(
            new Horde_Argv_Option(
                '-c',
                '--config',
                array(
                    'help'   => 'Path to PEAR configuration file.'
                )
            ),
            new Horde_Argv_Option(
                '-d',
                '--debug',
                array(
                    'action' => 'store_true',
                    'help'   => 'Provide full debugging output.'
                )
            ),
            new Horde_Argv_Option(
                '-s',
                '--halt-on-error',
                array(
                    'action' => 'store_true',
                    'help'   => 'Halt migration immediately on error.'
                )
            ),
            new Horde_Argv_Option(
                '-b',
                '--base-directory',
                array(
                    'action' => 'store',
                    'help'   => 'The base folder for the development checkout.'
                )
            ),
        )
    )
);
list($options, $args) = $parser->parseArgs();
if (empty($options['base_directory'])) {
    $options['base_directory'] = __DIR__ . '/../..';
}
$migration = new Horde_Core_Db_Migration($options['base_directory'], $options['config']);
if (empty($args[0])) {
    // Run all migrations.
    $apps = $migration->apps;
    $dirs = $migration->dirs;
} else {
    // Run a specific migration.
    $app = $args[0];

    if (($key = array_search($app, $migration->apps)) !== false) {
        $apps = array($app);
        $dirs = array($migration->dirs[$key]);
        array_shift($args);
    } elseif (($key = array_search($app, $migration->dirs)) !== false) {
        $apps = array($migration->apps[$key]);
        $dirs = array($app);
        array_shift($args);
    } elseif (in_array($app, array('--', 'up', 'down', 'status'))) {
        $apps = $migration->apps;
        $dirs = $migration->dirs;
        if ($app == '--') {
            array_shift($args);
        }
    } else {
        $cli->fatal(
            sprintf(
                '%s is neither a configured Horde application nor a migration directory

Supported applications:

%s

Supported directories:

%s',
                $app,
                join("\n  ", $migration->apps),
                join("\n  ", $migration->dirs)
            )
        );
    }
}

$action = 'up';
if (!empty($args[0])) {
    switch ($args[0]) {
    case 'up':
    case 'down':
    case 'status':
        $action = $args[0];
        break;

    default:
        $action = 'migrate';
        $targetVersion = $args[0];
        break;
    }
}

// Run
$db = $injector->getInstance('Horde_Db_Adapter');
if (!empty($options['debug'])) {
    $logger = new Horde_Log_Logger(new Horde_Log_Handler_Stream(STDOUT));
    $db->setLogger($logger);
}

switch ($action) {
case 'up':
    $cli->message('Migrating DB up.');
    break;

case 'down':
    $cli->message('Migrating DB down.');
    break;

case 'migrate':
    $cli->message('Migrating DB to schema version ' . $targetVersion . '.');
    break;

case 'status':
    $cli->message('Check Migration DB status.');
    break;

}

$logger = new Horde_Log_Logger(
    new Horde_Log_Handler_Stream(
        STDOUT, null, new Horde_Log_Formatter_Simple('%message%' . PHP_EOL)));

$exit_code = 0;

foreach ($apps as $app) {
    $migrator = $migration->getMigrator($app, $logger);

    $cli->message("Current $app schema version: " . $migrator->getCurrentVersion());

    try {
        switch ($action) {
        case 'up':
            $migrator->up();
            break;

        case 'down':
            $migrator->down();
            break;

        case 'migrate':
            $migrator->migrate($targetVersion);
            break;

        case 'status':
            if ($migrator->getCurrentVersion() != $migrator->getTargetVersion()) {
                $exit_code = 1;
            }
            $cli->message("Target $app schema version: " . $migrator->getTargetVersion());
            continue 2;
        }
    } catch (Exception $e) {
        echo $e->getMessage() . "\n";
        if (empty($options['halt-on-error'])) {
            continue;
        } else {
            exit(1);
        }
    }

    $cli->message("Ending $app schema version: " . $migrator->getCurrentVersion());
}

exit($exit_code);
