#!/usr/bin/env php
<?php
/**
 * This script creates softlinks to the library files you retrieved from
 * the framework module.
 *
 * Copyright 2002 Wolfram Kriesing <wolfram@kriesing.de>
 * Copyright 2003-2014 Horde LLC (http://www.horde.org/)
 *
 * See the enclosed file COPYING for license information (LGPL). If you
 * did not receive this file, see http://www.horde.org/licenses/lgpl21.
 *
 * @author   Wolfram Kriesing <wolfram@kriesing.de>
 * @author   Jan Schneider <jan@horde.org>
 * @author   Michael Slusarz <slusarz@horde.org>
 * @category Horde
 * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
 * @package  framework
 */

$destDir = $hordeDir = $srcDir = null;
$debug = $dryrun = false;

// Default to copying if this is run on Windows.
$copy = strncasecmp(PHP_OS, 'WIN', 3) ? false : true;

// All packages by default.
$pkg = null;

for ($i = 1; $i < count($argv); ++$i) {
    switch ($argv[$i]) {
    case '--copy':
        $copy = true;
        break;

    case '--debug':
        $debug = true;
        break;

    case '--dryrun':
        $dryrun = true;
        break;

    case '--help':
        print_usage();

    case '--horde':
        if (isset($argv[$i + 1])) {
            if (is_dir($argv[$i + 1])) {
                $hordeDir = $argv[++$i];
            } else {
                exit($argv[$i + 1] . " is not a directory");
            }
        }
        break;

    case '--src':
        if (isset($argv[$i + 1])) {
            if (is_dir($argv[$i + 1])) {
                $srcDir = $argv[++$i];
            } else {
                exit($argv[$i + 1] . " is not a directory");
            }
        }
        break;

    case '--dest':
        if (isset($argv[$i + 1])) {
            if (is_dir($argv[$i + 1])) {
                $destDir = $argv[++$i];
            } else {
                exit($argv[$i + 1] . " is not a directory");
            }
        }
        break;

    case '--pkg':
        $pkg = $argv[++$i];
        if (!is_dir($pkg) || !file_exists($pkg . '/package.xml')) {
            exit("$pkg is not a valid package directory.\n");
        }
        $pkg = preg_replace('|/+$|', '', $pkg);
        break;

    default:
        print_usage("Unrecognised option $argv[$i]");
    }
}

if (is_null($hordeDir)) {
    print_usage('Missing the horde installation directory.');
}

// Try to auto-detect the source and dest dirs.
$cwd = getcwd();
if (is_null($srcDir) && is_null($pkg)) {
    $srcDir = is_dir($cwd . '/framework')
        ? $cwd . DIRECTORY_SEPARATOR . 'framework'
        : __DIR__ . '/..';
}
if (is_null($destDir) && is_dir($cwd . '/lib')) {
    $destDir = $cwd . DIRECTORY_SEPARATOR . 'lib';
}

if ((is_null($srcDir) && is_null($pkg)) || is_null($destDir)) {
    print_usage('Failed to auto-detect source and destination directories,');
}

// Make $hordeDir an absolute path.
if (($hordeDir[0] != '/') &&
    !preg_match('/[A-Za-z]:/', $hordeDir) &&
    ($cwd = getcwd())) {
    $hordeDir = $cwd . '/' . $hordeDir;
}
$hordeDir = rtrim($hordeDir, '/');

// Make $srcDir an absolute path.
if (($srcDir[0] != '/') &&
    !preg_match('/[A-Za-z]:/', $srcDir) &&
    ($cwd = getcwd())) {
    $srcDir = $cwd . '/' . $srcDir;
}
$srcDir = rtrim($srcDir, '/');

// Make $destDir an absolute path.
if (($destDir[0] != '/') &&
    !preg_match('/[A-Za-z]:/', $destDir) &&
    ($cwd = getcwd())) {
    $destDir = $cwd . '/' . $destDir;
}
$destDir = rtrim($destDir, '/');

// Put $destDir into include_path.
if (strpos(ini_get('include_path'), $destDir) === false) {
    ini_set('include_path', $destDir . PATH_SEPARATOR . ini_get('include_path'));
}

// Do CLI checks and environment setup first.
if ((!@include_once __DIR__ . '/../Cli/lib/Horde/Cli.php') &&
    (!@include_once 'Horde/Cli.php')  &&
    (!@include_once $srcDir . '/Cli/lib/Horde/Cli.php') &&
    (!@include_once $cwd . '/../Cli/lib/Horde/Cli.php')) {
    print_usage('Horde_Cli library is not in the include_path or in the src directory.');
}

// Make sure no one runs this from the web.
if (!Horde_Cli::runningFromCLI()) {
    exit;
}

// Load the CLI environment - make sure there's no time limit, init
// some variables, etc.
$cli = Horde_Cli::init();

$cli->message('Source directory: ' . $srcDir);
$cli->message('Framework destination directory: ' . $destDir);
$cli->message('Horde directory: ' . $hordeDir);
$cli->message('Create symbolic links: ' . ($copy ? 'NO' : 'Yes'));

// Create the local PEAR config.
if (!(@include_once 'PEAR/Config.php') ||
    !(@include_once 'PEAR/PackageFile.php')) {
    print_usage('PEAR libraries are not in the PHP include_path.');
}

/* We are heavily relying on the PEAR libraries which are not clean with regard
 * to E_STRICT. */
if (defined('E_DEPRECATED')) {
    error_reporting(E_ALL & ~E_STRICT & ~E_DEPRECATED);
} else {
    error_reporting(E_ALL & ~E_STRICT);
}

$pear_config = PEAR_Config::singleton();
$pear_pkg = new PEAR_PackageFile($pear_config);

if ($pkg) {
    $pkgs = array(basename($pkg) => realpath($pkg));
} else {
    $di = new DirectoryIterator($srcDir);
    $pkgs = array();
    foreach ($di as $val) {
        $pathname = $val->getPathname();
        if ($val->isDir() &&
            !$di->isDot() &&
            file_exists($pathname . '/package.xml')) {
            $pkgs[basename($val)] = $pathname;
        }
    }
    asort($pkgs);
}

$cli->writeLn();
$cli->message('Package(s) to install: ' . ($pkg ? $pkg : 'ALL (' . count($pkgs) . ' packages)'));

foreach ($pkgs as $key => $val) {
    if ($debug) {
        $cli->writeLn();
    }
    $cli->message('Installing package ' . $key);

    $pkg_ob = $pear_pkg->fromPackageFile($val . '/package.xml', 0);
    if ($pkg_ob instanceof PEAR_Error) {
        $cli->message('Could not install package ' . $key . ': ' . $pkg_ob->getMessage(), 'cli.error');
        continue;
    }
    foreach ($pkg_ob->getInstallationFilelist() as $file) {
        if (!isset($file['attribs']['name'])) {
            $cli->message('Invalid <install> entry: ' . print_r($file['attribs'], true), 'cli.error');
            continue;
        }
        $orig = realpath($val . '/' . $file['attribs']['name']);
        if (empty($orig)) {
            $cli->message('Install file does not seem to exist: ' . $val . '/' . $file['attribs']['name'], 'cli.error');
            continue;
        }

        switch ($file['attribs']['role']) {
        case 'horde':
            if (isset($file['attribs']['install-as'])) {
                $dest = $hordeDir . '/' . $file['attribs']['install-as'];
            } else {
                $cli->message('Could not determine install directory (role "horde") for ' . $hordeDir, 'cli.error');
                continue;
            }
            break;

        case 'php':
            if (isset($file['attribs']['install-as'])) {
                $dest = $destDir . '/' . $file['attribs']['install-as'];
            } elseif (isset($file['attribs']['baseinstalldir'])) {
                $dest = $destDir . $file['attribs']['baseinstalldir'] . '/' . $file['attribs']['name'];
            } else {
                $dest = $destDir . '/' . $file['attribs']['name'];
            }
            break;

        default:
            $dest = null;
            break;
        }

        if (!is_null($dest)) {
            if (!$dryrun && file_exists($dest)) {
                @unlink($dest);
            } elseif (!$dryrun && !file_exists(dirname($dest))) {
                @mkdir(dirname($dest), 0777, true);
            }

            if ($copy) {
                if ($debug) {
                    print 'COPY: ' . $orig . ' -> ' . $dest . "\n";
                }
                if (!$dryrun && !copy($orig, $dest)) {
                    $cli->message('Could not link ' . $orig . '.', 'cli.error');
                }
            } else {
                if ($debug) {
                    print 'SYMLINK: ' . $orig . ' -> ' . $dest . "\n";
                }
                if (!$dryrun && !symlink($orig, $dest)) {
                    $cli->message('Could not link ' . $orig . '.', 'cli.error');
                }
            }
        }
    }
}

/**
 * Usage message.
 */
function print_usage($message = '')
{
    if (!empty($message)) {
        echo "install_framework: $message\n\n";
    }

    echo <<<USAGE
Usage: install_framework [OPTION]

Required options:
  --dest DIR    The destination directory for the framework libraries.
  --horde DIR   The horde application installation directory.

Optional options:
  --copy        Do not create symbolic links, but actually copy the libraries
                (this is done automatically on Windows).
  --debug       Output debug indormation.
  --dryrun      Perform a dry run (don't copy/link any files).
  --pkg DIR     Path to a single package to install.
  --src DIR     The source directory for the framework libraries.

USAGE;
    exit;
}
